NASM Forum > Programming with NASM

Tips for new assembly programmers

<< < (3/3)

fredericopissarra:
The stack
The process stack is used not only to keep record of the returing point for called functions, but as a place to pass arguments to the functions and local objets. Each time you call a function (call instruction) the RIP register (which containt the NEXT instruction address) is pushed to the stack. But, before that, in real and i386 modes, and if we use more then 4 (MS-ABI) or 6 (SysV ABI) integer arguments and/or mode than 4 (MS-ABI) or mode than 8 (SysV ABI) floating point arguments, the stack is used as well.

I've already shown a tip about using structures to manage "stack frames" in real and i386 modes. Let's extend this to usage of local objects. Let's say we declare an local array of 16 ints, as in:

--- Code: ---int f( int x )
{
  int a[16];
  ...
}
--- End code ---
In i386 mode x is passed through the stack. Remember that ESP points to where the return address pushed by CALL is placed, so ESP+4 is the address where x is. This 16 ints array is allocated on stack after the returning address, from ESP-4 to ESP-68 (64 bytes). So, it is common to subtract 68 bytes from ESP before using it to get both argument and access to local objects:

--- Code: ---f:
  sub esp,64  ; allocate space on stack for a.

  ... ESP points to the begining of a[].
  ... use ESP+68 to get x (64 bytes of a plus 4 bytes for the returning address).

  add esp,64  ; return ESP to its original state.
  ret
--- End code ---
This is easily done with structures also:

--- Code: ---struc fstk
.a: resd 16
.localstk:
    resd 1    ; the return address
.x: resd 1   ; x argument on stack
endstruc

f:
  sub  esp,fstk.localstk
  mov eax,[esp+fstk.x]   ; get x,
  ...
  add  esp,fsk.localstk
  ret
--- End code ---

fredericopissarra:
In i386 mode ESP must be aligned by DWORD (must be a multiple of 4), but in x86-64 RSP must be QWORD aligned ( multiple of 8 ). And there's another advantage for x86-64: There is a thing called "The Red Zone" (nothing like "The Twilight Zone"!).

Beware, ESP (or RSP) must be kept aligned all the time. If we declare a 11 bytes array locally, we must allocate 12 bytes (i386) or 16 bytes (x86-64).

The red zone is a space, before the original RSP, guaranteed not to be disturbed by interruptions. It is a 128 bytes zone before RSP. If our local data is inside this zone, we don't need to tweak RSP the same way we did before.

This zone exists only for funcitions that don't do other calls. If there is any calls, no red zone is present and you MUST allocate space as shown before, for local objects.

fredericopissarra:
There is one more thing about RSP alignment on x86-64 mode. Truly, RSP must be kept aligned by DQWORD (16 bytes), not 8. This is because x86-64 mode uses SSE for scalar floating point and XMM registers are 128 bits long and must be DQWORD aligned.

When calling a function the return address, pushed to the stack is QWORD aligned, but NOT DQWORD aligned, the next QWORD (before and after RSP) are garanteed to be DQWORD aligned.

fredericopissarra:
Using custom sections

An executable is divided into some "default" sections. Each section is a block of bytes where code or data are loaded into memory be your operating system process loader. There are 4 default sections for most operating systems: .text, .data, .rodata and .bss.

.text is used to contain instructions, the actual executable code; .data is used to contain initialized and writable data; .rodata is used to contain read only, non writable, data; and .bss is used to contain non-initialized data.

Tipically, .text, .data and .rodata are loaded from the executable to memory and .bss is initialized with zeros by the program itself.

These are the default sections. You can create your own, if necessary (usually the default sections are enough!). Section names beginning with '.' are, usually, reserved by the ABI (or the executable format), like .text or .bss, so you can create your own section naming it the way you like (there is no limit for the section name... well... not a 'practical' limit). But you have to describe your section. Here's an example:

--- Code: ---; test.asm - elf64 executable.
;
;   nasm -felf64 -o test.o test.asm
;   ld -o test test.o
;
  bits  64
  default rel

  section .text     ; default 'code' section

  global  _start

  align 4
_start:
  call writestr
  jmp  exit

  ; Custom 'code' section
  section strrtn progbits alloc exec nowrite align=4

writestr:
  lea   rsi,[msg]
  mov   eax,1
  mov   edi,eax
  mov   edx,msg_len
  syscall
  ret

  section .rodata   ; default 'readonly' data section.

msg:
  db    `Hello\n`,0
msg_len equ $ - msg

  ; Another custom 'code' section
  section system progbits alloc exec nowrite align=4

exit:
  mov   eax,60
  xor   edi,edi
  syscall
--- End code ---
Compiling and taking a look at the headers:

--- Code: ---$ nasm -felf64 -o test.o test.asm
$ objdump -h test.o
test.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         0000000a  0000000000000000  0000000000000000  000002c0  2**4
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 strrtn        00000016  0000000000000000  0000000000000000  000002d0  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  2 .rodata       00000007  0000000000000000  0000000000000000  000002f0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 system        00000009  0000000000000000  0000000000000000  00000300  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
--- End code ---
And it works:

--- Code: ---$ ./test
Hello
--- End code ---

To create a custum section is useful, mostly, when you are trying to create your own "operating system". You can mix 16 bits code with 32 bits code and with 64 bits code in different sections, if you like.

fredericopissarra:
PS: Take a look at Inigo Quilez Elevated demo source code, here. This is a 32 bits (i386) code, directed to Windows, using DX9. Notice the nasm codes uses a lot of custom sections.

Navigation

[0] Message Index

[*] Previous page

Go to full version