x86总结笔记

关于六种寻址方式

  • 立即寻址

    mov AX, 1234H(给AX寄存器赋值为十六进制,不加h则为十进制。注意在debug里面,如果是直接用a进入输入模式,那么输入的就直接是十六进制的(这一点与写代码是不同的),如下图)
    《x86总结笔记》

  • 直接寻址

    mov BX, DS:[2000H] 操作数放在存储器中,偏移量卸载操作数中

  • 寄存器寻址

    mov AX, BX 最常见的方式了

  • 寄存器间接寻址

    mov AX, [BP] 16位偏移地址存放在SI, DI, BP, BX四个寄存器之一中。如果是BX, SI, DI那么基址是DS, BP则是SS. 例如mov AX, [SI] (mov AX, SS:[SI]) 则是将16*SS+SI地址处的值给AX

  • 寄存器相对寻址

    mov AX,[SI+10H] 即操作数的有效地址是一个寄存器+常量。等价于mov AX,10H[SI]

  • 基址变址寻址
    即基址变址的方式。例如mov AX,[BX][SI]等价于 mov AX,[BX+SI]

堆栈

从内存中划分出的一块区域。栈底是固定的,随着不断的压栈使得SP(栈顶)的值不断减小。

栈服从FILO规则,每次都必须压入或者弹出一个字。例如下面的示例:

MOV AX, 1234H
PUSH AX

执行的过程是:

(1) SP <- SP – 2
(2) [SP] <- AX

《x86总结笔记》

一些指令

LEA BX, x ;将x的偏移地址赋值给BX
等价于mov BX, offset x

LDS命令是指将低字(在前面)送入src,将高字(在后面)送入DS寄存器。LES类似,只是送入ES寄存器。

示例LDS BX, src 则是把src处的双字取出来,低位(前面的)拷贝到src,高位的送入DS。LES功能类似,只是送到ES.

书上例题

例题5.15是查找回车换行(0DH, 0AH),不能直接用scasw的原因是因为读取会按照字来读取,而我们要查询的串可能会出现中间一个是0DH, 0AH的情况。(不过一般的scasb, cmpsb是没有问题的)

关于far与near

首先默认的是near即缺省情况下即是near,例如work proc即等价于work proc near。近指针的空间只有64K的数据段或代码段。而远指针则是可以指向内存的任意目标,但同时每次使用远指针都需要重新装载段寄存器。

  • 段内直接转移:jmp target。例如jmp short l1(其中l1与当前IP的偏移量是一个8位值,即-128~127)或者jmp l1(-256~255)
  • 段内间接转移 专项一个寄存器的内容。例如call x(其中x是一个变量名)或者call AX
  • 段间直接寻址 转移至的地址的代码段和偏移值都要给出。例如call far ptr p2,其中p2是由far属性定义的过程

关于函数调用的栈传递参数

除了保存寄存器现场的常见操作外,我正常是这么写的。


