C语言的Hello World的汇编剖析(64位 Intel架构)
文章目录
- C语言的Hello World的汇编剖析(64位 Intel架构)
- 一. 前提准备
- 二. C转换为汇编操作准备
- 2.1 创建目录&复制代码
- 2.2 C文件转换为汇编文件
- 三. 剖析汇编文件
- 四. 指令相关
- 五. 额外记录:指令段相关调用
一. 前提准备
-
Linux虚拟机
-
Gcc编译器(若采用Linux虚拟机剖析,则自带无需下载)
-
C语言的Hello World代码
#include <sudio.h> int main(){ printf("Hello World!"); return 1; }
二. C转换为汇编操作准备
2.1 创建目录&复制代码
2.2 C文件转换为汇编文件
若将C文件转换为汇编文件,则需要编译器作为桥梁,这里使用gcc编译器,由于为只需编译成汇编文件,所以采用—S这个选项命令即可
zhp@root:~$ gcc --help
....
-S Compile only; do not assemble or link.
....
汇编文件如图所示
三. 剖析汇编文件
前提概要:
- b:1字节,8bit
- l:2字节,16bit
- w:4字节,32bit
- r:8字节,64bit
Hello World所经历的步骤剖析:
- 栈空间的开辟,使栈基址指向新空间基址,并让栈针sp定位道栈基址bp位置
- 并通过Hello World拷贝到edi寄存器(这里涉及到寄存器字符串拷贝相关操作)
- 调用printf函数打印Hello World
- 返回值保存寄存器中
- 还原bp
- 还原栈空间,sp还原
ps:查看输出Hello World
四. 指令相关
ret指令:
- 弹出返回地址值并保存到指令地址寄存器
- 通过可选项n,从栈中释放参数
- 恢复调用过程
下图截至intel手册Volume 3 6.4节
五. 额外记录:指令段相关调用
就如Hello World的输出
OS正在运行自身程序,突然来了C语言一段代码,调用它
详细步骤分析
- 指令段A首先需要调用call命令,来调用指令段B
- 这时需要先开辟栈空间等一系列操作,上方已经讲过,不在赘述
- 当调用后,需要返回到指令段A继续执行,这时需要用到ret指令
指令段之间的调用,若有参数传递时,则会有2种方式
- 一种是存储到一个公共地方,即通用寄存器
- 另一种通过栈本身特性,为指令段A的数据开辟一段栈帧,指令段B通过bp的pop/其他方式,来获取数据
第二种方式的操作非常耗时,但也不是抛弃这个方式,由于寄存器数量有限(和计算机的位数相关,如你的计算机是32位,则有32个寄存器),当通用寄存器耗尽时,就可采用此方式。