汇编语言(第三版)-王爽

时间:2022-03-02 01:21:16

第二章

  1. CS:代码段寄存器
  2. IP:指令指针寄存器
  3. “jmp 段地址:偏移地址”:用指令给出的段地址修改CS,偏移地址修改IP
  4. “jmp某一合法寄存器”:用寄存器中的值修改IP

—————————————————————————————————————————————————————

第三章

  1. DS:存放要访问数据的段地址
  2. [address]表示一个内存单元,address表示偏移地址

  1. 存放栈:段寄存器SS,寄存器SP
  2. 栈顶的段地址存放在SS中,偏移地址存放在SP中
  3. 任意时刻,SS:SP指向栈顶元素
  4. 入栈时,栈顶从高地址向低地址方向增长(SP减操作)
  5. 出栈后,数据依然存在,但是,它已不在栈中,再次入栈时会被覆盖
  6. 防止入栈与出栈超界问题,栈的大小我们要自己管理

  1. push 寄存器(或段寄存器,或内存单元)
  2. pop 寄存器(或段寄存器,或内存单元)
  3. sub ax,ax的机器码为2字节
    mov ax,0的机器码为3字节
  4. push、pop实际上是一种内存传送指令

段的综述

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

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

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

对于数据段,将它的段地址存放在DS中 ,用mov,add,sub 等访问内存单元的指令时,CPU就将我们定义的数据段中内容当作数据来访问

对于代码段,将它的段地址放在CS中,将段中的第一条指令的偏移地址存放在IP中,这样CPU就将执行我们定义的代码段中的指令

对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作的时候,比如执行push,pop指令等,就将我们定义的栈段当作栈空间来用

可见,不管我们如何安排,CPU将内存的中的段内容当作代码,是因为CS:IP 指向了那里;CPU将段内存当作栈,是因为SS:SP指向了那里,我们一定要清楚,什么是我们安排,以及如何让CPU按我们的安排行事,要非常清楚CPU的工作原理,才能在控制CPU按照我们的安排运行的时候做到游刃有余

注意的是,一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么也不是,关键在于CPU中寄存器的设置,即 CS,IP,SS,SP,DS 的指向

—————————————————————————————————————————————————————

第四章

  1. segment与ends是一对成对使用的伪指令,功能是定义一个段,segment说明一个段开始,ends说明一个段结束,使用格式为:
    段名 segment
    ……
    段名 ends
  2. end是一个汇编程序的结束标记
  3. assume含义为”假设”,它假设某一段寄存器和程序中的某一个用segment…ends定义的段相关联
  4. 任何通用的操作系统,都要提供一个为shell(外壳)的程序,用户(操作人员)使用这个程序来操作计算机系统进行工作

—————————————————————————————————————————————————————

第五章

  1. 描述性的符号”()”表示一个寄存器或一个内存单元的内容
  2. “()”中的内容可以有三种类型:寄存器名,段寄存器名,内存单元的物理地址
  3. idata表示的是常量

  1. mov ax,[bx]
    bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中
  2. loop指令的格式是:loop 标号,CPU执行loop指令的时候,要进行两步操作:
    ①(cx)=(cx)-1;
    ②判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行

  1. 出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的”ds:”“cs:”“ss:”“es:”,在汇编语言中称为段前缀

—————————————————————————————————————————————————————

第六章

  1. dw:”define word”,定义字型数据
  2. dw定义的数据处于代码段的最开始,即偏移地址为0
  3. 在程序第一条指令的前面加上一个标号start,而这个标号在伪指令end后面出现.end除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方
  4. 归根结底,我们若要CPU何处开始执行程序,只要在源程序中用”end 标号”指明:
    assume cs:code
    code segment
    ……
    …数据…
    ……
    start:
    ……
    …代码…
    ……
    code ends
    end start

  1. dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    用dw定义16个字形数据,程序加载后,将取得16个字的内存空间,在后面的程序中将这段空间当作栈来使用

  1. 定义多个段,同定义代码段相同,定义仅仅是为了程序阅读方便
  2. assume cs:code,ds:data,ss:stack是伪指令,将定义的具有一定用途的段和相关的寄存器联系起来

—————————————————————————————————————————————————————

第七章

  1. and 按位与
  2. or 按位或
  3. ‘……’的方式指明数据是以字符的形式给出的

  1. 字母大小写转换:
    and al,11011111B ;将al中的ASCII码的第5个位置为0,变为大写字母
    or al,00100000B ;将al中的ASCII码的第5个位置为1,变为小写字母

  1. [bx+idata]表示一个内存单元,它的偏移地址为(bx)+idata
  2. 比较一下C程序和汇编程序的相似之处
    C语言:a[i],b[i]
    汇编语言:0[bx],5[bx]
    ( 0[bx]和5[bx]等价于[bx]和[bx+5] )
  3. si和di是8086CPU中和bx功能相近的寄存器,并且不能分成两个8位寄存器来使用
  4. [bx+si]和[bx+di]表示一个内存单元,它的偏移地址为(bx)+(si)和(bx)+(di)
  5. [bx+si+idata]和[bx+di+idata]同上

总结:
[idata] 用一个常量来表示地址,可以用于直接定位到一个内存单元
[bx] 用一个变量来表示内存地址,可以于间接定位到一个内存单元
[bx + idata]用一个变量和一个常量来表示地址,可在一个起始地址的基础上用变量间接定位到一个内存单元
[bx + si] 用两个变量表示地址
[bx + si + idata] 用两个变量和一个常量来表示地址


  1. 一般来说,在需要暂存数据的时候,我们都应该使用栈

—————————————————————————————————————————————————————

