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

Linux GCC编译代码:为什么整数声明需要几个语句?,linux,gcc,assembly,compilation,disassembly,Linux,Gcc,Assembly,Compilation,Disassembly,我正在学习AT&T汇编,我知道数组/变量可以用.int/.long来声明,也可以用.eq来声明一个符号,用汇编来代替 它们在.data节(初始化)或.bss节(未初始化)中声明 但是,当我使用gcc编译一个非常简单的.c文件并使用“-S”命令行选项检查反汇编代码时,我注意到: (1) .s不同时使用.data和.bss,而仅使用.data (2) 整数(.long)的声明需要几个语句,其中一些语句对我来说似乎是多余或无用的 如下图所示,我根据我的问题添加了一些评论 $cat n.c int i=

我正在学习AT&T汇编,我知道数组/变量可以用.int/.long来声明,也可以用.eq来声明一个符号,用汇编来代替

它们在.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 n.c $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可执行文件、对象文件和共享对象。同时阅读,

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

在检查由
gcc
生成的汇编程序文件时,我强烈建议至少传递
-fverbose asm
,要求
gcc
在汇编程序文件中发出一些额外的有用注释。我通常还建议使用一些优化标志,例如至少使用
-O1
(或者在最近版本的
gcc
上使用
-Og

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

否,生成的代码使用
.comm
部分,并将
j
的值放在那里

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

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

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

有个“.long23”,我们知道是4个字节

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

(我没有空间或时间来解释ELF格式,你需要阅读很多关于它的页面,它比你所相信的要复杂得多,也更完整)

顺便说一句,Drepper's相当长(超过40页),并解释了大量关于ELF文件的内容,重点是共享库。

(我猜您正在使用一些Linux系统)

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

不,您还有许多其他部分,特别是
.comm
(对于“common”部分,初始化数据与多个对象文件共用,链接器将“合并”)和
.rodata
用于只读数据。该格式足够灵活,允许在内存中加载多个节和多个段(其中一些未加载,更精确地说是内存映射)

文件中节的描述比您所相信的要复杂得多。花点时间多读一些,例如莱文的。请同时阅读和的文档和&。使用和浏览现有ELF可执行文件、对象文件和共享对象。同时阅读,

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

在检查由
gcc
生成的汇编程序文件时,我强烈建议至少传递
-fverbose asm
,要求
gcc
在汇编程序文件中发出一些额外的有用注释。我通常还建议使用一些优化标志,例如至少使用
-O1
(或者在最近版本的
gcc
上使用
-Og

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

否,生成的代码使用
.comm
部分,并将
j
的值放在那里

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

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