News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Using Local Variables

Started by Robert Collins, January 11, 2005, 12:31:21 AM

Previous topic - Next topic

Robert Collins

In a PROC I used the following:


MyProc Proc
  LOCAL Buffer
  '
  '
MyProc Endp


How does the assembler know what 'Buffer' is or does it depend on how I use it in the proc or does it matter?

hutch--

Within a stack frame that assembler substitutes the LOCAL variable name with an address on the stack, usually in the form of [ebp-4] etc .... and every LOCAL variable is assigned a seperate location on the stack. Without a stack frame, the addresses are expressed directly in relation to the stack pointer [esp-32] etc ...
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

If by what it is you meant what data type, MASM assumes a DWORD unless you specify otherwise, so:

; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .486                       ; create 32 bit code
    .model flat, stdcall       ; 32 bit memory model
    option casemap :none       ; case sensitive

    include \masm32\include\windows.inc
    include \masm32\include\masm32.inc
    include \masm32\include\kernel32.inc
    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\kernel32.lib
    include \masm32\macros\macros.asm
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call  MyProc   
    mov   eax, input(13,10,"Press enter to exit...")
    exit

MyProc proc
    LOCAL buffer
    LOCAL buffer1:BYTE
    LOCAL buffer2:WORD
    LOCAL buffer3:DWORD
    LOCAL buffer4:QWORD

    mov   ebx, SIZE buffer
    print chr$("SIZE:")
    print ustr$(ebx)

    mov   ebx, SIZE buffer1
    print chr$(13,10,"SIZE:")
    print ustr$(ebx)
   
    mov   ebx, SIZE buffer2
    print chr$(13,10,"SIZE:")
    print ustr$(ebx)

    mov   ebx, SIZE buffer3
    print chr$(13,10,"SIZE:")
    print ustr$(ebx)

    mov   ebx, SIZE buffer4
    print chr$(13,10,"SIZE:")
    print ustr$(ebx)

    ret
MyProc endp
   
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start

Returns:

SIZE:4
SIZE:1
SIZE:2
SIZE:4
SIZE:8


eschew obfuscation

Robert Collins

OK, that makes sense. In the proc where I defined LOCAL buffer, because it has no data type specified then MASM assumes it to be a DWORD but my usage in the proc was for it to be a buffer where text data will be saved. I think.


MyProc proc lpPart1, lpPart2
local Buffer

mov   ebx, len(lpPart1)             
mov   eax, len(lpPart2)           
add   eax, ebx   
 
mov   Buffer, alloc$(eax)         

strcat Buffer, lpPart1, lpPart2   

free$(Buffer)                     
mov eax, Buffer             
ret
MyProc endp


Actually this is a modified version of the code you posted for me the other day about concatenating strings. Since the text at lpPart1 and lpPart2 are being concatened (strcat Buffer, lpPart1, lpPart2) then I assume that Buffer is a memory area that will contain the total string value. So, is this not a DWORD? I don't know, I'm just too new to completely understand some of this. 

Robert Collins

BTW, Michael, is that sample you posted above just to demonstrate local variables in a proc or is it a working program? I assemble it without any errors but when I go to run it, it doesn't do anything. I kind of thought that 'mov   eax, input(13,10,"Press enter to exit...")' would display some kind of a dialog box with the text. 

jimh

The print and input macros Michael used in his sample use StdIn/StdOut to read from and write to the console window, so you'd want to link his sample as a /subsystem:console, instead of :windows

As to the Buffer local variable, when you called alloc$, what you did was call a function which allocated memory and then returned a pointer to that memory in the form of a dword.  That pointer is then used in any subsequent string manipulation calls including free$.  We don't actually care what actual value "Buffer" has in it (except if it were NULL, then we'd have problems), we simply use it to tell us where the first character of our allocated memory is.  Clear as mud, eh?  :-)

Robert Collins

Quote from: jimh on January 11, 2005, 02:51:14 AM
The print and input macros Michael used in his sample use StdIn/StdOut to read from and write to the console window, so you'd want to link his sample as a /subsystem:console, instead of :windows

As to the Buffer local variable, when you called alloc$, what you did was call a function which allocated memory and then returned a pointer to that memory in the form of a dword.  That pointer is then used in any subsequent string manipulation calls including free$.  We don't actually care what actual value "Buffer" has in it (except if it were NULL, then we'd have problems), we simply use it to tell us where the first character of our allocated memory is.  Clear as mud, eh?  :-)

Yeah, now I get it. I thought Buffer was the name of the actual memory location but as you explained it is a pointer to some area (I know not where, nor do I care) way out there. OK, Thanks, that gets me on the road again. And yes, I re-assembled his example as a console window and it works as expected.

Tedd

