 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Lexikos
Joined: 17 Oct 2006 Posts: 7299 Location: Australia
|
Posted: Fri Mar 21, 2008 12:45 am Post subject: |
|
|
It is even possible to load a DLL from memory, so I wouldn't rule this out...
| Quote: | | Usually, branches (like goto) are self-relative, but function calls are absolute | I think this is typically only true of imported functions. I'd post an example demonstrating that basic calls are relative, but it is too boring. From script2.cpp, BIF_RegisterCallback:
| Code: | // ... In essence:
// call xxx ; is relative
// call [ptr_xxx] ; is position independent
// Typically the latter is used when calling imported functions, etc., as only the pointers (import table),
// need to be adjusted, not the calls themselves... |
|
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Fri Mar 21, 2008 2:19 am Post subject: |
|
|
| In my experiences with floating point functions VS’05 generated relative calls to functions for each arithmetic operation, but they were scattered around in the code. One could copy the referenced ones after the user function, but patching the addresses is tedious. Also, some of the library functions call each other, which necessitate further address patches. After a couple days of struggle I gave up, and wrote my own little library, but either way it is a lot of work. Automating it is like writing a little private linker. |
|
| Back to top |
|
 |
Azerty
Joined: 19 Dec 2006 Posts: 72 Location: France
|
Posted: Fri Mar 21, 2008 8:21 am Post subject: |
|
|
Of course, everything is possible using a computer (please note italics, take the sentence correcly, my computer doesn't wash my underwear...), but at what cost ? The URL you pointed is very interesting, but the code is still beta (v0.0.2)... and is 16 Kbytes C source... To translate it in AHK will for sure be possible, but what will the cost (in CPU cycles) be ?...
Though when I have time, I might dig it further to make an MCoded AHK lib...
| Laszlo wrote: | | ... but they were scattered around in the code ... |
Might be due to optimization : I've studied the way VC works when compiling in RELEASE mode : it takes into account the CPU costs of memory accesses, so for instance, if you memset(mem,size,0) with size arg being low (20 or 30 for instance), the optimizer inlines it into several MOV which are in disorder, probably to optimize L1 cache usage. If you want code to be consistant and readable, better export DEBUG mode generated code. |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 8688
|
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 8688
|
Posted: Sat Mar 22, 2008 6:45 am Post subject: |
|
|
| Azerty wrote: | To translate it in AHK will for sure be possible, but what will the cost (in CPU cycles) be ?...
Though when I have time, I might dig it further to make an MCoded AHK lib... |
I compiled MemoryModule and the resultant file was 152 KB !!!
As is, it is unusable from AHK. It would be fantastic If some one can make it work, and also shrink the machine code to 50-100 K.
50K for this DLL Loader ( Loaded as a Resource )
50K for some useful external DLL ( Loaded as a Resource )
200K regular AHK Executable overhead
.. would still result in a no-dependency-whatsoever-standalone-executable under half MB.
Please share my enthusiasm.  |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Sat Mar 22, 2008 8:28 pm Post subject: base64 en/decode |
|
|
Here are my base64 conversion routines in C, using the decoding idea of Bob Trower, http://base64.sourceforge.net/b64.c. | Code: | void encode( UChar *src, UChar *dest, UInt32 linesize, const UChar *cb ) { // base64 encode with padding, line breaks
UChar in[3];
UInt32 i, len, blocksout = 0;
linesize >>= 2;
while( *src > 0 ) {
len = 0;
for( i = 0; i < 3; ++i ) {
in[i] = *src;
if( *src > 0) { ++len; ++src; }
else in[i] = 0;
}
*dest++ = cb[ in[0] >> 2 ];
*dest++ = cb[ ((in[0]<<4) | (in[1]>>4)) & 63];
*dest++ = len > 1 ? cb[ ((in[1]<<2) | (in[2]>>6)) & 63 ] : '=';
*dest++ = len > 2 ? cb[ in[2] & 63 ] : '=';
blocksout++;
if( blocksout >= linesize ) {
*dest++ = 10; // CR
blocksout = 0;
}
*dest = 0;
}
}
UInt32 decode( UChar *src, UChar *dest, const UChar *cd ) { // decode base64, discard padding, line breaks, noise
int i, len; UInt32 total = 0;
UChar in[4], v;
while( *src > 0) {
len = 0;
for( i = 0; (i < 4) && (*src > 0); ++i ) {
v = 0;
while( (*src > 0) && (v == 0) ) {
v = *src++;
v = ((v < 43) || (v > 122)) ? '$' : cd[v-43];
v = (v == '$') ? 0 : (v - 61);
}
if( v > 0 ) {
++len;
in[i] = v - 1;
}
else in[i] = 0;
}
if( len < 2) break;
*dest++ = in[0] << 2 | in[1] >> 4;
if (len > 2) *dest++ = in[1] << 4 | in[2] >> 2;
if (len > 3) *dest++ = in[2] << 6 | in[3];
total += len-1;
}
return total;
} | The compiled code in AHK is: | Code: | MCode(decode64, "558bec518365fc00568b75088a1684d20f86ac000000578b7d0c5333db33c0"
. "84d2764d32c984c975318aca80e92b4680f94f770c0fb6ca8b55108a4c11d5eb02b1240fb6d1"
. "80ea3d80f9240f94c1fec923ca8a1684d277cd84c9760943fec9884c0508eb05c64405080040"
. "83f8047caf83fb027c4b8a45098a4d08c0e102c0e8040ac18a4d0a88074783fb027e108a5509"
. "8ac1c0e802c0e2040ac288074783fb037e09c0e1060a4d0b880f478b45fc8a1684d28d4418ff"
. "8945fc0f875bffffff5b5f8b45fc5ec9c3")
MCode(encode64, "558bec51518b45088365f800c16d10028038000f86ac0000008b450c53568b"
. "75145733db33ff8b4d088a1184d28d4c3dfc8811760643ff4508eb03c601004783ff0372e20f"
. "b64dfc8bd1c1ea028a143288100fb655fdc1e1048bfac1ef040bf983e73f8a0c374088088a4d"
. "fe4083fb0176140fb6f9c1e202c1ef060bfa83e73f0fb61437eb036a3d5a88104083fb027609"
. "83e13f0fb60c31eb036a3d59880840ff45f88b4df83b4d107208c6000a408365f8008b4d08c6"
. "00008039000f8760ffffff5f5e5bc9c3") | It needs two small tables coded in strings: | Code: | CB=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
CD=|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\]^_``abcdefghijklmnopq | You can test it, by attaching the following commands to the above: | 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")
}
In =
( Join
Man is distinguished, not only by his reason, but by this singular passion from other animals,
which is a lust of the mind, that by a perseverance of delight in the continued and
indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.
)
Out =
(
TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0
aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1
c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0
aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdl
LCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=
)
VarSetCapacity(Out1,Ceil(StrLen(In)*(4/3+1/72)+1))
dllcall(&encode64, "UInt",&In, "str",Out1, "Uint",72, "str",CB, "CDECL")
MsgBox % (Out1==Out ? "Correct`n`n" : "Wrong`n`n") . Out1
VarSetCapacity(In1,ceil(StrLen(Out)*3/4)+1,0)
len := dllcall(&decode64, "str",Out, "UInt",&In1, "str",CD, "CDECL UINT")
VarSetCapacity(In1,-1)
MsgBox % "Length =" . len . " / ErrorLevel: " . ErrorLevel . "`n" . (In1==In ? "Correct`n`n" : "Wrong`n`n") . In1 |
|
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 8688
|
Posted: Sat Mar 22, 2008 9:14 pm Post subject: |
|
|
Many thanks Sir. I am grateful to you .. as always.
You example works fine..
One doubt: Is magic number 72 a variable ? I usually wrap my code at 90 chars and here - I believe this number should be divisible by both 4 and 3 ...
 |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Sat Mar 22, 2008 10:18 pm Post subject: |
