fp равен sp при запуске, но при копировании в увеличенный стек изменяется на ноль - почему? - PullRequest
0 голосов
/ 20 апреля 2020

Я изучаю сборку 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

1 Ответ

0 голосов
/ 20 апреля 2020

Хорошо, я отвечаю себе - это происходит в gdb/arm-tdep.c в исходном коде GDB:

  /* The frame size is just the distance from the frame register
 to the original stack pointer.  */
  if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
{
  /* Frame pointer is fp.  */
  framereg = ARM_FP_REGNUM;
  framesize = -regs[ARM_FP_REGNUM].k;
}
  else
{
  /* Try the stack pointer... this is a bit desperate.  */
  framereg = ARM_SP_REGNUM;
  framesize = -regs[ARM_SP_REGNUM].k;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...