وو

وحید آنلاین . آرشیو وبلاگ وحیدمی دات آی آر . شرکت بیان. vahidmy.blog.ir

وو

وحید آنلاین . آرشیو وبلاگ وحیدمی دات آی آر . شرکت بیان. vahidmy.blog.ir

Size Optimization



Size Optimization (DeVilMan) .



Intro


In this tutorial we will see how to optimize code in size, making it smaller to fit your needs. These kinds of optimizations are often used by virusers and crackers that need to write routines as small as possible to be put into really small caves. Anyway these tricks can be obviouvsly applied to ''normal'' programming, so have a look at them and keep trying to make your code ever more smaller and faster! This is the true ASM programmer spirit.


Firstly, I apologize for my bad english, I hope you'll understand what I mean , at least looking at examples.



LET'S BEGIN  , HaVe PHuN!




Zeroing a register


MOV register 0 is not a good way to do this. Instead use:


xor reg reg ; 1 byte.


or


mov reg reg ; 1 byte.


Use CDQ to zero out EDX if EAX is lower than 080000000h.


Remember that sometimes there's no need to clean a register before moving data into it. Consider his example:


xor eax eax ; 2 bytes.

mov ax W§esi+4 ; 4 bytes.


It can be optimized to:


movzx eax W§esi+4 ; 4 bytes.


, saving 2 bytes. 




Testing for zero


Well, NEVER use:


CMP reg 0 ; 6 bytes.

jz L2> ; 2 bytes.


it's a waste of space. Instead use:


OR reg reg ; 2 bytes.

jz L2> ; 2 bytes.


I think it's worth the effort, you've halved its size!




Moving data between registers


XCHG is a powerful instruction. It EXCHANGES the contents of two registers, but it takes only 1 byte if one of them is the accumulator (EAX). So XCHG eax, ecx will take only 1 byte, being very useful in some situations. 


For example:


MOV ebx eax

XOR eax eax


can be optimized to:


XCHG ebx eax

XOR eax eax


In fact it doesn't matter if you are putting the contents of ebx in eax, 'cause you're gonna clean it with the next instruction.


NOTE: XCHG takes less space than MOV , but it is slower and not pairable.




String instructions


String instructions (MOVS, SCAS, CMPS, STOS, LODS) can be very useful while dealing with strings. Even if they are pretty slow, they can be used to save a lot of bytes.


Have a look at these simple routines:


- find the end of an ASCIIZ string


mov edi StringAsciiZ

xor al al

L0: scasb | jnz L0<


- append two strings ( if you don't know their length)

mov edi StringAsciiZ

xor al al

L0: scasb | jnz L0<

mov esi SourceString

L1: lodsb

stosb | or al al | jnz L1<


-append two strings (if you know the length)

mov edi EndOfStringAsciiZ

mov esi SourceString

mov ecx D§SourceStringLenght

rep movsb




Pushing and Popping


A lot of Windows APIs require a lot of parameters which sometimes are optional or redundant, so you must push NULL many times. You can save some bytes in this way:


Instead of:


push &NULL ; 2 bytes.

push &NULL ; 2 bytes.

push &NULL ; 2 bytes.

call ...

use:


xor eax eax ; 2 bytes.

push eax ; 1 byte.

push eax ; 1 byte.

push eax ; 1 byte.

call ...


Also, if you are going to push and pop many registers 


push ecx

push ebx

push edx

push esi

push edi

...

pop edi

pop esi

pop edx

pop ebx

pop ecx

mov eax D§esi


you'd better use PUSHAD and POPAD 


PUSHAD

...

POPAD

mov eax D§esi


obviouvsly only if you don't mind to save the value of a particular register.




Checking for -1


There are some APIs that return -1 (0ffffffffh), often if an error is occurred. For example CreateFile returns -1 if it failed. A common and wasteful way to do this is:


call 'KERNEL32.CreateFileA' ...

CMP eax, 0_FFFF_FFFF ; 6 bytes

jz err_invalid_handle ; 2 bytes.


Think of it in this way:


call 'KERNEL32.CreateFileA' ...

inc eax ; 1 byte.

jz err_invalid_handle ; 2 bytes.

dec eax ; 1 byte.


in fact 0FFFFFFFF+1=0




Wiping the HIGHWORD


A nice way to do this is using a mask:


AND ecx, 0FFFF ; 6 bytes.


BUT , if ecx is lower than 08000h , you can halve the size using CWDE (Convert Word to Extended Doubleword), which extends the sign bit of AX throughout EAX.


XCHG eax ecx ; 1 byte.

CWDE ; 1 byte.

XCHG eax ecx ; 1 byte.

 

Nice, isn't it?




Words registers


Try to avoid the use of word registers , because 16-bit instructions executing in 32-bit mode require an operand-size prefix, which occupies 1 more additional byte.




Moving Immediate Values


MOV always takes a 4 byte immediate operand even if it's a byte sized one. This means that a


MOV eax 10 ; 5 bytes.


takes 5 bytes!


Instead, you can PUSH a byte sized immediate value in only 2 bytes:


PUSH 10 ; 2 bytes.


Thus you can save some bytes with a PUSH immediate/ POP reg combo.


PUSH 10 / pop EAX ; 3 bytes




Powerful IMUL instruction


IMUL can be used as to perform a multiplication by an immediate value


IMUL eax 30 ; 3 bytes


instead of using:


PUSH 30 ; 2 bytes.

POP ecx ; 1 byte.

MUL ecx ; 2 bytes


but also to perform a multiplication by an immediate and a move in only 3 bytes!


IMUL eax ecx 025 ; 3 bytes


which multiplies ecx by 025h an puts the result in eax ( ecx is not touched).




Random values


Instead of using a randomize() and then a random() functions, you can in some cases use RDTSC instruction (  Read Time-Stamp Counter), but remember it's a Pentium instruction. It loads the current value of the processor's time-stamp counter into the EDX:EAX registers. EAX, the lower 32 bits, is a kind of ''random'' value(it's NOT random at all, but it changes so fast that lower bits can be considered random).


So to do something , let's say, a time every 4 consider the following example:


RDTSC

cmp al 63

jnb over

  ; Do something

over:



Or if you want a pseudo-random value between 0 and 3 do the following:


RDTSC

shr eax 30 ; leaving only 2 bits, you've got a number between 0 and 3


NOTE: put a BSWAP EAX before shifting if you want a more random value...




LAST WORDS

I hope you've find these info useful :) Remember that in the PC world SMALL things are usually better than LARGE ones. (heh...not like real life, where lots of things SHOULD be as large as possible....). 



DeVilMAn  - 2001


< devilman@flymail.it >


EvIl GeNiuSes foR a BetTeR ToMoRrow


            ~~~~~~~