Lets go over how to create local variables inside of a pure assembly source code.
Much like always, you will start with a *.asm file that looks like this:
source code
So, the above is the general layout of an NASM source file. Our goal here is to create a local variable inside of the main method. The only way to create a local variable is by using the stack. Why? Because we can only declare variable in storage locations and the only available storage locations are: text, bss, and data. However, text section is only for code, so it is out of the question. The bss and data sections are appealing, but to declare our "local" variable in these sections will defeat the purpose of these variables being local, they would be global.
So really, the only way to declare local variables is by utilizing the stack. That no problem, in fact the stack is our friend. Refer to the image to the right, and you will find that the stack (stack frame) is nothing than a dynamic memory abstraction, designed to make our lives easier. Its got two components, esp (the stack pointer) and ebp (the base pointer). The esp is always changing while ebp is "created" and destroyed by moving the current value of esp into and out of it.
From our code template above, creation and destruction of our function main's stack frame is achieved by saving the callers ebp, creating a new ebp by assigning ebp a new value. Then we destroy the frame by restoring esp to where it was prior to main being code. Then finally by popping the value of the callers base pointer back into ebp.
Okay, okay, you just want to create local variables inside of main. So let us do that:
Effectively, what we did was reserve space on the stack, the store values inside of those reserved spaces. That is all there is to making local variables in assembly.
Much like always, you will start with a *.asm file that looks like this:
source code
SECTION .data SECTION .bss SECTION .text global main ;make main available to operating system(os) main: ;create the stack frame push ebp push mov ebp, esp ;destroy the stack frame mov esp, ebp pop ebp ret
So, the above is the general layout of an NASM source file. Our goal here is to create a local variable inside of the main method. The only way to create a local variable is by using the stack. Why? Because we can only declare variable in storage locations and the only available storage locations are: text, bss, and data. However, text section is only for code, so it is out of the question. The bss and data sections are appealing, but to declare our "local" variable in these sections will defeat the purpose of these variables being local, they would be global.
So really, the only way to declare local variables is by utilizing the stack. That no problem, in fact the stack is our friend. Refer to the image to the right, and you will find that the stack (stack frame) is nothing than a dynamic memory abstraction, designed to make our lives easier. Its got two components, esp (the stack pointer) and ebp (the base pointer). The esp is always changing while ebp is "created" and destroyed by moving the current value of esp into and out of it.
From our code template above, creation and destruction of our function main's stack frame is achieved by saving the callers ebp, creating a new ebp by assigning ebp a new value. Then we destroy the frame by restoring esp to where it was prior to main being code. Then finally by popping the value of the callers base pointer back into ebp.
Okay, okay, you just want to create local variables inside of main. So let us do that:
SECTION .data msg: db "the variable has value of %d",10,0 ;we use this to display the variable SECTION .bss SECTION .text extern printf ;tell nasm that we want to call printf in this asm global main ;make main available to operating system(os) main: ;create the stack frame push ebp push mov ebp, esp ;create local variables by reserving space on the stack sub esp, 0x10 ;reserve space of 16 bytes-- maybe 4 integers(4bytes*8bit=32bits) ;we use increment of 4 because check push is 4 bytes in length ;because the stack is structured to hold 32 bit(4byte) values ;notably address, which are 4 bytes in length mov DWORD [ebp-4], 0xf ;store 15 into first variable mov DWORD [ebp-8], 0xff ;255 mov DWORD [ebp-12],0xfff ;etc mov DWORD [ebp-12],0xffff ;etc push DWORD [ebp-4] ;push the value stored at ebp -4 onto stack push DWORD msg ;push the address of msg onto the stack call printf ;call the extern, c standard library push DWORD [ebp-8] ;push the value push DWORD msg ;push the address of msg onto the stack call printf ;call the extern, c standard library push DWORD [ebp-12] ;push the value push DWORD msg ;push the address of msg onto the stack call printf ;call the extern, c standard library push DWORD [ebp-16] ;push the value push DWORD msg ;push the address of msg onto the stack all printf call printf ;destroy the stack frame mov esp, ebp pop ebp ret
Effectively, what we did was reserve space on the stack, the store values inside of those reserved spaces. That is all there is to making local variables in assembly.
mov DWORD [ebp-12],0xffff ;etc
ReplyDeleteshould be
mov DWORD [ebp-16],0xffff ;etc
And in the create stack frame prologue:
ReplyDeletepush mov ebp, esp
should be
mov ebp, esp