【发布时间】: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-gccv4.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