"The role of register r9 is platform specific."
但是
"A virtual platform [...] may designate r9 as an additional callee-saved
variable register, v6."
问题是:Linux内核是否将r9用于某些特殊目的?还是将其用作普通的非易失性寄存器?
"The role of register r9 is platform specific."
"A virtual platform [...] may designate r9 as an additional callee-saved
variable register, v6."
CROSS_COMPILE=... ARCH=arm make vmlinux
),然后反汇编整个内核。${CROSS_COMPILE}objdump -d vmlinux.o | grep 'sb|r9'
要检查(使用r9
和sb
名称,因为它取决于您的objdump输出的确切内容)。
如果您在序言/尾声代码中发现它被使用(在指令如push {..., r9, ...}
,stmfd sp!, {..., r9, ...}
或其相应的pop
/ldmfd
中),那么它是被调用者保存的。否则,它只是另一个临时寄存器。结果可能取决于您的工具链、内核配置选项或ARM目标。
话虽如此,如果您编译了一个Thumb-2内核,它将不会被调用者保存。这是因为Thumb-2的push
/pop
仅操作较低的寄存器集(并以互补方式处理lr
/pc
,push lr
与pop pc
配对)。
简而言之 - 这取决于libc和编译器选项。对于大多数ARM Linux发行版,答案是它是被调用者保存的寄存器。
只有深度嵌入式的libc和工具可能会使用静态基址。
Linux内核本身不使用静态基址,r9可供使用。
不清楚问题是针对用户进程还是内核开发人员。
sb
代表静态基础。它是静态数据(包括程序全局变量)的引用。对于某些系统,您可能有多个共享相同代码但需要不同静态基础的进程。例如,网络网关可能会为每个端口创建一个包含该端口状态的静态基础进程。sb
。这不是实际操作系统和Linux的责任。它只会在上下文切换时保存/恢复r9。因此,实际答案取决于libc。
可以使用GOT和其他RAM thunk。但在深度嵌入式设备中,使用NOR闪存或ROM使用静态基址可能是最有效的。对于像Raspberry Pi、Beagle bone、Android手机等设备,它们都有MMU,没有必要进行静态基址的操作。
您可以使用objdump -d my_code | grep -E '(sb|r9)'
来确定r9的堆栈使用情况。仅在grep
中命中r9
是不够的。您需要查看堆栈操作。在一个系统上,您可以同时看到两者。仅因为一个二进制文件具有r9的堆栈使用并不意味着您构建的程序不会使用它。应该在工具输出上执行objdump
/grep
组合。
正确答案由编译器和libc确定;Linux本身可以支持任何一种。您应该查看libc文档。事实上,gcc通过使用不同的选项(如sb
)来支持使用。
https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
U-boot使用 静态基址 作为实例。一个静态二进制文件可以使用静态基址,而同一系统上的其他程序可以使用通用 r9
。Linux有一些关于ABI使用的命名惯例,但主要与系统调用机制有关,而不是寄存器使用。
可以确定的是,Linux内核不会管理sb/r9寄存器。它需要由libc加载器进行管理和设置,该加载器将调用 map
、sbrk
等来设置初始的 sb
,然后在进程的 main()
运行之前或在静态二进制文件中,在程序启动代码中设置。
更多技术细节请参见:静态共享库。
我认为寄存器定义存储在include/asm-arm/ptrace.h中。
不过我不确定100%...
objdump -DS -M reg-names-std net/core/dev.o | grep push | grep r9
(非架构代码)显示了相当多的条目,所以可以安全地假设r9
是一个非易失性寄存器。 - Mircear9
是不够的。您需要查看堆栈操作。正确的答案由编译器和libc确定;Linux本身可以支持任何一种。在一个系统上,您可以看到两者都有。仅因为一个二进制文件具有r9的堆栈使用并不意味着您构建的程序不会使用它。应该在工具输出上执行objdump
/grep
组合。 - artless noise