汇编学习笔记

进行一些笔记的整理

前言

上年暑假就学了 x86 汇编的实模式部分,当时用 Onenote 记了一些笔记,后来发现了 Markdown 这个好东西,就决定搬迁一下,也方便我上课查(bushi

格式有待整理(逃

寄存器

通用寄存器

寄存器 全称 中文名称
CS Code Segment 代码段寄存器
DS Data Segment 数据段寄存器
ES Extra Segment 附加段寄存器
SS Stack Segment 栈段
SP Stack Pointer 栈指针寄存器
IP Instruction Pointer 指令指针寄存器
SI Source Index 源索引(变址)寄存器
DI Destination Index 目标索引寄存器
AX Accumulator 累加器
BX Base Address Register 基地址寄存器
CX Counter 计数器
DX Data 数据寄存器

标志寄存器

Index 名称 说明
第0位 CF 进位标志,进行算术操作时,如果最高位有向前进位或借位的情况发生,则CF=1,否则CF=0,少数指令除外(如inc和dec)
第2位 PF 奇偶标志,运算结果最低8位,有偶数个为1的比特则PF=1,否则PF=0
第4位 AF
第6位 ZF(Zero Flag) 零标志,当处理器执行一条算数或者逻辑运算指令后,抓住逻辑部件送出的结果除了送到指令中指定位置,还送到一个或非门,如果计算结果为0,ZF被置成1,表示计算结果为零是“真”的,否则清除此位(0)
第7位 SF(Sign Flag) 符号位,如dec计算结果的最高位是比特“0”,SF置“0”,否则置“1”
第8位 TF
第9位 IF
第10位 DF(Direction Flag) 方向标志,可控制movsb和movsw的传送方向
第11位 OF 即溢出标志,用于指示两个有符号数的运算结果是否错误,如果结果正确,则OF=0,否则OF=1

指令

mov

示例:
mov ah,bh
mov ax,dx
mov [0x02],bl
mov ax,[0x06]
mov ah,0x05
mov word [0x1c],0xf000

db(Declare Byte)

伪指令,跟在后面的操作数都占一个字节的长度,如果要声明超过一个以上的数据,各个操作数之间必须以逗号隔开

div

  1. 用16位的二进制数除以8位的二进制数:
    被除数必须在寄存器AX中,必须先传送到AX寄存器里,除数可以由8位的通用寄存器或者内存单元提供
    执行后:商在AL中,余数在AH中
  2. 用32位的二进制数除以16位的二进制数:
    被除数的高16位在DX中,低16位在AX中
    执行后:商在AX中,余数在DX中

xor

0 xor 0 = 0
0 xor 1 = 1
1 xor 0 = 1
1 xor 1 = 0
常用于清零

times

伪指令,重复后面的指令若干次
例:times 100 db 0

movsb和movsw

原始数据串的段地址由 DS 指定,偏移地址由 SI 指定,简写为 DS:SI ,目的地址为 ES:DI ,传送的字节数或者字数由 CX 指定,每传送一次, CX 内容减一
正向传送时传送操作方向是从内存区域低地址端到高地址端,每传送一个字节或一个字时, SI 和 DI 加 1 或者加 2 ,反向传送则相反

cld和std

cld:将 DF 标志清零,指示传送是正方向的
std:与 cld 相反

loop

执行时 CX 减一,若 CX 内容不为零,转移到指定的位置执行,否则顺序后面的指令

rep

指令前缀,即 repeat
CX 不为零则重复

inc和dec

inc:加一指令,inc bxadd bx,1 功能一样,但前者机器码更短,速度更快
dec:减一指令,与 inc 格式相同

neg

用 0 减去指令中指定的操作数

cbw和cwd

两条指令后都没有操作数
cbw(Convert Byte to Word):将 AL 中的有符号数扩展到整个 AX
cwd(Convert Word to Double-word):将 AX 中的有符号数扩展到 DX:AX 中

idiv

div 为无符号除尘指令(Unsigned Divide)
idiv 指令格式与 div 相同,专门用于计算有符号数

sub

与加法指令 add 类似,但处理器没有减法运算电路,故 sub ah,al 等效
neg al
add ah,al

cmp

功能上和 sub 指令相同,但仅影响相应标志位(CF、OF、SF、ZF、AF和PF),而不保留计算结果,因此不会改变两个操作数的原有内容

or和and

or and
0 xor 0 = 0 0 xor 0 = 0
0 xor 1 = 1 0 xor 1 = 0
1 xor 0 = 1 1 xor 0 = 0
1 xor 1 = 1 1 xor 1 = 1
对标志寄存器影响: OF 和 CF 位被清零, SF、ZF、PF 的状态依计算结果而定

push和pop

操作数可以是寄存器或者内存单元,逻辑地址为 SS:SP ,不影响任何标志位
push:执行时将 SP 内容减去操作数的字长,从高地址端向低地址端推进
pop:执行时将 SP 内容加上操作数的字长

in和out

in 指令是从端口读,一般形式是
in al,dx
in ax,dx
in 指令的操作数必须是寄存器 AL 或者 AX ,用于访问 8 位或 16 位的端口,源操作数应当是寄存器 DX , in 指令为 2 字节形式时,后一字节是立即数
out 指令和 in 指令相反
两个指令均不影响任何标志位

call、ref和retf指令

8086处理器支持四种调用方式
i. 16位相对近调用。近调用的意思是被调用的目标过程位于当前代码段内,而非另一个不同的代码段,故只需得到偏移地址即可,计算过程为:用目标过程的汇编地址减去当前call指令的汇编地址,再减去当前call指令以字节为单位的长度(3),保留16位的结果,近调用的特征是在指令中使用关键字”near”,若没有提供任何关键字,则编译器认为该指令是近调用,其机器指令操作数是一个16位的有符号数,被调用过程的首地址必须位于距离当前call指令-32768~32767字节的地方
ii. 16位间接绝对近调用。这种调用也是近调用,只能调用当前代码段内的过程,指令中的操作数不是偏移量,而是被调用过程的真实偏移地址,故称为绝对地址,该偏移地址不直接出现在指令中,而是由16位的通用寄存器或者16位的内存单元间接提供,机器指令的操作是16位的绝对地址,故可以调用当前代码段任何位置处的过程
iii. 16位直接绝对远调用。这种调用属于段间调用,即调用另一个代码段的过程,”16位”是针对偏移地址来说的,而不是限定段地址,”直接”的意思,段地接和偏移地址直接在call指令中给出,先后将CS和IP进行压栈和出栈
iv. 16位间接绝对远调用。同样属于段间调用,”16位”同样用于限定偏移地址,必须使用关键字”far”,例:
proc_1 dw 0x0102,0x2000
call far [proc_1]
0x0102是偏移地址,0x2000是段地址,指令执行时,处理器访问DS指向的数据段,从指令中指定的偏移地址处取得两个字(段地址0x2000和偏移地址0x0102),再将CS和IP分别压栈和取代
ref是近返回指令,从栈中弹出一个字到IP中
retf是远返回指令,分别从栈中弹出两个字到IP和CS中

shr、shl、ror、rol

shr(Shift logical Right),即逻辑右移指令,将AX中的内容右移4位,执行时将操作数连续右移指定次数,每次溢出的比特被移到CF位,空出的位置用“0”填充,目的操作数可以是8位或16位通用寄存器/内存单元,源操作数可以是1或8位立即数或寄存器CL,当使用CL时,对于目的操作数是内存地址的情况,须使用关键字byte或word等来加限定,如:
shr al,cl
shr byte [bx],cl
ror(Rotate Right),即循环右移指令,执行时每右移一次,移出的比特既送到CF位,也送进左边空出的位

jmp

若JMP之后是标号,则编译为相对转移指令0xE9,操作数为相对偏移题,执行时IP+操作数+长度,此时为相对近转移
8086处理器的无条件转移指令(“16位”意为要转移到的目标位置的偏移地址是16位的)

  1. 相对短转移。操作码为0xEB,操作数是相对于目标位置的偏移量,仅1字节,且为有符号数,故该指令属于段内转移指令,且只允许转移到距离当前-128~127字节的地方,该指令须使用关键字“short”,例:
    jmp shor infinite
  2. 16位相对近转移。转移范围较相对短转移稍大,操作码为0xE9,操作数为2字节,属于段内转移,可转移到距当前指令-32768~32767字节的地方,该指令应使用关键字“near”
  3. 16位间接绝对近转移。转移到的目标偏移地址不是在指令中直接给出,而是用一个16位的通用寄存器或者内存地址间接给出,关键字“near“可以省略,例:
    jmp near bx
    jmp near cx
    jump_dest dw 0xc000
    jmp [jump_dest]
    jmp [bx]
  4. 16位直接绝对远转移。在指令中直接给出段地址和偏移地址的转移指令,例:
    jmp 0x0000:0x7c00
  5. 16位间接绝对远转移。该指令要使用关键字”far”,例:
    jump_far dw 0x33c0,0xf000
    jmp far [jump_far]

resb(REServe Byte)、resw和resd指令
resb:从当前位置开始,保留指定数量的字节,但不进行初始化

mul

可以用8位的通用寄存器或者内存单元中的数和寄存器AL中的内容相乘,结果是16位,在AX寄存器中,也可以用16位的通用寄存器或者内存单元中的数和寄存器AX中的内容相乘,结果是32位,高16位和低16位分别在DX和AX中,指令执行后,若结果的高一半全为0,则OF和CF清零,否则置1

参考

《x86汇编语言——从实模式到保护模式》——李忠 著

作者

未央

发布于

2022-04-06

更新于

2024-03-26

许可协议

评论