提纲记录

  1. ASCII:
    空格: 20H 换行:0ah 回车换行:0dh,0ah

  2. 8086/8088 CPU 组成:
    通用寄存器AX,BX,CX,DX,SP,BP,SI,DI
    段寄存器SS,CS,DS,ES
    指令指针寄存器IP
    程序状态字寄存器PSW
    ALU
    控制逻辑及指令队列

  3. 8086字长:2字节 16位

  4. 8个通用寄存器:AX,BX,CX,DX(数据寄存器) SP,BP,SI,DI(指针及变址寄存器)

    AX=AH(高位)+AL(低位)
    BX=BH(高位)+BL(低位)
    CX=CH(高位)+CL(低位)
    DX=DH(高位)+DL(低位)

    BX,SI,DI默认相对于数据段
    SP,BP默认相对于堆栈段
    但是[SP]是错误写法

    4个段寄存器: CS,DS,SS,ES

    指令指针寄存器:IP

    程序状态字寄存器:PSW
    用于存放9个标志寄存器:
    CF:进位标志 CY(1) NC(0)
    PF:奇偶标志 PE(1) OP(0)
    AF:辅助进位标志 AC(1) NA(0)
    ZF:零标志 ZR(1) NZ(0)
    SF:符号标志 NG(1) PL(0)
    TF:陷阱标志
    IF:中断标志 EI(1) DI(0)
    DF:方向标志 DN(1) UP(0)
    OF:溢出标志 OV(1) NV(0)
    控制标志:DF、IF、TF
    状态标志:OF、SF、ZF、AF、PF

  5. 内存中,低字节在前,高字节在后

    内存地址20位:段地址负责高16位,段内地址负责低16位

    逻辑地址
    1234H:5678H
    对应物理地址:
    12340H+5678H=179B8H(逢16进1)

  6. 1节(para)=16字节
    以节为单位分配内存区

  7. 堆栈压入弹出以字为单位

  8. 段超越:不使用隐含段寄存器
    seg字段为00,01,10,11 分别代表ES,CS,SS,DS

  9. 指令
    操作码 目的操作数,源操作数

    与数据有关的寻址方式:

    • 立即寻址 立即数出现在源操作数位置上(MOV AL,05H)
    • 寄存器寻址 操作数是CPU的某个寄存器(MOV AX,BX),可以是隐含寄存器如PUSHF、STD
    • 直接寻址 操作数的偏移地址直接在指令中指出(MOV AX,[2000H]、MOV AX,x+5)
    • 寄存器间接寻址 操作数有效地址EA位于BX,BP,SI,DI(MOV AX,[BX]、MOV AX,ds:[BX])
    • 寄存器相对寻址 操作数有效地址EA是一个基址寄存器或变址寄存器的内容和指令中指定的8位和16位位移量之和(MOV AX,[SI+10H]、MOV AX,10H[SI]、MOV AX,TABLE[DI+1])
    • 基址变址寻址 操作数有效地址EA等于一个基址寄存器和一个变址寄存器的内容之和(MOV AX,[BX][SI]、MOV AX,[BX+SI]、MOV ES:[BX+SI],AL、MOV [BP+DI],AX、MOV AX,[BX+SI+200])缺省时段地址看基址寄存器,只能是基址+变址
  10. 段名 segment [对齐类型][组合类型][类别名]

    段名 ends

    对齐类型:
    page 一页256字节
    para 一节16字节
    word 一字2字节
    byte 字节

    组合类型:
    none 缺省选项,该段独立
    public 与相同段名的段组合成一个逻辑段,共用同一个段基址
    common 与同名段有相同起始地址,会产生覆盖
    stack 该段为堆栈段的一部分,可省略对ss,sp的初始化
    memory
    at表达式 直接定义在内存的某个位置

    类别名
    必须用单引号或双引号括起来,不能与符号名和标号名相同
    相同类别名的段会被放在连续内存区

  11. debug调试
    r 显示或修改寄存器内容
    d 显示内存单元内容
    e 修改内存单元内容
    a 汇编命令,直接在内存中输入指令序列
    u 反汇编命令,查看内存中的程序
    t 单步跟踪
    p 单步执行
    g 运行
    q 退出debug

  12. 常见字符串操作
    LODSB AL<-DS:[SI],si++(df=0),si–(df=1)
    LODSW AX<-DS:[SI],si+=2(df=0),si-=2(df=1)
    STOSB ES:[DI]<-AL,di++(df=0),di–(df=1)
    STOSW ES:[DI]<-AL,di+=2(df=0),di-=2(df=1)
    MOVSB ES:[DI]<-DS:[SI],si++,di++(df=0),si–,di–(df=1)
    MOVSW ES:[DI]<-DS:[SI],si+=2,di+=2(df=0),si-=2,di-=2(df=1)
    CMPSB 比较DS:[SI],ES:[DI]一个字节,修改si,di
    CMPSW 比较DS:[SI],ES:[DI]一个字,修改si,di
    SCASB ES:[DI]是否有AL,修改di
    SCASW ES:[DI]是否有AX,修改di
    REP 串操作指令 每执行一次,CX–,直到CX==0
    REPZ/REPE 每执行一次,CX–,CX!=0且ZF=1继续执行
    REPNZ/REPNE 每执行一次,CX–,CX!=0且ZF=0继续执行
    CLD
    STD

  13. 系统调用

| AH | 功能 | 调用参数 | 返回参数 |
| — | — | — | — |
| 01     | 键盘输入并回显 | | AL=输入字符 |
| 02    | 显示输出  | DL=输出字符 | |
| 09 | 显示字符串  | DS:DX=串地址’$’结束字符串 | |
| 0A  | 键盘输入到缓冲区 | DS:DX=缓冲区首地址 | (DS:DX+1)=实际输入的字符数 (DS:DX)=缓冲区最大字符数| |
| 4C | 带返回码结束 | AL=返回码 | |

DOS系统功能调INT 21H

8086寻址范围

8086CPU地址总线有20根,能寻址1MB的存储单元。
8086CPU通过16条数据总线、20条地址总线和若干条控制总线与外部进行数据交换。由于地址总线有20条,所以CPU可以访问的存储单元数为2的20次方,即1M个存储单元。每个存储单元存放8位二进制数,即一个字节,且这些存储单元都是顺序排列的,每个单元用唯一的一个物理地址标示,这个物理地址既是由地址总线得到的20位二进制数。

关于寻址范围这里强调一下,N位地址线能访问2的N方个存储单元。比如:1位地址线只能访问2个存储单元,两位地址线能访问4个存储单元,等等。

8086是16位CPU,CPU内部寄存器都是16位。那么地址也是由CPU里面的寄存器提供的,故只能提供16位地址,可寻址64K空间。而8086觉得64K空间不够用,引脚地址线非要弄成20条,寻址1M空间。但CPU里面地址只能是16位提供16位地址,里面的16位地址和外面的20根地址线矛盾怎么解决呢?只好多加了那几个段寄存器,和一些如DI的指针寄存器。每次形成地址时,根据不同的指令,系统会自动选取一个段寄存器(16位)左移四位后再加上一个对应的指针寄存器(在BIU里的地址加法器中完成),形成实际的物理地址20位输出,可寻址1M空间。你看四个段左移四位后形成20位的实际物理地址的段基址,再加上各自的指针64K的范围,四个段每个都是64K。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注