我想把函数的地址加载到寄存器中。我写了下面的内联汇编程序。内联汇编程序返回错误“Error:未定义的符号x0用作立即数”。这段代码有什么问题?。我在ubuntu上使用的是ARM GNU工具链。
void MyFunction()
{
...
}
int main()
{
__asm volatile("mov x2, %[FnAddr] \n\t"::[FnAddr]"m"(MyFunction));
}
目标:在新启动的AArch64系统(在EL2中)中,我想转到EL1。因为此ELR_EL2寄存器将加载目标地址以继续执行
1条答案
按热度按时间cu6pst1q1#
到目前为止,您所拥有的产品存在以下几个问题:
首先,正如Peter Cordes在评论中指出的,
m
是错误的约束,它扩展为类似[x0]
的东西。但是进一步考虑,在寄存器中具体化函数的地址实际上有些复杂。单个
mov
指令通常不起作用,因为立即数被限制在16位。因此,即使你能让编译器发出mov x2, #MyFunction
,你的程序也会编译,但随后无法链接。通常你会用adrp/add序列来完成,请参阅了解ARM重定位(示例:字符串x 0,[临时,#:lo 12:zbi_paddr])。不过,最好的方法是让编译器为你做这件事。通过使用一个带有
r
约束的输入操作数,编译器会在内联asm之前加上一个adrp
、mov
或任何适合你的程序代码模型的序列,获取某个通用寄存器中的地址,并将操作数扩展到该寄存器的名称(x0
,x1
,等等)。这里你不关心选择哪个寄存器,因为你只是要用它作为msr
指令的输入,所以你无论如何都要避免硬编码x2
。(如果它必须是x2
,你可以用一个局部寄存器变量告诉编译器使用哪个寄存器。因此,您的代码可以简单地变成:
Try it on godbolt(向下滚动程序集输出以查看相关代码)。
从技术上讲,
volatile
关键字是不必要的,因为没有输出的asm
总是被认为是volatile
,但这并没有什么坏处,对阅读代码的人来说可能是一个很好的提示。