第八章

  1. bx,si,di,bp:只有这4个寄存器可以用在”[…]”中来进行内存单元的寻址
    正确:mov ax,[bx] ; mov ax,[bp]
    错误:mov ax,[cx] ; mov ax,[dx] ; mov ax,[ax] ; mov ax,[ds]
  2. 在”[…]”中,这4个寄存器可以单个出现,或只能以四种组合出现:bx和si,bx和di,bp和si,bp和di
    错误:mov ax,[bx+bp] ; mov ax,[si+di]
  3. 只要在”[…]”中使用寄存器bp,而指令中没有显性地给出段地址,段地址就默认在ss
    mov ax,[bp] ; ax=ss*16+bp
  4. 在没有寄存器名存在的情况下,用操作符 X ptr 指明内存单元的长度,X在汇编指令中可以位word或byte

  1. div:除法指令
    除数:8位或16位,在一个reg或内存单元中
    被除数:默认放在AX或DX和AX中,如果除数为8位,被除数则为16位,默认在AX中存放;如果除数为16位,被除数则为32位,在DX和AX中存放,DX存放高16位,AX存放低16位
    结果:如果除数为8位,则AL存储除法操作的商,AH存储除法操作的余数;如果除数为16位,则AX存储出发操作的商,DX存储除法操作的余数

  1. dd:定义dword(double word,双字)型数据
  2. dup:用来进行数据的重复
    db 重复的次数 dup (重复的字节型数据)
    db 重复的次数 dup (重复的字型数据)
    db 重复的次数 dup (重复的双字型数据)

—————————————————————————————————————————————————————

第九章

  1. offset:取得标号的偏移地址
  2. jmp short 标号(转到标号处执行指令) :功能为(IP)=(IP)+8位位移
  3. jmp near ptr 标号 :实现段内近转移,功能为(IP)=(IP)+16位位移
  4. jmp far ptr 标号 :实现段间转移,功能为far ptr指明了指令用标号的段地址和偏移地址修改CS和IP
  5. jmp 16位reg :功能为(IP)=(16位reg)
  6. jmp word ptr 内存单元地址(段内转移)
  7. jmp dword ptr 内存单元地址(段间转移) : (CS)=(内存单元地址+2) , (IP)=(内存单元地址)
    高地址存放目的段地址,低地址存放目的偏移地址
  8. jcxz 标号 :cx为0时跳转
    if((cx) == 0) jmp short 标号;
  9. loop 标号
    (cx)–; :cx不为0时跳转
    if((cx) != 0) jmp short 标号;

—————————————————————————————————————————————————————

第十章

  1. ret用栈中数据修改ip,实现近转移
    相当于:
    pop IP
  2. retf用栈中数据修改cs和ip,实现远转移
    相当于:
    pop IP
    pop CS

  1. call :不能实现短转移,实现转移的方法和jmp指令原理相同
  2. call 标号
    相当于:
    push IP
    jmp near ptr 标号
  3. call far ptr 标号
    相当于:
    push CS
    push IP
    jmp far ptr 标号
    3call 16位reg
    相当于:
    push IP
    jmp 16位reg
  4. call word ptr 内存单元地址
    相当于:
    push IP
    jmp word ptr 内存单元地址
  5. call dword ptr 内存单元地址
    相当于:
    push CS
    push IP
    jmp dword ptr 内存单元地址

  1. mul:乘法指令
    格式如下:
    mul reg
    mul 内存单元
  2. 两个相乘的数:两个相乘的数,要么都是8位,要么都是16位.如果是8位,一个默认放在AL中,另一个放在8位reg或内存单元中;如果是16位,一个默认在AX中,另一个放在16位reg或内存字单元中
  3. 结果:如果是8位乘法,结果默认放在AX中;如果是16位乘法,结果高位默认在DX中存放,低位在AX中放

—————————————————————————————————————————————————————

第十一章

  1. 11 10 9 8 7 6 4 2 0
    OF DF IF TF SF ZF AF PF CF

  1. ZF:零标志位,如果运算结果为零,则ZF=1
  2. PF:奇偶标志位,相关指令执行后,若1的个数为偶数,则PF=1
  3. SF:符号标志位,执行后,若指令进行的是有符号数运算且计算结果为负,则SF=1
  4. CF:进位标志位,无符号数加减发生最高有效位之外的进、借位时,则CF=1
  5. OF:溢出标志位,有符号数运算发生溢出时,则CF=1

  1. adc:带进位加法,实现的功能是: adc ax,bx ==> (ax)=(ax)+(bx)+CF
  2. sbb:带借位减法,实现的功能是: sbb ax,bx ==> (ax)=(ax)-(bx)-CF
  3. cmp:比较指令,相当于减法,但是不保存结果,只影响标志寄存器
    cmp指令格式: cmp 操作对象1,操作对象2
    功能: 计算操作对象1-操作对象2但并不保存结果,仅仅根据计算结果对标志寄存器进行设置
  4. 无符号比较跳转指令
    je,等于则转移,ZF=1
    jne,不等于则转移,ZF=0
    jb,低于则转移,CF=1
    jnb,不低于则转移,CF=0
    ja,高于则转移,CF=0 且 ZF=0
    jna,不高于则转移,CF=1 or ZF=1

  1. DF:方向标志位,在串处理指令中,控制每次操作后si、di的增减
    df=0 每次操作后si、di递增 ; df=1 每次操作后si、di递减
  2. movsb:将ds:si指向的内存字单元中的字节送入es:di中
  3. movsw:将ds:si指向的内存字单元中的送入es:di中
    一般使用格式为 rep movsb
    相当于:
    s:movsb
    loop s

  1. pushf:将标志寄存器值入栈
  2. popf:将标志寄存器值出栈