Assembly 为什么正向参考ADR指令在Thumb代码中的偏移量是偶数?
要Assembly 为什么正向参考ADR指令在Thumb代码中的偏移量是偶数?,assembly,arm,gnu-assembler,thumb,Assembly,Arm,Gnu Assembler,Thumb,要bx使用Thumb函数,需要设置地址的最低有效位。GNU as文档说明了当地址是从adr伪指令生成时,它是如何工作的: 药品不良反应 此指令将标签地址加载到指定的寄存器中。[……] 如果标签是thumb功能符号,则thumb互通已完成 通过-mthumb interwork选项启用,然后是 将设置存储在寄存器中的值。这允许以下顺序按预期工作: adr r0,拇指功能 blx r0 所以听起来事情应该就这么办了。然而,在一些反汇编中,某些地址似乎没有设置底部位 例如,组装和链接: .syntax
bx
使用Thumb函数,需要设置地址的最低有效位。GNU as文档说明了当地址是从adr
伪指令生成时,它是如何工作的:
药品不良反应
此指令将标签地址加载到指定的寄存器中。[……]
如果标签是thumb功能符号,则thumb互通已完成
通过-mthumb interwork
选项启用,然后是
将设置存储在寄存器中的值。这允许以下顺序按预期工作:
adr r0,拇指功能
blx r0
所以听起来事情应该就这么办了。然而,在一些反汇编中,某些地址似乎没有设置底部位
例如,组装和链接:
.syntax unified
.thumb
.align 2
table:
.4byte f1
.4byte f2
.4byte f3
.align 2
.type f1, %function
.thumb_func
f1:
adr r1, f1
adr r2, f2
adr r3, f3
bx r1
.align 2
.type f2, %function
.thumb_func
f2:
adr r1, f1
adr r2, f2
adr r3, f3
bx r2
.align 2
.type f3, %function
.thumb_func
f3:
adr r1, f1
adr r2, f2
adr r3, f3
bx r3
与:
使用arm none eabi objdump-D a.out检查,我得到:
00008000 <table>:
8000: 0000800d .word 0x0000800d
8004: 00008019 .word 0x00008019
8008: 00008025 .word 0x00008025
0000800c <f1>:
800c: f2af 0103 subw r1, pc, #3
8010: a201 add r2, pc, #4 ; (adr r2, 8018 <f2>)
8012: a304 add r3, pc, #16 ; (adr r3, 8024 <f3>)
8014: 4708 bx r1
8016: 46c0 nop ; (mov r8, r8)
00008018 <f2>:
8018: f2af 010f subw r1, pc, #15
801c: f2af 0207 subw r2, pc, #7
8020: a300 add r3, pc, #0 ; (adr r3, 8024 <f3>)
8022: 4710 bx r2
00008024 <f3>:
8024: f2af 011b subw r1, pc, #27
8028: f2af 0213 subw r2, pc, #19
802c: f2af 030b subw r3, pc, #11
8030: 4718 bx r3
8032: 46c0 nop ; (mov r8, r8)
00008000:
8000:0000800d。字0x0000800d
8004:00008019.字0x00008019
8008:00008025.字0x00008025
0000800c:
800c:f2af 0103 subw r1,pc,#3
8010:a201添加r2,pc,#4;(adr r2,8018)
8012:a304添加r3,pc,#16;(adr r3,8024)
8014:4708 bx r1
8016:46c0 nop;(mov r8,r8)
00008018 :
8018:f2af 010f地下室r1,pc,#15
801c:f2af 0207子图纸r2,pc,第7页
8020:a300加r3,pc,#0;(adr r3,8024)
8022:4710 bx r2
00008024 :
8024:f2af 011b subw r1,pc,#27
8028:f2af 0213 subw r2,个人电脑,19
802c:f2af 030b subw r3,pc,#11
8030:4718 bx r3
8032:46c0 nop;(mov r8,r8)
有几件事需要注意:
在表
中,f1
、f2
和f3
的绝对地址都是奇数,如预期的那样。因此,显然,汇编器和链接器知道这三个函数应该是Thumb
对于反向引用,adr
伪指令向下汇编为subw
,偏移量是奇数,正如预期的那样
但是对于正向引用,如果adr
伪指令汇编成add
,则偏移量是偶数
我遗漏了什么?您遗漏了ARM文档中的以下内容:
如果使用ADR为BX或BLX指令生成目标,则如果目标包含Thumb指令,则您有责任设置地址的Thumb位(位0)
正向引用ADR指令使用ADD指令的16位Thumb“ADD Rd,pc,#imm”形式。此指令的立即数在0-1020的范围内,并且必须是字对齐的(即,它用8位字段编码并乘以4)。使用的PC值也将较低的两位设置为0,因此它无法生成奇数地址
强制汇编程序始终使用带有ADR.W的32位Thumb指令应该会导致它在使用函数标签时始终生成奇数地址,但我不知道您是否可以依赖于此。最好只显式设置较低的位。回到这个问题。问题其实很简单:
if (inst.relocs[0].exp.X_op == O_symbol
&& inst.relocs[0].exp.X_add_symbol != NULL
&& S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
&& THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
inst.relocs[0].exp.X_add_number += 1;
在do_t_adr()函数中
S_IS_DEFINED检查符号是否已定义,当在此时间点进行正向参考时,符号未定义,因此线不会通过,它不会添加一个非常干扰清洁度的符号,但不管是什么。对于向后参考,定义符号以便进行调整。(当然,如果没有定义的符号,THUMB_IS_FUNC也无法工作)
ADR转换为BFD_RELOC_ARM_THUMB_ADD。这把我们带到了这里
case BFD_RELOC_ARM_THUMB_ADD:
/* This is a complicated relocation, since we use it for all of
the following immediate relocations:
3bit ADD/SUB
8bit ADD/SUB
9bit ADD/SUB SP word-aligned
10bit ADD PC/SP word-aligned
The type of instruction being processed is encoded in the
instruction field:
0x8000 SUB
0x00F0 Rd
0x000F Rs
*/
在这里面
else if (rs == REG_PC || rs == REG_SP)
{
/* PR gas/18541. If the addition is for a defined symbol
within range of an ADR instruction then accept it. */
在以后的过程中发生的代码(在定义符号并可以找到符号之后)不会修补立即数/偏移量
我发现如果没有语法统一,它就无法处理这个问题,这更令人不安/有问题
.thumb
.thumb_func
zero:
adr r0,zero
即使使用.syntax统一,他们也没有完成T16的ADR实现。只需在那里输入一个错误,并称其为“完成”。(当然可以在T16中实现,例如添加rx、pc、#0、sub rx、#offset。)
即使他们修复了它,我也会避免ADR指令。但很明显,他们并没有真正完成这个伪指令的实现
注意,在arm模式下,它们有相同的错误,在错误的时间检查符号
if (support_interwork
&& inst.relocs[0].exp.X_op == O_symbol
&& inst.relocs[0].exp.X_add_symbol != NULL
&& S_IS_DEFINED (inst.relocs[0].exp.X_add_symbol)
&& THUMB_IS_FUNC (inst.relocs[0].exp.X_add_symbol))
inst.relocs[0].exp.X_add_number |= 1;
请注意,ORR没有添加一个更好/不同的作者,但没有完全考虑这个解决方案
如果我删除S_IS_定义和THUMB_IS_FUNC检查
.arm
zero:
adr r0,two
.thumb
.thumb_func
two:
nop
从
00000000 <zero>:
0: e24f0004 sub r0, pc, #4
00000004 <two>:
4: 46c0 nop ; (mov r8, r8)
6: 46c0 nop ; (mov r8, r8)
给予
(该错误与您指出的错误位于同一代码段中)
首先看看其他汇编程序的文档中关于ADR和thumb的内容,然后看看他们是否真的按照该文档实现了它,和/或带着错误或警告退出了。您是否尝试过查看一些C代码(例如静态或本地函数指针数组)的GCC输出看看是否有额外的指令用于确保汇编器知道它是函数符号?或者,如果在这种情况下asm最终没有得到奇数地址,adr.w将生成一个T3变体,如armv7-m文档中所述。它允许从0到4095的任何偏移量,不限于四次方,比如T1编码,没有统一语法,它是为我而不是为t3生成T1编码。@PeterCordes C编译器不生成adr指令,它们以其他方式解决这个问题,或者是由链接器填充并与pc相对负载一起使用的字,或者蹦床(gnu ld确实有蹦床的问题,所以不要依赖它们)。或者,如果您只是想再次使用C代码中的地址,则会留出一个单词
00000000 <zero>:
0: e24f0004 sub r0, pc, #4
00000004 <two>:
4: 46c0 nop ; (mov r8, r8)
6: 46c0 nop ; (mov r8, r8)
00000000 <zero>:
0: e24f0003 sub r0, pc, #3
00000004 <two>:
4: 46c0 nop ; (mov r8, r8)
6: 46c0 nop ; (mov r8, r8)
.syntax unified
.thumb
adr r0,two
nop
nop
.thumb_func
two:
nop
00000000 <two-0x8>:
0: f20f 0005 addw r0, pc, #5
4: 46c0 nop ; (mov r8, r8)
6: 46c0 nop ; (mov r8, r8)
00000008 <two>:
8: 46c0 nop ; (mov r8, r8)
.syntax unified
.cpu cortex-m0
.thumb
adr r0,two
nop
nop
.thumb_func
two:
nop
/path/so.s: Assembler messages:
/path/so.s:5: Error: invalid immediate for address calculation (value = 0x00000003)