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

What is the right way to create a constant pool for inline assembly?

问题是在 C 函数中我有一个内联程序集。 像

  ldr r7, =0xdeadbeef
  svc 0

如果没有显式创建文字池(就是这种情况),汇编器 在翻译单元的末尾创建一个。通常这很好,但如果 翻译单元原来真的很大,这是行不通的,因为 文字池距离 ldr 指令太远。

所以,我想知道处理该问题的最佳方法是什么。最明显的方法是 在内联程序集内手动创建文字池:

  ldr r7, =0xdeadbeef
  svc 0
  b 1f
  .ltorg
1:

  ldr r7, 1f
  svc 0
  b 2f
1:
  .word 0xdeadbeef
2:

不幸的是,由于冗余分支,这导致了次优代码 操作说明。我不希望汇编程序足够聪明以找到合适的 在函数中放置常量池。我想做的是 在函数末尾创建一个常量池。有什么办法可以告诉 编译器 (gcc) 在函数的末尾 创建文字池 ?

PS 我最终使用了 movw/movt 对而不是常量池。尽管, 首先,movw/movt 解决方案的可移植性略低于文字池,并且, 其次,我只是想知道是否可以在内联汇编中使用常量池 既可靠又高效。


更新: 那么,最好的处理方法是什么?

强制工具链在可以放置的函数之后创建一个常量池 该函数在单独的代码部分中。它之所以有效,是因为在翻译单元的末尾,汇编程序会生成 每个部分都有单独的常量池。

虽然,事实上,最好的方法是避免将常量加载到寄存器中 内联汇编。最好让编译器来做。就我而言,我 最终写出了类似于

的代码
register int var asm("r7") = 0xdeadbeef;
asm volatile("svc 0\n" :: "r" (var));

您可以使用 -ffunction-sections 并根据 query on -ffunction-section,使用 ld --gc-sections 删除未使用的代码。

分割文件明显

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

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


旁白:由于缓存效应,movw/movt 效率更高。它还适用于 ARMv6 和更高版本的 Thumb2 代码。我不认为可移植性有什么大不了的(因为内联汇编器是不可移植的,你可能更喜欢性能而不是 可移植性),但这个问题与 ARMv4/5 用户有关。


我调查了 R 约束的使用 gcc machine constraints,

R
      An item in the constant pool

但是,sample with gcc-4.8 gives an error impossible constraint. Using alternative letters like C also give the same error message. Inspection of the source contraints.md 似乎表明 R 约束是仅文档功能。不幸的是,这听起来是为了解决这个问题而设计的。

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

  asm(" add %0, %0, %1\n" : "+r" (0xdeadbeef) : "r" (0xbaddeed0));