Это должно поставить вас на правильный путь, но не отвечает фактическому разрыву:
- Стек растет вниз, и вы пытаетесь прочитать его вверх
- Что вы
&a
, &b
и &c
- это не переданные параметры, а локальное хранилище, которое можно использовать, если (например) вы скажете a=1
в пределах function()
.Я считаю, что они оптимизируются, если вы не сделаете -O0 a
, b
и c
передаются через регистры в функцию вместо стека, поэтому вы не найдетеих там дважды.Т.е. вызывающая сторона не помещает их в стек. buffer1
и buffer2
не выровнены в стеке и упакованы вместе в виде строк.
Например, сразу после (до) buffer2
вы можете найти сохраненное значение RBP
и затем обратный адрес.Для меня:
(gdb) p &buffer1
$102 = (char (*)[6]) 0x7fffffffde82
(gdb) p &buffer2
$103 = (char (*)[11]) 0x7fffffffde77
(buffer1
оканчивается на 0x7fffffffde87
)
А потом сохраняется RBP
:
(gdb) p/x (char [8]) *0x7fffffffde88
$104 = {0xb0, 0xde, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0}
А потом обратный адрес:
(gdb) p/x (char [8]) *0x7fffffffde90
$105 = {0x80, 0x51, 0x55, 0x55, 0x55, 0x55, 0x0, 0x0}
Что вы также можете увидеть из gdb:
(gdb) info frame
Stack level 0, frame at 0x7fffffffde98:
rip = 0x55555555513f in function (c.c:3); saved rip = 0x555555555180
^^^^^^^^^^^^^^
called by frame at 0x7fffffffdec0
source language c.
Arglist at 0x7fffffffde88, args: a=1, b=2, c=3
Locals at 0x7fffffffde88, Previous frame's sp is 0x7fffffffde98
Saved registers:
rbp at 0x7fffffffde88, rip at 0x7fffffffde90
^^^^^^^^^^^^^^^^^^^^^^
Вы также можете увидеть это, посмотрев код сборки:
gcc -S c.c -o c.s
или есливы предпочитаете intel:
gcc -masm=intel -S c.c -o c.s
Я не знаю, почему gcc оставляет этот пробел, хотя:
mov DWORD PTR -36[rbp], edi
mov DWORD PTR -40[rbp], esi
mov DWORD PTR -44[rbp], edx
mov DWORD PTR -6[rbp], 1633771873 <-- aaaa
mov WORD PTR -2[rbp], 97 <-- a\0
movabs rax, 7089336938131513954 <-- bbbbbbbb
mov QWORD PTR -17[rbp], rax
mov WORD PTR -9[rbp], 25186 <-- bb
mov BYTE PTR -7[rbp], 0 <-- \0