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

时间:2015-03-03 13:35:26

标签: c gcc arm 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));

1 个答案:

答案 0 :(得分:3)

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

有明显的分割文件。

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

您可以依赖源代码中遇到的编译器发射函数,而不需要特殊的部分。但是,我不确定这是标准还是发生的立场。编译器可以通过在调用层次结构的某些DAG排序中发出函数来更好地进行优化。


除此之外:由于缓存效应,movw / movt效率更高。它也适用于ARMv6及以上的Thumb2代码。我不认为可移植性是一个大问题(因为内联汇编程序是不可移植的,你可能更喜欢性能而不是可移植性),但这个问题与ARMv4 / 5用户有关。


我调查了gcc machine constraints

R 约束的使用情况
  

R
  常量池中的项目

但是,sample with gcc-4.8会出现错误无法约束。使用 C 等替代字母也会显示相同的错误消息。检查source contraints.md似乎表明 R 约束是仅限文档的功能。不幸的是,因为它听起来是为解决这个问题而建的。

可以让编译器加载该值,但这可能是次优的,具体取决于inline汇编程序。例如,

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