编程语言
首页 > 编程语言> > 《汇编语言》chapter3 note

《汇编语言》chapter3 note

作者:互联网

第三章:程序设计初步

目录

第三章:程序设计初步

堆栈的作用

过程调用和返回指令

参数传递

局部变量

算术逻辑运算指令

乘除运算指令

符号扩展指令

扩展传送指令

逻辑运算指令

一般移位指令

循环移位指令

双精度移位指令

分支程序设计

无条件和条件转移指令

多路分支的实现

循环程序设计

循环指令

计数器转移指令

多重循环程序

子程序设计

传递参数方法

安排局部变量地方法

保护寄存器的约定


堆栈的作用

过程调用和返回指令

CALL LABEL

  1. 不影响状态标志
  2. 段内直接调用指令:①把返回地址偏移压入堆栈;②使得EIP的内容为目标地址偏移(实现转移,和JMP指令操作是一样的)
  3. 段内间接调用指令:CALL OPRD 由OPRD给出入口地址偏移的子程序,把OPRD的内容送到EIP,操作数可以是32位的通用寄存器或者双字存储单元。
  4. 段间调用指令:相似,先把CS压入堆栈,再把EIP压入堆栈。

RET

  1. 不影响标志寄存器中的状态标志
  2. 从堆栈弹出地址偏移(调整ESP),送到指令指针寄存器EIP
  3. 段内带立即数返回指令:RET count ,其中count是一个16位的立即数,第一步不变,再把count加到ESP上
  4. 函数的返回值在寄存器EAX中

参数传递

方法:

  1. 寄存器传递法
  1. 把参数放在约定的寄存器中
  2. 由于寄存器数量有限,只适用于传递少量参数的情形
  1. 堆栈传递法
  1. C语言的函数通常利用堆栈传递入口参数,而利用寄存器传递出口参数
  2. 用堆栈传递入口参数时,主程序在调用子程序之前,把需要传递的参数依次压入堆栈,然后子程序从堆栈中取入口参数
  3. 有时候需要考虑保护寄存器
  1. 约定内存单元传递法、CALL后续区传递法等

局部变量

局部变量放堆栈中,EBP指向堆栈,能够以EBP作为基址寄存器来访问局部变量。

算术逻辑运算指令

乘除运算指令

有时操作数是隐含的

MUL OPRD

  1. 无符号数乘法指令,另一个操作数隐含,位于寄存器AL,AX,EAX中
  2. OPRD可以是通用寄存器、存储单元,但不能是立即数!
  3. 乘积的高半部分不等于0,则CF=1,OF=1(表示高位含有结果的有效数呗);否则都为0。对其他状态标志无定义

IMUL OPRD

IMUL DEST(只能是通用寄存器),SRC(可以是立即数,尺寸不能超过目的操作数)

IMUL DEST(只能是通用寄存器),SRC1(不能为立即数),SRC2(只能为立即数)

  1. 有符号数乘法指令
  2. 双数或三数,乘积有可能溢出,那么高位部分将被截掉
  3. 单数和无符号乘法指令一样,高位含有效位,则CF=OF=1;双数和三数,溢出高位截断则CF=OF=1。对其他状态标志无定义

DIV OPRD

  1. 无符号数除法指令
  2. 和mul相反,被除数位于AX,DX:AX,EDX:EAX
  3. 字节操作数:AX除以OPRD,商送到AL,余数送到AH
  4. 字操作数:DX:AX除以OPRD,商送到AX,余数送到DX
  5. 双字操作数:EDX:EAX除以OPRD,商送到EAX,余数送到EDX
  6. OPRD不能是立即数
  7. 对状态标志的影响无定义
  8. 除数为0或商太大,则引起除法出错异常

IDIV OPRD

  1. 有符号数除法指令
  2. 被除数位于和DIV一样,商和余数也都和DIV一样
  3. 如果不能整除,余数的符号与被除数一致,而且余数的绝对值小于除数的绝对值
  4. 对状态标志无影响
  5. 有时需要在除操作之前扩展被除数

符号扩展指令

CBW

  1. 字节→字
  2. AL符号扩展到AH

CWD

  1. 字→双字
  2. AX符号扩展到DX

CWDE

  1. 字→双字
  2. AX符号扩展到EAX的高16位

CDQ

  1. 双字→四字
  2. EAX符号扩展到EDX

  1. 四条符号扩展指令均不影响各状态标志。
  2. 在无符号数除操作之前,不宜利用CBW、CWD、CDQ指令来扩展符号位,一般采用逻辑异或XOR指令把高位直接清零(即无符号扩展)

扩展传送指令

MOVSX DEST,SRC

  1. 符号扩展传送指令,扩展SRC的符号后送至DEST
  2. SRC可以是通用寄存器或存储单元,但DEST只能是通用寄存器,且尺寸必须大于SRC
  3. 不改变源操作数,也不影响状态标志

MOVZX DEST,SRC

  1. 零扩展传送指令
  2. SRC、DEST要求同上,也两不

逻辑运算指令

  1. 按位进行
  2. 目的操作数:只能是通用寄存器或存储单元,用于存放运算结果
  3. 如果只有一个操作数,则该操作数既是源又是目的
  4. 两个操作数,最多只能有一个存储单元。操作数们尺寸必须一致。源操作数可以是立即数

NOT OPRD

  1. 将OPRD按位取反
  2. 对标志无影响

AND DEST,SRC

  1. 与运算
  2. 使CF=OF=0,PF、ZF、SF反应运算结果,AF无定义
  3. 操作数自己与自己and,值不变,可以使CF清零
  4. 常用于使操作数若干位不变,另外若干位清零的场合

