I know there is align directive in MASM for aligning variables in .data and .data? segments, but is it possible to align variables on the stack when LOCAL statement is used?
Posted on 2004-10-05 10:44:21 by Mikky
Hi Mikky,

It looks like that by default, MASM aligns the stack to DWORD


.code
start:
call main
invoke ExitProcess,0
main PROC
LOCAL var[6]:BYTE ; not a multiple of 4 the DWORD alignment value
mov var,1
ret
main ENDP
END start


Disassembly of code


start:
call loc_0040100c
push 00h
call _ExitProcess
; XREFS First: 1000:00401000 Number : 1
loc_0040100c:
push ebp
mov ebp, esp
add esp, -08h ; DWORD alignment
mov byte ptr [ebp-06h], 01h
leave
ret
Posted on 2004-10-05 13:14:01 by Vortex
hi mikky
i feel it is possible to align local stack variables.
i have never tried this but the logic behind wat i feel is that
element of structure, an array or even particular variables must be aligned by addresses that are multiples of a specific power of 2 but since the stack top pointer is undefined in any compiler hence the compiler does not know the index value.For this it has a trick to overcome the problem.it just discards the lower order bits esp register.

as u must have known local variales are addressed by negative offsets.
like if u see in older disassemblers u ll find stack variable like this
add esp,
and in debuggers as add esp, fffffffc
however, modern disassemblers like ida omits the minus sign and gives names to local variables.this creates a big mess however, because the smallest index of an aray is at smaller address, but it is addressed by a larger offset relative to the pointer register of the stack frame.

i feel i am diverting so lets get back to know how ida just escapes showing messy big hex no.(however it creates another big mess.)now u might ask, how does it align local stack variables???

well, compiler does not know the index value.For this it has a trick to overcome the problem.it just discards the lower order bits esp register.
the lower order bit of an even no. is 0.to ensure that the value of the stack top varianle is divisible by 2 without a remainder, it just simply forces the lower order bits to 0.now, if 2 lower order bits are set to 0, the resulting value will be a multiple of four.If 3 lower order bits are set to 0, then it ll be a multiple of eight and so on.
in most cases bits are reset using and instruction.For example
and esp, fffffff0
makes esp a multiple of 16.how??just convert fffffff0 to its binary form.
it is 11111111 11111111 11111111 11110000
the 4 zeros means that four lower order bits of any no. will be masked.
the no. will divisible by 2 to power of 4, which is 16


If i have not misunderstood u i guess this is ur answer else please correct me.
thank you
nickdigital
Posted on 2004-10-05 14:55:53 by nickdigital
Hey guys,
Vortex I think you are right about MASM always allocates 4byte divisable
memory on the stack, but it appears to me that variables are not starting on the 4byte boundary.

So let's suppose we dont mess with esp and ebp registers, and that they always point on the memory that is dword aligned.
to put it simply my problem, let's consider this snippet


DummyProc proc
LOCAL a:byte
LOCAL b:byte

mov a,1
mov b,2
ret

DummyProc endp


Here MASM will generate stack buffer of 4 bytes even though I need only two, but what I need is to have "a" and "b" variables aligned on the 4 byte boundary. This means in my pseudo disassembly, stack will look like this



1000: LOCAL a:byte
1001: dummy byte
1002: dummy byte
1003: dummy byte
1004: LOCAL b:byte
1005: dummy byte
1006: dummy byte
1007: dummy byte


but this is not how MASM generates the code, instead it will be like this


1000: LOCAL a:byte
1001: LOCAL b:byte
1002: dummy byte
1003: dummy byte


So, variable "b" starts exactly 1 byte after var "a", so if "a" is dword aligned "b" will not be.


In case someone asks why I need all this, it's because of the performance and also in some rare cases API's will just return error if you don't provide them buffer that starts on the dword alignment.
Posted on 2004-10-05 16:57:52 by Mikky
hey mikky
"variables are not starting on the 4byte boundary."

i dont agree to this.why??? the reason is given below.

i forgot to add that if 2 lower order bits are set to 0, the resulting value will be a multiple of 4 (which is a minimal value as for all 32 bits computers have minimal 4 bytes boundary limit ).

