【问题标题】:inline ARMv7-M assembly code into c using gcc (Load Register literal)使用 gcc(加载寄存器文字)将 ARMv7-M 汇编代码内联到 c 中
【发布时间】: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


【解决方案1】:

编译器不必要地使用寄存器 r2 和 r3。

那是因为你在这里要求寄存器:

[stackTop] "r"(&_vStackTop), [stackBase] "r"(&_vStackBase):

要请求编译器提供内存引用,请使用 "m" 而不是 "r"

Error: cannot represent T32_OFFSET_IMM relocation in this object file format

由于您要求注册,编译器会用一个寄存器代替%[stackTop],从而得到ldr r8, r3ldr 指令的第二个操作数是内存引用,由于文件中没有名为 r3 的内存位置(或者它在另一个部分中),因此汇编器将在目标文件中留下一个重定位以供链接器修复,但这不被 ELF 和其他目标文件格式支持,因为这不是很有用,因为 PC 相对内存引用的范围很短。

【讨论】:

  • 对于内存操作数,您还需要请求内存中的值,而不是寄存器中的地址。喜欢[stackTop] "m" (_vStackTop)。编译器将替换一种寻址模式,该模式到达内存中保存您要求的值,因此如果它是诸如&_vStackTop 之类的表达式,它将必须创建一个本地临时保存该地址。
  • @timoty 我编辑了我的帖子
  • @PeterCordes 不清楚你说什么,但我尝试使用[stackBase] "m"(&_vStackBase),但是gcc报错:error: memory input 1 is not directly addressable
  • @mastupristi:哦,对了,GCC/clang 要求"m" 内存操作数的左值,并且不会为表达式的临时结果发明内存位置。所以无论如何,就像我说的你需要[stackTop] "m" (_vStackTop),而不仅仅是将"r" 更改为"m"
猜你喜欢
  • 2015-09-25
  • 2021-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多