不知道gcc怎么查看汇编代码?学一手!(C/C++杂谈3)

459 阅读4分钟

在做一个测试博客的时候发现自己对使用gcc/g++ 查看汇编代码以及C/C++的汇编等阶段还有一点模糊,特此记录一下。

源代码编译过程

1.预处理

C/C++的预处理其实就是一个词法(而不是语法)预处理器,其主要完成文本替换、宏展开以及删除注释等,完成这些操作之后,将会获得真正地“源代码”。

常见的include语句即是一个预处理器命名,在预处理器中它将所有的头文件包含进来。(该步骤的文件扩展名为.i)

2.编译

在这一步骤,将.i文件翻译为.s,得到汇编程序语言,值得注意的是所有的编译器输出的汇编语言都是同一种语法。

注:内联函数就是在这一环节“膨胀”进源码的,它的作用即在于:不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处,适用于功能简单,规模较小又使用频繁的函数。递归函数无法内联处理,内联函数不能有循环体,switch语句,不能进行异常接口声明。**仅仅省去了函数调用的开销,从而提高函数的执行效率。**如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间

3.汇编

将.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件.o中(把汇编语言翻译成机器语言的过程)。

4.链接

链接(ld):gcc会到系统默认的搜索路径”/usr/lib”下进行查找,也就是链接到libc.so.6库函数中去。

函数库一般分为静态库和动态库两种。静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为”.a”。动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统存储的开销。动态库一般后缀名为”.so”,如前面所述的libc.so.6就是动态库。gcc在编译时默认使用动态库

查看汇编

复习了基础知识,用实例来介绍如何使用gcc/g++查看各阶段代码(限于篇幅只介绍汇编):

建立一个源文件如下:

#include <stdio.h>

int main(){
	int a=1;
	int b=2;
	int c=a+b;
	return c;
}

使用指令编译成汇编代码:

img

cat/gedit/vim等方式查看汇编代码:

	.file	"test_gcc.c"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$1, -12(%rbp)
	movl	$2, -8(%rbp)
	movl	-12(%rbp), %edx
	movl	-8(%rbp), %eax
	addl	%edx, %eax
	movl	%eax, -4(%rbp)
	movl	-4(%rbp), %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609"
	.section	.note.GNU-stack,"",@progbits

根据命令选项的不同,可以生成各个阶段的文件,详细指令如下:

参数说明
-c只编译不链接,生成*.o文件
-S生成汇编代码*.s文件
-E预编译 生成*.i文件
-g在可执行程序里包含了调试信息,可用 gdb 调试
-o把输出文件输出到指定文件里
-static链接静态链接库
-library链接名为library的链接库

本人博客均为原创,不定时更新(2021/4/22),转载请注明链接:juejin.cn/post/695378…

创作不易,如果你觉得博客写的还不错,请点个赞或者留个言。

希望在以后的日子里我们能够一起探寻计算机的!

——来自一个默默积累总结的准码农

参考资料:

blog.csdn.net/alps1992/ar…