AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Machine code functions: Bit Wizardry
Goto page 1, 2, 3 ... 11, 12, 13  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Laszlo



Joined: 14 Feb 2005
Posts: 3958
Location: Pittsburgh

PostPosted: Mon Jul 16, 2007 4:31 am    Post subject: Machine code functions: Bit Wizardry Reply with quote

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
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 5697

PostPosted: Mon Jul 16, 2007 5:50 am    Post subject: Reply with quote

Amazing! Surprised
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 3958
Location: Pittsburgh

PostPosted: Mon Jul 16, 2007 6:27 am    Post subject: Reply with quote

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
View user's profile Send private message
Washboard
Guest





PostPosted: Mon Jul 16, 2007 9:30 am    Post subject: Reply with quote

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

PostPosted: Mon Jul 16, 2007 9:48 am    Post subject: Reply with quote

What more to say?
BTW, I'm proud of being the one who requested the function pointer support in DllCall.
Back to top
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 5697

PostPosted: Mon Jul 16, 2007 9:54 am    Post subject: Reply with quote

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:


Rolling Eyes Smile


Last edited by SKAN on Tue Jul 17, 2007 4:16 am; edited 1 time in total
Back to top
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 5697

PostPosted: Mon Jul 16, 2007 9:54 am    Post subject: Reply with quote

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 Very Happy
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 3958
Location: Pittsburgh

PostPosted: Mon Jul 16, 2007 5:30 pm    Post subject: Lightning fast Bin2Hex: Reply with quote

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
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 3958
Location: Pittsburgh

PostPosted: Mon Jul 16, 2007 5:52 pm    Post subject: Wrapper for Bin2Hex Reply with quote

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
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 3958
Location: Pittsburgh

PostPosted: Mon Jul 16, 2007 9:34 pm    Post subject: Reply with quote

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
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 3958
Location: Pittsburgh

PostPosted: Tue Jul 17, 2007 12:10 am    Post subject: Reply with quote

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
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 5697

PostPosted: Tue Jul 17, 2007 5:35 am    Post subject: Reply with quote

Thanks Sir!. Very Happy 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 Sad . Please point it out.

PS: Any particular reason that the function accepts parameters different from the DLL ?
Back to top
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 5697

PostPosted: Tue Jul 17, 2007 6:02 am    Post subject: Reply with quote

This is where I got the BinToHex.DLL : http://www.softcircuits.com/sw_tools.htm Smile

Edit: 20080305

That link is broken
Working one : http://www.softcircuits.com/sw_tools.aspx


Last edited by SKAN on Wed Mar 05, 2008 2:27 pm; edited 1 time in total
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 3958
Location: Pittsburgh

PostPosted: Tue Jul 17, 2007 6:09 am    Post subject: Reply with quote

It works for me. What is the problem you get?
Back to top
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 5697

PostPosted: Tue Jul 17, 2007 6:15 am    Post subject: Reply with quote

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

Rolling Eyes
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page 1, 2, 3 ... 11, 12, 13  Next
Page 1 of 13

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group