Space is allocated on the stack (esp is adjusted), so if you go overwriting past the length of the buffer you'll make a nice mess of the rest of the stack ;)
No snowflake in an avalanche feels responsible.

Robert Collins

Quote from: Tedd on January 11, 2005, 01:16:53 PM
Space is allocated on the stack (esp is adjusted), so if you go overwriting past the length of the buffer you'll make a nice mess of the rest of the stack ;)

I'm a little confused here. I thought the 'stack' was for placing data that was PUSH'd there and retrived by POP. I also thought that when you, either directly or indirectly, aquire memory that it is memory from the 'heap' area which is not the same as the stack, or is it, or am I all mixed up.

hutch--

Robert,

Stack memory is allocate according to the specs in the PE file when its loaded by the OS where heap or any other dynamically allocatable memory can only be done at runtime using normal memory based API calls. Stack memory is handy fro smaller highly repetitive code like function parameters and the like but when you need bigger blocks you use one of the dynamic allocation routines. There are a number of types available for different requirements directly from the OS.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Tedd

The stack's cheap and convenient spare space. So for allocating a few local variables, it's madness to have to go to the trouble of a whole function call that screws around with the whole memory allocation, when all you need to do is "sub esp,4"
Push also stores things on the stack, but what happens when you enter a 'proc' is "mov ebp,esp" and then any modifications to esp don't mess you up on referencing variables through ebp. Not that you need to worry about any of this too much, since it's mostly hidden by the masm syntax, but it's detail if you want it ;)
The 'heap' is a block of memory allocated to a newly loaded process. So then when you alloc memory from the OS it's taken out of this space. It's sort of a primary reserve. Of course, the stack is still in memory (somewhere!) but it's not some mystical area that only push and pop can access.
No snowflake in an avalanche feels responsible.

Robert Collins

Ok, so if I need some memory let's say to store a string (a long string) then is the memory allocated for that string on the stack or from the heap or is it a matter of how I go about aquiring that memory? Like hutch said the stack is good for smaller pieces of memory (I can understand that) but if I read a file into my program and I want to hold on to it then here is where I would want memory from the heap rather than the stack. Yes, No, Depends?

Tedd, you stated ".....the stack is still in memory (somewhere!).........". Isn't that 'somewhere' actually part of your program space (I remember somewhere back in time, I had to allocate a stack at design time and also allocate it's size) and the heap is memory somewhere else (not physically part of your program or program space, but somewhere far away and only the OS can go get some of it if you so desire?

hutch--

Robert,

To store a string depends on its size and what scope you require it in. If its just short duration of a small string, you can handle it with a local buffer fine but if it is of any size and you need it for long duration across different procedures, it is better to allocate memory dynamically. Windows has a multitude of methods for allocating different types of memory and they tend to have overlapping advantages.

You have two methods in the MASM32 macro system that are easy enough to use and to store a string I would tend to use the OLE string memory version. Just make sure you create the string handle within the scope you need and if this is across multiple procedures, this means in the .DATA? section.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

#13
Robert,

For an example of local variables, MASM assembles this:

MyProc proc
   LOCAL yaba:DWORD, daba:DWORD, do:DWORD

   mov   eax, yaba
   mov   ebx, daba
   mov   ecx, do
   ret
MyProc endp

As this (comments added):

; Preserve EBP on the stack.
00401000 55                     push    ebp

; Load ESP into EBP. Local variables and parameters are
; accessed relative to EBP because any stack operations
; within the procedure will change ESP.
00401001 8BEC                   mov     ebp,esp

; Reserve 12 bytes on the stack by substracting 12 from ESP.
; The stack expands downwards as values are pushed, so stack
; operations within the procedure will not overwrite the
; local variables.
00401003 83C4F4                 add     esp,0FFFFFFF4h

; Reference the stack variables relative to EBP.
00401006 8B45FC                 mov     eax,[ebp-4]
00401009 8B5DF8                 mov     ebx,[ebp-8]
0040100C 8B4DF4                 mov     ecx,[ebp-0Ch]

; Restore ESP from EBP, and recover EBP from the stack.
; LEAVE is equivalent to
;  mov esp, ebp
;  pop ebp
0040100F C9                     leave

; At this point the local variables still exist on the
; stack, but because ESP is now pointing to a stack
; location above the local variables, subsequent stack
; operations will overwrite them.

00401010 C3                     ret

; If the procedure had parameters, MASM would have
; encoded the RET instruction such that an appropriate
; value would be added to ESP after the return,
; removing the parameters from the stack.


MSDN: MemoryManagement




eschew obfuscation

Rain Dog

The convention for variables is that local variables are generally declared on the stack.

in c code

void myfunc()
{
    int x = 5;
}

the variable x is declared ont he stack.