我想了解arm链接寄存器是如何工作的以及它对调试有何帮助。我首先编写了一个简单的函数。
#define MACRO_TEST() (event_log__add_args(MACRO_TEST,__return_address()))
static void do_print_r14(void) {
printf_all("return address 0x%08X \n",__return_address()); //prints 0x823194BB
MACRO_TEST();
printf_all("return address 0x%08X \n",__return_address()); //prints 0x823194BB
}
Run Code Online (Sandbox Code Playgroud)
事件日志打印以下内容: 返回地址:0x0000ABAB
我的问题是为什么 do_print_r14 函数中的打印输出相同的值。如果我只登录行号和函数名称,这将指向代码的确切位置,这不是更有帮助吗?为什么开发者在调试时使用r14?
这个问题对你们来说可能听起来非常基本,但我完全不确定为什么我们需要 r14 寄存器。
行号和函数名称告诉您所在位置,但返回地址告诉您如何到达那里- 这在更复杂的代码中非常有用。在调试纯汇编、高度优化的代码或其他可能没有可理解的堆栈帧的情况时,有时检查链接寄存器是了解该地址的唯一方法。
当然,这总是相对于当前函数,因此将“打印返回地址”包装在自己的小函数中是弄巧成拙的,因为它只会告诉您从哪里调用该函数(假设编译器没有) t 决定内联它),在这种情况下,您确实可能使用而不是__LINE__调用。
现在微妙但重要的一点:内在函数的意图__return_address()是“当前函数的返回地址”,这绝不是“R14 的当前内容”相同的东西 - 如果编译器在入口处保存了返回地址然后它就可以自由地使用 R14 做任何它想做的事情。这两行都do_print_r14()打印 0x823194BB,因为这是do_print_r14()调用的地方,并且在调用期间没有任何内容会改变这一点。如果您想深入了解 C 环境的抽象级别并了解R14 在执行过程中实际发生的情况,则需要使用内联汇编技巧,或使用调试器单步执行。