为内联汇编创建常量池的正确方法是什么?
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));
问题是在 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));