在ARM Inline汇编中获取地址
ARM Cortex-M3的IAR编译器提供了内联汇编。 如何将特定函数的地址存储到堆栈上的某个位置?
C代码会喜欢这个
void tick();
void bar()
{
int x;
// modify a value on stack
(&x)[4] = &tick;
}
虽然这一般起作用,但它在发行版本中由编译器进行了优化。 我试图用内联汇编来编写代码
void bar()
{
int x;
asm("ldr r0,%0" : : "i" (&tick));
asm("str r0,[sp+#0x10];
}
ldr
指令不被IAR编译器接受。 问题是这条指令需要一个带寄存器和偏移量的寻址模式。 函数tick
的实际地址存储在函数后面, ldr
指令只保存实际地址所在的存储单元的偏移量。 反汇编是这样的:
ldr r0,??tick_address
str r0,[sp+#0x10]
bx lr ; return
??tick_address dd tick
我怎样才能立即得到tick
的地址给寄存器使用它来进行堆栈操作?
GNU GCC内联汇编可以通过伪空asm()
语句完成分配,如:
asm("" : "=r"(foo) : "0"(tick));
这告诉编译器:
foo
将从寄存器中获取 tick
将被传入 - 在同一个寄存器(参数零) 编译器完全决定要使用哪个寄存器的实际选择。
这里的诀窍是输出和输入约束 - 我们只是输出到输出的唯一输入,编译器会自己选择一个合适的寄存器,并生成加载/存储各个变量所需的指令“实际”内联汇编代码之前/之后。 你甚至可以这样做:
asm("" : "=r"(foo1), "=r"(foo2) : "0"(tick1) , "1"(tick2));
在单个内联汇编语句中执行两个“分配”。
这种编译器生成的“设置输入,检索输出”代码生成即使实际内联程序集为空(如此处)。
另一个例子:假设你想读取当前程序计数器 - PC
寄存器。 您可以通过两种不同的行内汇编语句在ARM上执行此操作:
asm("" : "=pc"(foo));
asm("mov %0, PC" : "=r"(foo));
这不是100%相同; 在第二种情况下,编译器知道无论希望在asm
之后看到foo
寄存器,它都会在那里找到它。 在前者中,编译器知道如果在语句后使用foo
,它需要从PC
检索它。 两者之间的区别是,如果你这样做了:
uintptr_t *val;
uintptr_t foo;
asm("" : "=pc"(foo));
*val = foo;
在这种情况下,编译器可能会识别出它可以变成单个str [R...], PC
因为它知道foo
在asm之后的pc
。 你是通过写这个吗?
asm("mov %0, PC" : "=r"(foo));
*val = foo;
编译器将被迫创建(假设它为foo
/ val
选择R0
/ R1
):
MOV R0, PC
STR [R1], R0
此行为的文档主要在GCC手册的“扩展ASM”部分中,请参阅设计的combine
指令的示例。
代码中没有赋值变量x
,因此它的值未定义,并且将foo
设置为未定义的值不需要更改foo
。
您需要将值赋予变量,而不是您假定编译器用于实现它的某个内存位置。
链接地址: http://www.djcxy.com/p/87131.html