汇编语言是直接对应系统指令集的低级语言,在语言越来越抽象的今天,汇编语言并不像高级语言那样使用广泛,仅仅在驱动程序,嵌入式系统等对性能要求苛刻的领域才能见到它们的身影。但是这并不表示汇编语言就已经没有用武之地了,通过阅读汇编代码,有助于我们理解编译器的优化能力,并分析代码中隐含的低效率,所以能够阅读和理解汇编代码也是一项很重要的技能。因为我平时都是在linux环境下工作的,这篇文章就讲讲linux下的汇编语言。

一、汇编语法风格

汇编语言分为intel风格和AT&T风格,前者被Microsoft Windows/Visual C++采用,Linux下,基本采用的是AT&T风格汇编,两者语法有很多不同的地方。
1. 寄存器访问格式不同。在 AT&T 汇编格式中,寄存器名要加上 '%' 作为前缀;而在 Intel 汇编格式中,寄存器名不需要加前缀。例如:

AT&T Intel
pushl %eax push eax

2. 立即数表示不同。在 AT&T 汇编格式中,用 '$' 前缀表示一个立即操作数;而在 Intel 汇编格式中,立即数的表示不用带任何前缀。例如:

AT&T Intel
pushl $1 push 1

3. 操作数顺序不同。在 Intel 汇编格式中,目标操作数在源操作数的左边;而在 AT&T 汇编格式中,目标操作数在源操作数的右边。例如:

AT&T Intel
addl $1, %eax add eax, 1

4. 字长表示不同。在 AT&T 汇编格式中,操作数的字长由操作符的最后一个字母决定,后缀'b'、'w'、'l'分别表示操作数为byte、word和long;而在 Intel 汇编格式中,操作数的字长是用 "byte ptr" 和 "word ptr" 等前缀来表示的。例如:

AT&T Intel

5. 寻址方式表示不同。在 AT&T 汇编格式中,内存操作数的寻址方式是
section:disp(base, index, scale)
而在 Intel 汇编格式中,内存操作数的寻址方式为:
section:[base + index*scale + disp]
由于 Linux 工作在保护模式下,用的是 32 位线性地址,所以在计算地址时不用考虑段基址和偏移量,而是采用如下的地址计算方法:
disp + base + index * scale
由此分为以下几种寻址方式:

Intel AT&T
内存直接寻址 seg_reg: [base + index * scale + immed32] seg_reg: immed32 (base, index, scale)
寄存器间接寻址 [reg] (%reg)
寄存器变址寻址 [reg + _x] _x(%reg)
立即数变址寻址 [reg + 1] 1(%reg)
整数数组寻址 [eax*4 + array] _array (,%eax, 4)

二、IA32寄存器

1.通用寄存器
顾名思义,通用寄存器是那些你可以根据自己的意愿使用的寄存器,但有些也有特殊作用,IA32处理器包括8个通用寄存器,分为3组
1) 数据寄存器
EAX 累加寄存器,常用于运算;在乘除等指令中指定用来存放操作数,另外,所有的I/O指令都使用这一寄存器与外界设备传送数据。
EBX 基址寄存器,常用于地址索引
ECX 计数寄存器,常用于计数;常用于保存计算值,如在移位指令,循环(loop)和串处理指令中用作隐含的计数器.
EDX 数据寄存器,常用于数据传递。
2) 变址寄存器
ESI 源地址指针
EDI 目的地址指针
3) 指针寄存器
EBP为基址指针(Base Pointer)寄存器,存储当前栈帧的底部地址。
ESP为堆栈指针(Stack Pointer)寄存器,一直记录栈顶位置,不可直接访问,push时ESP减小,pop时增大。
2. 指令指针寄存器
EIP 保存了下一条要执行的指令的地址, 每执行完一条指令EIP都会增加当前指令长度的位移,指向下一条指令。用户不可直接修改EIP的值,但jmp、call和ret等指令也会改变EIP的值,jmp将EIP修改为目的指令地址,call修改EIP为被调函数第一条指令地址,ret从栈中取出(pop)返回地址存入EIP。

