控制功能';arm gcc中的s预记录和epilog
我注意到,有时在编译C代码时,汇编代码有时会在方法1中生成:控制功能';arm gcc中的s预记录和epilog,c,gcc,assembly,arm,C,Gcc,Assembly,Arm,我注意到,有时在编译C代码时,汇编代码有时会在方法1中生成: STR R11, [SP, #-4]! ADD R11, SP, #0 SUB SP, SP, #4 有时在方法2中: STMFD SP!, {R11, LR} ADD R11, SP, #4 SUB SP, SP, #4 第一种方法和第二种方法的区别在于,第二种方法将LR保存到堆栈中 现在我面临着一个问题,我的函数,像第一个方法一样启动,使用链接寄存器(BL)调用另一个函数,由于我的函数没有首先保存LR,它导致了一个严重的问题。
STR R11, [SP, #-4]!
ADD R11, SP, #0
SUB SP, SP, #4
有时在方法2中:
STMFD SP!, {R11, LR}
ADD R11, SP, #4
SUB SP, SP, #4
第一种方法和第二种方法的区别在于,第二种方法将LR保存到堆栈中
现在我面临着一个问题,我的函数,像第一个方法一样启动,使用链接寄存器(BL)调用另一个函数,由于我的函数没有首先保存LR,它导致了一个严重的问题。
如果我能告诉编译器使用第二种方法,它就能解决我的问题
这可能与函数使用内联汇编调用内部函数有关,因此“无法识别”存在对另一个函数的调用,并且认为保存LR没有意义。调用内联程序集是有义务的,因为被调用的函数获取SP的值作为参数
这真是一个两难的局面,希望有人能帮我解决这个问题。
谢谢 有几种解决方案可以节省LR 1) 您可以手动保存它,因为您编写了内联程序集,所以您可以在调用函数之前保存LR,并在调用之后恢复它 2) 您可以声明一个虚拟变量,该变量将使用以下C代码放入LR中:
register int foo asm ("lr");
3) 使用
请注意,最好的解决方案可能是第三个。将
lr
标记为clobbred,以使编译器保存它:
extern void foo(void);
extern void bar(void)
{
asm ( "bl foo" : : : "lr" );
}
生成以下代码:
bar:
str lr, [sp, #-4]!
bl foo
ldr lr, [sp], #4
bx lr
有关更多详细信息,请参阅。记住,也要将您使用的所有其他寄存器标记为clobbered。否则,编译器可能会在其中一个中放入一个变量。您可能还需要将所有调用者保存的寄存器标记为clobbered。最简单/直接的答案是将
lr
添加到clobber,但您可能需要添加更多
为什么?? 编译器根据函数的类型生成不同的序言/尾声。它们可以是泛型函数、叶函数(不调用其他函数)或尾部调用。您没有显示任何代码,因此很难了解您的具体情况。然而,如果您没有记录内联汇编程序正在调用另一个函数,那么gcc认为它是一个叶函数,而不是 从 在不使用输入/输出操作数的情况下访问C程序中的数据(例如直接使用汇编程序模板中的全局符号)可能无法按预期工作。类似地,直接从汇编程序模板调用函数需要详细了解目标汇编程序和ABI 出于这个原因,我认为将
r0
-r3
和lr
添加到缓冲区也是最安全的。也可能需要霓虹灯/浮点寄存器。编译器应该知道,这些可以通过“inlineasm
”语句进行更改
如果在汇编语句之后没有代码,并且假设没有使用“帧指针”或其他寄存器,则可以使用尾部调用。即,将bl inline\u asm\u target
替换为b inline\u asm\u target
,其中inline\u asm\u target函数仍然执行bx lr
(或任何适合使用的编译器选项/ABI的操作)
相关:-
-为什么在没有显示函数在C中的外观的情况下,就将问题标记为“C”?最好将在内联汇编中完成的调用替换为在C中完成的调用。如果您需要汇编来获取SP,则使用它来获取SP;调用是不相关的,所以在C中进行。这应该不难,但您没有显示代码,因此我们无法知道。在C中的等价物是编写“int func(){}”,因为我谈到了函数prelog。但既然这没有提供任何信息,我觉得这没有什么意义。@YouYou,我很高兴。