【问题标题】:Inline ASM - Use 16 or 32 bit C Variable (GCC ARM, Thumb Mode)内联 ASM - 使用 16 或 32 位 C 变量(GCC ARM,Thumb 模式)
【发布时间】:2016-05-22 23:27:39
【问题描述】:

我目前正在为 Cortex-M3 使用以下内联 ASM 以跳转到闪存中的特定地址。

__asm("LDR R0, =0x8000"); //  Load the branch address
__asm("LDR R1, [R0]");    //  Get the branch address
__asm("ORR R1, #1");      //  Make sure the Thumb State bit is set.
__asm("BX R1");           //  Branch execution
  • 但是,我想将硬编码值 0x8014 替换为将根据其他一些条件计算的 C 变量。
  • 这个变量可以取的最大可能值是 0x20000,所以我打算使用 uint32_t 来存储它。
  • 使用的编译器是arm-none-eabi-gcc v4.9.3

我尝试如下修改我的内联 ASM:

uint32_t destination_address = 0x8000;
__asm( "LDR R0, =%[dest]" : : [dest]"r"(destination_address) );

但是,这会产生编译器错误:

undefined reference to `r3'

总的来说,我对内联 ASM 相当陌生。我已经尝试研究这个问题两天左右,但由于编译器的多样性以及我在 Cortex-M3 上使用 Thumb 指令这一事实,我一直对相互矛盾的答案感到困惑。

认为我的问题是我需要为变量 destination_address(范围 0x0 - 0x20000)找到正确的约束,但我不确定。

【问题讨论】:

  • 好消息是该错误很容易修复 (godbolt.org/g/3B9YqC)。如果你打算使用内联 asm,你应该习惯使用-S(这是 Godbolt 在这里使用的)。不利的一面是,当您在 asm 中跳转时,gcc 不喜欢它。这真的会搞砸优化、符号引用等。
  • @DavidWohlferd 我不太确定我是否跟随。 (i) 根据您的链接示例,将 =%[dest] 重写为 [%[dest]] 确实允许编译代码! (ii) 但我不明白为什么? (iii) -S 是什么意思,更重要的是它在你的例子中体现在哪里? (iv) 您应该将此作为答案发布! (v) 关于从 ASM 跳转,在这个用例中,我将离开二进制文件并且永远不会回来。
  • ii) 从输出中可以看出,0x8000 被移入 r3 寄存器(您对 LDR R0, =0x8000 所做的操作)。您的第二行 (LDR R1, [R0]) 假定该值在 r0 中,但是当使用“r”约束时,gcc 可以选择任何可用的寄存器。我们没有猜测或假设,而是替换为 s/R0/%[dest]。更直接的答案是 =%[dest] 将扩展到 =r3,我认为这不是有效的汇编程序。 iii) -S 在此处记录 (gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#index-S-83)。
  • iv) 我不是皮质程序员,这意味着我在猜测。 v) 嗯,那可能是安全的。如果您要读取二进制写入的任何数据,请添加“memory”clobber。
  • 请注意,除非您在不接触链接寄存器的情况下bx 绝对重要,否则您最好只使用do the whole lot with plain C code

标签: inline-assembly cortex-m3 thumb


【解决方案1】:

为什么要使用内联汇编?

extern void HOP ( unsigned int );
...
unsigned int some_address;
..
some_address = some_math;
HOP(some_address);

还有几行真正的 asm,如果你真的觉得必须从链接中创建一个对象,你可以使用 c 编译器。

.globl HOP
HOP:
   bx r0

额外的好处是它基本上是一个分支链接,如果你想的话。

编译器已经计算出它听起来像的地址,所以你“简单地”需要将它放入一个寄存器并bx它。内联汇编是非常特定于编译器的,因此您需要从谈论您正在使用的汇编器、版本等开始。

如果你有这个,你可以做的另一件事是

unsigned int some_address;
..
some_address = some_math;

你可以在项目的某个地方使用这个程序集。

ldr r0,=some_address;
ldr r0,[r0]
bx r0

链接器会将地址解析为 C 变量。所以可以使用真正的汇编器或内联来做类似的事情。 (如果内联不支持类似 mov %0,some_address; bx %0 并为您完成工作)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 2020-04-11
    相关资源
    最近更新 更多