|
|
| This number is divided by 4 to specify the number of 4-character blocks in a line. If you set it to 0xffffffff (-1), there will be no new lines. If you set it to 90, 88 characters will appear in every line, except the last one. |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 8688
|
Posted: Sat Mar 22, 2008 10:40 pm Post subject: |
|
|
Thanks for the clarification, Sir.
I will stress-test it and revert back by Monday.
I had been facing random problems with ASCII 85 .. like the first Char of any line in continuation section should not be ) etc..
But the real problem was intermittently created by the presence of =
I guess there should not be a problem with B64 since = will appear only on the tail of the last chunk..
Have a nice weekend.  |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Sat Mar 22, 2008 10:54 pm Post subject: |
|
|
| If you don’t want to follow the standard, you could easily modify the ascii85 algorithm: the first character used should be * (ascii 42), the last one is ~ (ascii126). This range is also 85 characters long, but avoids most of the problematic characters. The only thing you have to remember is to use literal backtick characters. For repeated 0's there are safe characters: $, !, etc. |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 8688
|
Posted: Sun Apr 06, 2008 8:15 am Post subject: |
|
|
@Laszlo:
Sir, it would be of immense help if we had a flip() function to deal with big-endian byte order ( motorola byte align )
I have been writing Exif Tag interpreter and exif tags can be encoded use any of the byte order. Excluding ascii data, 95% ( of the rest of data ) are ushort/ulong which I am able to deal with your BSwap16/BSwap32 mcode. But there is this "undefined" tag type on which TIFF specification does not imply any size limit. I am handling it like in the following example:
| Code: | flip( Var := "Quick", 5 )
MsgBox, % Var
flip( byref var, sz ) {
varsetcapacity( var2,sz )
loop %sz% ; move it to var2 in reverse order
numput( numget(var,a_index-1,"uchar"), var2, sz-a_index, "uchar" )
loop %sz% ; copy var2 to var1
numput( numget(var2,a_index-1,"uchar"), var, a_index-1,"uchar" )
varsetcapacity(var2,0)
return &var
} |
Overall, I find my code is slower when dealing with Motorola byte aligned jpeg files.
If you can give me mcode for flip, it should take care of all the needs.
Please help.
 |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Sun Apr 06, 2008 8:15 pm Post subject: |
