Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Machine code functions: Bit Wizardry


  • Please log in to reply
144 replies to this topic
Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
In AHK v1.0.46.08+, the 1st parameter of a DllCall can be an integer, the address of a function to call. If we copy the binary machine code of a function into an AHK variable, its addresses can be used in DllCalls, executing our machine code function. For convenience we use hex digits for the code, and write a simple function, which allocates also the necessary memory:
MCode(ByRef code, hex) { ; allocate memory and write Machine Code there
   VarSetCapacity(code,StrLen(hex)//2)
   Loop % StrLen(hex)//2
      NumPut("0x" . SubStr(hex,2*A_Index-1,2), code, A_Index-1, "Char")
}
For example, the following line stores the code of the function swapping the bytes of short (16-bit) value.
MCode(BSwap16,"8AE18AC5C3")
We can call it the ususal way:
MsgBox % dllcall(&BSwap16, "short",0x1234, "cdecl ushort")
The result is 0x3412 in hex form. These do not involve any external dll's, so swapping bytes is almost as fast as if it was a built-in function. We can extend the list of built-in function arbitrarily.

There is a slight difficulty: the function has to be programmed in i386 machine code. However, any programming language can be used, which exports (C or standard call) functions in a dll or static library, or get the function from a public dll file. I used Visual C++ 2005 and gcc vers. 3.4.2, under MinGW. (Sometimes one, sometimes the other produces better code.)

Follow this link for information on converting C functions to machine code using Microsoft's free Visual C++ Express compilers.
Look at Jamie's mod of the script helping to extract machine code from the assembler listing. Of course, one can use a disassembler, too, to get the machine code in hex format, to be copied into the AHK script.


Here is a collection of low level bit manipulation functions, which I used for experimenting with random number generator designs.
MCode(MSb32,"5589E58B45085D0FBDC0C3")
MCode(LSb32,"5589E58B45085D0FBCC0C3")
MCode(SHR32,"8B4424048B4C2408D3F8C3")
MCode(SRL64,"8B4C240C83E13F83F92073108B4424048B5424080FADD0D3EAC20C00") ; 64-bit Shift-Right-Logical (unsigned,standard call)
MCode(ROL32,"5589E58B45088B4D0C5DD3C0C3") ; Rotate Left  32 bits (unsigned)
MCode(ROR32,"5589E58B45088B4D0C5DD3C8C3") ; Rotate Right 32 bits (unsigned)
MCode(ROL64,"5589E583EC0C891C248B5D08897424048B750C89D8897C24088B7D1089F289F9D3E00FA5DAF6C120740489C231C0B94"
. "000000029F90FADF3D3EEF6C120740489F331F609D809F28B1C248B7424048B7C240889EC5DC3")
MCode(ROR64,"5589E583EC0C891C248B5D08897424048B750C89D8897C24088B7D1089F289F9D3EA0FADF0F6C120740489D031D2B94"
. "000000029F90FA5DED3E3F6C120740489DE31DB09D809F28B1C248B7424048B7C240889EC5DC3")
MCode(BSwap16,"8AE18AC5C3")
MCode(BSwap32,"8BC10FC8C3") ; Byte Swap (little <--> big endian)
MCode(BSwap64,"8B5424088B4424040FCA0FC88BC88BC28BD1C3")
MCode(Parity64,"8B4C2408334C24048BC1D1E833C88BC1C1E80233C88BC1C1E80433C88BC1C1E80833C88BC1C1E81033C183E001C3")
MCode(Parity32,"8B4C24048BC1D1E833C88BC1C1E80233C88BC1C1E80433C88BC1C1E80833C88BC1C1E81033C183E001C3")
MCode(Parity16,"5589E50FB755085D89D0D1E831D089C1C1E90231C189C8C1E80431C889C2C1EA0831D083E001C3")
MCode(Parity8,"8A4424048AC8D0E932C18AC8C0E90232C10FB6C88BC1C1E80433C183E001C3")
MCode(BitRev32,"5589E58B4D085D89C8255555555581E1AAAAAAAA01C0D1E909C889C281E23333333325CCCCCCCCC1E202C1E80209"
. "C289D0250F0F0F0F81E2F0F0F0F0C1E004C1EA0409D00FC8C3")
MCode(BitCnt32,"8B4C24048BC1D1E825555555552BC88BC1C1E802BA3333333323C223CA03C18BC8C1E90403C881E10F0F0F0F8BC1"
. "C1E80803C88BC1C1E81003C125FF000000C3")
MCode(BitZip32,"8B44240433C98A6C24068BD025FF0000FF81E200FF000056C1E2080BCA0BC88BC18BF1C1E804BAF000F00023F223"
. "C2C1E6040BC681E10FF00FF00BC18BC88BF0BA0C0C0C0C23F2C1E902C1E60223CA0BCE25C3C3C3C30BC88BC1BA222222228BF1D1E823F223C203F60BC681E1999999990BC15EC3")
MCode(BitUnZip32,"8B4C2404568BC18BF1D1E881E199999999BA2222222223C223F203F60BC60BC18BC88BF0C1E902BA0C0C0C0C23"
. "F223CA25C3C3C3C3C1E6020BCE0BC88BC18BF1C1E804BAF000F00023C223F2C1E6040BC681E10FF00FF00BC18944240833C98A6C240A8BD081E200FF0000C1E20825FF0000FF5E0BCA0BC1C3")
MCode(I2Gray32,"8B442404D1E833442404C3")
MCode(Gray2I32,"8B4C24048BC1D1E833C88BC1C1E80233C88BC1C1E80433C88BC1C1E80833C88BC1C1E81033C1C3")
MCode(NextGray32,"5589E58B4D085389C88D1C09D1E831C889C2C1EA0231C289D0C1E80431D089C2C1EA0831C289D0C1E81031D031"
. "D2A8010F94C209DA5B89D0F7D821D031C85DC3")
The functions:
MSb32: finds the index of the most significant bit in a 32-bit unsigned integer
LSb32: finds the index of the least significant bit in a 32-bit unsigned integer
SHR32: arithmetic shift-right of a 32-bit signed integer (keeping negative results)
SRL64: 64-bit Shift-Right-Logical (unsigned), which shifts in 0's from the left
ROL32: Rotate Left 32 bits (unsigned)
ROR32: Rotate Right 32 bits (unsigned)
ROL64: Rotate Left 64 bits (unsigned)
ROR64: Rotate Right 64 bits (unsigned)
BSwap16: Swaps the two bytes of a 16-bit number
BSwap32: Reverse the byte order of 32-bit numbers (little <--> big endian)
BSwap64: Reverse the byte order of 64-bit numbers
Parity8/16/32/64: Computes the parity (0 if there is an even number of 1-bits, 1 is otherwise)
BitRev32: Reverses the sequence of bits in a 32-bit number
BitCnt32: Counts the number of 1-bits in a 32-bit number
BitZip32/BitUnZip32: UnZip: Moves the odd indexed bits to the MS bytes, the even indexed bits to the LS bytes / Zip: reverses this
I2Gray32/ Gray2I32: converts a 32-bit integer to the corresponding Gray code or back
NextGray32: gives the next Gray code (Gray counter)

Another important application of the machine code functions is array searching and sorting. The C runtime library (msvcrt.dll) exports the necessary procedures: _lsearch, _lfind, bsearch and qsort. They require a callback function for the comparison. If we use an AHK function, it will be several hundred times slower than with machine code. For the most common case here are the comparison callbacks:
MCode(LI8,"8B4424048A008B4C24088A0933D23AC1530F9FC233DB3AC10F9CC32BD38BC25BC3")
MCode(GI8,"8B4424048A008B4C24088A0933D23AC1530F9CC233DB3AC10F9FC32BD38BC25BC3")
MCode(LU8,"8B4424040FB6088B4424088A103AD11BC0F7D83ACA1BC9F7D92BC1C3")
MCode(GU8,"8B4424040FB6088B4424088A103ACA1BC0F7D83AD11BC9F7D92BC1C3")

MCode(LI16,"5589E58B55088B450C5D0FB70A0FB71031C06639D10F9FC06639D10F9CC10FB6D129D0C3")
MCode(GI16,"5589E58B55088B450C5D0FB70A0FB71031C06639D10F9CC06639D10F9FC10FB6D129D0C3")
MCode(LU16,"8B4424040FB7088B4424080FB710663BD11BC0F7D8663BCA1BC9F7D92BC1C3")
MCode(GU16,"8B4424040FB7088B4424080FB710663BCA1BC0F7D8663BD11BC9F7D92BC1C3")

MCode(LI32,"5589E58B55088B450C5D8B0A8B1031C039D10F9FC039D10F9CC10FB6D129D0C3")
MCode(GI32,"5589E58B55088B450C5D8B0A8B1031C039D10F9CC039D10F9FC10FB6D129D0C3")
MCode(LU32,"8B4424048B088B4424088B103BD11BC0F7D83BCA1BC9F7D92BC1C3")
MCode(GU32,"8B4424048B088B4424088B103BCA1BC0F7D83BD11BC9F7D92BC1C3")

MCode(LI64,"8B4424048B4C24088B108B4004568B318B49043BC1577C0B7F043BD6760533FF47EB0233FF3BC17F0B7C043BD6730533"
. "C941EB0233C98BC75F2BC15EC3")
MCode(GI64,"8B4424048B4C24088B108B4004568B318B49043BC1577F0B7C043BD6730533FF47EB0233FF3BC17C0B7F043BD6760533"
. "C941EB0233C98BC75F2BC15EC3")
MCode(LU64,"8B4424048B4C24088B108B4004568B318B49043BC157720B77043BD6760533FF47EB0233FF3BC1770B72043BD6730533"
. "C941EB0233C98BC75F2BC15EC3")
MCode(GU64,"8B4424048B4C24088B108B4004568B318B49043BC157770B72043BD6730533FF47EB0233FF3BC1720B77043BD6760533"
. "C941EB0233C98BC75F2BC15EC3")
Here the first letter tells that Less-than or Greater-than type of comparison is used. The second letter tells if (signed) Integer or Unsigned comparisons are used, and the trailing number tells the precision, the width of the elements in the array. Here is an example:
dllcall("msvcrt\qsort", "UInt",&Array, "UInt",10, "UInt",1, "UInt",&GI8)
We sort an array of 10 signed bytes, such that greater values come first (GI8).

Below is a list of test cases, with the expected result in the comment:
a0 := 0, NumPut( 0,a0,0,"Char")
a5 := 0, NumPut( 5,a5,0,"Char")
af := 0, NumPut(-1,af,0,"Char")
MsgBox % dllcall(&LU8, "uint",&a0, "uint",&a5, "cdecl int") ; -1
MsgBox % dllcall(&LU8, "uint",&a5, "uint",&af, "cdecl int") ; -1
MsgBox % dllcall(&LU8, "uint",&a5, "uint",&a5, "cdecl int") ;  0

MsgBox % dllcall(&LI8, "uint",&a0, "uint",&a5, "cdecl int") ; -1
MsgBox % dllcall(&LI8, "uint",&a5, "uint",&af, "cdecl int") ;  1
MsgBox % dllcall(&LI8, "uint",&a5, "uint",&a5, "cdecl int") ;  0

MsgBox % dllcall(&GI8, "uint",&a0, "uint",&a5, "cdecl int") ;  1
MsgBox % dllcall(&GI8, "uint",&a5, "uint",&af, "cdecl int") ; -1
MsgBox % dllcall(&GI8, "uint",&a5, "uint",&a5, "cdecl int") ;  0

VarSetCapacity(a0,8,0), NumPut( 0,a0,0,"Int64")
VarSetCapacity(a5,8,0), NumPut(55,a5,0,"Int64")
VarSetCapacity(af,8,0), NumPut(-1,af,0,"Int64")
MsgBox % dllcall(&GI64, "uint",&a0, "uint",&a5, "cdecl int") ;  1
MsgBox % dllcall(&GI64, "uint",&a5, "uint",&a0, "cdecl int") ; -1
MsgBox % dllcall(&GI64, "uint",&a0, "uint",&a0, "cdecl int") ;  0
MsgBox % dllcall(&GU64, "uint",&a5, "uint",&af, "cdecl int") ;  1

VarSetCapacity(Array,10,0)
Loop 8
   NumPut(88-9*A_Index,Array,A_Index,"Char")
NumPut(-1,Array,5,"Char")

dllcall("msvcrt\qsort", "UInt",&Array, "UInt",10, "UInt",1, "UInt",&GI8) ; decending-signed order

s := NumGet(Array,0,"Char")
Loop 9
   s .= ", " . NumGet(Array,A_Index,"Char")
MsgBox %s%     ; 79, 70, 61, 52, 34, 25, 16, 0, 0, -1

VarSetCapacity(Array,80,0)
Loop 9
   NumPut(100000000000-10000000000*A_Index,Array,8*A_Index,"Int64")
NumPut(-1,Array,5*8,"Int64")

dllcall("msvcrt\qsort", "UInt",&Array, "UInt",10, "UInt",8, "UInt",&LU64) ; ascending-unsigned order

s := NumGet(Array,0,"Int64")
Loop 9
   s .= "," . NumGet(Array,8*A_Index,"Int64")
MsgBox %s% ;0,10000000000,20000000000,30000000000,40000000000,60000000000,70000000000,80000000000,90000000000,-1

SetFormat Integer, HEX

MsgBox % x:=dllcall(&NextGray32, "uint", 8, "cdecl uint") ; 0x18
MsgBox % x:=dllcall(&NextGray32, "uint", x, "cdecl uint") ; 0x19
MsgBox % x:=dllcall(&NextGray32, "uint", x, "cdecl uint") ; 0x1B
MsgBox % x:=dllcall(&NextGray32, "uint", x, "cdecl uint") ; 0x1A

MsgBox % dllcall(&Gray2I32, "uint", 0x08, "cdecl uint") ; 0x0f
MsgBox % dllcall(&Gray2I32, "uint", 0x18, "cdecl uint") ; 0x10
MsgBox % dllcall(&Gray2I32, "uint", 0x19, "cdecl uint") ; 0x11
MsgBox % dllcall(&Gray2I32, "uint", 0x1B, "cdecl uint") ; 0x12

MsgBox % dllcall(&I2Gray32, "uint", 0x0f, "cdecl uint") ; 0x08
MsgBox % dllcall(&I2Gray32, "uint", 0x10, "cdecl uint") ; 0x18
MsgBox % dllcall(&I2Gray32, "uint", 0x11, "cdecl uint") ; 0x19
MsgBox % dllcall(&I2Gray32, "uint", 0x12, "cdecl uint") ; 0x1B

MsgBox % dllcall(&BitZip32, "uint", 0x0000ffff, "cdecl uint") ; 0x55555555 Merge MS and LS half words (bit0 stays)
MsgBox % dllcall(&BitUnZip32,"uint",0xaaaaaaaa, "cdecl uint") ; 0xffff0000 Odd index bits . Even index bits

MsgBox % dllcall(&BitCnt32, "uint", 0, "cdecl uint")          ; 0
MsgBox % dllcall(&BitCnt32, "uint", 0x01010101, "cdecl uint") ; 4
MsgBox % dllcall(&BitCnt32, "uint", 0xffffffff, "cdecl uint") ; 32

MsgBox % dllcall(&BitRev32, "uint", 0x12345678, "cdecl uint") ; 0x1E6A2C48

MsgBox % dllcall(&Parity64, "int64", 0x0800000010001234, "cdecl uint") ; 1
MsgBox % dllcall(&Parity64, "int64", 0x0200000010001235, "cdecl uint") ; 0

MsgBox % dllcall(&Parity32, "uint", 0x10001234, "cdecl uint") ; 0
MsgBox % dllcall(&Parity32, "uint", 0x10001235, "cdecl uint") ; 1

MsgBox % dllcall(&Parity16, "ushort", 0x1234, "cdecl uint") ; 1
MsgBox % dllcall(&Parity16, "ushort", 0x1235, "cdecl uint") ; 0

MsgBox % dllcall(&Parity8, "uchar", 0, "cdecl uint")    ; 0
MsgBox % dllcall(&Parity8, "uchar", 1, "cdecl uint")    ; 1
MsgBox % dllcall(&Parity8, "uchar", 7, "cdecl uint")    ; 1
MsgBox % dllcall(&Parity8, "uchar", 0x12, "cdecl uint") ; 0

MsgBox % dllcall(&ROL32, "uint", 0x12345678, "UInt",4, "cdecl uint") ; 0x23456781
MsgBox % dllcall(&ROR32, "uint", 0x12345678, "UInt",4, "cdecl uint") ; 0x81234567

MsgBox % dllcall(&ROL64, "int64", 0x2000000000000020, "UInt",1, "cdecl int64") ; 0x400..0040
MsgBox % dllcall(&ROL64, "int64",-4, "UInt",2, "cdecl int64")                  ; -13 = -0xD (-4*4 + 3(MS))
MsgBox % dllcall(&ROL64, "int64", 0x34567890abcdef12, "UInt",4, "cdecl int64") ; 0x4567890abcdef123

MsgBox % dllcall(&ROR64, "int64", 0x4000000000000020, "UInt",1, "cdecl int64") ; 0x200..0010
MsgBox % dllcall(&ROR64, "int64",-4, "UInt",2, "cdecl int64")                  ; 0x3fffffffffffffff
MsgBox % dllcall(&ROR64, "int64", 0x34567890abcdef12, "UInt",4, "cdecl int64") ; 0x234567890abcdef1

MsgBox % dllcall(&LSb32, "Int",0x81234567, "cdecl UInt") ; 0
MsgBox % dllcall(&LSb32, "Int",0x01234560, "cdecl UInt") ; 5
MsgBox % dllcall(&LSb32, "Int",16, "cdecl UInt")         ; 4
MsgBox % dllcall(&LSb32, "Int",0, "cdecl UInt")          ; 0

MsgBox % dllcall(&MSb32, "Int",0x81234567, "cdecl UInt") ; 31 (0x1f)
MsgBox % dllcall(&MSb32, "Int",0x01234567, "cdecl UInt") ; 24 (0x18)
MsgBox % dllcall(&MSb32, "Int",1, "cdecl UInt")          ; 0
MsgBox % dllcall(&MSb32, "Int",0, "cdecl UInt")          ; 0

MsgBox % dllcall(&SHR32, "Int",0x81234567, "UInt",1, "cdecl UInt")    ; 0xC091a2b3

MsgBox % dllcall(&BSwap16, "short",0x1234, "cdecl ushort")            ; 0x3412
MsgBox % dllcall(&BSwap32, "int",  0x12345678, "cdecl uint")          ; 0x78563412
MsgBox % dllcall(&BSwap64, "int64",0x34567890abcdef12, "cdecl int64") ; 0x12efcdab90785634

MsgBox % dllcall(&SRL64, "int64", 0x34567890abcdef12, "UInt",4, "int64") ; 0x034567890abcdef1 (standard call)
MsgBox % dllcall(&SRL64, "int64",-0x8000000000000000, "UInt",2, "int64") ; 0x2000000000000000

There is an excellent collection of useful C functions collected by Jörg Arndt: The FXT library: Fast transforms and low level algorithms. Some of the functions above were adapted from the FXT book.

Below you find Bin2Hex, another small machine code function. It converts binary data to hex strings.

See here the CPUID function, which is a 27 byte AHK machine code wrapper for the CPUID command of Intel compatible processors. It tells everything about the CPU, its capabilities, version number, unique ID, etc. See here the returned values for different first parameter (the info selector).

Please post here your favorite machine code functions, so we can put together a large collection of useful ones!

Edit 20070903: added references to Bin2Hex and CPUID
Edit 20100621: removed reference to a now obsolete disassembler

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Amazing! :O

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Thanks! If someone has a need for very fast, short functions, post the request here, with proper description. There could be a volunteer, who might code it.

Washboard
  • Guests
  • Last active:
  • Joined: --
Seems to be very usefull, but very far of my knowledge...
I think that binary tree and data sorting functions would be interesting to implement.
Thanks for the hard work.

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007
What more to say?
BTW, I'm proud of being the one who requested the function pointer support in DllCall.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

If someone has a need for very fast, short functions, post the request here, with proper description.


Sir, I would like to know whether BinToHex.DLL ( 3KB - Assembly ) can be absorbed into a script to avoid dependency.

Function call - working example:

FileGetSize, dataSz , %A_AhkPath%
FileRead   , binData, %A_AhkPath%
VarSetCapacity( hexData, dataSz*3[color=red]+1[/color] )

DllCall( "[color=red]BINTOHEX.DLL\BinToHex[/color]", Str,binData, Str,hexData, UInt,dataSz )
StringReplace, hexData, hexData, % A_Space,, All ; Remove all spaces
MsgBox, % hexData

Disassembled with DisAsm : BinToHex.TXT ( 6.4KB )

Snapshot:
Posted Image

:roll: :)

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

