Skip to main content

Creating local variables In Assembly

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

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.

stack frame looks visualize tutorial
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.

Comments

  1. mov DWORD [ebp-12],0xffff ;etc

    should be

    mov DWORD [ebp-16],0xffff ;etc

    ReplyDelete
  2. And in the create stack frame prologue:
    push mov ebp, esp
    should be
    mov ebp, esp

    ReplyDelete

Post a Comment

Popular posts from this blog

Introduction to Linux Kernel Programming

The Linux kernel is designed as a mixture of a monolithic binary image and a micro-kernel.  This combination allows for the best of both worlds.  On the monolithic side, all the code for the kernel to work with the user and hardware is already installed and ready for fast access, but the downside is that to add more functionality you need to rebuild the entire kernel.   In a different manner, a micro-kernel is composed of small pieces  of code that can be meshed today and more pieces can be added or removed as needed.  However, the downside to micro-kernel is a slower performance. Adding a module to the Kernel Linux is organized as both monolithic, one huge binary, and micro-kernel, as you can add more functionality to it.  The process of adding more functionality to the kernel can be illustrated by the crude image to the left. The process begins by using the command insmod with the name of the kernel module you want (which usually ends with extension *.ko).  From here, the mod

NASM Programming

Many of you, if you are like me, might be interested in how assembly works.  You will be very surprised that assembly is very very easy, especially after you write a couple of simple programs.  But don't get me wrong, you will be frustrated at first, however that frustration, if you channel it right, will lead to serious life long learning and will give you a deeper appreciation of the beauty of assembly. For more tutorial on assembly and visualization of these information, visit my youtube channel . Okay so lets get started. We will be using Netwide Assembler (NASM) to write our program. The general format of NASM file is this: ;This is a comment SECTION .data ;declare variable here SECTION .bss ;declare actual, dynamic variable SECTION .text ;where your program code/assembly code lives ; Working with Data Section In your .data section, you can declare variables like this: nameOfVariable: db 32 ;this declares a variable names nameOfVariable with byte valu