为什么不可能?
您已链接到 GAS 文档,但这种无能的原因是什么?
答:GAS 必须通过 ELF 目标文件将操作传达给链接器,像这样可以传达的唯一内容是+
and -
(-
只是+
一个负值)。所以这是 ELF 格式的一个基本限制,而不仅仅是 GAS 开发人员的懒惰。
当 GAS 编译到目标文件时,将遵循一个链接步骤,它是重定位将决定符号的最终值。
问题:为什么可以+
传达,但不能&
?
答案:因为+
是及物的:(a + b) + c == a + (b + c)
但+
和&
不是“一起传递的”:(a & b) + c!= a & (b + c)
。
让我们看看如何+
通过 ELF 格式传达来说服自己这&
是不可能的。
不熟悉的先了解一下什么是重定位:https ://stackoverflow.com/a/30507725/895245
让我们用另一个会产生相同错误的示例来最小化您的示例:
a: .long s
b: .long s + 0x12345678
/* c: .long s & 1 */
s:
编译和反编译:
as --32 -o main.o main.S
objdump -dzr main.o
输出包含:
00000000 <a>:
0: 08 00 or %al,(%eax)
0: R_386_32 .text
2: 00 00 add %al,(%eax)
00000004 <b>:
4: 80 56 34 12 adcb $0x12,0x34(%esi)
4: R_386_32 .text
忽略反汇编,因为这不是代码,只看符号、字节和重定位。
我们有两次R_386_32
搬迁。根据 IA-32 的 System V ABI(定义 ELF 格式),该类型的重定位计算如下:
S + A
在哪里:
S
:目标文件中重定位前的值。
a
重定位前的值== 08 00 00 00
==8
小端
b
重定位前的值== 80 56 34 12
==0x12345680
小端
A
: addend,重定位项的字段,在这里0
(未显示objdump
),所以让我们忘记它。
搬迁发生时:
a
将替换为:
address of text section + 8
有一个+ 8
因为s:
是文本部分的第 8 个字节,前面是 2 个 long。
b
将替换为:
address of text section + (0x12345678 + 8)
==
address of text section + 0x12345680
啊哈,这就是为什么0x12345680
出现在目标文件上的原因!
所以正如我们刚刚看到的,可以+
通过添加到实际偏移量来表达 ELF 文件。
但是用这种机制(或者我知道的任何其他机制)是不可能表达&
的,因为我们不知道重定位后文本部分的地址是什么,所以我们不能应用&
它。