【问题标题】:ARM: Call stack generation with no frame pointerARM:没有帧指针的调用堆栈生成
【发布时间】:2013-10-28 19:05:35
【问题描述】:

我正在尝试在 Cortex-M3 处理器(ARMv7-M 架构)上构建调用堆栈,没有操作系统(裸机)。但是,该 ABI 没有帧指针寄存器。因此,当我没有帧指针时,我正在努力生成调用堆栈。

无论在 GCC 中使用-mapcs-frame-fno-omit-frame-pointer-O0 选项,都不会保留帧指针。我想知道是否有不同的 ABI 我可以强制 GCC 使用,所以我有一个帧指针/堆栈帧?如果没有,是否有其他可靠的方法来生成调用堆栈?

提前致谢。

【问题讨论】:

  • 为什么调用堆栈需要帧指针寄存器?我很困惑。帧指针寄存器是一种懒惰的解决方案,只需使用堆栈指针,不要浪费另一个寄存器。只需编译一些 C 代码,看看编译器是如何做的,然后模仿它。
  • 实际上是带有 armv7m thumb 2 扩展的 thumb(大约 140-150 条附加说明),这意味着您可以使用类似 arm 的解决方案。
  • 我不能只使用堆栈指针,因为我不知道调用函数中每个堆栈帧的大小。同样在浪费寄存器方面,GCC 的 ARM 程序集输出非常奇怪,因为它使用寄存器作为堆栈指针的近似副本(尽管我正在使用 -OO 进行编译)
  • 在拇指模式下GCC不使用r7作为FP吗?
  • 我不确定,因为它没有可靠的记录(或者我找错地方了!)请参阅我的 cmets 关于 SilverCode 的回答,了解为什么 r7 不能用作帧指针。

标签: c arm stack-trace eabi


【解决方案1】:

顺便说一句,ARM 调用标准与 Thumb 相同,参见 (AAPCS Arm calling standard) 指令集不同,但 CPU 寄存器集不同。

我更愿意在 cmets 中提问,但目前我还没有足够的分数。 考虑到这一点......

您是否有成功构建和执行的二进制文件,但您正试图转储某种调用跟踪?我的困惑是“无帧指针寄存器”语句 - r13 是堆栈帧指针。我认为您指的是存储帧指针。

已经有一段时间了,但我认为这些是我使用的选项

arm-none-eabi-gcc - -nostdlib -ggdb -mthumb -mcpu=cortex-m3 -mtpcs-frame -mtpcs-leaf-frame myfile.c

这是在gcc-arm-none downloaded from linaro. gdb 能够使用 Atmel SAM3X 上的这些选项进行回溯。 Thumb ABI 与 ARM EABI 相同,或者至少看起来是通过 objdump -D 查看汇编程序。

当指定(或隐含)-fno-omit-frame-pointer 时,前一帧指针存储在 r7 中

void test2(int i) {}
void main() { test(0); 

使用 -fomit-frame-pointer 编译

00008000 <test2>:
    8000:   b082        sub   sp, #8
    8002:   9001        str   r0, [sp, #4]
    8004:   b002        add   sp, #8
    8006:   4770        bx lr

00008008 <main>:
    8008:   b508        push  {r3, lr}
    800a:   f04f 0000   mov.w r0, #0
    800e:   f7ff fff7   bl 8000 <test2>
    8012:   bd08        pop   {r3, pc}

使用 -fno-omit-frame-pointer 编译

00008000 <test2>:
    8000:   b480        push  {r7}
    8002:   b083        sub   sp, #12
    8004:   af00        add   r7, sp, #0
    8006:   6078        str   r0, [r7, #4]
    8008:   f107 070c   add.w r7, r7, #12
    800c:   46bd        mov   sp, r7
    800e:   bc80        pop   {r7}
    8010:   4770        bx lr
    8012:   bf00        nop

00008014 <main>:
    8014:   b580        push  {r7, lr}
    8016:   af00        add   r7, sp, #0
    8018:   f04f 0000   mov.w r0, #0
    801c:   f7ff fff0   bl 8000 <test2>
    8020:   bd80        pop   {r7, pc}
    8022:   bf00        nop

所以使用 r7 获取上一个堆栈帧,然后从该位置获取下一个 r7,依此类推。

【讨论】:

  • 我如何告诉 GCC 使用 EABI?另外,堆栈指针不是指向不适合寄存器的局部变量的开头吗?
  • 正确,sp 将指向进入“函数”的第 5 个参数,例如foo( 1,2,3,4,5 ) 调用者将在 sp 位置存储“5”,r0..r4 将包含 1,2,3,4 被调用者将从 sp 位置读取“5”。请注意,堆栈是“写入前递减”
  • 我没有操作系统,无法使用 GDB,MBED 板上运行的映像不是 ELF,只是二进制机器码。您说我正在尝试生成呼叫跟踪是正确的。如果没有帧指针,这是不可能的,因为我无法遍历堆栈。因此我的问题是如何强制 GCC 使用帧指针(因为 -fno-omit-frame-pointer 似乎没有任何效果),或者更确切地说,我怎样才能找到调用函数的地址,以及调用函数的地址在此之前,无限期。
  • 啊,我在使用带有 JTAG (openocd) 的 gdb - 它工作得非常好。否则你可能不得不用这样的方式来做这件事: arm-none-eabi-objdump -D a.out > dis 然后查看每次调用中使用的堆栈数量 手工操作需要很长时间。
  • -fno-omit-frame -pointer 正在工作。在我刚刚运行的测试中,帧指针存储在 r7 中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
  • 2014-11-28
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多