0. 引子
Why 汇编
CPU不能理解,如 c = (a + b) * d
但是CPU可以理解,如将这俩个寄存器的值相加,并将结果存在第一个寄存器中
基础知识
编译
- 数据和代码在内存中分开存储
-
代码(存储在cs+ip)
mov eax,dword ptr[ebp-4]
(1)C语言代码与汇编代码并不是一一对应,可以一对
(2)汇编窗口显示的地址是机器码的地址,而不是汇编的地址,因为虚拟内存执行的字节流,要不是机器码,要不是数据
(3)机器码长度不同,用后一个指令地址减去前一个指令地址得到 -
数据(存储在stack+ebp)
in stack, accessed via [ebp-4]
- Function:指令的基本功能
- Affection:指令的执行对Flag R/ PSW 标志位的影响
- Data-addressing mode: 寻址方式
- Limitation: 寄存器使用上的要求和限制
- ECX + REP 重复
- GAS(GNU Assember)/AT&T
GNU计划,又称革奴计划,是由Richard Stallman在1983年9月27日公开发起的。它的目标是创建一套完全自由的操作系统.。GNU汇编器(GNU Assembler),简称为GAS - Intel/MASM Microsoft Macro Assembler
VC ++ IDE使用的,是使用intel语法的x86汇编器 - 整数常量
例如:-10、42d、10001101b、0FF3Ah、777o
下标: b = 二进制,d = 十进制,h = 十六进制,o = 八进制 - 字符和字符串常量
单引 或双引 中的字符串或字符串
示例:A,“d”,ABC,“ABC”,“single quote ’ inside”, ‘double quote ” inside’
每个 ASCII 字符占用一个字节 - 可执行指令 executable
- 伪指令directives:伪指令不属于指令集,所以不可执行。用于定义段、内存变量
- 宏指令 marcos:是源程序中的一段有独立功能的程序代码。由汇编器转换为真实指令,目的是简化程序员任务
- .TITLE 标题行(可选)
包含程序和磁盘文件名的简短标题 - .MODEL
指定内存配置
出于我们的目的,FLAT 内存模型将在同一 seg 中使用//数据代码
线性 32 位地址空间(无分段)
STDCALL 指令告诉汇编器使用 …
名称和过程调用的标准约定 - .686 处理器指令
在MODEL指令之前使用。
程序可以使用奔腾 P6 架构的说明
至少.686 指令使用 FLAT 内存 - .STACK 堆栈指令
告诉汇编程序为程序定义运行时堆栈
堆栈的大小可以由此指令有选择地指定
过程调用需要运行时堆栈 - .DATA 数据指令
为程序数据定义内存中的区域
程序变量应在此指令下定义
汇编程序将分配和初始化变量的存储 - .CODE 指令
定义包含指令的程序的代码部分
汇编器将指令放在内存中的代码区域 - PROC 和 ENDP 指令
用于定义过程
作为一个约定,我们将主定义为第一个过程
其他过程可以在主 - 结束指令
标记程序的结束
标识程序启动过程的名称(主) - 可以在可执行文件或 .o 文件上运行
- 分析位模式的指令集
- 生成装配代码的近似再现
- 高:开发后
导致更激进的优化,需要更长的时间来编译
对于人和调试器来说,很难将生成的机器代码与原始源代码相关联 - 低:开发期间
导致执行缓慢 - 我们查找指令表,找到指令”mov”,并在操作码字段上写下相应的 6 位。
- 控制位
D 指示数据流的方向,从内存到寄存器或寄存器到内存。在这种情况下,源代码存储在内存中,目标数据存储在寄存器 EAX 中,因此 D 设置为 1。
W 指示操作数是否为单词。1 表示单词 。
Mod 表示寻址模式,01 表示我们在这里使用的寄存器相对模式。
REG 指示用于保存操作数的寄存器,eax 的代码为 000,因此我们在此处填 充 000。
R/M 指示在寻址模式下使用哪个寄存器,ebp 的代码为 110。 - 最后一步是将相对地址 -4 附加到最右侧的 8 位。-4 表示在 2 的补数中。
最多一个16位的寄存器只能编216个地址,这样决定了寻址的能力只有64K,所以每一个段大小为64K。但是有20根数据线,所以段地址(可以理解成对字的寻址左移四位(十六进制x10H)得到物理地址
段寄存器:在8086系统中,访问存储器的地址码由段地址和段内偏移地址两部分组成。段寄存器用来存放各分段的逻辑基值,并指示当前正在使用的4个逻辑段,包括以下:
1, 代码段寄存器CS:存放当前正在运行的程序代码所在段的段基值,表示当前使用的指令代码可以从该段寄存器指定的存储器段中取得,相应的偏移值则由IP提供。
2, 数据段寄存器DS:指出当前程序使用的数据所存放段的最低地址,即存放数据段的段基值。
3, 堆栈段寄存器SS:指出当前堆栈的底部地址,即存放堆栈段的段基值。
4, 附加段寄存器ES:指出当前程序使用附加数据段的段基址,该段是串操作指令中目的串所在的段。
1.2 (操作数)寻址模式 (operand-)addressing mode
什么是寻址模式 addressing moder> 机器指令是计算机CPU可执行的指令,一条指令要包含操作符和操作的对象(操作数)。对于Intel Processors指令集而言,有的指令没有操作数,有的有多个操作数(大于1个)。
所谓寻址模式,就是我们写的代码要指明操作数在那里,这样CPU才能正确的找到操作数,执行这条指令。
提取哪个数据项r> 在 c 中 :使用变量
在机器代码中:操作数寻址模式
(操作数)寻址模式分为三类:(mov 目的操作数,源操作数)
类型 | 解释 | 源操作数 | 目的操作数 | 例子 | 备注 |
---|---|---|---|---|---|
Immediate立即寻址 | 一条指令的操作数,可以直接包含在指令中,不需要去别的地方寻找 | 寄存器 | 寄存器 | mov ax,10H | 数据存储在代码段 |
Register | 放在寄存器 | 常量 | 寄存器 | mov ax,bx | 寄存器大小相等 |
Memory | 操作数放在内存中 有的是取这个内存地址的数据就可以,所谓直接方式 有的需要计算得出其存放地址,再通过地址取得内存中的数据,所谓间接方式。 |
一个操作数必须是内存地址,另一个操作数可以是直接编 或寄存器 | mov ax, [10H] mov ax, [bx] |
需要将DS的值左移4位(即十六进制的x10H) |
规律
1. 立即数immediate只能显示为源操作数。
2. 不允许进行内存到内存操作,但字符串操作(movs)除外
3. 避免使用段寄存器。
4. 有些操作数是显式指定的,有些则是隐含的。
每条指令都包含:
指令分类:
栈是字Word之间的顺序
大小端是字内字节顺序:x86是小端,字内的低字节在前
类型 | 例子 |
---|---|
Data transforming/数据传送类 | MOV dest,source lea,加载内存位置的有效地址 PUSH AX 表示 AH 将移动到 SP-1 寻址的堆栈段内存位置,而 AL 将移动到 SP-2 POP BX 将导致从堆栈中删除前两个字节的数据,并将第一个字节移动到 BL,将第二个字节移动到 BH 中 |
Arithmetic operation/算术运算类 | ADD (Add), ADC (Add with carry), INC (Increment by 1) SUB (Subtraction ), SBB (Subtraction with borrow ), DEC (Decrement by 1 ), NEG (Two’s complement negation) CMP (Compare operands )不改变目的操作数,只改变标志位的减法 MUL (Unsigned multiply ), IMUL (Signed multiply ) DIV (Unsigned divide), IDIV (Signed divide ) CBW (Convert byte to word), CWD (Convert word to doubleword ) |
Bits and logic operation/位与逻辑运算类 | NOT, AND, OR, XOR TEST (Logical compare (AND) )//不改变目的操作数,只改变标志位的ADD SHL, SHR SAL, SAR ROL (Rotate left ), ROR (Rotate right ) RCL (Rotate left (with carry) ), RCR (Rotate right (with carry) ) |
String operation/字符串处理类 | STOS 指令将数据存储在 AL、AX 或 EAX 中,位置由 DI 严格器寻址的额外段内存位置 MOVSB (Move byte from string to string) STOSB (Store byte in string ), LODSB (Load byte) CMPSB (Compare bytes in memory) SCASB (Compare byte string) |
Branch and loop/控制转移类 | JMP 是一个无条件的跳转指令 call通过更改 ip 甚至 cs 寄存器将流重定向到刚刚调用的过程。CALL 指令与跳转指令不同,在堆栈上保存返回地址,RET后继续call的下一条指令 |
CPU control/处理器控制类 | CLC (Clear carry flag), STC (Set carry flag), CMC (Complement carry flag) CLD( Clear direction flag ),STD (Set direction flag ) CLI (Clear interrupt flag ),STI (Set interrupt flag ) NOP (No operation ) HLT (Enter halt state)halts the CPU until the next external interrupt is fired. WAIT (Wait until not busy ) LOCK (Assert BUS LOCK# signal ) (for multiprocessing) ESC (Escape) |
前缀: REPxx (重复 xx, xx可以是CMPS/MOVS/SCAS/STOS ) /REPZ
例子:
将 eax (0CCCCCCCCh)的值ecx(14h)次写入 由 edi 寻址存位置,edi 在每次迭代中自动增加 4(因为每次是写入的双字)。
2. 分支
JE/JNE:jump equal / not equal
3. 编写x86汇编程序(与CPU相关)
就像其它任何一种语言一样,光有指令是无法完成一个完整的程序,还需要宏定义,程序结构,库调用等等
汇编器和编译器
相同点:都将一种语言转换为另一种语言
不同点:编译器更智能、更复杂,因为它分析代码的含义、通过生成较小的可执行文件来优化程序或提高执行效率。汇编器只根据制造商的准则将指令转换为机器代码。一些汇编器也可以执行一些简单的指令集进行特定优化。
两种类型的汇编语言(都可以生成x86的汇编指令集)
The difference:
两者的源操作数和目的操作数的位置相反
前者的汇编指令中带有后缀(如b/w/l),指示操作数的长度(8/16/32 bits)
前者在寄存器前加“%”,在常数和符 地址前加“$”
前者间接寻址用( )表示,而后者用[ ]表示
E.g:
movl %edx,%eax mov eax,edx
movl (%edx),%eax mov eax,[edx]
汇编代码
汇编程序
常量
程序包括
前两个都是规定的,最后一个是你自己设计的。
x86指令格式:
inc一般是include文件用于编写同用代码的
bin二进制文件,其用途依系统或应用而定 ,也可是 镜像文件
com/DOS可执行命令文件,一般小于64KB
4. 反汇编
Register Allocation
编译器希望能够为源程序中的每个变量分配一个寄存器,因为寄存器中变量会加快程序执行速度
汇编语言:程序员
C 语言:编译器
分配寄存器很难,编译器不会尝试以尽可能最好的方式分配寄存器
为什么r> 最好的方式意义冲突(长时间的分析和思考,结果不容易被理解)
优化级别
编译器优化寄存器分配的程度取决于优化级别
5. 机器码
我们如何获得代码地址、找出代码的大小h2>
使用 IDE 中的反汇编窗口,内存窗口
全局变量是用的绝对地址,而局部变量是相对地址
列表文件 listing file:使用它查看程序是如何汇编的
map file: LST为扩展名,列表文件同时给出源程序和机器语言程序(每个段都有),使调试程序变得方便。LST文件可有可无

如何获得汇编代码对于的机器码
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!