I have just converted this piece of code in assembly:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {
    return (1);

Here are my questions:

  1. Once you push the base-pointer value on to the stack, RSP will decrement automatically (to a lower address). This will also happen when memory was allocated for argc and argv ("mov dword" and "mov qword"). Is this correct? I don't see any instruction to move the stack-pointer up the stack, so I am assuming this is done implicitly.
  2. The instruction "mov dword [rbp-4H], edi" is 4 bytes less than the address in RBP, this is as expected since DWORD is 4 bytes in length. What I am confused about is why "mov qword [rbp-10H], rsi" is 10H (16 bytes)? Isn't QWORD 8 bytes in length? I was expecting the instruction to be "mov qword [rbp-CH], rsi", since 4+8=12 bytes.
  3. Can you explain to me what the comments on the right-side are?

Below is the assembly code generated from my c program:

SECTION .text   align=1 execute                         ; section number 1, code

main:   ; Function begin
push    rbp                                     ; 0000 _ 55
mov     rbp, rsp                                ; 0001 _ 48: 89. E5
mov     dword [rbp-4H], edi                     ; 0004 _ 89. 7D, FC
mov     qword [rbp-10H], rsi                    ; 0007 _ 48: 89. 75, F0
mov     eax, 1                                  ; 000B _ B8, 00000001
pop     rbp                                     ; 0010 _ 5D
ret                                             ; 0011 _ C3
; main End of function

SECTION .data   align=1 noexecute                       ; section number 2, data

SECTION .bss    align=1 noexecute                       ; section number 3, bss

Variables are aligned to some extent to help faster access to them. The alignment value is usually an implementation detail, but compilers usually follow Intel's recommendations to align/place variables next to each other.

According to Intel® 64 and IA-32 Architectures Optimization Reference Manual, section 3.6.7 Stack Alignment*:

Performance penalty of unaligned access to the stack happens when a memory reference splits a cache line. This means that one out of eight spatially consecutive unaligned quadword accesses is always penalized, similarly for one out of 4 consecutive, non-aligned double-quadword accesses, etc.

Aligning the stack may be beneficial any time there are data objects that exceed the default stack alignment of the system. For example, on 32/64bit Linux, and 64bit Windows, the default stack alignment is 16 bytes, while 32bit Windows is 4 bytes.

Assembly/Compiler Coding Rule 55. (H impact, M generality) Make sure that the stack is aligned at the largest multi-byte granular data type boundary matching the register width.

In your case on x64 the registers are 8 bytes wide and argc being an int is 4 bytes wide. Following the guideline above the variables are aligned to 8-byte boundary.

 ► 0x5555555545fe <main+4>                   mov    dword ptr [rbp - 4], edi
   0x555555554601 <main+7>                   mov    qword ptr [rbp - 0x10], rsi
   0x555555554605 <main+11>                  mov    eax, 0x2a
   0x55555555460a <main+16>                  pop    rbp
   0x55555555460b <main+17>                  ret    

edi stores argc a 32 bit value - packed in a 64 bit boundary with the upper 32 bits of no use for you.

pwndbg> tele rbp-0x10
00:0000│          0x7fffffffdf10 —▸ 0x7fffffffe000 ◂— 0x1
01:0008│          0x7fffffffdf18 ◂— 0x0
02:0010│ rbp rsp  0x7fffffffdf20 —▸ 0x555555554610 (__libc_csu_init) ◂— push   r15

So the argv starts 8 bytes above argv

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.