【问题标题】:Get the address in ARM Inline assembly获取 ARM 内联汇编中的地址
【发布时间】:2013-03-25 10:13:53
【问题描述】:

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];
}

IAR 编译器不接受ldr 指令。问题是这条指令需要一个带有寄存器和偏移量的寻址模式。函数tick 的实际地址存储在函数后面,ldr 指令仅保存到保存实际地址的内存位置的偏移量。反汇编类似这样:

    ldr r0,??tick_address
    str r0,[sp+#0x10]
    bx lr ; return
??tick_address dd tick

如何立即将tick 的地址保存到寄存器中以用于堆栈操作?

【问题讨论】:

  • 那是 GCC 内联汇编语法吗?我相信 IAR 允许在内联汇编中直接引用符号,而无需任何额外的繁文缛节。 IE。类似asm("ldr,=tick");
  • 它看起来类似于 GCC 语法。但正如我的编辑所示,LDR 需要一个非直接参数。
  • IAR 汇编器手册将LDR Rd,=immed32 列为受支持的伪指令。他们不支持内联汇编似乎很奇怪。
  • @Michael 看来是的。 “i”导致立即数-# 被添加到符号前面。但这需要将实际值放置在函数末尾的代码中,以便在 [PC+offset] 处访问它。在内联汇编中这可能有点复杂。
  • 你想在这里实现什么 - 分配函数指针的任务可以在纯 C 中完成,根本不需要汇编。如果有的话,asm("" : "=r"(foo) : "0"(tick)) 将“分配”它。请您提供更多背景信息吗?

标签: inline-assembly iar


【解决方案1】:

GNU GCC 内联汇编可以通过伪空的asm() 语句完成赋值,例如:

asm("" : "=r"(foo) : "0"(tick));

这告诉编译器:

  1. 变量foo 将从内联汇编块之后的寄存器中获取
  2. 变量tick将被传入-在相同寄存器中(参数0)

使用哪个寄存器的实际选择完全留给编译器。

这里的技巧是 outputinput 约束 - 我们只是 alias 将(唯一的)输入到输出,而编译器将自行选择合适的寄存器,并生成在“实际”内联汇编代码之前/之后加载/存储各个变量所需的指令。你甚至可以这样做:

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;

编译器将被强制创建(假设它选择R0 / R1 for foo/val):

MOV R0, PC
STR [R1], R0

此行为的文档主要是 in the "Extended ASM" section of the GCC manuals,请参阅人为设计的 combine 指令的示例。

【讨论】:

  • 确认这在 IAR 中有效。我还必须注意,输入参数不能用作立即数,因此asm("mov r0, %0" : "=r"(foo) : "0"(tick)); 有效,asm("bkpt %0" : "=r"(foo) : "0"(tick)); 无效。但也许有人可以指出一个巧妙的技巧来规避这一点?
【解决方案2】:

您的代码中没有分配变量x,因此它的值是未定义的,并且不需要将foo 设置为未定义的值来更改foo

您需要将值分配给变量,而不是您假设编译器用来实现它的某个内存位置。

【讨论】:

  • x 由内联汇编分配。
猜你喜欢
  • 1970-01-01
  • 2010-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多