Я изучаю сборку x32 ARM на RaspberryPi с помощью Raspbian. Я написал следующий код:
@ Define my Raspberry Pi
.cpu cortex-a53
.fpu neon-fp-armv8
.syntax unified @ modern syntax
.text
.align 2
.global main
.type main, %function
main:
mov r0, 1 @ line added only for breakpoint purposes
sub sp, sp, 8 @ space for fp, lr
str fp, [sp, 0] @ save fp
str lr, [sp, 4] @ and lr
add fp, sp, 4 @ set our frame pointer
Сборка с g cc:
gcc -g test.s -o test
Используйте gdb
для проверки значений fp
и sp
в строках 13 и 16 и разыменовывает их:
$ gdb ./test
(gdb) break 13
Breakpoint 3 at 0x103d4: file test.s, line 13.
(gdb) break 16
Breakpoint 4 at 0x103e0: file test.s, line 16.
(gdb) run
Starting program: /home/pi/assembly/nine/bob/test
Breakpoint 3, main () at test.s:13
13 sub sp, sp, 8 @ space for fp, lr
(gdb) print {$sp, $fp}
$1 = {0x7efffae8, 0x7efffae8}
(gdb) x $sp
0x7efffae8: 0x76f9e000
(gdb) x $fp
0x7efffae8: 0x76f9e000
(gdb) continue
Continuing.
Breakpoint 4, main () at test.s:16
16 add fp, sp, 4 @ set our frame pointer
(gdb) print {$sp, $fp}
$2 = {0x7efffae0, 0x7efffae0}
(gdb) x $sp
0x7efffae0: 0x00000000
(gdb) x $fp
0x7efffae0: 0x00000000
Как видите, fp
при запуске равно sp
и не равно нулю:
(gdb) print {$sp, $fp}
$1 = {0x7efffae8, 0x7efffae8}
(gdb) x $sp
0x7efffae8: 0x76f9e000
(gdb) x $fp
0x7efffae8: 0x76f9e000
, но при копировании в увеличенный стек это меняется на ноль
(gdb) x $fp
0x7efffae0: 0x00000000
Почему он меняется на ноль? Почему это вообще меняет значение? Является ли базовая реализация каким-либо образом связывающей значения fp
и sp
, так что при перемещении sp
в инициализированную память, которая может иметь все нули, fp
также изменяется? Я нашел только this :
fp
Is the frame pointer register. In the obsolete APCS variants that
use fp, this register contains either zero, or a pointer to the
most recently created stack backtrace data structure. As with the
stack pointer, the frame pointer must be preserved, but in
handwritten code it does not need to be available at every
instant. However, it must be valid whenever any strictly
conforming function is called. fp must always be preserved.
Этот комментарий говорит, что lr
хранится как первый элемент в стеке, но это определенно нет - он остается прежним и не равен нулю:
(gdb) print {$sp, $fp, $lr}
$1 = {0x7efffae8, 0x7efffae8, 0x76e6b718 <__libc_start_main+268>}
и после sp
изменяется:
(gdb) x/2xw $sp
0x7efffae0: 0x00000000 0x76e6b718