【文章福利】小编在群文件上传了一些个人觉得比较好得学习书籍、视频资料,有需要的可以进群【977878001】领取!!!额外赠送一份价值699的内核资料包(含视频教程、电子书、实战项目及代码)

 内核资料直通车:Linux内核源码技术学习路线+视频教程代码资料https://link.zhihu.com/?target=https%3A//docs.qq.com/doc/DUGZVQk1qWVBHTEl3

学习直通车(腾讯课堂免费报名):Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂https://link.zhihu.com/?target=https%3A//ke.qq.com/course/4032547%3FflowToken%3D1044374

三、函数调用过程

函数调用时的具体步骤如下:
1. 调用函数将被调用函数参数入栈,入栈顺序由调用约定规定,包括cdecl,stdcall,fastcall,naked call等,c编译器默认使用cdecl约定,参数从右往左入栈。
2. 执行call命令。
call命令做了两件事情,一是将EIP寄存器内的值压入栈中,称为返回地址,函数完成后还要到这个地址继续执行程序。然后将被调用函数第一条指令地址存入EIP中,由此进入被调函数。
3. 被调函数开始执行,先准备当前栈帧的环境,分为3步
pushl %ebp 保存调用函数的基址到栈中,
movl %esp, %ebp 设置EBP为当前被调用函数的基址指针,即当前栈顶
subl $xx, %esp 为当前函数分配xx字节栈空间用于存储局部变量
4. 执行被调函数主体
5. 被调函数结束返回,恢复现场,第3步的逆操作,由leave和ret两条指令完成,
leave 主要恢复栈空间,相当于
movl %ebp, %esp 释放被调函数栈空间
popl %ebp 恢复ebp为调用函数基址
ret 与call指令对应,等于pop %EIP,
6. 返回到调用函数,从下一条语句继续执行
我们来看两个具体例子,第一个求数组和,

int ArraySum(int *array, int n)
{int t = 0;for(int i=0; i<n; ++i) t += array[i];return t;
}
int main()
{int a[5] = {1, 2, 3, 4, 5 };int sum = ArraySum(a, 5);return sum;
}

编译成汇编代码
gcc -std=c99 -S -o sum.s sum.c
gcc加入了很多汇编器和连接器用到的指令,与我们讨论的内容无关,简化汇编代码如下:

ArraySum:pushl    %ebpmovl    %esp, %ebp   subl    $16, %esp  //分配16字节栈空间movl    $0, -8(%ebp)  //初始化tmovl    $0, -4(%ebp)  //初始化ijmp    .L2
.L3:movl    -4(%ebp), %eaxsall    $2, %eax  //i<<2, 即i*4, 一个int占4字节addl    8(%ebp), %eax  //得到array[i]地址,array+i*4movl    (%eax), %eax   //array[i]addl    %eax, -8(%ebp) //t+=array[i]addl    $1, -4(%ebp)
.L2:movl    -4(%ebp), %eax   cmpl    12(%ebp), %eax  //比较i<njl    .L3movl    -8(%ebp), %eax //return t; 默认eax存函数返回值leaveret
main:
.LFB1:pushl    %ebpmovl    %esp, %ebpsubl    $40, %esp       movl    $1, -24(%ebp) //初始化a[0]movl    $2, -20(%ebp) //初始化a[1]movl    $3, -16(%ebp) //初始化a[2]movl    $4, -12(%ebp) //初始化a[3]movl    $5, -8(%ebp)   //初始化a[4]movl    $5, 4(%esp)    //5作为第二个参数传给 ArraySumleal    -24(%ebp), %eax  //leal产生数组a的地址movl    %eax, (%esp)   //作为第一个参数传给ArraySumcall    ArraySummovl    %eax, -4(%ebp)  //返回值传给summovl    -4(%ebp), %eax  //return sumleaveret

栈变化过程如下:

