汇编学习之一个最简单的c程序对应的汇编

一、基础了解

对于系统工程师来说,汇编属于一种基本功,应长期关注。在一些性能分析、问题定位时,有时需要读汇编代码,在学习linux内核过程中,也需要读汇编代码。

所以先以x86为例,学习一个最简单的c语言程序对应的汇编。

基础知识介绍:

  1. 首先了解一下x86处理器拥有的寄存器

x86_64寄存器如下所示:

0-63

0-31

0-15

8-15

0-7

使用惯例

%rax

%eax

%ax

%ah

%al

保存返回值

%rbx

%ebx

%bx

%bh

%bl

被调用者保存

%rcx

%ecx

%cx

%ch

%cl

第4个参数

%rdx

%edx

%dx

%dh

%dl

第3个参数

%rsi

%esi

%si

%sil

第2个参数

%rdi

%edi

%di

%dil

第1个参数

%rbp

%ebp

%bp

%bpl

被调用者保存

%rsp

%esp

%sp

%spl

栈指针

%r8

%r8d

%r8w

%r8b

第5个参数

%r9

%r9d

%r9w

%r9b

第6个参数

%r10

%r10d

%r10w

%r10b

调用者保存

%r11

%r11d

%r11w

%r11b

调用者保存

%r12

%r12d

%r12w

%r12b

被调用者保存

%r13

%r13d

%r13w

%r13b

被调用者保存

%r14

%r14d

%r14w

%r14b

被调用者保存

%r15

%r15d

%r15w

%r15b

被调用者保存

2.函数传参

   函数调用参数传递时,%rdi%rsi%rdx%rcx%r8%r9用于存储函数调用第1,2,3,4,5,6个参数,如果函数有那么多参数的话,如果超过6个参数,超出来的参数保存在栈中。

3.栈的伸缩

%rsp用于保存栈顶指针,由于栈的伸长方向一般是从高地址像低地址扩展,当需要扩充栈的时候,rsp值就减小,如 sub $0x60,%rsp , 当栈需要收缩的时候,rsp值就增大

二、c程序与汇编对应

C语言如下:

#include

char test(int a)

{

  int b = 2;

  b = b + a;

  return a;

}

int main()

{

    int i ,buf[20];

 

    i++;

    i = test(i);

    return 0;

}

 

编译上面的简单c语言,使用objdump -d 反编译可执行文件后得到汇编如下,

00000000004004e6

:

  4004e6:       55                    push   %rbp                rbp压栈   rsp - 8

  4004e7:       48 89 e5               mov    %rsp,%rbp           重新开始一段rbp

  4004ea:       48 83 ec 60             sub    $0x60,%rsp           扩栈用于存局部变量

  4004ee:       83 45 fc 01             addl   $0x1,-0x4(%rbp)        执行 i++

  4004f2:       8b 45 fc                mov    -0x4(%rbp),%eax   

  4004f5:       89 c7                  mov    %eax,%edi           edi传递第参数i

  4004f7:       e8 d1 ff ff ff             callq  4004cd          调用test函数

  4004fc:       0f be c0                movsbl %al,%eax           

  4004ff:       89 45 fc                mov    %eax,-0x4(%rbp)       返回值放到i中

  400502:       b8 00 00 00 00          mov    $0x0,%eax            return 0准备

  400507:       c9                    leaveq   

/* leaveq指令将rbp寄存器的内容复制到rsp寄存器中,以释放分配给该过程的所有堆栈空间。然后,它从堆栈恢复rbp寄存器的旧值。*/

 

  400508:       c3                      retq

  400509:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

 

test函数汇编如下:

00000000004004cd :

  4004cd:       55                      push   %rbp            rbp压栈,同时rsp - 8  

  4004ce:       48 89 e5                mov    %rsp,%rbp        重新开始一段rbp

  4004d1:       89 7d ec                mov    %edi,-0x14(%rbp)   

  4004d4:       c7 45 fc 02 00 00 00       movl   $0x2,-0x4(%rbp)       

  4004db:       8b 45 ec                mov    -0x14(%rbp),%eax    

  4004de:       01 45 fc                 add    %eax,-0x4(%rbp)    传入的参数值 + 2

  4004e1:       8b 45 ec                mov    -0x14(%rbp),%eax   eax用于存放返回值

  4004e4:       5d                      pop    %rbp             出栈rbp  rsp  + 8  

  4004e5:       c3                      retq

三、gdb调试体会程序

使用gdb调试可执行程序 gdb ./a.out -tui

设置实时显示寄存器信息layout regs

设置以后的程序自动反汇编set disassemble-next-line on

设置断点后进行单步调试

si 、ni 单步调试汇编级  s 、n 调试c语言级

 

汇编学习之一个最简单的c程序对应的汇编_第1张图片

查看内存指令x使用:

x/

x/ 后可加参数,n、f、u是可选的参数。

x/nfu  n代表显示内存的长度,f 表示显示的格式,如果地址是字符串,则f 为s ,u表示显示的地址的字节数,b表示单字节,h表示双字节,w表示四字 节,g表示八字节

x/8g addr  表示从addr开始显示8个八字节的数。

 

汇编学习之一个最简单的c程序对应的汇编_第2张图片

 

你可能感兴趣的:(汇编学习之一个最简单的c程序对应的汇编)