汇编语言知识点复习

本文最后更新于:2024年5月9日 下午

王爽-汇编语言

tips

  • 使用debug ××.exe调试时,首次进入调试界面时,寄存器CX中存放的是可执行文件长度。
  • inc bx 等价于add bx,1
  • XOR操作是一种逻辑运算符,用于执行异或操作,英文全称是 exclusive or。XOR 操作的结果是两个二进制位相同则结果为 0,否则结果为 1。例如 XOR AX, AX 可以将 AX 寄存器中的值清零。
  • 在汇编源程序中,数据不能以字母开头
  • 遇到loop指令时,使用P命令来执行。Debug就会自动重复执行循环中的指令,直到(cx)=0为止
  • DOSBOX中,int 21 后面要用 p 指令来结束。
  • dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
    • “dw”的含义是定义字型数据。dw即“define word”。
    • 在这里,使用dw定义了8个字型数据(数据之间以逗号分隔),它们所占的内存空间的大小为16个字节
  • db 字节型,dd双字型
  • 通过DS=0B2D,可以知道程序从0B3D:0000开始存放
  • NOT 实现按位取反,例如(AL)=00010010B,则 NOT AL 使得(AL)=11101101B。XOR 为异或运算。
  • var dd 252 dup(10)
    • var dd 252 dup(10) 是一种伪指令,用于在汇编语言中定义一个名为 var 的变量,并初始化它为重复出现的值。
    • 根据这个伪指令的语法,252 是要重复的次数,dup(10) 表示要重复的值为 10。因此,该指令的作用是将值为 10 的双字型数据重复 252 次,然后存储到名为 var 的变量中。
  • VAR3 DB 'HOW ARE YOU?','$',,,VAR3 = 13 字节 (12 + 1)
  • VAR2 DW 5DUP(?),0,,,,,VAR2 = 12 字节 (5 * 2 + 2)
  • 段地址(SA)Segment Address 和 偏移地址(EA)Effective Address
  • 要用八位二进制表示 -9 的补码,可以按照以下步骤进行计算:
    • 将 -9 的绝对值转换为二进制。9 的二进制表示为 00001001。
    • 获取 9 的反码。即将二进制数的每一位取反,得到 11110110。
    • 将反码加 1 得到补码。在这种情况下,11110110 + 1 = 11110111。
    • 因此,-9 在八位二进制补码表示中为 11110111。十六进制为F7
  • dec bx ;dec指令和inc指令的功能相反,dec bx 进行操作为:(bx) = (bx) - 1
  • mul是乘法指令,使用 mul 做乘法的时候:
    • 相乘的两个数:要么都是8位,要么都是16位。
      • 8 位:一个默认放在 AL中 ,另一个放在 8位寄存器或内存字节单元中;
      • 16 位: 一个默认放在AX中,另一个放在16 位寄存器或内存字单元中。
    • 结果
      • 8位:AX中;
      • 16位:DX(高位)和AX(低位)中。
    • 格式如下:
      • mul reg
      • mul 内存单元
    • 比如:mul byte ptr ds:[0]
      • 含义为: (ax)=(al) * ((ds) * 16+0)
    • mul word ptr [bx+si+8]
      • 含义为:
      • (ax)=(ax) * ((ds) * 16+(bx)+(si)+8)结果的低16位;
      • (dx)=(ax) * ((ds) * 16+(bx)+(si)+8)结果的高16位;
  • 小写字母的ASCII码范围61H-7AH
  • 一般情况下: 从0000:0200至0000:02FF的256个字节的空间所对应的中断向量表项都是空的,操作系统和其他应用程序都不占用
  • (IP) = 5,说明 ss:sp = 5,

第1章 基础知识


