AutoHotkey Community

It is currently May 25th, 2012, 11:39 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 356 posts ]  Go to page 1, 2, 3, 4, 5 ... 24  Next
Author Message
PostPosted: July 16th, 2007, 4:31 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
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.)

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.
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
Edit 20100621: removed reference to a now obsolete disassembler


Last edited by Laszlo on June 21st, 2010, 8:34 pm, edited 3 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 5:50 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8775
Amazing! :o


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 6:27 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 9:30 am 
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.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 9:48 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
What more to say?
BTW, I'm proud of being the one who requested the function pointer support in DllCall.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 9:54 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8775
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:
Image

:roll: :)


Last edited by SKAN on July 17th, 2007, 4:16 am, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 9:54 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8775
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 :D


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Lightning fast Bin2Hex:
PostPosted: July 16th, 2007, 5:30 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
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 July 16th, 2007, 9:58 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject: Wrapper for Bin2Hex
PostPosted: July 16th, 2007, 5:52 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
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 July 16th, 2007, 10:04 pm, edited 2 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 16th, 2007, 9:34 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2007, 12:10 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2007, 5:35 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8775
Thanks Sir!. :D 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 ?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2007, 6:02 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8775
This is where I got the BinToHex.DLL : http://www.softcircuits.com/sw_tools.htm :)

Edit: 20080305

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


Last edited by SKAN on March 5th, 2008, 2:27 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2007, 6:09 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
It works for me. What is the problem you get?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 17th, 2007, 6:15 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8775
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

:roll:


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 356 posts ]  Go to page 1, 2, 3, 4, 5 ... 24  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: JamixZol, Morpheus and 29 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group