【问题标题】:What is the right way to create a constant pool for inline assembly?为内联汇编创建常量池的正确方法是什么?
【发布时间】:2015-05-04 04:27:52
【问题描述】:

问题是在 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));

【问题讨论】:

标签: c gcc arm inline-assembly


【解决方案1】:

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

分割文件是很明显的。

一个可行的解决方案是使用带有unused 注释的naked 函数,因为它永远不会被调用。在这里放置一个.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));

【讨论】:

  • 感谢您的精彩回答!我喜欢你摆弄部分的想法!至于“R”约束,目前constraints.md中的注释说“我们曾经在ARM状态下有S和R的约束字母,但现在这些的所有使用似乎都已被删除”。
  • 也和armv6系统相关,armv6t2有movw/movt,bitbaseline armv6没有。
猜你喜欢
  • 2011-10-06
  • 1970-01-01
  • 2019-05-04
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-27
相关资源
最近更新 更多