执行call指令前 执行call指令后
从图中可以看出
1. 数组连续排列,用move指令逐个赋值,读取数组元素方法是,用leal得到数组首地址,再计算偏移量
2. 参数从右往左入栈
3. gcc为了保证数据是严格对齐的,分配的空间大于使用的空间,有部分空间是浪费的
下面这个例子说明了struct结构的实现方法,

struct Point
{int x;int y;
};
void PointInit(struct Point *p, int x, int y)
{p->x = x;p->y = y;
}
int main()
{struct Point p;int x = 10;int y = 20;PointInit(&p, x, y);return 0;
}

编译成汇编代码,简化如下:

PointInit:pushl    %ebpmovl    %esp, %ebpmovl    8(%ebp), %eax    //p的地址movl    12(%ebp), %edx  //xmovl    %edx, (%eax)      //p->x=xmovl    8(%ebp), %eaxmovl    16(%ebp), %edx  //ymovl    %edx, 4(%eax)    //p->y=ypopl    %ebpret
main:pushl    %ebpmovl    %esp, %ebpsubl    $28, %espmovl    $10, -8(%ebp)  //x=10movl    $20, -4(%ebp)  y=20movl    -4(%ebp), %eaxmovl    %eax, 8(%esp)movl    -8(%ebp), %eaxmovl    %eax, 4(%esp)leal    -16(%ebp), %eax  //取p地址&pmovl    %eax, (%esp)call    PointInitmovl    $0, %eaxleaveret

栈图就不画了,可以清楚地看出struct跟数组类似,连续排列,通过相对位移访问struct的成员,p->y与*(p+sizeof(p->x))有一样的效果。

四、disassemble和objdump

在linux下有两个跟汇编有重要关系的命令,一个是objdump,另一个是gdb中的disassemble。
objdump帮助我们从可执行文件中反汇编出汇编代码,从而逆向分析工程。
objdump -d sum
部分汇编代码如下

080483b4 <ArraySum>:80483b4:    55                       push   %ebp80483b5:    89 e5                    mov    %esp,%ebp80483b7:    83 ec 10                 sub    $0x10,%esp80483ba:    c7 45 f8 00 00 00 00     movl   $0x0,-0x8(%ebp)80483c1:    c7 45 fc 00 00 00 00     movl   $0x0,-0x4(%ebp)80483c8:    eb 12                    jmp    80483dc <ArraySum+0x28>80483ca:    8b 45 fc                 mov    -0x4(%ebp),%eax80483cd:    c1 e0 02                 shl    $0x2,%eax80483d0:    03 45 08                 add    0x8(%ebp),%eax80483d3:    8b 00                    mov    (%eax),%eax80483d5:    01 45 f8                 add    %eax,-0x8(%ebp)80483d8:    83 45 fc 01              addl   $0x1,-0x4(%ebp)80483dc:    8b 45 fc                 mov    -0x4(%ebp),%eax80483df:    3b 45 0c                 cmp    0xc(%ebp),%eax80483e2:    7c e6                    jl     80483ca <ArraySum+0x16>80483e4:    8b 45 f8                 mov    -0x8(%ebp),%eax80483e7:    c9                       leave  80483e8:    c3                       ret