基础概念

  1. 每一种微处理器,由于硬件设计和内部结构的不同,就需要用不同的电平脉冲来控制,使它工作。所以每一种微处理器都有自己的机器指令集,也就是机器语言。
  2. 汇编语言的主体是汇编指令。
  3. 汇编指令和机器指令的差别在于指令的表示方法上,汇编指令是机器指令便于记忆的书写格式。汇编指令是机器指令的助记符。
  4. 汇编语言由以下3类指令组成:
    1. 汇编指令:机器码的助记符,有对应的机器码。
    2. 伪指令:由编译器执行,没有对应的机器码,计算机并不执行。
    3. 其他符号:如+、-、*、/等,由编译器识别,没有对应的机器码。
  5. CPU要想进行数据的读写,必须和外部器件(标准的说法是芯片)进行三类信息的交互:
    1. 存储单元的地址(地址信息);
    2. 器件的选择,读或写命令(控制信息);
    3. 读或写的数据(数据信息)。
  6. CPU是通过地址总线来指定存储器单元的。地址总线上能传送多少个不同的信息,CPU就可以对多少个存储单元进行寻址。
  7. CPU与内存或其它器件之间的数据传送是通过数据总线来进行的。数据总线的宽度决定了CPU和外界的数据传送速度。
  8. 8088CPU数据总线宽度为8,8086CPU数据总线宽度为16。
  9. 控制总线:有多少根控制总线,就意味着CPU提供了对外部器件的多少种控制。所以,控制总线的宽度决定了CPU对外部器件的控制能力。
  • 前面所讲的内存读或写命令是由几根控制线综合发出的:其中有一根名为读信号输出控制线负责由CPU 向外传送读信号,CPU 向该控制线上输出低电平表示将要读取数据;
  1. b:bit,B:Byte

  2. 1B = 8b,1KB = 1024B,1MB = 1024KB,1GB = 1024MB

  3. 将各类存储器看作一个逻辑存储器: 所有的物理存储器被看作一个由若干存储单元组成的逻辑存储器;每个物理存储器在这个逻辑存储器中占有一个地址段,即一段地址空间; CPU在这段地址空间中读写数据,实际上就是在相对应的物理存储器中读写数据。

  4. 8086PC机的内存地址空间分配:

    H4BhK0b.png

  5. 图 1.9 告诉我们,从地址 0 ~ 9FFFF 的内存单元中读取数据,实际上就是在读取主随机存储器中的数据;向地址 A0000 ~ BFFFF 的内存单元中写数据,就是向显存中写入数据,这些数据会被显示卡输出到显示器上;我们向地址 CO00O ~ FFFFF 的内存单元中写入数据的操作是无效的,因为这等于改写只读存储器中的内容。

  6. 内存地址空间:最终运行程序的是CPU,我们用汇编编程的时候,必须要从CPU角度考虑问题。 对CPU来讲,系统中的所有存储器中的存储单元都处于一个统一的逻辑存储器中,它的容量受CPU寻址能力的限制。这个逻辑存储器即是我们所说的内存地址空间。😭

牢🐏,this is for you,2024.05.09

第2章 寄存器


