 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Laszlo
Joined: 14 Feb 2005 Posts: 3958 Location: Pittsburgh
|
Posted: Mon Jul 16, 2007 4:31 am Post subject: Machine code functions: Bit Wizardry |
|
|
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: | Code: | 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. | Code: | | MCode(BSwap16,"8AE18AC5C3") | We can call it the ususal way: | Code: | | 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.) With a disassembler you can get the machine code in hex format, to be copied into the AHK script. I used Sang Cho's very simple and fast disasm.exe: http://www.geocities.com/~sangcho/disasm.html.
See here instructions for using the free VS'05/08 express compiler alone, w/o disassembler.
Here is a collection of low level bit manipulation functions, which I used for experimenting with random number generator designs. | Code: | 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: | Code: | 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: | Code: | | 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: | Code: | 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
Last edited by Laszlo on Mon Jan 07, 2008 10:42 pm; edited 2 times in total |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5697
|
Posted: Mon Jul 16, 2007 5:50 am Post subject: |
|
|
Amazing!  |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 3958 Location: Pittsburgh
|
Posted: Mon Jul 16, 2007 6:27 am Post subject: |
|
|
| 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. |
|
| Back to top |
|
 |
Washboard Guest
|
Posted: Mon Jul 16, 2007 9:30 am Post subject: |
|
|
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. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 1279
|
Posted: Mon Jul 16, 2007 9:48 am Post subject: |
|
|
What more to say?
BTW, I'm proud of being the one who requested the function pointer support in DllCall. |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5697
|
Posted: Mon Jul 16, 2007 9:54 am Post subject: |
|
|
| Laszlo wrote: | | 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:
| Code: | FileGetSize, dataSz , %A_AhkPath%
FileRead , binData, %A_AhkPath%
VarSetCapacity( hexData, dataSz*3+1 )
DllCall( "BINTOHEX.DLL\BinToHex", 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:

Last edited by SKAN on Tue Jul 17, 2007 4:16 am; edited 1 time in total |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5697
|
Posted: Mon Jul 16, 2007 9:54 am Post subject: |
|
|
| Sean wrote: | | I'm proud of being the one who requested the function pointer support in DllCall. |
.. and I am grateful to you for that  |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 3958 Location: Pittsburgh
|
Posted: Mon Jul 16, 2007 5:30 pm Post subject: Lightning fast Bin2Hex: |
|
|
I compiled the following C code (with the obvious typedefs) | Code: | 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: | Code: | 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
Last edited by Laszlo on Mon Jul 16, 2007 9:58 pm; edited 1 time in total |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 3958 Location: Pittsburgh
|
Posted: Mon Jul 16, 2007 5:52 pm Post subject: Wrapper for Bin2Hex |
|
|
Here is a standalone (wrapper) version, which does not even need the MCode function: | Code: | 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.
Last edited by Laszlo on Mon Jul 16, 2007 10:04 pm; edited 2 times in total |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 3958 Location: Pittsburgh
|
Posted: Mon Jul 16, 2007 9:34 pm Post subject: |
|
|
I had to deviate from Skan's dll code above, because it contains a non-portable data reference: | Code: | | 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: | 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: | Code: | | 8B4C2404578B7C241085FF7E30568B7424108A168AC2C0E804463C0976040437EB02043080E20F88018AC2413C0976040437EB0204308801414F75D65EC601005FC3 |
|
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 3958 Location: Pittsburgh
|
Posted: Tue Jul 17, 2007 12:10 am Post subject: |
|
|
If you are after speed, not code size, the following C code could be faster: | 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;
*(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: | Code: | | 8B54240C85D2568B7424087E3A53578B7C24148A07478AC8C0E90480F9090F97C3F6DB80E30702D980C330240F881E463C090F97C1F6D980E10702C880C130880E464A75CE5F5BC606005EC3 |
|
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5697
|
Posted: Tue Jul 17, 2007 5:35 am Post subject: |
|
|
Thanks Sir!. The standalone version works great, but I have trouble in adapting to the MCode() :
| Code: | 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 ? |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5697
|
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 3958 Location: Pittsburgh
|
Posted: Tue Jul 17, 2007 6:09 am Post subject: |
|
|
| It works for me. What is the problem you get? |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5697
|
Posted: Tue Jul 17, 2007 6:15 am Post subject: |
|
|
| Laszlo wrote: | | 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
 |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|