.bss 符号就像编译器(或汇编器)生成的任何其他符号一样被解析。通常这是通过将相关符号放在“部分”中来实现的。例如,编译器可能会将程序代码放在名为“.text”的节中(出于历史原因;-),将初始化数据放在名为“.data”的节中,将统一数据放在名为.“.bss”的节中。
例如:
int i = 4;
int x[10];
char chArray[100];
int main(int argc, char**argv)
{
}
产生(使用 gcc -S):
.file "test.c"
.globl i
.data
.align 4
.type i, @object
.size i, 4
i:
.long 4
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
addl $4, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.comm x,40,32
.comm chArray,100,32
.ident "GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)"
.section .note.GNU-stack,"",@progbits
.data 指令告诉汇编器将 i 放在数据段中,“.long 4”给它它的初始值。当文件被组装时,i 将被定义在数据段的偏移量 0 处。
.text 指令将 main 放在 .text 部分中,偏移量也为零。
这个例子的有趣之处在于 x 和 chArray 是使用 .comm 指令定义的,而不是直接放在 .bss 中。两者都只给出了一个大小,而不是一个偏移量(还)。
当链接器获取目标文件时,它通过将所有具有相同名称的部分组合在一起并相应地调整符号偏移来将它们链接在一起。它还为每个部分提供了一个绝对地址,应该在该地址处加载它。
.comm 指令定义的符号被组合(如果存在多个同名定义)并放置在 .bss 部分。正是在这一点上,他们得到了他们的地址。