I wrote a program and compiled it with GCC 12.2.1 on Fedora x64 Linux using the flags -Wall and -g3
, and I disassembled it in gdb-gef. Source code:
#include <stdio.h>
int addNumbers(int a,int b,int c,int d, int e, int f, int g, int h);
int main(void)
{
printf("%d\n", addNumbers(5,17,900,2483,24,67,98,4923));
return 0;
}
int addNumbers(int a, int b, int c, int d, int e, int f, int g, int h)
{
int local1 = 16;
int local2 = 24;
return a + b + c + d + e + f + g + h + local1 + local2;
}
Below is the disassembly:
gef➤ disass addNumbers
Dump of assembler code for function addNumbers:
0x0000000000401172 <+0>: push rbp
0x0000000000401173 <+1>: mov rbp,rsp
0x0000000000401176 <+4>: mov DWORD PTR [rbp-0x14],edi
0x0000000000401179 <+7>: mov DWORD PTR [rbp-0x18],esi
0x000000000040117c <+10>: mov DWORD PTR [rbp-0x1c],edx
0x000000000040117f <+13>: mov DWORD PTR [rbp-0x20],ecx
0x0000000000401182 <+16>: mov DWORD PTR [rbp-0x24],r8d
0x0000000000401186 <+20>: mov DWORD PTR [rbp-0x28],r9d
=> 0x000000000040118a <+24>: mov DWORD PTR [rbp-0x4],0x10
0x0000000000401191 <+31>: mov DWORD PTR [rbp-0x8],0x18
0x0000000000401198 <+38>: mov edx,DWORD PTR [rbp-0x14]
0x000000000040119b <+41>: mov eax,DWORD PTR [rbp-0x18]
0x000000000040119e <+44>: add edx,eax
0x00000000004011a0 <+46>: mov eax,DWORD PTR [rbp-0x1c]
0x00000000004011a3 <+49>: add edx,eax
0x00000000004011a5 <+51>: mov eax,DWORD PTR [rbp-0x20]
0x00000000004011a8 <+54>: add edx,eax
0x00000000004011aa <+56>: mov eax,DWORD PTR [rbp-0x24]
0x00000000004011ad <+59>: add edx,eax
0x00000000004011af <+61>: mov eax,DWORD PTR [rbp-0x28]
0x00000000004011b2 <+64>: add edx,eax
0x00000000004011b4 <+66>: mov eax,DWORD PTR [rbp+0x10]
0x00000000004011b7 <+69>: add edx,eax
0x00000000004011b9 <+71>: mov eax,DWORD PTR [rbp+0x18]
0x00000000004011bc <+74>: add edx,eax
0x00000000004011be <+76>: mov eax,DWORD PTR [rbp-0x4]
0x00000000004011c1 <+79>: add edx,eax
0x00000000004011c3 <+81>: mov eax,DWORD PTR [rbp-0x8]
0x00000000004011c6 <+84>: add eax,edx
0x00000000004011c8 <+86>: pop rbp
0x00000000004011c9 <+87>: ret
So one major difference (it's been a while since I stared at disassembly between the x86-32 programs I've recently disassembled and this x86-64 one is that we see during the first few lines of that addNumbers
function, that the compiler has accepted the function arguments into registers rdi
, rsi
, rdx
, rcx
, r8d
, r9d
, and the rest on the stack as the System V calling convention states, then it moves these into stack locations via mov DWORD PTR [rbp-0x14], edi
and so on... My question pertains to this part... For all intents and purposes, is this behavior considered proper stack usage? The reason I ask is because as far as I learned, the stack is an abstract data structure that has a conceptual top of the stack which is typically denoted by rsp
or just SP
and a bottom for this frame, typically denoted as rbp
or BP
. However, in this case, the compiler is using mov
instructions like the one shown to put things in areas of stack memory without using the stack in a traditional way which is to push or pop. It is likely doing this because mov
instructions on this sort of data are faster than push
/pop
, but would we state that the compiler is actually using the stack as a proper stack here or is it breaking any sort of stack conventions or rules by addressing areas of the stack without first extending the stack pointer to properly include those areas? One final example is that clearly in the below stack memory dump, both rbp
and rsp
point to the same address and the mov
s are occurring during this state, which means the mov
s do occur outside the scope of the stack frame between rbp
and rsp
:
gef➤ telescope $rbp-0x20
0x00007fffffffda10│+0x0000: 0x00000384000009b3
0x00007fffffffda18│+0x0008: 0x0000000500000011
0x00007fffffffda20│+0x0010: 0x0000000000000000
0x00007fffffffda28│+0x0018: 0x0000000000000000
0x00007fffffffda30│+0x0020: 0x00007fffffffda50 → 0x0000000000000001 ← $rsp, $rbp
0x00007fffffffda38│+0x0028: 0x0000000000401156 → <main+48> add rsp, 0x10
0x00007fffffffda40│+0x0030: 0x0000000000000062 ("b"?)
0x00007fffffffda48│+0x0038: 0x000000000000133b
0x00007fffffffda50│+0x0040: 0x0000000000000001
0x00007fffffffda58│+0x0048: 0x00007ffff7c29550 → <__libc_start_call_main+128> mov edi, eax