汇编期末复习

别来无恙 提交于 2020-01-07 08:19:03

汇编

记忆部分

  1. 进制转换

  2. 逻辑地址转换物理地址

    • 1234h:0058h = 12340h+0058h = 12398h
  3. 数据存放为小端原则

    • 低字节在前,比如 12h 34h 56h 78h
  4. 短跳,近跳

    • jmp short target 机器码:EBXX
    • jmp near ptr target 机器码:E9XXXX
    • 近跳的相对长度只能有1个字节长
    • 近跳占3个字节,也就是近跳可以跳2个字节长
    • XX的计算公式是目标位置减去下一条指令位置,注意:小段规则。
    • 如果是跳回前面的指令,就是100h-XX,比如跳回上一条指令,就是EBFC,这里FC=100h-04h,04h相当于下一条指令减去目标指令
  5. 远跳

    • jmp far ptr target
    • 写法是:jmp 段地址:偏移地址
  6. 寄存器是CPU中可以存储数据的器件

寄存器

  1. ax, bx, cx, dx。
  2. cs, ds, ss, es。
    • cs:代码段寄存器
    • ds:数据段寄存器
    • ss:栈段寄存器
    • es:程序首个段前100h的地址,用来存放exe的相关信息。
  3. ip, sp, 注意ip只有jmp类型指令可以修改
  4. 只有bx,bp,si,di可以放到[]里面,bx, bp为基寄存器。
    • 其中[bx] == ds:[bx]
    • [bp] == ss:[bp]

标志位

影响标志位的指令有很多,比如位运算,加减乘除等。需要记住的只有下面这些。

  • mov不会影响任何标志位
  • inc, dec不会影响cf标志位
  • neg ax等价于执行了0-ax
  • 对于sf,of这种标志位,只有当运算需要考虑符号的时候才会有所变化的,比如加减乘除,neg等,位运算不会影响。
  1. cf进位标志

    • clc:清0
    • std:置1
    • cmc:反转
    • 当产生进位或者借位的时候变为1,比如ffffh+1h=0000h,cf就会变为1。
  2. zf零标志

    • 运算结果为0,zf=1
  3. sf符号标志

    • 正数为0,负数为1,0也是0
  4. of溢出标志

    • 执行运算的时候发生溢出变为1,指的是正数变负数这种溢出。
  5. pf奇偶标志

    • 低8位中,1的个数为奇数则pf=0,偶数pf=1
  6. af

    • 在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0
    • 在字操作时,发生低字节向高字节进位或借位时
    • 在字节操作时,发生低4位向高4位进位或借位时
  7. df

    • std:使df=1
    • cld:使df=0
    • 0代表正方向,这是使用复制相关命令时的复制顺序
  8. if

    • if=1代表允许硬件中断
    • cli,sti
    • int 9h键盘中断
    • int 8h时钟中断(118s\frac{1}{18}s 一次)
    • 用cli和sti把一段代码包围起来可以达到该段代码在执行过程中不会被打断的效果:
      cli; 禁止硬件中断
      ...; 重要代码
      sti; 允许硬件中断
      
  9. tf

    • tf=1时cpu进入单步模式,每执行一条指令,插入一条int 1h并执行

指令

mov指令

mov指令可以是寄存器到寄存器,寄存器到地址,地址到寄存器。但是有一些是违法的操作,比如:

  1. 段寄存器不能和段寄存器或直接赋值
    • mov ds, 1 ; 非法
    • mov ds, es ; 非法
  2. 寻址可以相加
    • mov ax, [bx+si+2]
    • mov ax, [bx+bp] ; 注意这样是不行的,不可以有两个基寄存器
  3. 直接写变量名的情况
    • mov ax, arr ; 等价于 mov ax, [arr]
    • mov ax, ds:[0] ; ds:[0]不可以省略ds

lea指令

使用方法:lea ax, ds:[0] ; 或 lea ax, [bx+si+2]。需要注意的地方如下:

  1. 左操作数必须是普通16位寄存器,不能是al,ah这种,也不能是段寄存器
  2. 实际效果相当于mov ax, offset ds:[0],也就是ax=0
  3. 好处在于lea ax, [bx+si+2],相当于直接运行了ax=bx+si+2,要用mov,add实现就很麻烦了。

运算类型指令

运算类型的指令有inc,dec,add,sub,mul,div,adc,sbb。

  1. inc和dec就是普通的加1,减1,没有什么特殊的。

  2. add和sub都有下列类似写法

    • add ax, 3
    • add ax, bx
    • add ax, al ; 这种是不行的,因为数据位数不匹配
  3. adc和sbb会在运算的时候相应的加上(减去)cf标志位

    • adc ax, 1 ; 这相当于ax=ax+1+cf
    • sbb ax, 1 ; 这相当于ax=ax-1-cf
    • 注意在运算之后,cf标志位按照计算结果来变化
  4. mul指令

    • 写法:mul bx 或 mul byte ptr ds:[0]
    • 根据mul的操作数数据宽度进行判断,并按照下列规则运算。
    • 指令 实际操作
      mul bl ax = al * bl
      mul bx dx:ax = ax * bx
      mul ebx edx:eax = eax * ebx
  5. div指令

    • 与mul非常相似,记忆方法是高位会做余数
    • 指令 实际操作
      div bl ax / bl = al…ah
      div bx dx:ax / bx = ax…dx
      div ebx edx:eax / ebx = eax…edx
    • 如果发生结果不能存下来,也就是发生溢出的情况,程序会显示溢出信息接下来退出。
  6. imul, idiv

    • 这两个会把运算的数当作符号数进行运算,结果当然也是符号数表示的。

