【发布时间】:2021-10-13 10:29:02
【问题描述】:
我希望能够使用 LDR 文字指令来加载寄存器。
我有:
extern uint32_t _vStackBase;
extern uint32_t _vStackTop;
__asm volatile
(
" mov r10, #0x5a5a5a5a \n"
" ldr r8, %[stackTop] \n"
" ldr r7, %[stackBase] \n"::
[stackTop] "r"(&_vStackTop), [stackBase] "r"(&_vStackBase):
"r7", "r8", "r10"
);
产生的代码是:
216 ???? 484B ldr r3, .L66+8
217 ???? 494A ldr r2, .L66+12
218 .syntax unified
219 @ 98 "src/startup/startup.c" 1
220 ???? 4FF05A3A mov r10, #0x5a5a5a5a
221 ???? 5FF80480 ldr r8, r3
222 ???? 5FF80470 ldr r7, r2
有两个问题:编译器不必要地使用了寄存器 r2 和 r3。 我想做的事情是:
ldr r8, .L66+8
ldr r7, .L66+12
[...]
但我可以处理这种低效率。
第二个也是更严重的问题是汇编器给出了这个错误:
Error: cannot represent T32_OFFSET_IMM relocation in this object file format
我怎样才能得到我想要的?
编辑 2021-10-27
我按照@timoty 的建议尝试了
extern uint32_t _vStackBase;
extern uint32_t _vStackTop;
__asm volatile
(
" mov r10, #0x5a5a5a5a \n"
" ldr r8, %[stackTop] \n"
" ldr r7, %[stackBase] \n"::
[stackTop] "m"(_vStackTop), [stackBase] "m"(_vStackBase):
"r7", "r8", "r10", "memory"
);
生成的代码还是错误的:
226 0038 4B4B ldr r3, .L66+8
227 003a 4C4A ldr r2, .L66+12
228 .syntax unified
229 @ 127 "src/startup/startup.c" 1
230 003c 4FF05A3A mov r10, #0x5a5a5a5a
231 0040 D3F80080 ldr r8, [r3]
232 0044 1768 ldr r7, [r2]
[...]
701 .L66:
702 0160 00C00A40 .word 1074446336
703 0164 A5FAAF5A .word 1521482405
704 0168 00000000 .word _vStackTop
705 016c 00000000 .word _vStackBase
再说一遍,这不是我想要的,也是错误的。
为了再试一次,我做了这个:
extern uint32_t *_vStackBase;
extern uint32_t *_vStackTop;
__asm volatile
(
" mov r10, #0x5a5a5a5a \n"
" ldr r8, %[stackTop] \n"
" ldr r7, %[stackBase] \n"::
[stackTop] "m"(*_vStackTop), [stackBase] "m"(*_vStackBase):
"r7", "r8", "r10", "memory"
);
又错了:
225 .loc 1 127 9 view .LVU59
226 0038 4B4A ldr r2, .L66+8
227 003a 4C4B ldr r3, .L66+12
228 003c 1268 ldr r2, [r2]
229 .syntax unified
230 @ 127 "src/startup/startup.c" 1
231 003e 4FF05A3A mov r10, #0x5a5a5a5a
232 0042 D3F80080 ldr r8, [r3]
233 0046 1768 ldr r7, [r2]
【问题讨论】:
-
如果你想要的是 r3(又名 %[stackTop]),为什么不直接使用它呢?为什么要将值从一个寄存器复制到另一个?你在修改值吗?
-
你为什么需要组装呢?
"r"(&_vStackTop),所以这实际上是内存中的一个地址,为什么不这样声明它extern uint32_t* _vStackTop;,只需将指针解引用到您需要的任何变量 -
@DavidWohlferd 我不知道 r3 包含我想要的东西。可以决定的是gcc。从 c 翻译成汇编后,我看到了它。我只写了你在帖子中看到的
__asm volatile代码。我不是那种想把一个寄存器复制到另一个寄存器的人。 -
@user3124812 在项目的启动代码中,我必须预先填充主堆栈,因此我不能将堆栈本身用于变量和函数调用。在此之前,我使用
register变量编写了c 代码,但gcc 可以随意进行隐式memset调用。此外,存储类说明符register只是传递给 gcc 的首选项,它仍然可以忽略它并将变量放在堆栈上。我认为最安全的事情是在程序集中编写预填充以确保没有变量进入堆栈并且没有调用函数。 -
godbolt.org/z/q5f35vo5v 显示 GCC 11.1 使用 movw/movt 在寄存器中构造地址,而不是从文字池中加载。你说你想要
ldr r8, .L66+8,那么为什么不首先询问r8中的地址并将其留给编译器,而不是尝试在你自己的asm 语句中使用ldr? (使用register uint32_t *r8 asm("r8") = &_vStackTop;,因为 ARM 没有特定的寄存器约束)。如果您不想从该地址加载,请不要使用另一个ldr。
标签: gcc arm inline-assembly armv7