Linux下的C语言的执行流程与汇编分析

时间:2022-10-30 03:34:40

作者:鲍迪
原创作品转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000


1. 汇编基础

本汇编基础均建立在Linux系统下,也就是采用AT&T汇编格式

1.1一些主要的汇编指令


汇编指令 功能 等价指令
mov 传送字或字节 -
add 加法 -
sub 减法 -
pushl %eax 压栈 subl $4,%esp
movl %eax,(%esp)
popl %eax 出栈 movl (%esp),%eax
addl $4,%esp
call 0x12345 过程调用 pushl %eip
movl $0x12345,%eip
enter 重设堆栈 pushl %ebp
movl %esp,%ebp
leave 撤销堆栈 movl %ebp,%esp
popl %ebp
ret 过程返回 popl %eip
注:命令后面的b、w、l、q分别代表着8位、16位、32位和64位,例如:movl即代表传送一个32位的数据。


1.2 几种主要的寻址方式


寻址方式 示例 操作结果
寄存器寻址(register mode) movl %eax,%edx edx = eax
立即数寻址(immediate) movl $0x123 edx = 0x123
直接寻址(direct) movl 0x123,%edx edx = * (int32_t*)0x123
间接寻址(indrect) movl (%ebx),%edx edx = * (int32_t*)ebx
变址寻址(displaced) movl 4(%ebx),%edx edx = * (int32_t*)(ebx+40)


1.3 堆栈介绍


说到汇编还有个不得不提的就是堆栈(即栈),下图是大多数体系结构虚拟地址空间的分配情况:


Linux下的C语言的执行流程与汇编分析
( 图片来自网络)


而堆栈是虚拟地址空间里面比较特殊的一段,除了栈是从高地址往低地址方向增长,其他部分均是由低往高增长,而pop和push指令正是借助这一特性进行压栈和出栈。它的操作方式是只在栈顶进行压栈和出栈操作,如下图所示:

Linux下的C语言的执行流程与汇编分析
( 图片来自网络)



2. C语言的执行流程与汇编分析


学过C语言的都知道,C程序要被CPU执行,还要被编译为汇编程序,再由汇编程序翻译成为能被CPU识别的可执行程序。接下来我们利用下面一段简单的C程序来编译成汇编代码以分析其工作过程及堆栈变化。

int g(int x)
{
return x + 4;
}

int f(int x)
{
return g(x);
}

int main(void)
{
return f(4) + 4;
}

经过
gcc –S –o main.s main.c -m32 命令
编译之后得到汇编代码,如图:


Linux下的C语言的执行流程与汇编分析


删除了代码里面的辅助信息之后得到纯汇编代码,如下图:


Linux下的C语言的执行流程与汇编分析

即:

g:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $4, %eax
popl %ebp
ret
f:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
ret
main:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl $4, (%esp)
call f
addl $4, %eax
leave
ret

从上面的汇编代码可以看出,不论是main函数还是f,g函数,函数头部的语句必为

pushl   %ebp
movl %esp, %ebp

即指令enter,在本函数功能执行之前重设一个新的堆栈给本函数使用,保存前一个函数的栈基址,而同时注意到main和f函数后部都有leave,而g函数因为esp寄存器没有变化了,所以被编译器优化了只剩

popl    %ebp

进行退栈操作。

除此之外,main函数剩余指令的操作为

subl    $4, %esp   将栈顶指针esp的值减4
movl $4, (%esp) 指将参数4压入栈
call f 先把eip压入栈,在跳转到f处去执行
addl $4, %eax 指函数返回值存在寄存器eax中,并对其值加4

跳转到f函数时剩余语句的操作为

subl    $4, %esp       将f函数栈顶地址减4
movl 8(%ebp), %eax 间接寻址,将ebp寄存器加8的位置里面存放的内容移
到eax寄存器中
movl %eax, (%esp) 将eax值写入堆栈
call g 先把eip压入栈,在跳转到g处去执行

跳转到g函数时剩余语句的操作为

movl    8(%ebp), %eax 间接寻址,将ebp寄存器加8的位置里面存放的内容移到
eax寄存器中
addl $4, %eax 寄存器eax加4

汇编程序执行期间,堆栈的操作示意图如下
Linux下的C语言的执行流程与汇编分析

最后由ret指令执行各个函数的返回操作。


3. 总结


经过对由C语言编译成的汇编代码执行过程分析,可以看出,计算机的工作原理为由编译器链接器等工具将高级语言转换成计算机能理解的可执行程序,借助堆栈机制在保证程序的执行,然后由CPU按照eip寄存器的指向一步一步执行程序,从而形成计算机的执行流程。