I'm proud of being the one who requested the function pointer support in DllCall.


.. and I am grateful to you for that :D

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
I compiled the following C code (with the obvious typedefs)
void Bin2Hex0(UInt8 *hex, UInt8 *bin, UInt32 len) { // in hex room for 2*len+1 bytes 
    UInt8 c, d, *end = bin+len; 
    while (bin < end) { 
        c = *(bin++); 
        d = c >> 4; 
        *(hex++) = d + (d>9 ? 55 : 48); 
        d = c & 15; 
        *(hex++) = d + (d>9 ? 55 : 48); 
    } 
    *hex = 0; 
}
The resulting machine code function with the calling example:
MCode(Bin2Hex,"8B44240C568B742408578B7C24108D14073BFA7332538A07478AC8C0E904B3093AD91ADB80E30780C3"
. "3002D9240F881E46B1093AC81AC980E10780C13002C8880E463BFA72D05B5FC606005EC3")

bin := "123", VarSetCapacity(hex,9)
dllcall(&Bin2Hex, "uint",&hex, "uint",&bin, "uint",4, "cdecl")
VarSetCapacity(hex,-1) ; update StrLen
MsgBox %hex%           ; 31323300

Edit: fixed constants

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Here is a standalone (wrapper) version, which does not even need the MCode function:
Bin2Hex(addr,len) {
   Static fun
   If (fun = "") {
      h=8B4C2404578B7C241085FF7E30568B7424108A168AC2C0E804463C0976040437EB02043080E20F88018AC2413C0976040437EB0204308801414F75D65EC601005FC3
      VarSetCapacity(fun,StrLen(h)//2)
      Loop % StrLen(h)//2
         NumPut("0x" . SubStr(h,2*A_Index-1,2), fun, A_Index-1, "Char")
   }
   VarSetCapacity(hex,2*len+1)
   dllcall(&fun, "uint",&hex, "uint",addr, "uint",len, "cdecl")
   VarSetCapacity(hex,-1) ; update StrLen
   Return hex
}

bin = 123
MsgBox %  Bin2Hex(&bin,4)
At the very first call to the Bin2Hex function, it creates the binary machine code in the static variable fun. Later calls just use this already stored code, so all the dirty details remain hidden from the user.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
I had to deviate from Skan's dll code above, because it contains a non-portable data reference:
BB00300010              mov ebx, 10003000
It is hard to guess, what an optimizing compiler (VS'05) does with different code versions. I tried a few variants, and the following (longer) C function resulted in 11 bytes shorter machine code:
void Bin2Hex(UInt8 *hex, UInt8 *bin, Int32 len) { // in hex room for 2*len+1 bytes
   Int32 i; UInt8 c, d;
   for (i=0; i<len; ++i) {
       c = *(bin++);
       d = c >> 4;
       if (d > 9) *(hex++) = d + 55;
       else       *(hex++) = d + 48;
       d = c & 15;
       if (d > 9) *(hex++) = d + 55;
       else       *(hex++) = d + 48;
   }
   *hex = 0;
}
The machine code is:
8B4C2404578B7C241085FF7E30568B7424108A168AC2C0E804463C0976040437EB02043080E20F88018AC2413C0976040437EB0204308801414F75D65EC601005FC3


Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
If you are after speed, not code size, the following C code could be faster:
void Bin2Hex(UInt8 *hex, UInt8 *bin, Int32 len) { // in hex room for 2*len+1 bytes

   Int32 i; UInt8 c, d;

   for (i=0; i<len; ++i) {

        c = *(bin++);

        d = c >> 4;

        *(hex++) = d+48 + (7 & -(d>9));

        d = c & 15;

        *(hex++) = d+48 + (7 & -(d>9));

    }

    *hex = 0;

}
It trades conditional statements to arithmetic and logic instructions, which can prevent a pipeline flush in the processor. Indexing an array may also prevent parallel execution of some instructions. The corresponding machine code (generated by VS'05) is:
8B54240C85D2568B7424087E3A53578B7C24148A07478AC8C0E90480F9090F97C3F6DB80E30702D980C330240F881E463C090F97C1F6D980E10702C880C130880E464A75CE5F5BC606005EC3


SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Thanks Sir!. :D The standalone version works great, but I have trouble in adapting to the MCode() :

FileGetSize, dataSz , %A_AhkPath%
FileRead   , bin    , %A_AhkPath%
VarSetCapacity( hex, dataSz*2+1 )

Bin2Hex_v1:="8B4C2404578B7C241085FF7E30568B7424108A168AC2C0E804463C0976040437EB02043080E20F88018AC2413C0976040437EB0204308801414F75D65EC601005FC3"
Bin2Hex_v2:="8B54240C85D2568B7424087E3A53578B7C24148A07478AC8C0E90480F9090F97C3F6DB80E30702D980C330240F881E463C090F97C1F6D980E10702C880C130880E464A75CE5F5BC606005EC3"

MCode( Bin2Hex, Bin2Hex_v1  )
DllCall( &Bin2Hex, "uint",&hex, "uint",&bin, "uint",dataSz, "cdecl" ) 
MsgBox, %hex%

Return

MCode(ByRef code, hex) { ; allocate memory and write Machine Code there
   VarSetCapacity(code,StrLen(hex)//2)
   Loop % StrLen(hex)//2
      NumPut("0x" . SubStr(hex,2*A_Index-1,2), code, A_Index-1, "Char")
}

I am missing something obvious :( . Please point it out.

PS: Any particular reason that the function accepts parameters different from the DLL ?

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
This is where I got the BinToHex.DLL : <!-- m -->http://www.softcircu...om/sw_tools.htm<!-- m --> :)

Edit: 20080305

That link is broken
Working one : <!-- m -->http://www.softcircu...m/sw_tools.aspx<!-- m -->

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
It works for me. What is the problem you get?

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

What is the problem you get?


%Hex% appears to be null.
errorlevel is 0 after the DllCall()
OS: Win XP SP2
AHK : 1.0.47.00

:roll: