美文网首页
一个简单C程序的汇编程序执行分析

一个简单C程序的汇编程序执行分析

作者: FlyingReganMian | 来源:发表于2017-11-29 23:27 被阅读0次

1.冯诺依曼体系结构——存储程序式计算机

冯诺依曼体系结构核心是存储程序,将数据和代码都存储在存取器中,都是二进制数据,通过特定模块来区分数据和代码。冯诺依曼体系结构的计算机包括运算器、控制器、存储器、输入单元、输出单元五大件。


image

2.x86汇编

2.1 32位CPU寄存器结构

x86寄存器结构.png
1.开头为e的寄存器一般都为32位寄存器,以R开头的寄存器一般为64位寄存器
2.通常情况下eax作为累加器,ebx作为基址寄存器,ecx作为计数器,edx作为数据寄存器,ebp作为堆栈基指针寄存器(栈底),esi、edi作为变址寄存器,esp作为堆栈顶指针寄存器。

2.2 汇编指令

1.mov:movl l 代表32位

mov.png

register mode :寄存器寻址。
immediate:立即寻址 $+数字:代表的是一个立即数。只有数字:代表的是一个地址
direct:直接寻址。直接访问一个指定的内存地址数据
indirect:间接寻址。将ebx中存储的值作为一个地址,从这个地址取出的值赋给edx
displaced:变址寻址。

2.pushl:入栈
栈是向下增长的,ebp(栈基址指针)指向栈底,esp(堆栈顶指针)指向栈顶。入栈:esp向乡下移动4个字节,然后将eax中的值村放入esp中。
pushl %eax相当于:

subl $4, %esp
movl %eax, (%esp)

3.popl: 出栈
popl %eax相当于:

movl (%esp), %eax
add $4, %esp            

4.call 0x12345:

pushl %eip(*)
movl 0x12345, %eip(*)

eip寄存器,用来存储CPU下一条要执行的指令的地址
5.ret

popl %eip(*)

(*)表示 程序员不能直接使用
6.leave:

movl %ebp, %esp
pop %ebp

3.C程序反汇编分析

代码如下:

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

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

int main(void)
{
    return f(8) + 1;    
}

编译成汇编代码:

gcc -S main.c -o main.s -m32 //以32位编译

汇编后的代码(去掉以.开头的部分,这部分是编译器链接用的)

g:
    pushl   %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    addl    $3, %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    $8, (%esp)
    call    f
    addl    $1, %eax
    leave
    ret

eip:当一个指令执行完成之后,自动指向下一个指令
eax:函数返回值默认使用eax寄存器存储返回给上一级函数

接下来,分析一下堆栈调用过程:
首先main():假设栈在内存中的起始地址为0,ebp和esp均指向栈首地址0.

pushl   %ebp
movl    %esp, %ebp
subl    $4, %esp
movl    $8, (%esp)

以上代码为:main函数中开辟新的内存区域,然后将参数 8 入栈、


image

接下来,调用

call    f

call f 相当于;

pushl %eip
movl f, %eip

eip中存的是当前指令的的地址。首先将eip入栈,然后将f中第一个指令的地址赋给eip。此时栈情况如下图所示:


image

此时,此时eip指向f中的pushl %ebp

pushl   %ebp
movl    %esp, %ebp
subl    $4, %esp
movl    8(%ebp), %eax
movl    %eax, (%esp)

为f函数开辟栈空间,然后将参数8赋值给eax,最后将eax入栈,具体操作过程如下:


image

接下来,运行

call    g

调用g函数,此时栈情况如下:


image

接下来,执行

 pushl   %ebp
 movl    %esp, %ebp
 movl    8(%ebp), %eax
 addl    $3, %eax
 popl    %ebp //将ebp指向的值赋给ebp
 ret//相当于:popl eip

栈调用过程如下:


image

此时,eip指向否f函数中的 leave

leave
ret

此时eip指向 MIan函数中的 addl $1, %eax


image

接下来执行 main函数

 addl    $1, %eax//11 + 1

此时eax = 12
接下来执行

leave
ret
image

4.总结

堆栈:高级语言的函数调用。是高级语言的基础
堆栈是C程序运行时必须的一个记录调用路径和参数的空间。
堆栈作用:

  • 函数调用框架
  • 传递参数
  • 保存返回地址
  • 提供局部变量空间

相关文章

网友评论

      本文标题:一个简单C程序的汇编程序执行分析

      本文链接:https://www.haomeiwen.com/subject/lmlmbxtx.html