基础概念

  1. 8086CPU有14个寄存器,它们的名称为:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。

    AX:accumulator register,累加器寄存器

    BX: base register,基数寄存器

    CX: count register,计数寄存器

    DX:data register,通用数据寄存器

    SI:source index,源变址寄存器

    DI:destination index,目的变址寄存器

    SP:stack pointer,堆栈指针寄存器

    BP:base pointer,基址指针寄存器,指示堆栈段中一个数据区的基址位置,通常与SS配对

    IP:instruction pointer,码段地址指针寄存器

    CS:code segment,代码段寄存器

    SS:stack segment,堆栈段~,存放当前堆栈段的段地址,一般和SP连用

    DS:data segment,数据段~,存放当前数据段的段地址

    ES:extra segment,附加段~

    PSW:program state word,标志~

  2. 8086CPU所有的寄存器都是16位的,可以存放两个字节。

  3. AX、BX、CX、DX 通常用来存放一般性数据,被称为通用寄存器。

  4. 一个16位寄存器所能存储的数据的最大值为多少? 答案:\(2^{16}-1=65535。\)

  5. 汇编指令不区分大小写。

  6. 8086有20位地址总线,可传送20位地址,寻址能力为1M。

  7. 地址加法器如何完成段地址×16的运算?就是将以二进制形式存放的段地址左移4位。

  8. “段地址×16+偏移地址=物理地址”的本质含义是: CPU 在访问内存时,用一个基础地址(段地址x16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。

  9. 有两点需要注意:段地址✖16 必然是 16 的倍数,所以一个段的起始地址也一定是 16 的倍数;偏移地址为 16 位,16 位地址的寻址能力为 64KB,所以一个段的长度最大为 64KB

  10. CS和IP是8086CPU中最关键的寄存器,它们指示了CPU当前要读取指令的地址。

  11. 8086PC工作过程的简要描述

    1. 从CS:IP指向内存单元读取指令,读取的指令进入指令缓冲器;
    2. IP = IP + 所读取指令的长度,从而指向下一条指令;
    3. 执行指令。 转到步骤 (1),重复这个过程。
  12. mov指令不能用于设置CS、IP的值,8086CPU没有提供这样的功能。

第3章 寄存器(内存访问)


基础概念

  1. 8086CPU不支持将数据直接送入段寄存器的操作,ds是一个段寄存器。(硬件设计的问题)
  • mov ds,1000H 是非法的。
  • 数据 → 一般的寄存器 → 段寄存器
  1. 字在内存中存储时 ,要用两个地址连续的内存单元来存放,字的低位字节存放在低地址单元中,高位字节存放再高地址单元中。

  2. 合法格式:

  • mov 寄存器,寄存器/内存单元/段寄存器/立即数
  • mov 内存单元,寄存器/段寄存器/立即数
  • mov 段寄存器,寄存器/内存单元 ~注意:
  • mov指令中的目的操作数不能是立即数、IP和CS寄存器;
  • mov指令中不允许在两个存储单元之间直接传送数据;
  • mov指令中不允许在两个段寄存器之间直接传送数据;
  • mov指令中立即数不能直接传送给段寄存器(CS、DS、SS、ES)。
  1. 栈:
  • 8086CPU提供了栈操作机制,方案如下:在SS,SP中存放栈顶的段地址和偏移地址;提供入栈和出栈指令,他们根据SS:SP指示的地址,按照栈的方式访问内存单元。

  • push指令的执行步骤

    1. SP=SP-2;

    2. 向SS:SP指向的字单元中送入数据。

  • pop指令的执行步骤

    1. 从SS:SP指向的字单元中读取数据;
    2. SP=SP+2。
  • 任意时刻,SS:SP指向栈顶元素。

  • 8086CPU只记录栈顶,栈空间的大小我们要自己管理。

  • 用栈来暂存以后需要恢复的寄存器的内容时 ,寄存器出栈的顺序要和 入栈的顺序相反。

  • push、pop实质上是一种内存传送指令,注意它们的灵活应用。

  1. 一个栈段的容量最大为64KB。

  2. 如果我们将10000H~1FFFFH这段空间当作栈段,初始状态是空的,此时,SS=1000H,SP=?、、、

    答案:0,(SP原来为FFFEH,加2后SP=0,所以,当栈为空的时候,SS=1000H,SP=0。)

  3. 我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。这完全是我们自己的安排。

    • 我们可以用一个段存放数据,将它定义为“数据段”
    • 我们可以用一个段存放代码,将它定义为“代码段”
    • 我们可以用一个段当作栈,将它定义为“栈段”

    我们可以这样安排,但若要让CPU按照我们的安排来访问这些段,就要:

    • 对于数据段,将它的段地址放在 DS中,用mov、add、sub等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当作数据来访问;
    • 对于代码段,将它的段地址放在 CS中,将段中第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码段中的指令;
    • 对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地置放在 SP 中,这样CPU在需要进行栈操作的时候,比如执行 push、pop 指令等,就将我们定义的栈段当作栈空间来用。
    • 可见,不管我们如何安排 ,CPU 将内存中的某段内存当作代码 ,是因为CS:IP指向了那里;CPU将某段内存当作栈 ,是因为 SS:SP 指向了那里。

第4章 第一个程序


基础概念

  1. DOS系统中.EXE文件中的程序的加载过程:

    H6suidv.md.png

  2. 程序加载后,ds中存放着程序所在内存区的段地址,这个内存区的偏移地址为 0 ,则程序所在的内存区的地址为:ds:0;这个内存区的前256 个字节中存放的是PSP,dos用来和程序进行通信。 从 256字节处向后的空间存放的是程序。

  3. 所以,我们从ds中可以得到PSP的段地址SA,PSP的偏移地址为 0,则物理地址为SA×16+0。因为PSP占256(100H)字节,所以程序的物理地址是:SA×16+0+256= SA×16+16×16=(SA+16)×16+0可用段地址和偏移地址表示为:SA+10:0

    • 如:DS=129E,则PSP的的地址为129E:0,程序的地址为12AE:0。
  4. 一个源程序从写出到执行的过程:编写、编译、连接、执行(使用汇编语言编译程序对源程序文件中的源程序进行编译,产生目标文件;再用连接程序对目标文件进行连接,生成可在操作系统中直接运行的可执行文件。)

  5. 说明伪指令和汇编指令的区别:汇编指令是有对应的机器码的指令,可以被编译为机器指令,最终为CPU所执行。而伪指令没有对应的机器指令,最终不被CPU所执行,是由编译器来执行的。

  6. 说明汇编语言程序中标号的作用:汇编源程序中一个标号指代了一个地址,比如codesg在segment的前面,作一个段的名称,这个段的名称最终将被编译、连接程序处理为一个段的段地址。

第5章 [bx]和loop指令


基础概念

  1. 描述性符号“()”,例如:对于push ax的功能,我们可以这样来描述:
    • (sp) = (sp)-2
    • ((ss) * 16+(sp))=(ax)
  2. (2000:0)、((ds):1000H)等是错误的用法
  3. (ax)、(ds)、(al)、(2000H)、((ds) * 16+(bx))等是正确的用法
  4. 指令的格式是:loop 标号,CPU 执行loop指令的时候,要进行两步操作:
    1. (cx)=(cx)-1;
    2. 判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行。
  5. ffff:0006 单元中的数是一个字节型的数据,范围在0~255之间
  6. 我们在Debug中写过类似的指令:mov ax,[0] 表示将ds:0处的数据送入ax中。但是在汇编源程序中,指令mov ax,[0]被编译器当作指令mov ax,0处理。
  7. 为防止上述情况发生,在源程序中,可采用两种方法访问2000:0单元:
  • 方法一:

    1
    2
    3
    4
    5
    6
    mov ax,2000h 
    mov ds,ax
    mov bx,0
    mov al,[bx]

    X86ASM
  • 方法二:

    1
    2
    3
    4
    5
    mov ax,2000h
    mov ds,ax
    mov al,ds:[0] 一般用第二种方法

    X86ASM
  1. DOS方式下,一般情况, 0:200 ~ 0:2FF 空间中没有系统或其他程序的数据或代码;以后,我们需要直接向一段内存中写入内容时,就使用0:200 ~ 0:2FF这段空间。
  2. 利用栈对CX寄存器内容进行保护push和恢复pop可以实现多重loop循环。如:
1
2
3
4
5
6
7
8
9
10
mov cx, m
s1: ;循环体1
push cx
mov cx,n
s2: ;循环体2
loop s2
pop cx
loop s1

X86ASM

程序

  1. 将内存ffff:0~ffff:b段单元中的数据拷贝到 0:200~0:20b单元中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
assume cs:code

code segment

start: mov ax,offffh
mov ds,ax

mov ax,0020h
mov es,ax

mov bx

mov cx,12

s: mov al,ds:[bx]
mov es:[bx],al ;al作为中转寄存器

inc bx
loop s

mov ax,4c00h
int 21h

code ends
end start


X86ASM
  1. 编写程序片断,利用 loop 指令,实现斐波那契数列前 9 个数字 1、1、2、3、5、8、13、21、34 的求和,并将求和结果保存到内存字单元 0:200 中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
assume cs:code
code segment

start:
mov ax,0 ;ax中的值依次为1、1、2、3、5、8、13、21、34
mov bx,1
mov dx,0 ;来存最后的计算结果
mov cx,9 ;循环次数
s: push bx
add bx,ax
pop ax
add dx,ax

loop s
mov ax,0
mov ds,ax
mov ds:[200h],dx

mov ax,4c00h
int 21h

code ends
end start


X86ASM

第6章 包含多个段的程序


基础概念

  1. 我们在源程序中用伪指令 “assume cs:code,ds:data,ss:stack”将cs、ds和ss分别和code、data、stack段相连。这样做了之后,CPU是否就会将 cs指向ode,ds 指向 data,ss 指向stack,从而按照我们的意图来处理这些段呢?
  2. 当然也不是,要知道 assume 是伪指令,是由编译器执行的,也是仅在源程序中存在的信息,CPU并不知道它们。我们不必深究 assume 的作用,只要知道需要用它将你定义的具有一定用途的段和相关的寄存器联系起来就可以了。
  3. 若要CPU按照我们的安排行事,就要用机器指令控制它,源程序中的汇编指令是CPU要执行的内容。
  4. 总之,CPU到底如何处理我们定义的段中的内容,是当作指令执行,当作数据访问,还是当作栈空间,完全是靠程序中具体的汇编指令,和汇编指令对CS:IP、SS:SP、DS等寄存器的设置来决定的。

第7章 更灵活的定位内存地址的的方法


基础概念

  1. (1)and 指令:逻辑与指令,按位进行与运算。(2)or 指令:逻辑或指令,按位进行或运算。
  2. 在ASCII编码方案中,用61H 表示“a”,62H表示“b”。用41H 表示“A”,42H表示“B”。
  3. 就ASCII码的二进制形式来看,除第5位(位数从0开始计算)外,大写字母和小写字母的其他各位都一样。大写字母ASCII码的第5位(位数从0开始计算)为0,小写字母的第5位为1。
  4. or al,00100000b ;将al中的ASCII码的第5位置为1,变为小写字母
  5. and al,11011111b ;将al中的ASCII码的第5位置为0,变为大写字母
    • and byte ptr [si],11011111b,等到了后面就是这样了
  6. 指令mov ax,[bx+200]也可以写成如下格式(常用)
    • mov ax,[200+bx]
    • mov ax,200[bx]
    • mov ax,[bx].200
  7. SI(source index register)和DI(destination index register)是8086CPU中和bx功能相近的寄存器,SI和DI不能够分成两个8 位寄存器来使用
  8. 指令mov ax,[bx+si]的数学化的描述为:(ax)=( (ds) * 16+(bx)+(si) )。 该指令也可以写成如下格式(常用):mov ax,[bx][si]
  9. 指令mov ax,[bx+si+200],该指令也可以写成如下格式(常用):
    • mov ax,[bx+200+si]
    • mov ax,[200+bx+si]
    • mov ax,200[bx][si]
    • mov ax,[bx].200[si]
    • mov ax,[bx][si].200

第8章 数据处理的两个基本问题


基础概念

  1. 我们将使用reg来表示一个寄存器,用sreg表示一个段寄存器。reg的集合包括:ax、bx、cx、dx、ah、al、bh、bl、ch、cl、dh、dl、sp、bp、si、di;sreg的集合包括:ds、ss、cs、es。
  2. 在8086CPU 中,只有这4个寄存器(bx、bp、si、di)可以用在“[…]” 中来进行内存单元的寻址。
  3. 在“[…]” 中,这4个寄存器(bx、bp、si、di)可以单个出现,或只能以四种组合出现:bx和si、bx和di、bp和si、bp和di
  4. 只要在[…]中使用寄存器bp,而指令中没有显性的给出段地址,段地址就默认在ss中
  5. mov ax,1 对应机器码:B80100;mov ax,076a的机器码?B86A07
  6. 在没有寄存器名存在的情况下,用操作符X ptr指明内存单元的长度,X在汇编指令中可以为word或byte。
  7. push指令只进行字操作
  8. div是除法指令,使用div作除法的时候:
    • 除数:8位或16位,在寄存器或内存单元中
    • 被除数:(默认)放在AX 或 DX(高16位)和AX(低16位)中
    • 结果:如果除数为 8位,商:AL,余数:AH;如果除数为16位,商:AX,余数:DX
  9. div指令格式: div reg div 内存单元
  10. div byte ptr ds:[0]
    • 含义为:(al)=(ax)/((ds) * 16+0)的商;
    • (ah)=(ax)/((ds) * 16+0)的余数
  11. div word ptr [bx+si+8]
    • 含义为:(ax)=[(dx) * 10000H+(ax)]/((ds) * 16+(bx)+(si)+8)的商;
    • (dx)=[(dx) * 10000H+(ax)]/((ds) * 16+(bx)+(si)+8)的余数
  12. dd 1,数据为00000001H,占2个字;
  13. dup是一个操作符,在汇编语言中同db、dw、dd 等一样,也是由编译器识别处理的符号。 它是和db、dw、dd 等数据定义伪指令配合使用的,用来进行数据的重复。
    • db 3 dup (0) 定义了3个字节,它们的值都是0,相当于 db 0,0,0
    • db 3 dup (0,1,2)定义了9个字节,它们是0、1、2、0、1、2、0、1、2,相当于 db 0,1,2,0,1,2,0,1,2
    • db 3 dup (‘abc’,’ABC’)定义了18个字节,它们是‘abcABCabcABCabcABC’,相当于db ‘abcABCabcABCabcABC’

第9章 转移指令的原理


基础概念

  1. jmp指令要给出两种信息: 转移的目的地址, 转移的距离(段间转移jmp far、段内短转移jmp short,段内近转移jmp near)
  2. jmp short 标号(转到标号处执行指令)这种格式的 jmp 指令实现的是段内短转移,它对IP的修改范围为 -128~127,也就是说,它向前转移时可以最多越过128个字节,向后转移可以最多越过127个字节。
  3. 在“jmp short 标号”指令所对应的机器码中,并不包含转移的目的地址,而包含的是转移的位移。 这个位移,是编译器根据汇编指令中的“标号”计算出来的。
  4. 实际上,指令“jmp short 标号”的功能为(IP)=(IP)+8位位移。
    • 8位位移=“标号”处的地址-jmp指令后的第一个字节的地址
    • short指明此处的位移为8位位移;
    • 8位位移的范围为-128~127,用补码表示。
    • 8位位移由编译程序在编译时算出。
  5. jmp near ptr 标号它实现的时段内近转移IP修改范围为:-32768~32767
  6. 指令 jmp far ptr 标号 实现的是段间转移,又称为远转移。far ptr指明了指令用标号的段地址和偏移地址修改CS和IP。IP修改范围:随意。
  7. jmp far ptr s所对应的机器码:EA 0B 01 BD 0B ,其中包含转移的目的地址
  8. 转移地址在内存中的jmp指令有两种格式:
    • jmp word ptr 内存单元地址(段内转移)
      • 功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。
    • jmp dword ptr 内存单元地址(段间转移)
      • 功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址
      • (CS)=(内存单元地址+2)
      • (IP)=(内存单元地址)
      • 内存单元地址可用寻址方式的任一格式给出。
  9. jcxz指令(jump if cx equals zero)为有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围都为-128~127。指令格式:jcxz 标号 (如果(cx)=0,则转移到标号处执行。)
  10. jcxz 标号 指令操作:
    • 当(cx)=0时,(IP)=(IP)+8位位移)
      • 8位位移=“标号”处的地址-jcxz指令后的第一个字节的地址;
      • 8位位移的范围为-128~127,用补码表示;
      • 8位位移由编译程序在编译时算出。
    • 当(cx)不为0时,什么也不做(程序向下执行)。
  11. loop指令为循环指令,所有的循环指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围都为-128~127。指令格式:loop 标号

