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¬ 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 1
和 code 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
.
并不重要
这是一个简单的 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 1
和 code 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
.