ELF中全局变量的顺序
Order of global variables in ELF
我有一个带有四个全局变量的简单 C 程序:
$ cat example.c
int x;
int y;
int z;
int w;
int main()
{
x = 5;
y = 6;
z = 7;
w = 8;
return x+y+z+w;
}
当我查看它们在 ELF 文件中的位置时,我 感到惊讶,因为根据它们的声明,它们没有组织:
x, y, z, w
。相反,它是 z (0x60102c), x(0x601030), w(0x601034), y(0x601038)
:
$ clang -g -O0 -o example example.c
$ objdump -S example | cat -n | sed -n '100,123p;124q'
100 int main()
101 {
102 400460: 55 push %rbp
103 400461: 48 89 e5 mov %rsp,%rbp
104 400464: c7 45 fc 00 00 00 00 movl [=11=]x0,-0x4(%rbp)
105 x = 5;
106 40046b: c7 04 25 30 10 60 00 movl [=11=]x5,0x601030
107 400472: 05 00 00 00
108 y = 6;
109 400476: c7 04 25 38 10 60 00 movl [=11=]x6,0x601038
110 40047d: 06 00 00 00
111 z = 7;
112 400481: c7 04 25 2c 10 60 00 movl [=11=]x7,0x60102c
113 400488: 07 00 00 00
114 w = 8;
115 40048c: c7 04 25 34 10 60 00 movl [=11=]x8,0x601034
116 400493: 08 00 00 00
117
118 return x+y+z+w;
119 400497: 8b 04 25 30 10 60 00 mov 0x601030,%eax
120 40049e: 03 04 25 38 10 60 00 add 0x601038,%eax
121 4004a5: 03 04 25 2c 10 60 00 add 0x60102c,%eax
122 4004ac: 03 04 25 34 10 60 00 add 0x601034,%eax
123 4004b3: 5d pop %rbp
这是随意的吗?是否有特定的理由不组织他们
根据他们的声明?谢谢!
您正在使用暂定定义(没有非零初始值设定项),因此编译器实际上并未确定数据布局。某处的文件中可能有一个定义(可能是用汇编程序编写的),它强加了与编译器在汇编程序文件中生成的顺序完全不同的顺序,然后 link 编辑器将被迫以特定顺序分配对象在输出部分。
在我的例子中,Clang 实际上产生了这个:
.type x,@object # @x
.comm x,4,4
.type y,@object # @y
.comm y,4,4
.type z,@object # @z
.comm z,4,4
.type w,@object # @w
.comm w,4,4
外部 汇编程序(来自 GNU binutils)将其转换为(如 eu-readelf -s
所示;readelf -sW
应该同样有效):
18: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON x
19: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON y
20: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON z
21: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON w
(COMMON
因为暂定定义。)
Clang 中的内部 汇编器本身产生:
8: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON w
9: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON x
10: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON y
11: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON z
在我的系统上,binutils 的 BFD ld 将其转换为:
54: 000000000060102c 4 OBJECT GLOBAL DEFAULT 23 z
55: 0000000000601030 4 OBJECT GLOBAL DEFAULT 23 x
65: 0000000000601034 4 OBJECT GLOBAL DEFAULT 23 w
66: 0000000000601038 4 OBJECT GLOBAL DEFAULT 23 y
奇怪的是,来自同一个 binutils (2.28) 版本的 gold 产生:
25: 0000000000402014 4 OBJECT GLOBAL DEFAULT 24 w
26: 0000000000402020 4 OBJECT GLOBAL DEFAULT 24 z
27: 000000000040201c 4 OBJECT GLOBAL DEFAULT 24 y
28: 0000000000402018 4 OBJECT GLOBAL DEFAULT 24 x
我最好的猜测是,在 BFD ld 的情况下,它恰好是一些哈希 table 迭代顺序,而 gold 使用词典符号排序。
请注意,发生这种情况的主要原因是暂定定义和通用符号。汇编器和 link 编辑器不允许在同一节内对常规数据对象定义重新排序,因此如果禁用公共符号的使用,您将获得编译器在汇编器输出中生成的任何内容。对象定义顺序在语言标准中仍然没有定义,但是你可以查看编译器手册是否有额外的保证。
我有一个带有四个全局变量的简单 C 程序:
$ cat example.c
int x;
int y;
int z;
int w;
int main()
{
x = 5;
y = 6;
z = 7;
w = 8;
return x+y+z+w;
}
当我查看它们在 ELF 文件中的位置时,我 感到惊讶,因为根据它们的声明,它们没有组织:
x, y, z, w
。相反,它是 z (0x60102c), x(0x601030), w(0x601034), y(0x601038)
:
$ clang -g -O0 -o example example.c
$ objdump -S example | cat -n | sed -n '100,123p;124q'
100 int main()
101 {
102 400460: 55 push %rbp
103 400461: 48 89 e5 mov %rsp,%rbp
104 400464: c7 45 fc 00 00 00 00 movl [=11=]x0,-0x4(%rbp)
105 x = 5;
106 40046b: c7 04 25 30 10 60 00 movl [=11=]x5,0x601030
107 400472: 05 00 00 00
108 y = 6;
109 400476: c7 04 25 38 10 60 00 movl [=11=]x6,0x601038
110 40047d: 06 00 00 00
111 z = 7;
112 400481: c7 04 25 2c 10 60 00 movl [=11=]x7,0x60102c
113 400488: 07 00 00 00
114 w = 8;
115 40048c: c7 04 25 34 10 60 00 movl [=11=]x8,0x601034
116 400493: 08 00 00 00
117
118 return x+y+z+w;
119 400497: 8b 04 25 30 10 60 00 mov 0x601030,%eax
120 40049e: 03 04 25 38 10 60 00 add 0x601038,%eax
121 4004a5: 03 04 25 2c 10 60 00 add 0x60102c,%eax
122 4004ac: 03 04 25 34 10 60 00 add 0x601034,%eax
123 4004b3: 5d pop %rbp
这是随意的吗?是否有特定的理由不组织他们 根据他们的声明?谢谢!
您正在使用暂定定义(没有非零初始值设定项),因此编译器实际上并未确定数据布局。某处的文件中可能有一个定义(可能是用汇编程序编写的),它强加了与编译器在汇编程序文件中生成的顺序完全不同的顺序,然后 link 编辑器将被迫以特定顺序分配对象在输出部分。
在我的例子中,Clang 实际上产生了这个:
.type x,@object # @x
.comm x,4,4
.type y,@object # @y
.comm y,4,4
.type z,@object # @z
.comm z,4,4
.type w,@object # @w
.comm w,4,4
外部 汇编程序(来自 GNU binutils)将其转换为(如 eu-readelf -s
所示;readelf -sW
应该同样有效):
18: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON x
19: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON y
20: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON z
21: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON w
(COMMON
因为暂定定义。)
Clang 中的内部 汇编器本身产生:
8: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON w
9: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON x
10: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON y
11: 0000000000000004 4 OBJECT GLOBAL DEFAULT COMMON z
在我的系统上,binutils 的 BFD ld 将其转换为:
54: 000000000060102c 4 OBJECT GLOBAL DEFAULT 23 z
55: 0000000000601030 4 OBJECT GLOBAL DEFAULT 23 x
65: 0000000000601034 4 OBJECT GLOBAL DEFAULT 23 w
66: 0000000000601038 4 OBJECT GLOBAL DEFAULT 23 y
奇怪的是,来自同一个 binutils (2.28) 版本的 gold 产生:
25: 0000000000402014 4 OBJECT GLOBAL DEFAULT 24 w
26: 0000000000402020 4 OBJECT GLOBAL DEFAULT 24 z
27: 000000000040201c 4 OBJECT GLOBAL DEFAULT 24 y
28: 0000000000402018 4 OBJECT GLOBAL DEFAULT 24 x
我最好的猜测是,在 BFD ld 的情况下,它恰好是一些哈希 table 迭代顺序,而 gold 使用词典符号排序。
请注意,发生这种情况的主要原因是暂定定义和通用符号。汇编器和 link 编辑器不允许在同一节内对常规数据对象定义重新排序,因此如果禁用公共符号的使用,您将获得编译器在汇编器输出中生成的任何内容。对象定义顺序在语言标准中仍然没有定义,但是你可以查看编译器手册是否有额外的保证。