chap1.2_数据和指令
1 指令执行
1.1 指令寻址
cs寄存器,ip寄存器
每次从 [cs,ip] 指向的内存位置取一条指令执行,执行后ip值增加,指向下一条指令的内存位置
CPU执行时,会一直的从内存单元中读取指令,坊到指令缓冲器执行。而取指令时,是根据CS寄存器和IP寄存器来获取一个地址[CS:IP]。这个地址指向内存单元中的代码段。CPU从中读取一条指令执行,然后IP指向下一条指令,继续读取执行。如此循环。
[CS+IP]:CS=段地址,IP=偏移地址。CPU一直从[CS+IP]指向的内存单元处读取指令。
1.2 访问数据
当CPU需要获取一个数据时,这时候代码段中能够获得的是DS寄存器和一个偏移地址。[DS*0x10 + 偏移地址],指定地址时候可以不显示的写出DS。
这个地址指向内存单元中的数据。CPU根据这个地址获取到需要的数据。
基本地址:DS存储的是基本地址,但是在程序中段寄存器DS一般可以不显示说明。只用 [偏移地址] 来表示内存单元的地址。
偏移地址:是一个常数,可以直接使用数字来表示,比如:[553]。也可以使用BX,BP,SI,DI(其他的寄存器不能表示内存地址)中的值来表示。比如[BX]。[DS+BX]:DS=段地址,BX=偏移地址,内存单元地址为DS*0x10+BX。计算其寻址能力根据可指定的内存范围大概为0-1M之间。
2.3 指令跳转
当CPU执行完一块内存中的代码段时,使用JMP命令来修改CS寄存器和IP寄存器的值。从而控制计算机指令执行的跳转。
jmp:jmp指令转移就是修改cs,ip寄存器的指向。来完成跳转的功能。JMP导致[CS:IP]指向新的内存单元,CPU从新的内存单元读取指令。
汇编指令
以nasm为例
1. 赋值操作
- mov
mov ax, 0x1
1)将值赋给寄存器:mov 寄存器,寄存器|内存单元|立即数
1 | mov ax,0x0018H ;ax = 0x0018H |
1)将值赋给内存单元:mov 内存单元,寄存器|内存单元|立即数
1 | mov [0x0a200H],0x0018H ;ax = 0x0018H |
2. 算术操作
下面是算术操作指令的简单列表:
| 指令 | 说明 |
|---|---|
| add | 整数加 |
| sub | 减法 |
| mul | 乘法(无符号) |
| IMUL | 乘法(有符号) |
| DIV | 除法(无符号) |
| IDIV | 除法(有符号) |
| INC | 自增 |
| DEC | 自减 |
| NEG | 取反 |
| CMP | 比较大小 |
1)加法: add 寄存器,寄存器|立即数
add ax,0x0017H ;ax=ax+0x0017H
add ax,bx ;ax=ax+bx
2)减法: sub 寄存器,寄存器|立即数
sub ax,0x0017H ;ax=ax-0x0017H
sub ax,bx ;ax=ax-bx
3)乘法(无符号): mul 寄存器.
使用寄存器: AX存放目标操作数,操作后AX和DX存放结果。
mov eax 0x0100H
mul 寄存器
4) 除法: div 寄存器|内存单元(除数).
使用寄存器: AX和DX存放被除数,操作后AX和DX存放商和余数。
div 寄存器|内存单元
5)自增1:inc 寄存器
inc ax
6) 自减1:dec 寄存器
dec ax
7)取补码:nec
3. 转移操作
| 指令 | 说明 | |
|---|---|---|
| JE | 如果相等则跳转 | |
| JNE | 如果不相等则跳转 | |
| JZ | 如果为 0 则跳转 | |
| JNZ | 如果不为 0 则跳转 | |
| JC | 如果进位 则跳转 | |
| JNC | 如果不进位 则跳转 | |
| JG | 如果第一个操作数比第二个大则跳转 | |
| JGE | 如果第一个操作数比第二个大或者相等则跳转 | |
| JA | 与 JG 指令相同,只不过比较的是无符号数则跳转 | |
| JAE | 与 JGE 指令相同,只不过比较的是无符号数则跳转 |
4. 跳转指令
jmp指令
cs寄存器,ip寄存器
通过修改 [cs,ip] 内容,达到跳转效果。
- jmp near 短转移 : [ ip <- new ip val]
- jmp far 远转移 : [ cs<- new cs val, ip <- new ip val]
- jmp word 段间转移,可从32位跳转64位指令
call指令
cs寄存器,ip寄存器,栈寄存器
1)压栈当前指令位置 [ss, sp] <- [cs, ip]
- 跳转到函数执行
3)返回,出栈当前指令位置 [cs, ip] <- [ss, sp]
4)继续执行指令
- call
- call far
- call world
ret指令
cs寄存器,ip寄存器,栈寄存器
3)返回,出栈当前指令位置 [cs, ip] <- [ss, sp]
4)继续执行指令
loop指令
cx寄存器
判断 [cs] 寄存器值是否为0,为0停止循环,不为0继续循环。
每次执行 [cs内容]=cx-1
5. 栈操作
栈寄存器
首先CPU进行出栈入栈操作时,需要先分配一段栈空间的内存,来存储数据使用。
这段内存的位置由栈段寄存器SS和栈指针寄存器SP来指定。
1 | 栈顶地址 = 栈段寄存器SS << 4 + 栈指针寄存器SP |
每次进行出栈入栈操作时,SS和SP会更新得到新的栈顶位置。
我们可以通过指定 栈段寄存器SS和栈指针寄存器SP的值来初始化栈空间分配。
栈顶地址: [ss:sp] (默认 [ss:0xf] )
栈空间 : [ss:0] -> [ss:0xf]
push指令
push:入栈,将寄存器的数据入栈
ss寄存器,sp寄存器
通过修改 [ss,sp] 内容,改变栈顶位置
[cs, sp] <- 栈顶位置
执行后, 栈值增加,指向新的地址
[cs,sp+2] <- 栈顶位置
pop指令
pop: 出栈,数据存储到寄存器中
ss寄存器,sp寄存器
通过修改 [ss,sp] 内容,改变栈顶位置
执行后, 栈值减少,指向上一个地址
[cs,sp-2] <- 栈顶位置
其他指令
CLI : Clear Interupt
STI :Set Interupt
CLD : Clear Director
STD :Set Director
REP:Repeat
MOVSB: Move String Byte