跳转指令

cmp指令用来比较两个数,实际上是对两个数做差从而修改了标志位,运算结果被丢弃。接下来可以使用跳转系列指令进行跳转。

  1. jmp:无条件跳转
  2. ja:大于跳转,cf=0&&zf=0
  3. jae:大于等于跳转,cf=0
  4. jb:小于跳转,cf=1
  5. jbe:小于等于跳转,cf=1||zf=1
  6. jg:(符号数)大于跳转,sf==of&&zf=0
  7. jge:(符号数)大于等于跳转,正数且没有溢出或者负数且溢出或者为0,(sf==of)
  8. jl:(符号数)小于挑战,sf!=of
  9. jle:(符号数)小于等于跳转,sf!=of||zf=1
  10. jc:cf=1跳转
  11. jnc:cf=0跳转
  12. je:相等跳转,等价于zf=1
  13. jne:不相等跳转,等价于zf=0
  14. jz:zf=1跳转
  15. jnz:zf=0跳转
  16. jcxz:cx=0跳转
  17. js:sf=1跳转
  18. jns:sf=0跳转
  19. jo:of=1跳转
  20. jno:of=0跳转

此外还有一些不同的命令,int和iret。int 21h事实上做了四件事情。

  • pushf
  • push cs
  • push 下条指令偏移地址
  • jmp dword ptr 0:[84h] ; 84h=21h*4

接下来iret执行了三件事情

  • pop ip
  • pop cs
  • popf

call指令差不多也是这样,但是他不会pushf,ret不会popf

字符串指令

  1. rep movsb / rep movsw / rep movsd
    • es:di是目标地址,ds:si是源地址,一次复制一个byte,复制cx次,df=0则正向复制,df=1则反向复制。
    • 注意起点都是从si,di开始的,且复制结束后,di,si也会有相应变化。
    • movsw一次复制两个字节过去
    • movsd一次复制四个字节过去
  2. repe cmpsb / repe cmpsw / repe cmpsd
    • 和上面基本一样,只是这次是比较,repe表示若相等则接着比较
    • 比较后,先让si,di,cx发生变化,再判断是否相等,不相等则停止
    • 所以停下来的时候如果不相等,其实是si-1,di-1这一位不相等
    • 只要停下来的时候zf=0,就一定是全等的
  3. repe scasb / repe scasw / repe scasd
    • 会将al / ax / eax 与 es:di进行比较
    • 如果相等则继续执行
    • 停下来的时候是不相等的那一位的下一位
  4. stosb / stosw / stosd
    • 将al / ax / eax 存到 es:di 中,并且会变化di
    • 当然也可以加前缀rep重复执行cx次
  5. lodsb / lodsw / lodsd
    • 将 ds:si 存到 al / ax / eax中,并且变化si
    • 也可以加rep

远近指针指令

  • 简单来说,偏移地址就是近指针,16位汇编就是16位,32位汇编就是32位
  • 16位汇编,远指针是16位段地址:16位偏移地址
    • 存储时默认当作long int看待存储(小端规则)
    • les di, dword ptr ds:[0000h] ; es=1234h, di=5678h
    • lds si, dword ptr ds:[0000h] ; ds=1234h, si=5678h
  • 32位汇编,远指针是16位段地址:32位偏移地址
    • 存储时默认当作48位整数看待存储(小端规则)
    • les ebx, fword ptr cs:[p]; es=18h ebx=12345678h

零散指令

  1. xchg:交换两个寄存器的值(不可以有段寄存器)
    • xchg ax, ds:[0] ; 这种写法也是支持的,反过来也可以
  2. and, or, xor, not, neg(这个是相反数指令)
  3. shl, shr, sal, sar, rol, ror, rcl, rcr, test
    • test指令相当于使用and,但是不影响值,类似cmp
    • 每一个移位指令都影响cf标志位,移出去的一位在cf中
    • sal 算术左移,等价于 shl
    • sar 算术右移,也就是负数时候左边补1
    • rol 普通的循环左移
    • ror 普通的循环右移
    • rcl 会把 (cf 操作数) 合在一起,然后进行循环左移
    • rcr 会把 (cf 操作数) 合在一起,然后进行循环右移
  4. cbw, cwd, cdq指令
    • cbw 扩展al,变为word类型(ax)。
    • cwd 扩展ax,变为dword类型(dx:ax)
    • cdq 扩展eax,变为edx:eax
  5. loop指令
    • loop 标号 ; (1)cx=cx-1 (2)cx!=0则跳转
  6. xlat指令
    • 先设置好ds:bx指向数组,在设置al为下标
    • 执行xlat后,al=ds:bx之后的第al个字节的内容
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!