加入收藏 | 设为首页 | 会员中心 | 我要投稿 财气旺网 - 财气网 (https://www.caiqiwang.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

linux下汇编语言开发

发布时间:2022-11-05 12:48:40 所属栏目:Linux 来源:
导读:  汇编语言是直接对应系统指令集的低级语言,在语言越来越抽象的今天,汇编语言并不像高级语言那样使用广泛,仅仅在驱动程序,嵌入式系统等对性能要求苛刻的领域才能见到它们的身影。但是这并不表示汇编语言就已经
  汇编语言是直接对应系统指令集的低级语言,在语言越来越抽象的今天,汇编语言并不像高级语言那样使用广泛,仅仅在驱动程序,嵌入式系统等对性能要求苛刻的领域才能见到它们的身影。但是这并不表示汇编语言就已经没有用武之地了,通过阅读汇编代码,有助于我们理解编译器的优化能力,并分析代码中隐含的低效率,所以能够阅读和理解汇编代码也是一项很重要的技能。因为我平时都是在linux环境下工作的,这篇文章就讲讲linux下的汇编语言。
 
  一、汇编语法风格
 
  汇编语言分为intel风格和AT&T风格,前者被Microsoft Windows/Visual C++采用,Linux下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。
 
  三、函数调用过程
 
  函数调用时的具体步骤如下:
 
  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,
 

(编辑:财气旺网 - 财气网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!