OR DEST,SRC

  1. 或运算
  2. 使CF=OF=0,PF、ZF、SF反应运算结果,AF无定义

XOR DEST,SRC

  1. 异或运算
  2. 使CF=OF=0,PF、ZF、SF反应运算结果,AF无定义
  3. 自己与自己异或,结果总为0。经常会采用xor把寄存器清零

TEST DEST,SRC

  1. 和and类似,但结果不送到dest,仅影响标志位,使CF=OF=0,PF、ZF、SF反应运算结果,AF无定义
  2. 通常用于检测某些位是否为1,但又不希望改变操作数值的场合

一般移位指令

移位指令需要标明移动的位数,可以是8位立即数,也可以是CL。通过截取count的第五位,实际的移位数被限制于0~31之间。

SAL OPRD,count              //算数左移指令(同逻辑左移)

SHL OPRD,count             //逻辑左移指令(同算数左移)

SAR OPRD,count              //算数右移指令

SHR OPRD,count             //逻辑右移指令

  1. CF受影响,SF、ZF、PF反应移位后的结果,OF很复杂,AF未定义
  2. 左移都是一样的,每向左移动一位,右边用0补足,最高位进入CF
  3. 算数右移左边的符号位保持不变,最低位进入CF
  4. 逻辑右移左边用0补足,最低位进入CF

循环移位指令

ROL OPRD,count             //左循环移位指令

ROR OPRD,count             //右循环移位指令

RCL OPRD,count             //带进位左循环移位指令

RCR OPRD,count             //带进位右循环移位指令

  1. CF受影响, OF很复杂,其他状态标志不受影响
  2. 前两条没有把CF包含在循环的环中,CF和一般循环的变化一样
  3. 每移动一位,CF都会变
  4. 循环移位指令,方便实现一个操作数内部的移位
  5. 带进位循环指令,能够实现跨操作数之间的移位。(将CF作为中间桥梁)

双精度移位指令

老师说不建议使用

SHLD OPRD1,OPRD2,count

SHRD OPRD1,OPRD2,count

  1. OPRD1作为目的操作数可以是通用寄存器或存储单元,字或双字
  2. OPRD2只能是寄存器。操作数尺寸一致。
  3. count都同理,如果超过操作数的尺寸,则目的操作数的结果无定义,状态标志也无定义
  4. 对目的操作数操作,左移把OPRD2放右边,右移把OPRD2放左边
  5. 仅移动一位,若符号位发生变化,则置OF,否则清OF;SF、ZF、PF反应移位后的结果,AF未定义

分支程序设计

  1. 利用条件转移指令和无条件转移指令实现分支
  2. 减少转移(在判断之前先假设满足简单的情形)充分利用寄存器(可以把寄存器作为形参变量之类的)等,都有助于提高执行的效率。

无条件和条件转移指令

(简单转移指令见此处

条件转移指令和循环指令只能实现段内转移,无条件转移指令和过程调用返回指令都可以实现,软中断指令和中断指令一定是段间转移。

又分为直接转移和间接转移。

JMP LABEL

  1. 无条件段内直接转移指令机器码:操作码OP+地址差rel——地址差是转移目标地址偏移与紧随JMP指令的下一条指令的地址偏移之间的差值。执行无条件段内直接转移指令时,实际上时rel+EIP——相对转移

JMP OPRD

  1. 无条件段内间接转移:在保护方式下,OPRD是32位通用寄存器或双字存储单元,其内容直接被装入EIP

多路分支的实现

  1. switch
  2. 当多路分支在5路以上时,可以考虑通过无条件间接转移指令和目标地址表实现

循环程序设计

循环=初始化+循环体+调整+控制(计数控制法和条件控制法)

循环指令

LOOP LABEL

  1. =DEC ECX ; JNZ LABEL
  2. 段内转移,相对转移,转移范围-128~+127
  3. 自动以ECX作为循环计数器
  4. 不影响各状态标志
  5. 先要设置好ECX的初值
  6. 执行时,首先使ECX减1(不影响标志!),再判断是否为0,所以循环最多可进行232次

LOOPE LABEL         //等于循环指令

LOOPZ LABEL          //全零循环指令

还要看ZF等于1,则跳转

LOOPNE LABEL             //不等于循环指令

LOOPNZ LABEL              //非全零循环指令

还要看ZF等于0,则跳转

计数器转移指令

JECXZ LABEL

  1. 当寄存器ECX=0时,转移到LABEL(即循环次数为0,不进行循环)
  2. 通常在循环体开始之前使用该指令,当循环次数为0时,就可以跳过循环体

多重循环程序

实践过后再说吧。

子程序设计

  1. 必须遵循与主程序的约定
  2. 注意传递参数的方法、安排全局变量的方式、保护寄存器的约定、表述子程序的说明

传递参数方法

  1. 希望利用寄存器传递入口参数:在C源程序中明确_fastcall的调用规定
  2. 给动态局部变量分配寄存器,能有效地提高执行效率

安排局部变量地方法

  1. 利用堆栈来安排局部变量

保护寄存器的约定

  1. 函数代码虽然使用寄存器eax、ecx、edx,但并不事先保护他们;
  2. 函数代码只要使用了寄存器ebx、esi、edi、ebp,总是先保护它们,过后再恢复(这就是默契)
  3. 函数代码对堆栈指针ESP的使用是极其谨慎的
  4. 保护和恢复的时候一定要注意堆栈平衡

标签:操作数,汇编语言,CF,chapter3,OPRD,note,指令,寄存器,循环
来源: https://blog.csdn.net/bakugo_kiyoko/article/details/120586935