How to interpret particularities of Intel x86 assembly?

103 Views Asked by At

Consider this simple piece of C code:

#include <stdio.h>

int add(int a, int b)
{
    return a + b;
}

int main()
{
    int var = 6;
    int var2 = 5;
    int var3 = add(var, var2);

    return 0;
}

Compiling this code with gcc core.c -O0 -g yields this assembly code:

    .file   "core.c"
    .text
    .globl  add
    .type   add, @function
add:
.LFB0:
    .cfi_startproc
    endbr64
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    -4(%rbp), %edx
    movl    -8(%rbp), %eax
    addl    %edx, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   add, .-add
    .globl  main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    endbr64
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    $6, -12(%rbp)
    movl    $5, -8(%rbp)
    movl    -8(%rbp), %edx
    movl    -12(%rbp), %eax
    movl    %edx, %esi
    movl    %eax, %edi
    call    add
    movl    %eax, -4(%rbp)
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
    .section    .note.GNU-stack,"",@progbits
    .section    .note.gnu.property,"a"
    .align 8
    .long   1f - 0f
    .long   4f - 1f
    .long   5
0:
    .string "GNU"
1:
    .align 8
    .long   0xc0000002
    .long   3f - 2f
2:
    .long   0x3
3:
    .align 8
4:

In gdb, I am setting a breakpoint when entering the add function. Taking a look at the stack in memory at this point ($rbp = 0x7fffffffdb10 and $rsp = 0x7fffffffdb10):

        0x7fffffffdb50: 0xffffdc30    0x00000001    0xffffdc48    0x00007fff
        0x7fffffffdb40: 0x00000000    0x00000000    0x55555141    0x00005555
        0x7fffffffdb30: 0x00000001    0x00000000    0xf7c29d90    0x00007fff    frame ptr, main RA 
        0x7fffffffdb20: 0x00001000    0x00000006    0x00000005    0x00005555    4096, var, var2, var3
rbp --> 0x7fffffffdb10: 0xffffdb30    0x00007fff    0x5555516a    0x00005555    main frame, add RA
        0x7fffffffdb00: 0x00000002    0x00000000    0x00000005    0x00000006    (8 rand byte), var2, var

We can see several things:

  1. the current base pointer (rbp) points towards the main frame address.
  2. Above it is the return address (0x55555555516a) to the main function.
  3. Following this logic, the base pointer of the main frame (0x...db30) points towards 0x1 and the return address is 0x7ffff7c29d90.
  4. As main has 3 local variables, and it reserves 16 bytes (0x...db20 to 0x...db2c) and puts them there in reverse order.
  5. the add function pushes the values needed for calculation on stack without moving the stack pointer (0x...db08 and 0x...db0c).

To the questions:

Q1: Are the values of the return address and the base frame in main special values? At least the RA cannot be constant as there is no guarantee its free.

Q2: When memory for the local variables is allocated, why are 16 bytes allocated instead of the expected 12? (suspecting aligning?) And what is that does the 0x1000 in the extra byte mean?

Q3: When add calculates the result, why is the stack pointer not adjusted when it clearly puts data on the stack? Couldn't that lead to loss of information?

I would be grateful for any help, also pointers to resources would be appreciated.

0

There are 0 best solutions below