one more thing, as u pointed out

"So, variable "b" starts exactly 1 byte after var "a", so if "a" is dword aligned "b" will not be. "

i guess the esp value has nothing to do with that. it stores the boundry value under which all variables can come.its 4 bytes minimally
however as u have tried compiling the code


DummyProc proc
LOCAL a:byte
LOCAL b:byte

mov a,1
mov b,2
ret
DummyProc endp

u must notice the add esp, fffffffch in the dissassembly. which means that since ur local variables are under the 4 bytes boundary limit hence it show just add -4h bytes to ebp and store it in esp(fffffffch which means -4h bytes.)
dasm of ur code


.text:00401000 public start
.text:00401000 start proc near
.text:00401000
.text:00401000 var_2 = byte ptr -2
.text:00401000 var_1 = byte ptr -1
.text:00401000
.text:00401000 push ebp
.text:00401001 mov ebp, esp
.text:00401003 add esp, 0FFFFFFFCh <---this is i am talking about
.text:00401006 mov [ebp+var_1], 1
.text:0040100A mov [ebp+var_2], 2
.text:0040100E leave
.text:0040100F retn
.text:0040100F start endp
.text:0040100F

however if u try compiling


DummyProc proc
LOCAL a:dword
LOCAL b:byte
local p:byte

mov a,66666666
mov b,2
mov p,4
ret
DummyProc endp

you will notice add esp,fffffff8h which means -8h bytes are added to ebp and saved in esp.

dasm of my code


.text:00401000 public start
.text:00401000 start proc near
.text:00401000
.text:00401000 var_6 = byte ptr -6
.text:00401000 var_5 = byte ptr -5
.text:00401000 var_4 = dword ptr -4
.text:00401000
.text:00401000 push ebp
.text:00401001 mov ebp, esp
.text:00401003 add esp, 0FFFFFFF8h <---this is i am talking about
.text:00401006 mov [ebp+var_4], 3F940AAh
.text:0040100D mov [ebp+var_5], 2
.text:00401011 mov [ebp+var_6], 4
.text:00401015 leave
.text:00401016 retn
.text:00401016 start endp

Hence i conclude that value moved into esp is changed only if it is above 4 bytes boundary.If it is below as was the case with ur code then it just takes 4bytes of space in memory.
however if its above 4 bytes, like in my case then it is incremnted by another 4 bytes to make
esp ==ebp-8h and store it in memory
to allocate space of 8bytes

If i have not misunderstood u i guess this is ur answer else please correct me.
thank you
nickdigital
Posted on 2004-10-05 18:45:21 by nickdigital
and mikky as far as indexing is concerned like var4 var5 and var6
it gets it the way i told u earlier, but that does not affect the esp register value.Its solely done by ida to change negative offsets to name also removing the minus sign.for the variables
to be more specific
p is dword ptr so -4 so it becomes removing sign var4
b is byte ptr so -1 becomes var(4+1) = var5
a is byte ptr so -1 becomes var var(4+1+1) = var6

however this creates a messy code for us when disassembling and trying to figure out things.but thats a different topic.
please lemme know if i am wrong.ill love to correct myself
nickdigital
Posted on 2004-10-05 19:05:10 by nickdigital
nickdigital, I appreciate your effort but dont get me wrong with this,you are talking much but actually say a little. I dont understand what you are trying to explain me and I am not sure if it has to do much with my question.
So lets put things simple without much theory, can you make a 2 local byte vars to be dword aligned on the stack by using MASM? That's all I need :)
Posted on 2004-10-06 15:21:03 by Mikky
Mickey,

The trick is to write a simple test piece and disassemble it to see what the address are. From memory MASM will 4 byte align a BYTE size parameter on the stack because for obvious reasons you cannot push a BYTE value but I have never bothered to look at locals that are byte size.

You can directly write a local to ensure it IS aligned the way you need but usually a BYTE value does not need more than BYTE alignment. If you are using a stack frame in normal procs,


mov [ebp-4], BYTE PTR 127
mov [ebp-8], WORD PTR 65534
mov [ebp-12], DWORD PTR -1

Without a stack frame you can write to ESP instead.
Posted on 2004-10-06 19:46:00 by hutch--