|
|
The following C code was compiled: | Code: | rev_bytes(char* dest, char* source, int n) {
int i = 0, j = n;
for (;i<n;) dest[i++] = source[--j];
} | From AHK call it with | Code: | MCode(rev,"568b74241033c985f67e178b44240c03c6578b7c240c488a10881439413bce7cf15f5ec3")
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")
}
In = Quick
Out := In ; allocate memory with terminating NUL
dllcall(&rev,"UInt",&Out, "UInt",&In, "UInt",5, "CDECL") ; Reverse byte sequence
MsgBox % "[" Out "]" |
|
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 8688
|
Posted: Sun Apr 06, 2008 9:40 pm Post subject: |
|
|
Many thanks, Sir
I have one more request: Cannot my model Flip() be exactly reproduced ?
That is in/out should be the same variable ..
It would be very beneficial if the same variable is operated upon, as it would simplify my code much if the variable name stays the same. I cannot assign it back to the source variable as the contents would contain null.
The workaround I can think of: Use your memcpy mcode to assign the reversed contents back to the original var.. but I would be very happy if rev handles the memcpy itself.
Please help.  |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Sun Apr 06, 2008 11:12 pm Post subject: |
|
|
The C code for in-place reversal: | Code: | rev_bytes(char* d, int n) { // Reverse byte sequence
char t, *c = d+n;
while (c > d) { t = *--c; *c = *d; *d++ = t; }
} | From AHK call it with: | Code: | MCode(flip,"8b4c24048b44240803c13bc17610538a19488a1088188811413bc177f25bc3")
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")
}
In = Quick
dllcall(&flip,"UInt",&In, "UInt",5, "CDECL") ; Reverse byte sequence
MsgBox [%In%] |
|
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 8688
|
Posted: Mon Apr 07, 2008 12:07 am Post subject: |
|
|
Many thanks, Sir.
I have adapted the machine code as follows:
| Code: | VarSetCapacity( flip,32,00 ), Numput( 0x04244C8B,flip,00 ), Numput( 0x0824448B,flip,04 )
Numput( 0xC13BC103,flip,08 ), Numput( 0x8A531076,flip,12 ), Numput( 0x108A4819,flip,16 )
Numput( 0x11881888,flip,20 ), Numput( 0x77C13B41,flip,24 ), Numput( 0x00C35BF2,flip,28 )
In = Quick
dllcall(&flip,"UInt",&In, "UInt",5, "CDECL") ; Reverse byte sequence
MsgBox [%In%] |
Edit: 2010-May-21
Thanks to DerRaphael for mCode UDF Benchmarking, machine code is now 'load-time optimised'
Flip() is renamed to original: rev_bytes()
| Code: | ; Machine code for Byte-stream reversal - by Laszlo Hars
varsetcapacity(rev_bytes,32), numput( 0x00C35BF2, numput( 0x00C35BF2, numput( 0x00C35BF2
, numput( 0x77C13B41, numput( 0x11881888, numput( 0x108A4819, numput( 0x8A531076
, numput( 0xC13BC103, numput( 0x0824448B, numput( 0x04244C8B, rev_bytes ))))))))))
; C source and Hex for rev_bytes() www.autohotkey.com/forum/viewtopic.php?p=189469#189469
;Usage example follows:
In = The Quick Brown Fox
dllcall( &rev_bytes, UInt,&In, UInt,19, "cdecl" ) ; Reverse byte sequence
MsgBox <%In%> |
Last edited by SKAN on Fri May 21, 2010 9:13 am; edited 1 time in total |
|
| 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
|