为内联汇编创建常量池的正确方法是什么?

Nik*_*lai 6 c gcc arm inline-assembly

问题是在C函数内部我有一个内联汇编.就像是

  ldr r7, =0xdeadbeef
  svc 0
Run Code Online (Sandbox Code Playgroud)

如果没有显式创建文字池(这是这种情况),汇编程序会在翻译单元的末尾创建一个文字池.通常这很好,但是如果翻译单元真的很大,那么这不起作用,因为文字池离ldr指令太远了.

所以,我想知道处理这个问题的最佳方法是什么.最明显的方法是在内联汇编中手动创建文字池:

  ldr r7, =0xdeadbeef
  svc 0
  b 1f
  .ltorg
1:
Run Code Online (Sandbox Code Playgroud)

要么

  ldr r7, 1f
  svc 0
  b 2f
1:
  .word 0xdeadbeef
2:
Run Code Online (Sandbox Code Playgroud)

不幸的是,由于冗余分支指令,这导致了次优代码.我不希望汇编器足够聪明,为函数内部的常量池找到合适的位置.我想要做的是在函数的末尾创建一个常量池.有没有办法告诉编译器(gcc)在函数末尾创建一个文字池?

PS我最终使用了movw/movt对而不是常量池.虽然,首先,movw/movt解决方案的可移植性略低于文字池,其次,我只是想知道是否可以可靠而有效地在内联汇编中使用常量池.


更新: 那么,处理问题的最佳方法是什么?

要强制工具链在函数之后创建一个常量池,可以将函数放在单独的代码部分中.它的工作原理是因为在翻译单元结束时汇编程序为每个部分生成单独的常量池.

实际上,最好的方法是避免将常量加载到内联汇编中的寄存器中.让编译器这样做会更好.在我的情况下,我最终写了一个类似的代码

register int var asm("r7") = 0xdeadbeef;
asm volatile("svc 0\n" :: "r" (var));
Run Code Online (Sandbox Code Playgroud)

art*_*ise 4

您可以使用-ffunction-sections和 根据上的查询-ffunction-section,使用 ald --gc-sections来删除未使用的代码。

很明显,文件被分割了。

一个可行的解决方案是使用naked带有unused注释的函数,因为它永远不会被调用。将一个函数放在.ltorg这里,并将两个函数放在一个特殊的部分;.text.ltorg_kludge例如。链接器脚本应将.text*相同子部分中的使用和函数放置在一起。在某些方面,这就像拆分文件,因为编译器将尝试内联static函数。

您可以依赖编译器发出源代码中遇到的函数,而无需特殊部分。但是,我不确定这是否是标准或偶然的情况。编译器可以通过按调用层次结构的某些 DAG 顺序发出函数来更好地优化。


旁白:movw/movt由于缓存效应,效率更高。它还适用于 ARMv6 及以上的 Thumb2 代码。我不认为可移植性是一个大问题(因为内联汇编器是不可移植的,并且您可能更喜欢性能而不是可移植性),但问题与 ARMv4/5 用户相关。


我研究了gcc 机器约束R约束的使用,

R
      常量池中的一项

然而,gcc-4.8 的示例给出了错误不可能的约束。使用C等替代字母也会给出相同的错误消息。检查源contraints.md似乎表明R约束只是文档功能。不幸的是,因为这听起来是为了解决这个问题而设计的。

可以让编译器加载该值,但这可能不是最佳的,具体取决于inline汇编器。例如,

  asm(" add %0, %0, %1\n" : "+r" (0xdeadbeef) : "r" (0xbaddeed0));
Run Code Online (Sandbox Code Playgroud)