C 程序的汇编和 gcc 生成的东西无处可寻,如果我在汇编中而不是在 C 中编程,我是否需要这些部分和符号

Assembly of C program and gcc generated things that nowhere can be found, do I need those sections & symbols if I am programming in assembly&not in C

这是一个简单的 C 程序。

char a;
void main(){};

它导致此程序集从

开始生成
.text
.globl  a
.bss
.type   a, @object
.size   a, 1

所以我想知道如何解释上面的内容

所以我看到 .text 我相信这只是符号 .text 表示代码部分的开始 你看到 .global 所以我相信紧随其后的变量将是全局变量或函数等,或者我是否需要写部分名称,即 .text 就在所有变量和职能?这就是问题

然后你看到 .bss 之后 .bss 所有未初始化的变量和函数都被声明了

然后我终于看到类似于我的 C 程序有一个名为 char a 的全局变量的东西 喜欢

.type   a, @object

所以 .type 告诉它是什么所以我假设它的对象类型如 @object.type a,@object

中提到的

所以现在大小是 1 个字符。所以这一行

.size   a, 1

所以我假设如果我有全局 int a; 那么那将是

.size a,4

char 为 1 个字节 int 是 4 个字节

然后继续

我有

a:

所以前几行变成如下

假设这是代码 1

# my comment 1
# my comment 2
    .text
    .globl  a
    .bss
    .type   a, @object
    .size   a, 1
a:

所以问题是为什么 a: 在底部

如果我这样做怎么办

这是代码 2

a:
    .text
    .globl  a
    .bss
    .type   a, @object
    .size   a, 1

所以我想知道 code 1code 2 是一样的吗?声明或定义 a: 出现在第一个和第二个 code 2

所以从上面我的 a.text.global.bss.type 是 @object 而 size 是 1字节。这是定义一个 char 变量的大量代码。那么这样理解正确吗???我应该怀疑吗

继续前进,现在轮到 .text 部分加上 .global

的全局主程序

原来如此

.zero   1
.text
.globl  main
.type   main, @function

主要内容:

所以我真的不想关心 .zero 1 行,但如果我不关心是错误的,请告诉我它的用途。所以我的 gcc 再次将 main 放在 .zero(某些部分???)和 .text 部分加上 .global 代码部分,类型是 @function 所以现在我知道类型在 , 之后,如 .type main,@function 和 在 .type a, @object

然后我遇到完全BS,搜索.LFB0:带来零google搜索结果

是.LFB0:我的x86-64处理器可以运行

的一段程序

和 .cfi_startproc 是 eh_frame 所以我读到 .eh_frame 是程序加载部分中的一个部分。所以我想知道我是否在汇编代码中可以忽略 .cfi_startproc 行。但是这有什么意义呢。这是否意味着在此之后所有内容都加载到内存或寄存器中并且是 .ehframe

main:
.LFB0:
    .cfi_startproc
    endbr64 
    pushq   %rbp    #
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp  #,
    .cfi_def_cfa_register 6

所以如果我在汇编中制作一个简单的汇编程序类似于上面的 C 程序我是否需要从 .LFB0: 编码到 movq %rsp, %rbp #,\n.cfi_def_cfa_register 6 如果不需要那么我可以假设我的程序将成为

    .text
    .globl  a
    .bss
    .type   a, @object
    .size   a, 1
a:
    .zero   1
    .text
    .globl  main
    .type   main, @function
main:
             .cfi_startproc
    pushq   %rbp    
    movq    %rsp, %rbp  
    nop 
    popq    %rbp    

    ret 
             .cfi_endproc

所以我的完整程序就变成了上面,如何用nasm编译这个,谁能告诉我 我相信我必须用 .s 或 .S 扩展名保存它,哪个是小 S 或大 S?我在 Ubuntu

编码

