GCC编译代码:为什么整型声明需要几个语句



我正在学习AT&T汇编,我知道数组/变量可以使用。int/。long来声明,或者使用。equ来声明一个符号,这将被汇编取代。

它们在.data节(初始化)或.bss节(未初始化)中声明。

但是,当我使用gcc编译一个非常简单的。c文件时,使用'-S'命令行选项来检查反汇编代码,我注意到:(1) .s不同时使用。data和。bss,而只使用。data(2)一个整数(.long)的声明需要几个语句,其中一些对我来说似乎是多余的或无用的。

如下所示,我根据我的问题添加了一些评论。

$ cat n.c

int i=23; 
int j; 
int main(){ 
   return 0; 
} 

$ gcc -S$ cat n.s

     .file    "n.c" 
     .globl    i 
     .data 
     .align 4 
     .type    i, @object #declare i, I think it's useless
     .size    i, 4 #There's '.long 23', we know it's 4 bytes, why need this line?
i: 
     .long    23       #Only this line is needed, I think
     .comm    j,4,4    #Why j is not put inside .bss .section?
     .text 
     .globl    main 
     .type    main, @function 
main:
.LFB0:                 #What does this symbol mean, I don't find it useful.
     .cfi_startproc 
     pushq    %rbp 
     .cfi_def_cfa_offset 16 
     .cfi_offset 6, -16 
     movq    %rsp, %rbp 
     .cfi_def_cfa_register 6 
     movl    $0, %eax 
     popq    %rbp 
     .cfi_def_cfa 7, 8 
     ret 
     .cfi_endproc 
.LFE0:                 #What does this symbol mean, I don't find it useful.
     .size    main, .-main 
     .ident    "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609" 
     .section    .note.GNU-stack,"",@progbits 

我所有的问题都在上面的评论中,我在这里再次强调:

     .type    i, @object 
     .size    i, 4
i: 
     .long    23
我真的认为上面的代码是多余的,应该像这样简单:
i: 
     .long    23

同样,"j"没有符号标签,也没有放在。bss节中。

我做错了什么吗?请帮忙更正。非常感谢。

(我猜你使用的是Linux系统)

它们在.data节(初始化)或.bss节(未初始化)中声明。

不,您有许多其他节,特别是.comm(用于"公共"节,具有初始化的数据common到多个目标文件,链接器将"合并")和.rodata用于只读数据。ELF格式足够灵活,可以允许许多节和许多段(其中一些没有加载-更准确地说是内存映射-在内存中)。

ELF文件中节的描述比您想象的要复杂得多。花点时间阅读更多内容,例如Levine的《链接器和加载器》。还要阅读GNU binutils的文档和脚本,也要阅读old (1) &(1)。使用objdump(1)和readelf(1)来浏览现有的ELF可执行文件、目标文件和共享对象。也可阅读execve(2) &精灵(5)

但是当我使用gcc来编译一个非常简单的.c文件与-S命令行选项

当检查由gcc生成的汇编文件时,我强烈建议至少传递-fverbose-asm,以要求gcc在汇编文件中发出一些额外的和有用的注释。我也经常建议使用一些优化标志-例如至少-O1(或者gcc的最新版本可能是-Og)。

我注意到:(1) .s不同时使用。data和。bss,而只使用。data

不,你生成的代码使用.comm部分,并把j的值放在那里。

(2)一个整数(.long)的声明需要几个语句,其中一些对我来说似乎是多余的或无用的。

这些大多不是汇编语句(翻译成机器码),而是汇编指令;它们非常有用(并且它们不会浪费ld产生的内存段中的空间,但是ELF格式在其他地方有信息)。特别是.size.type都是需要的,因为ELF文件中的符号表包含的不仅仅是地址(它还有一个大小的概念,以及一个非常原始的类型的概念)。

.LFB0gcc(实际上是cc1 -)生成的标签。GCC并不关心生成无用的标签(对于GCC后端的汇编器生成器来说更简单),因为它们不会出现在目标文件中。

"。长23',我们知道它是4字节,

您可能知道long是4字节,但是该信息(j的大小)应该进入ELF文件,因此需要显式的汇编指令....

(我没有空间和时间来解释ELF格式,你需要阅读很多页,它比你想象的要复杂和完整得多)

顺便说一句,Drepper的如何编写共享库相当长(超过40页),并解释了很多关于ELF文件,重点是共享库。

最新更新