linux下汇编语言开发相关推荐

  1. linux下汇编语言开发总结

    汇编语言是直接对应系统指令集的低级语言,在语言越来越抽象的今天,汇编语言并不像高级语言那样使用广泛,仅仅在驱动程序,嵌入式系统等对性能要求苛刻的领域才能见到它们的身影.但是这并不表示汇编语言就已经没有 ...

  2. Linux下C++开发工具介绍

    概述     就C++开发工具而言,与Windows下微软(VC, VS2005等)一统天下相比,Linux/Unix下C++开发,可谓五花八门,各式各样.Emacs, vi, eclipse, an ...

  3. 【转载】Visual Studio 2015 for Linux更好地支持Linux下的开发

    原文:Visual Studio 2015 for Linux更好地支持Linux下的开发 英文原文:Targeting Linux Made Easier in Visual Studio 2015 ...

  4. (转)Linux下C++开发初探

    1.开发工具 Windows下,开发工具多以集成开发环境IDE的形式展现给最终用户.例如,VS2008集成了编辑器,宏汇编ml,C /C++编译器cl,资源编译器rc,调试器,文档生成工具, nmak ...

  5. Linux下服务器端开发流程及相关工具介绍(C++)

    原文:Linux下服务器端开发流程及相关工具介绍(C++) 去年刚毕业来公司后,做为新人,发现很多东西都没有文档,各种工具和地址都是口口相传的,而且很多时候都是不知道有哪些工具可以使用,所以当时就想把 ...

  6. Linux下Java开发环境的搭建Tomcat6+jdk6+eclipse3.5.2+Myeclipse9.0+mysql5.1.47

    Tomcat6+jdk6+eclipse3.5.2+Myeclipse9.0+mysql5.1.47 1.JDK的安装:usr/java/jdk1.6.0_25 下载:jdk-6u25-linux-i ...

  7. Linux下golang开发环境搭建

    对于golang开发来说,Windows下可以用vscode或者liteide都不错,但是Linux下的开发也就只有vim了,所以怎么搞笑的利用vim进行golang开发呢? 参考官方推荐的一个插件: ...

  8. Linux下c开发 之 线程通信

    Linux下c开发 之 线程通信 1.Linux"线程" 进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种"多进程单线 ...

  9. linux应用程序是什么,linux下c开发了一个应用程序,它的扩展名是什么?

    这个貌2113似涉及到linux文件系统.linux文件系统与windows的不相同5261,windows系统应该是通4102过文件后缀来进行文件类型是别的,而1653linux虽然也会借鉴后缀信息 ...

最新文章

  1. [Android]打开eclipse报错:发现了以元素 'd:skin' 开头的无效内容。此处不应含有子元素。...
  2. jQuery插件开发(一):jQuery类方法
  3. KMP算法的理解,伪代码,c代码实现
  4. python 调用c++
  5. redis List的用途及常用命令
  6. cookie购物车php简单,php中利用cookie实现购物车实例_PHP教程
  7. ora-01033 解决方法
  8. 计算机辅助翻译政府工作报告,Trados辅助翻译软件在科技英语翻译中的应用
  9. USB驱动——键盘驱动(控制传输)
  10. 【面经】五面阿里巴巴达摩院
  11. Python实现头像换脸(AI换脸)
  12. 关于debug时的断点无效问题 [已解决,不知原因]
  13. ospfdr选举规则_OSPF中DR和BDR的选举原则和注意事项
  14. 数据挖掘总结之消极学习与积极学习
  15. 每个程序员都应该了解的 CPU 高速缓存
  16. matlab代码建立不允许缺货,允许缺货的经济订货批量模型.doc
  17. PHP1c型GNAS,8盘位HP ML110 G9开箱测试,刷群晖改装20盘位
  18. TiDB GC 之处理案例 FAQ
  19. 超详细的张飞硬件90天读书笔记02
  20. wdr7661散热问题_深入测评普联TL-WDR7661千兆版怎么样??比较好不好呀?

热门文章

  1. R语言曲线回归:多项式回归、多项式样条回归、非线性回归数据分析
  2. opencv-python简易文档(三)图像处理算法
  3. 互联互通社区祝大家中秋节快乐!
  4. RIA E100 操作方式
  5. Unity 编辑器代码打开场景
  6. 数据库网关-欧姆龙PLC与MySQL/SQLServer/PostgreSQL数据库实时双向通讯
  7. ppt转换器免费下载在哪儿
  8. python零基础爬虫练习:如何用python爬取高德地图
  9. pattern java怎么用_Pattern Java设计模式23种每个一个举例使用,名称直接对应英文,简单明了 Develop 238万源代码下载- www.pudn.com...
  10. Windows平台的SDK、DDK与WDK