问题描述
我正在尝试学习一些关于汇编的知识。我决定从简单的源代码中查看生成的程序集文件开始。当然,我被指令轰炸,我不知道它们的意思,我开始在互联网上搜索它们的含义。在搜索时,我意识到我不知道我在寻找什么汇编语言..
有没有办法知道 gcc 生成哪种汇编语言?这个问题还有意义吗? 我主要对我的系统接受的程序集感兴趣(或者我应该说......)。下面是使用 gcc 生成的代码。
系统:
操作系统:Windows 10 专业版
处理器:Intel(R) Core(TM) i5-5200U cpu @ 2.20GHz 2.20 GHz
类型:64 位操作系统,基于 x64 的处理器
//test.c
int main(){
int x = 2;
return 0;
}
//test.s
.file "test.c"
.text
.def __main; .scl 2; .type 32; .endef
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp,%rbp
.seh_setframe %rbp,0
subq $48,%rsp
.seh_stackalloc 48
.seh_endprologue
call __main
movl $2,-4(%rbp)
movl $0,%eax
addq $48,%rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (Rev10,Built by MSYS2 project) 10.2.0"
解决方法
GCC 总是产生 GNU assembler 可以在任何平台上组装的 asm 输出。 (GAS / GNU as
是 GNU Binutils 的一部分,还有 ld
这样的工具,一个链接器。)
就您而言,目标是 x86-64 Windows(可能来自 x86_64-w64-mingw32-gcc),
并且指令语法为AT&T syntax(x86 包括x86-64 的GCC 和GAS 默认值)。
在 GAS for x86(包括 x86-64)中,注释字符为 #
。
任何以 .
开头的都是指令;一些,比如 .globl main
导出符号 main
作为链接在 .o
中可见,通常对 GAS 是通用的;检查 GAS manual。
像 .seh_setframe %rbp,0
这样的 SEH 指令是 Structured Exception Handling 的特定于 Windows 的堆栈展开元数据,特定于 Windows 对象文件格式。 (您可以 100% 忽略,直到/除非您想了解回溯和异常处理如何在幕后工作,而不依赖于传统的帧指针链。AFAIK,它基本上等同于 ELF/Linux .eh_frame
元数据来自 .cfi
指令。)
事实上,您几乎可以忽略所有指令,唯一真正重要的是像 .text
与 .data
这样的部分,以及.globl
使链接工作有些重要。这就是默认情况下 https://godbolt.org/ 过滤指令的原因。
如果您需要 Intel 语法/助记符,您可以使用 gcc -masm=intel
,您可以在 Intel 手册中查找这些内容。 (https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html / https://www.felixcloutier.com/x86/)。另见How to remove "noise" from GCC/clang assembly output?。 (gcc -O1 -fverbose-asm
可能很有趣。)
如果您想学习 AT&T 语法,请参阅 https://stackoverflow.com/tags/att/info。 GAS 手册还有一个关于 AT&T 与 Intel 语法的页面,但它不是作为教程编写的,即它假设您知道 x86 指令的工作原理,并且正在寻找 GAS 用来描述它们的语法的详细信息:{{3} }
(请记住,CPU 实际上运行机器代码,字节如何进入内存并不重要,只要它们这样做。所以不同的汇编程序(如 NASM 与 GAS)和不同的语法(如 {{ 1}}) 最终对机器在一条指令中可以做什么或不做什么都有相同的限制。所有主流汇编程序都可以让您表达每条指令可以做的几乎所有事情,只需了解立即数的语法,寻址模式,等等。Intel 和 AMD 的手册准确地记录了 CPU 可以做什么,使用 Intel 语法,但没有确定语法或指令的细节。)
资源(包括上面链接的一些):
- Matt Godbolt 的 CppCon2017 演讲“https://sourceware.org/binutils/docs/as/i386_002dVariations.html”和What Has My Compiler Done for Me Lately? Unbolting the Compiler's Lid
- How to remove "noise" from GCC/clang assembly output?
- x86 tag wiki
- https://stackoverflow.com/tags/att/info GAS 手册
- https://sourceware.org/binutils/docs/as/ 英特尔手册
- https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html(AMD vol.3 手册:通用说明)
有没有办法知道 gcc 生成哪种汇编语言?
是的,您的目标端口。这似乎是x86。反过来,这种汇编语言有各种风格和方言,有着大量的历史:https://en.wikipedia.org/wiki/X86_assembly_language
当然,我会被指令轰炸,我不知道它们是什么意思
阅读 C 编译器生成的汇编程序比阅读手工编码的汇编程序要困难得多。我建议从一些汇编教程开始,而不是由人类编写的代码示例。
x86 也可能是其中最难的一个,因为它有所有的风格,而且核心的复杂性。一般建议先学习一些简单的汇编程序来掌握它。
8 位微控制器是一个不错的起点。