这是 gcc 生成的代码

        .file   "test.c"
    # GNU C17 (Ubuntu 11.2.0-7ubuntu2) version 11.2.0 (x86_64-linux-gnu)
    #   compiled by GNU C version 11.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.0, isl version isl-0.24-GMP

    # GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
    # options passed: -mtune=generic -march=x86-64 -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection
        .text
        .globl  a
        .bss
        .type   a, @object
        .size   a, 1
    a:
        .zero   1
        .text
        .globl  main
        .type   main, @function
    main:
    .LFB0:
        .cfi_startproc
        endbr64 
        pushq   %rbp    #
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp  #,
        .cfi_def_cfa_register 6
    # test.c:2: void main(){};
        nop 
        popq    %rbp    #
        .cfi_def_cfa 7, 8
        ret 
        .cfi_endproc
    .LFE0:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 11.2.0-7ubuntu2) 11.2.0"
        .section    .note.GNU-stack,"",@progbits
        .section    .note.gnu.property,"a"
        .align 8
        .long   1f - 0f
        .long   4f - 1f
        .long   5
    0:
        .string "GNU"
    1:
        .align 8
        .long   0xc0000002
        .long   3f - 2f
    2:
        .long   0x3
    3:
        .align 8
    4:

.text 是一个指令,它告诉汇编程序开始一个程序代码部分(程序的“文本”部分,read-only executable 部分主要包含指令被执行)。这是因为没有优化的 GCC 总是在文件的顶部放置一个 .text,即使它即将切换到另一个部分(如本例中的 .bss)然后返回到 .text 当它准备好将一些字节发送到该部分时(在您的情况下,是 main 的定义)。不过,GCC 仍然会在发出任何 asm 之前解析整个编译单元;它不仅仅是一次编译一个全局变量/函数。

.globl a 是一个指令,它告诉汇编程序 a 是一个“全局”符号,因此它的定义应该被列为 linker 到 link 与.

.bss 是一个指令,它告诉汇编程序开始“块起始符号”部分(它将包含初始化为零的数据,或者在某些系统上,大多数较旧的系统未初始化)。

.type a @object.size a, 1 是描述名为 a 的对象的类型和大小的指令。汇编器将此信息添加到符号 table 或它输出的目标文件中的其他信息。调试器了解对象的类型很有用。

a: 是标签。它用于定义符号。当汇编程序读取程序集时,它会计算当前生成的部分中的字节数。每个数据声明或指令占用一些字节,汇编器计算这些字节。当它看到一个标签时,它会将标签与当前计数相关联。 (这通常称为程序计数器,即使它正在计算数据字节数。)当汇编程序将有关 a 的信息写入符号 table 时,它将包括从开始的字节数这部分。当程序加载到内存中时,这个偏移量用于计算对象a将在内存中的地址。

So the question is why a: is at the bottom

a: 必须在 .bss 之后,因为 a 将被放入汇编程序当前正在处理的部分,因此需要在声明之前将其设置为所需的部分标签。 a 相对于其他指令的位置可能是灵活的,因此重新排序它们不会产生任何后果。

so I like to know is code 1 and code 2 same?

不,a: 必须出现在 .bss 之后,以便将其放入正确的部分。

.zero 1 表示在当前部分发出 1 个零字节。就像(几乎?)GCC 使用的所有指令一样,它在 GNU 汇编器手册中有详细记录:https://sourceware.org/binutils/docs/as/Zero.html

so again have my gcc place main in .zero

不,.text 启动(或切换回)代码部分,因此 main 将在代码部分。

is .LFB0: a some section of program that my x86-64 processor can run

任何以冒号结尾的都是标签。 .LFB0 是编译器在需要它作为跳转或分支目标时使用的本地标签。

so I like to know if I am coding in assembly can I ignore .cfi_startproc line.

在为没有异常处理和相关功能的简单函数编写程序集时,您可以忽略 .cfi_startproc 和其他 call-frame 信息指令,这些指令生成 .eh_frame 部分中的元数据。 (没有执行,它只是作为文件中的数据存在,供异常处理程序和调试器读取。)

… if not needed then I can assume my program will become…

如果您要省略一些 .cfi... 指令,我会省略所有这些指令,除非您查看它们的作用并确定哪些可以选择性地省略。

I believe I have to save it with .s or .S extension which one s small or large S?

对于 GCC 和 Clang,以 .S 结尾的汇编文件在汇编之前由“预处理器”处理,而以 .s 结尾的汇编文件则不会。这是 C 中熟悉的预处理器,具有 #define#if 和其他指令。其他工具可能不会这样做。如果您不使用预处理器功能,通常使用 .s.S.

并不重要