rbp - $offset
. For example, if the first argument passed to the callee is int
(4 bytes) and there are no local variables defined in the function, we could access it via rbp - 0x4
; long int
), we'd access it via rbp - 0x8
;int
would be accessed via rbp - (0x10 + 0x4)
or simply rbp - 0x14
;int
via rbp - 0x24
, which suggests that with every 16 bytes worth of local variables defined, the first argument is shifted by 0x10 bytes as shown here;rbp + 0x10
, argument 8 via rbp + 0x18
and so on.0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9
passed to the function test(int a, int b, int c, int d, int e, int f, int g, int h, int i)
end up in registers and the stack:test
stack frame looks like on a 64-bit platform:edi
, esi
, edx
, ecx
, r8d
, r9d
(orange);push
(blue);test()
function did not have any local variables defined, so let's see how the stack changes once we have some variables and how we can access them.int a1 = 0x555577
(4 bytes, lime) as in our case shown below (lime), we'd access the first argument not via rbp - 0x4
as it was the case previously when the callee had no local variables, but via rbp - 0x14
(i.e it shifted by 0x10 bytes, red):test()
function stack frame, would now look like this:rbp - 0x4
has been shifted up by 0x10 bytes and is now accessible via rbp - 0x14
whereas the local variable is now at rbp - 0x4
(where the 1st argument was when the function did not have a local variable defined) followed by 0x10 bytes of padding.rbp - 0x24
(i.e another 0x10 bytes shift from rbp - 0x14
):rbp - 0x34
(i.e yet another 0x10 bytes shift):main()
:RDI
contains the the count of arguments our program was launched with (argc
);RSI
contains the address to an array of arguments our program was run with (argv[]
) and the first one (argv[0]
), as expected, is always the full path to the program itself, which is /home/kali/labs/stack/stack
in our case.