第10章 CALL和RET指令


基础概念

  1. ret指令用栈中的数据,修改IP的内容,从而实现近转移;
    • CPU执行ret指令时,相当于进行:pop IP
  2. retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移;
    • CPU执行retf指令时,相当于进行:
      • pop IP(注意!这是违法的,只是效果
      • pop CS
  3. CPU执行call指令,进行两步操作:
    • 将当前的 IP 或 CS 和 IP 压入栈中;
    • 转移。
  4. CPU 执行指令“call 标号”时,相当于进行:
    • push IP
    • jmp near ptr 标号
  5. call s 在指令缓冲器时,IP已经改变了,指向了下一条指令,suoooooo以,call指令指向时将下一条指令的IP入栈
  6. CPU 执行指令 “call far ptr 标号”时,相当于进行:
    • push CS
    • push IP
    • jmp far ptr 标号
  7. CPU执行call 16位reg时,相当于进行:
    • push IP
    • jmp 16位寄存器
  8. call word ptr 内存单元地址, 汇编语法解释:
    • push CS
    • push IP
    • jmp dword ptr 内存单元地址
  9. call dword ptr 内存单元地址, 汇编语法解释:
    • push CS
    • push IP
    • jmp dword ptr 内存单元地址

第11章 标志寄存器


基础概念

  1. flag的第6位是ZF(zero flag),零标志位。它记录相关指令执行后,其结果是否为0
    • 结果为0 ,ZF = 1
    • 结果不为0,ZF = 0
  2. 在8086CPU的指令集中,有的指令的执行是影响标志寄存器的,比如:add、sub、mul、div、inc、or、and等,它们大都是运算指令(进行逻辑或算术运算);有的指令的执行对标志寄存器没有影响,比如:mov、push、pop等,它们大都是传送指令。
  3. flag的第2位是PF,奇偶标志位。它记录指令执行后,结果的所有二进制位(低8位)中1的个数:
    • 为偶数,PF = 1;
    • 为奇数,PF = 0。
  4. flag的第7位是SF,符号标志位。它记录指令执行后,其结果是否为负
    • 结果为负,SF = 1;
    • 结果为正,SF = 0。
    • 与有符号数的符号位规定一致
    • SF 标志,就是CPU对有符号数运算结果的一种记录 ,它记录数据的正负。
    • 在我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。
    • 如果我们将数据当作无符号数来运算,SF的值则没有意义,虽然相关的指令影响了它的值。
  5. 比如指令sub al,al执行后,ZF、PF、SF等标志位都要受到影响,它们分别为:1、1、0。
  6. flag的第0位是CF,进位标志位。
    • 一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
    • 比如:
      • mov al,98H
      • add al,al ;
      • 执行后: (al)=30H,CF=1,CF记录了最高有效位向更高位的进位值
  7. flag的第11位是OF,溢出标志位。
    • 一般情况下,OF记录了有符号数运算的结果是否发生了溢出。
    • 如果发生溢出,OF=1,
    • 如果没有,OF=0。
    • CF是对无符号数运算有意义的标志位;而OF是对有符号数运算有意义的标志位。
  8. 对于无符号数运算,CPU用CF位来记录是否产生了进位;对于有符号数运算,CPU 用 OF 位来记录是否产生了溢出。当然,还要用SF位来记录结果的符号。
    • 对于无符号数运算,98+99没有进位,CF=0;
    • 对于有符号数运算,98+99发生溢出,OF=1。
  9. adc是带进位加法指令 ,它利用了CF位上记录的进位值。
    • 格式: adc 操作对象1,操作对象2
    • 功能:操作对象1=操作对象1+操作对象2+CF
    • 比如:adc ax,bx 实现的功能是:(ax)=(ax)+(bx)+CF
  10. 下面的指令和add ax , bx具有相同的结果:add al,bl ,adc ah,bh,看来CPU提供 adc 指令的目的,就是来进行加法的第二步运算的。adc指令和add指令相配合就可以对更大的数据进行加法运算。
  11. sbb是带借位减法指令,它利用了CF位上记录的借位值。
    • 格式:sbb 操作对象1,操作对象2
    • 功能:操作对象1=操作对象1–操作对象2–CF
    • 比如:sbb ax,bx,实现功能: (ax) = (ax) – (bx) – CF
  12. cmp指令
    • 格式:cmp 操作对象1,操作对象2
    • 功能:计算操作对象1–操作对象2 但并不保存结果,仅仅根据计算结果对标志寄存器进行设置。
  13. 比如:cmp ax,ax做(ax)–(ax)的运算,结果为0,但并不在ax中保存,仅影响flag的相关各位。指令执行后:
    • ZF=1,
    • PF=1,0是偶数
    • SF=0,
    • CF=0,
    • OF=0。
    • 根据cmp指令执行后ZF的值,就可以知道两个数据是否相等。
  14. 如果没有溢出发生的话,那么,实际结果的正负和逻辑上真正结果的正负就一致了。所以,我们应该在考察SF(得知实际结果的正负)的同时考察OF(得知有没有溢出),就可以得知逻辑上真正结果的正负,同时就可以知道比较的结果。
  15. 虽然 je 的逻辑含义是“相等则转移”,但它进行的操作是,ZF=1时则转移。“相等则转移”这种逻辑含义,是通过和 cmp 指令配合使用来体现的,因为是cmp 指令为“ZF=1”赋予了“两数相等”的含义。虽然我们分别讨论了cmp指令和与其比较结果相关的有条件转移指令,但是它们经常在一起配合使用。所以我们在联合应用它们的时候,不必再考虑cmp指令对相关标志位的影响和je 等指令对相关标志位的检测。我们可以直接考虑cmp和je等指令配合使用时,表现出来的逻辑含义。它们在联合使用的时候表现出来的功能有些像高级语言中的IF语句。意思就是说je可以直接用,je就是等于则转移
  16. jb 含义是低于则转移,ja 含义是高于则转移。
  17. jna 含义是不高于则转移,即小于等于则转移;jnb 含义是不低于则转移,即大于等于则转移。

HPSgh7e.md.png

  1. flag的第10位是DF,方向标志位。
    • 在串处理指令中,控制每次操作后si,di的增减。
    • DF = 0:每次操作后si,di递增;
    • DF = 1:每次操作后si,di递减。
  2. 串传送指令:movsb 我们可以用汇编语法描述movsb的功能如下:
    • mov es:[di],byte ptr ds:[si];8086 并不支持这样的指令,这里只是个描述。
    • 如果DF=0:inc si,inc di
    • 如果DF=1:dec si,dec di
    • 就是ds:si 传到 es:di
  3. rep movsb 用汇编语法来描述rep movsb的功能就是: s : movsb loop s
  4. cld指令:将标志寄存器的DF位置0,std指令:将标志寄存器的DF位置1
  5. pushf :将标志寄存器的值压栈;
  6. popf :从栈中弹出数据,送入标志寄存器中。
  7. pushf和popf,为直接访问标志寄存 器提供了一种方法。

程序

  1. 编程计算1EF000H+201000H,结果放在ax(高16位)和bx(低16位)中。
1
2
3
4
5
6
7
8
程序:
mov ax,001EH
mov bx,0F000H
add bx,1000H
adc ax,0020H
adc 指令执行后,也可能产生进位值,所以也会对CF位进行设置

X86ASM
  1. 计算003E1000H–00202000H,结果放在ax,bx中。
1
2
3
4
5
6
7
程序如下:
mov bx,1000H
mov ax,003EH
sub bx,2000H
sbb ax,0020H

X86ASM

第12章 内中断


基础概念

  1. 我们更简洁的描述中断过程,如下:
    • (1)取得中断类型码N;
    • (2) pushf
    • (3) TF = 0,IF = 0
    • (4) push CS
    • (5) push IP
    • (6)(IP) = (N * 4),(CS) = (N * 4+2)
    • 在最后一步完成后,CPU 开始执行由程序员编写的中断处理程序。
  2. iret指令的功能用汇编语法描述为:
    1. pop IP
    2. pop CS
    3. popf
  3. CPU当然不能让这种情况发生,解决的办法就是,在进入中断处理程序之前,设置TF=0。从而避免CPU在执行中断处理程序的时候发生单步中断。 这就是为什么在中断过程中有 TF=0这个步骤。

第13章 int指令


程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
;编程:在屏幕的5行12列显示字符串“welcome to masm!”。
assume cs:code
data segment
db 'Welcome to masm!','$'
data ends
code segment
start: mov ah,2 ;置光标
mov bh,0 ;第0页
mov dh,5 ;dh中放行号
mov dl,12 ;dl中放列号
int 10h

mov ax,data
mov ds,ax
mov dx,0 ;ds:dx指向字符串的首地址data:0
mov ah,9
int 21h

mov ax,4c00h
int 21h
code ends
end start

X86ASM

第14章 端口


基本概念

  1. in al,60h;从60h号端口读入一个字节
    • 执行时与总线相关的操作:
    • ① CPU通过地址线将地址信息60h发出;
    • ② CPU通过控制线发出端口读命令,选中端口所在的芯片,并通知它,将要从中读取数据;
    • ③ 端口所在的芯片将60h端口中的数据通过数据线送入CPU。
  2. 注意:在in和out 指令中,只能使用 ax 或al 来存放从端口中读入的数据或要发送到端口中的数据。访问8 位端口时用al ,访问16 位端口时用ax 。
  3. 对0~255以内的端口进行读写:
    • in al,20h ;从20h端口读入一个字节
    • out 20h,al ;往20h端口写入一个字节
  4. 对256~65535的端口进行读写时,端口号放在dx中:
    • mov dx,3f8h ;将端口号3f8送入dx
    • in al,dx ;从3f8h端口读入一个字节
    • out dx,al ;向3f8h端口写入一个字节
  5. 70h为地址端口,存放要访问的CMOS RAM单元的地址;71h为数据端口,存放从选定的CMOS RAM 单元中读取的数据,或要写入到其中的数据。
  6. shl逻辑左移指令,功能为:
    • 将一个寄存器或内存单元中的数据向左移位;
    • 将最后移出的一位写入CF中;
    • 最低位用0补充。
  7. 如果移动位数大于1时,必须将移动位数放在cl中。
  8. shr逻辑右移指令

程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
;编程,读CMOS RAM的2号单元的内容

mov al,2
out 70h,al ;将 2 送入端口 70h
in al,71h ;从 71h 读出 2 号单元的内容

;编程,向CMOS RAM的2号单元写入0

mov al,2
out 70h,al ;将 2 送入端口 70h
mov al,0
out 71h,al ;向 2 号单元写入 0



X86ASM

第15章 外中断


基本概念

  1. 外设的输入不直接送入内存和CPU ,而是送入相关的接口芯片的端口中; CPU 向外设的输出也不是直接送入外设,而是先送入端口中,再由相关的芯片送到外设。
  2. 可屏蔽中断是CPU 可以不响应的外中断。CPU 是否响应可屏蔽中断,要看标志寄存器的IF 位的设置。
    • 当CPU 检测到可屏蔽中断信息时:
    • 如果IF=1,则CPU 在执行完当前指令后响应中断,引发中断过程;
    • 如果IF=0,则不响应可屏蔽中断。
  3. 内中断所引发的中断过程:
    • (1)取中断类型码n;
    • (2)标志寄存器入栈,IF=0,TF=0;
    • (3)CS 、IP 入栈;
    • (4)(IP)=(n* 4),(CS)=(n* 4+2),
    • 由此转去执行中断处理程序。
  4. 将IF置0的原因就是,在进入中断处理程序后,禁止其他的可屏蔽中断。
  5.  不可屏蔽中断是CPU 必须响应的外中断。当CPU 检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程。 对于8086CPU 不可屏蔽中断的中断类型码固定为2。所以中断过程中,不需要取中断类型码。
  6. 不可屏蔽中断的中断过程:
    • 1、标志寄存器入栈,IF=0,TF=0;
    • 2、CS、IP入栈;
    • 3、(IP)=(8),(CS)=(0AH)。
  7. 一般将按下一个键时产生的扫描码称为通码,松开一个键产生的扫描码称为断码。
  8.  扫描码长度为一个字节,通码的第7 位为 0 ,断码的第7位为1,即:断码=通码+80H

第16章 直接定址表


基本概念

  1. 对于程序中的a db 1,2,3,4,5,6,7,8 :
    • 指令:mov al,a [si],,相当于:mov al,cs:0[si],
    • 指令:mov al,a[3],,相当于:mov al,cs:0[3]
    • 指令:mov al,a[bx+si+3] ,,相当于:mov al,cs:0[bx+si+3]
  2. 以后,我们将这种标号称为数据标号。它标记了存储数据的单元的地址和长度。它不同于仅仅表示地址的地址标号。

牢🐏,当你看到这的时候,你就稳了,加油🧐🧐🧐


汇编语言知识点复习
http://viper2383.github.io/2023/05/27/汇编语言知识点复习/
作者
w1per3
发布于
2023年5月27日
许可协议