汇编语言程序设计 Assembly Language Programming 第4讲
回顾上次课内容 1、按要求写出把首地址为ARRAY的字数组的第6个字送到DX寄存器的指令。 (1)直接寻址 (2)寄存器间接寻址 (3)寄存器相对寻址 (4)基址变址寻址 MOV DX, ARRAY+10 MOV BX, OFFSET ARRAY ADD BX, 10 MOV DX, [BX] MOV BX, 10 MOV DX, ARRAY[BX] MOV BX, OFFSET ARRAY MOV DX, [BX+10] MOV BX, OFFSET ARRAY MOV SI, 10 MOV DX, [BX+SI]
第2章 数据定义与传送 2.1 数据的定义 2.2 数据的传送 2.2.1 指令格式 2.2.2 代码段 2.2.3 传送指令 2.2.4 堆栈 2.2.5 操作数表达式 作业 复习指导
2.2.2 代码段 [例]编写程序:将数据段中字节变量A与附加段字节变量B相加,结果放在数据段的字节变量SUM中. 第2章 数据定义与传送 2.2.2 代码段 [例]编写程序:将数据段中字节变量A与附加段字节变量B相加,结果放在数据段的字节变量SUM中. DATA SEGMENT ;数据段定义开始 A DB 55 ;第一个加数 SUM DB ? ;准备用来存放和的单元 DATA ENDS ;数据段定义结束 DSEG SEGMENT ;附加段定义开始 X DB 10 ;第二个加数 DSEG ENDS ;附加段定义结束
CODE SEGMENT ;代码段定义开始 ASSUME CS:CODE, DS:DATA, ES:DSEG START: MOV AX, DATA MOV DS, AX MOV AX, DSEG MOV ES, AX MOV AL, A ADD AL, X MOV SUM, AL MOV AX, 4C00H INT 21H CODE ENDS ;段定义结束 END START ASSUME伪指令用来指定段和段寄存器之间的对应关系,供汇编程序使用. 将段地址装入段寄存器中. 问题:变量A和变量X的段地址和偏移地址分别为? 返回DOS. END伪指令表示源程序结束.
(1) ASSUME伪指令 ASSUME 段寄存器:段名1,段寄存器:段名2… 用来指定段和段寄存器之间的对应关系, 供汇编程序使用。 如: 第2章 数据定义与传送 (1) ASSUME伪指令 ASSUME 段寄存器:段名1,段寄存器:段名2… 用来指定段和段寄存器之间的对应关系, 供汇编程序使用。 如: ASSUME CS:CODE, DS:DATA, ES:DSEG
操作系统自动将代码段段地址装入CS寄存器,不需在程序中指定。 第2章 数据定义与传送 (2)段地址装入段寄存器 常常在程序开始处把数据段,附加段,堆栈段的段基址装入相应段寄存器中。 操作系统自动将代码段段地址装入CS寄存器,不需在程序中指定。 如:DATA段的段基址送DS MOV AX, DATA MOV DS, AX 而不能是: MOV DS, DATA × 立即数不能直接送段寄存器
× 分析代码段! CODE SEGMENT 不正确!相当于: ASSUME CS:CODE, DS:DATA, ES:DSEG START: MOV AX, DATA MOV DS, AX MOV AX, DSEG MOV ES, AX MOV AL, A ADD AL, X MOV SUM, AL MOV AX, 4C00H INT 21H CODE ENDS END START 不正确!相当于: MOV AL, DS:[0000H] ADD AL, DS:[0000H] 相当于: MOV AL, DS:[0000H] ADD AL, ES:[0000H] × MOV SI, OFFSET A MOV DI, OFFSET X MOV AL, [SI] ADD AL, [DI] 正确! MOV SI, OFFSET A MOV DI, OFFSET X MOV AL, [SI] ADD AL, ES:[DI]
(3)标号 标号与变量不同,标号在代码段中; 标号与指令之间用冒号“:”分开; 第2章 数据定义与传送 (3)标号 标号与变量不同,标号在代码段中; 标号与指令之间用冒号“:”分开; 本程序的执行从标有“START”的第一条指令开始,其地址称为这个程序的“入口地址”。
(4)返回DOS 指令“INT 21H”表示调用由操作系统提供的21H号服务程序。 AH中为“功能号”,AH=4CH表示返回操作系统的操作。 第2章 数据定义与传送 (4)返回DOS 指令“INT 21H”表示调用由操作系统提供的21H号服务程序。 AH中为“功能号”,AH=4CH表示返回操作系统的操作。 AL中的代码称为“返回代码”,00H表示“正常返回”。
第2章 数据定义与传送 (5)程序结束伪指令 END [程序入口地址标号] 表示整个程序结束,所有段的定义必须写在END伪操作前。
(6)处理器选择伪指令 确定使用哪一种指令系统; 放在整个程序的最前面; .8086(默认) .286 .286P .386 .386P 第2章 数据定义与传送 (6)处理器选择伪指令 确定使用哪一种指令系统; 放在整个程序的最前面; .8086(默认) .286 .286P .386 .386P .486 .486P .586 .586P
2.2.3 传送指令 MOV LEA LDS, LES, LFS, LGS MOVZX, MOVSX, CBW,CWD, CWDE, CDQ 第2章 数据定义与传送 2.2.3 传送指令 MOV LEA LDS, LES, LFS, LGS MOVZX, MOVSX, CBW,CWD, CWDE, CDQ XCHG, BSWAP XLAT
1、MOV传送指令 MOV DEST, SRC 功能: (DEST) (SRC) SRC:寄存器、存储器、立即数 第2章 数据定义与传送 1、MOV传送指令 MOV DEST, SRC 功能: (DEST) (SRC) SRC:寄存器、存储器、立即数 DEST:寄存器、存储器。 MOV指令不破坏源操作数内容. MOV指令不影响标志位.
MOV指令举例1(寄存器寄存器) MOV CL,DH MOV ECX, EDX MOV AX, CS MOV SS, CX 第2章 数据定义与传送 MOV指令举例1(寄存器寄存器) MOV CL,DH MOV ECX, EDX MOV AX, CS MOV SS, CX ;字节传送指令,DH内容送入CL ;双字传送指令,EDX内容送ECX ;字传送指令,CS内容送入AX ;字传送指令,CX内容送入SS MOV CL, DX MOV AX, CX+2 MOV CS , AX MOV DS, CS MOV AX, FLAGS ;错误,操作数类型不匹配 ;错误,不可计算的表达式 ;错误,CS不能作为目的操作数 ;错误,不能同时为段寄存器 ;错误,不能使用标志寄存器
MOV指令举例2(立即数寄存器) MOV AL,30H ;字节传送指令,执行后(AL)= 30H MOV AX,30H 第2章 数据定义与传送 MOV指令举例2(立即数寄存器) MOV AL,30H MOV AX,30H MOV EAX,30H MOV AL, -5 MOV AX, -5 ;字节传送指令,执行后(AL)= 30H ;字传送指令,执行后(AX)= 0030H ;双字传送, (EAX)=00000030H ;字节传送指令,执行后(AL)= 0FBH ;字传送指令,执行后(AX)= 0FFFBH MOV 30H, AL MOV AL, 300 MOV DS, DATA ;错误,立即数不能用作目的操作数 ;错误,源操作数超出范围 ;错误,立即数不能直接送段寄存器
问题:指令 MOV AL, X+2 正确吗? 设变量X用DB定义 MOV [BP], BL MOV [BX], AX 第2章 数据定义与传送 MOV指令举例3(存储器寄存器,寄存器存储器) 设变量X用DB定义 MOV [BP], BL MOV [BX], AX ;字节传送指令,BL内容送SS:[BP] ;字传送指令,AL内容送DS:[BX], ;AH内容送DS:[BX+1] MOV [DX], BL MOV X, AX MOV EAX, [EBX][EBP*3] MOV AL, X*2 ;错误,DX不能用来寄存器间接寻址 ;错误, 操作数类型不匹配 问题:指令 MOV AL, X+2 正确吗? ;错误,比例因子错误 ;错误,不可计算的表达式
MOV指令举例4(立即数存储器) 设变量X用DB定义,Y用DW定义 MOV X, -5 ;字节传送指令,0FBH送X MOV Y, -5 第2章 数据定义与传送 MOV指令举例4(立即数存储器) 设变量X用DB定义,Y用DW定义 MOV X, -5 MOV Y, -5 ;字节传送指令,0FBH送X ;字传送指令, 0FFFBH送Y MOV X, 300 MOV [BX], 30H ;错误,源操作数超出范围 ;错误,操作数类型不能确定
“类型 PTR”用于指定或改变操作数的类型 第2章 数据定义与传送 问题:指令 MOV [BX], 30H 错误原因在于操作数类型不能确定, 如何修改指令正确? MOV BYTE PTR[BX], 30H 字节30H送DS:[BX] MOV WORD PTR[BX], 30H 立即数30H送DS:[BX], 00H送DS:[BX+1] MOV DWORD PTR[BX], 30H 00000030H送DS:[BX]开始4个字节
设变量X用DB定义,Y用DW定义 MOV X, 300 ;错误,源操作数超出范围 MOV AL, Y ;错误,两操作数类型不匹配 第2章 数据定义与传送 设变量X用DB定义,Y用DW定义 MOV X, 300 ;错误,源操作数超出范围 MOV AL, Y ;错误,两操作数类型不匹配 MOV WORD PTR[X], 300 ;正确,立即数300送变量X开始的2字节 MOV AL, BYTE PTR[Y] ;正确, 变量Y的第一字节送AL寄存器
总结: MOV指令使用规则 不能直接从存储单元送存储单元. MOV [BX], [2000H] 立即数不能作DEST. MOV 250BH, AX DEST与SRC类型必须相同. MOV AL,32FAH FLAGS,EFLAGS,IP, EIP不能做操作数. MOV AX, FLAGS DEST 不能是 CS. MOV CS,AX DEST、SRC 不能同时为段寄存器. MOV DS, ES 立即数不能直接送段寄存器. MOV DS, 2000H MOV DS, SEG ARRAY 总结: MOV指令使用规则
2、LEA装载有效地址指令 LEA REG16, MEM 功能:把源存储器操作数的偏移地址装入16位寄存器中。 第2章 数据定义与传送 2、LEA装载有效地址指令 LEA REG16, MEM 功能:把源存储器操作数的偏移地址装入16位寄存器中。 例1:变量X的偏移地址为1020H, (BX)=1200H. LEA DI, X ;执行后(DI)= 1020H LEA AX, [BX+10H] ;执行后,(AX)=1210H 等效于指令: MOV DI, OFFSET X
注意:指令的源操作数是存储器,而目的操作数是16位寄存器。 LEA AX, 201EH 第2章 数据定义与传送 注意:指令的源操作数是存储器,而目的操作数是16位寄存器。 LEA AX, 201EH LEA 3105H, [SI] LEA BL, X
3、地址传送指令 LDS REG16, MEM32 ;送入REG16和DS LES REG16, MEM32 ;送入REG16和ES 第2章 数据定义与传送 3、地址传送指令 从存储器取出4B,低16位送指令指定寄存器, 高16位送由指令操作码包含的段寄存器. LDS REG16, MEM32 ;送入REG16和DS LES REG16, MEM32 ;送入REG16和ES LFS REG16, MEM32 ;送入REG16和FS LGS REG16, MEM32 ;送入REG16和GS 不影响标志位。LFS和LGS是80386新增的。
例2:假设(DS)=3000H, (BX)=080AH, (3080AH)=05AEH, (3080CH)=4000H. 则执行指令 第2章 数据定义与传送 例2:假设(DS)=3000H, (BX)=080AH, (3080AH)=05AEH, (3080CH)=4000H. 则执行指令 LDS SI, [BX] 后(SI)=05AEH, (DS)=4000H.
4、扩展传送指令 后4条指令是80386新增 问题1:将AL中的无符号数/有符号数扩展为16位并存放在AX中的指令分别是什么? 第2章 数据定义与传送 4、扩展传送指令 后4条指令是80386新增 CBW ;(AL)符号扩展成16b(AX) CWD ;(AX)符号扩展成32b(DX,AX) CWDE ;(AX)符号扩展成32b(EAX) CDQ ;(EAX)符号扩展成64b(EDX,EAX) MOVZX REG32/REG16, REG16/MEM16/REG8 /MEM8 ;将16/8位寄存器/存储器数零扩展送入32/16位寄存器 MOVSX REG32/REG16, REG16/MEM16/REG8 /MEM8 ;将16/8位寄存器/存储器数符号扩展送入32/16位寄存器 问题1:将AL中的无符号数/有符号数扩展为16位并存放在AX中的指令分别是什么? 问题2:使用80386以上CPU新增指令时需在程序中加入哪条伪指令?
(AX)=0060H 例3: 若(EAX)= 00008060H,分析下列指令执行结果. CBW CWD (DX)=0FFFFH 第2章 数据定义与传送 例3: 若(EAX)= 00008060H,分析下列指令执行结果. CBW CWD CWDE CDQ MOVZX EBX, AX MOVSX EBX, AX MOVSX EBX, AL (AX)=0060H (DX)=0FFFFH (AX)= 8060H (EAX)= 0FFFF 8060H (EDX)=0000 0000H (EAX)=0000 8060H (EBX)=0000 8060H (EBX)=0FFFF 8060H (EBX)=0000 0060H
5、交换指令 XCHG REG/MEM, REG/MEM 交换源、目的操作数的内容。 第2章 数据定义与传送 5、交换指令 XCHG REG/MEM, REG/MEM 交换源、目的操作数的内容。 BSWAP REG32 (80486新增指令) 交换32位寄存器的最高字节和最低字节、次高字节和次低字节 例4:若(EAX)=12345678H,分析指令执行结果. XCHG AH, AL BSWAP EAX (AX)= 7856H (EAX)= 78563412H
XCHG指令使用规则 (1)不影响标志位 (2)不允许使用段寄存器 XCHG DS, AX × (3)不允许使用立即数 XCHG AX, 1234H × (4)SRC与DEST字长应该一致 XCHG AX, BL × (5)SRC与DEST不能同时为存储器操作数 XCHG [BX], [1000H] × XCHG A, B ;字节变量A, B × XCHG指令使用规则 第2章 数据定义与传送
6、换码指令 XLAT ;AL←DS: [BX+AL] 用AL寄存器的内容查表,结果存回AL寄存器。表格的首地址事先存放在DS: BX中。 第2章 数据定义与传送 6、换码指令 XLAT ;AL←DS: [BX+AL] 用AL寄存器的内容查表,结果存回AL寄存器。表格的首地址事先存放在DS: BX中。 XLAT MEM16 以MEM16对应段寄存器为段地址,以BX为偏移地址查表
例5: 编写指令序列将AL中的十六进制数码转换为相应的ASCII. 32 H F004:0002H 30 H F004:0000H 31 H F004:0001H 33 H F004:0003H TABLE 35 H F004:0005H 36 H F004:0006H 37 H F004:0007H 38 H F004:0008H 39 H F004:0009H 41 H F004:000AH 42 H F004:000BH 43 H F004:000CH 44 H F004:000DH 45 H F004:000EH 34 H F004:0004H 46 H F004:000FH TABLE DB '0123456789ABCDEF' MOV BX, SEG TABLE MOV DS, BX LEA BX, TABLE MOV AL, 0AH XLAT ; AL←DS: [BX+AL] XLAT指令执行前(AL)=0AH. XLAT指令执行后(AL)=41H.
第2章 数据定义与传送 2.2.4 堆栈 堆栈(STACK)是用户使用的存储器的一部分,用来存放临时性的数据和其他信息,例如函数使用的局部变量、调用子程序的入口参数、返回地址等。 堆栈的段基址必须装入SS中. 堆栈段的“栈顶”的偏移地址在SP中.
1、堆栈段定义 SSEG SEGMENT ;堆栈段开始 DW 100 DUP(?) ;大小为100个字SSEG ENDS ;堆栈段结束 第2章 数据定义与传送 1、堆栈段定义 SSEG SEGMENT ;堆栈段开始 DW 100 DUP(?) ;大小为100个字SSEG ENDS ;堆栈段结束 SP永指向栈顶,初始为0000H+100*2=00C8H. 从高地址开始分配和使用,而数据段、代码段则从低地址开始分配和使用。 后进先出。 SP00C8H 00C7H 00C6H 00C5H 00C4H 0000H ……
例6:若(AX) = 1234 H , 执行 PUSH AX SP00C8H PUSH AX 执行前 00C7H 00C6H 00C5H 第2章 数据定义与传送 例6:若(AX) = 1234 H , 执行 PUSH AX SP00C8H PUSH AX 执行前 00C7H 00C6H 00C5H 00C4H 0000H …… SP00C6H 低地址 高地址 PUSH AX 执行后 进栈方向 00C7H 00C5H 00C4H 0000H …… 00C8H 34H 12H
例7: 分析执行指令: POP BX 后堆栈的变化. 第2章 数据定义与传送 例7: 分析执行指令: POP BX 后堆栈的变化. POP BX 执行前 SP00C4H 00C7H 00C5H 00C6H 0000H …… 00C8H 34H 12H 2CH 1EH 出栈方向 POP BX 执行后 (BX) = 1E2CH 00C4H 00C7H 00C5H SP00C6H 0000H …… 00C8H 34H 12H 2CH 1EH
2、8086CPU堆栈指令 (1)进栈指令: PUSH SRC 第2章 数据定义与传送 2、8086CPU堆栈指令 (1)进栈指令: PUSH SRC 执行操作: (SP) (SP) – 2 ( (SP)+1, (SP) ) (SRC) SRC是16b的寄存器/存储器/段寄存器。 PUSH AX ;SRC为16位寄存器 PUSH CS ;SRC为16位段寄存器 PUSH ARR[BX] ;设变量ARR是DW定义,则SRC为16位存储器数
堆栈操作必须以字(或双字)为单位,不允许字节堆栈: PUSH AL × 第2章 数据定义与传送 注意: 堆栈操作必须以字(或双字)为单位,不允许字节堆栈: PUSH AL × 8086/8088不能用立即数操作数: PUSH 1234H 指令执行后,操作数的内容不变。不影响标志位。
(2)出栈指令: POP DEST 执行操作:(DST) ( (SP)+1, (SP)) (SP) (SP) + 2 第2章 数据定义与传送 (2)出栈指令: POP DEST 执行操作:(DST) ( (SP)+1, (SP)) (SP) (SP) + 2 DEST是16b寄存器/存储器/段寄存器(CS除外). 指令执行后,DEST内容发生变化。 不影响标志位。 注意1:DEST不能为立即数寻址方式 POP 32FAH 注意2:DEST不能是CS POP CS
问题:如何使用PUSHF和POPF指令设置标志寄存器内容? 第2章 数据定义与传送 (3)标志进栈指令—把FLAGS寄存器内容压栈,指令执行后,FLAGS内容不变。 指令格式:PUSHF (4)标志出栈指令—从堆栈弹出16b送入FLAGS寄存器,指令执行后各标志位被刷新。 指令格式:POPF
(5)标志送AH指令—把FLAGS寄存器的低8位送入AH寄存器。 第2章 数据定义与传送 (5)标志送AH指令—把FLAGS寄存器的低8位送入AH寄存器。 指令格式:LAHF (6)AH送标志寄存器指令--把AH寄存器内容送入FLAGS寄存器的低8位,指令执行后SF, ZF, AF, PF, CF标志位变化。 指令格式:SAHF
3、扩展的堆栈指令 (1)32位PUSH和POP指令(80386) PUSH REG32/MEM32 ;32位寄存器/存储器压栈 第2章 数据定义与传送 3、扩展的堆栈指令 (1)32位PUSH和POP指令(80386) PUSH REG32/MEM32 ;32位寄存器/存储器压栈 POP REG32/MEM32 ;弹出32位送入操作数 PUSH IMM ;16/32位立即数压入堆栈
PUSHA—16位通用寄存器依次进栈:AX、CX、DX、BX、SP、BP、SI、DI 第2章 数据定义与传送 (2)所有寄存器进栈/出栈指令(80286) PUSHA—16位通用寄存器依次进栈:AX、CX、DX、BX、SP、BP、SI、DI POPA—从堆栈弹出8个16位数据到通用寄存器(出栈顺序与进栈顺序相反)。 PUSHDA—32位通用寄存器依次进栈:EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI POPDA—弹出8个32位数据到通用寄存器。 都不影响标志位
把32位EFLAGS寄存器内容压入堆栈,原寄存器内容不变 第2章 数据定义与传送 (3)标志进栈/出栈指令(80386) PUSHFD 把32位EFLAGS寄存器内容压入堆栈,原寄存器内容不变 POPFD 从堆栈中弹出32b,存入EFLAGS,寄存器内容被更新
第2章 数据定义与传送 作业 P44 2.4、2.8 1、已知堆栈段寄存器SS的内容是0FFA0H,堆栈指针寄存器SP的内容是00B0H,先执行两条把8057H和0F79H分别进栈的PUSH指令,再执行一条POP指令。请画出堆栈区和SP的内容变化过程示意图(标出存储单元的物理地址)。
复习指导 1、程序段 一个汇编源程序至少要有一个代码段吗?可以包括多个代码段和多个数据段吗? ASSUME伪指令的作用是什么? 第2章 数据定义与传送 复习指导 1、程序段 一个汇编源程序至少要有一个代码段吗?可以包括多个代码段和多个数据段吗? ASSUME伪指令的作用是什么? 将各段的段地址装入到相应段寄存器中的指令序列是什么?需要用指令将代码段的段地址装入到CS寄存器中吗? 什么时候需要段跨越前缀?指令MOV AX, ES:BX 正确吗? 汇编源程序的第一条指令需要用标号标示吗?为什么? END伪指令放在汇编源程序何处? 什么时候需要处理器选择伪指令?
MOV指令执行后源操作数和目的操作数的内容发生变化吗? SRC和DEST必须有相同类型吗?如何改变或指定操作数类型呢? 第2章 数据定义与传送 2、MOV指令 MOV指令会影响标志位吗? MOV指令执行后源操作数和目的操作数的内容发生变化吗? SRC和DEST必须有相同类型吗?如何改变或指定操作数类型呢? DEST可以是立即数或CS寄存器吗? 可以直接在两个存储器数之间传送吗?可以直接在两个段寄存器之间传送吗?可以将立即数直接传送给段寄存器吗?
3、LEA指令 若X是变量名,则指令LEA BX, X与哪条指令等价? LEA指令的源操作数可以是立即数或寄存器数吗? 第2章 数据定义与传送 3、LEA指令 若X是变量名,则指令LEA BX, X与哪条指令等价? LEA指令的源操作数可以是立即数或寄存器数吗? LEA指令的目的操作数可以是立即数、存储器数吗?可以是8位寄存器吗? LEA指令影响标志位吗?
LDS、LES的功能分别是什么?指令格式是什么?影响标志位吗? 第2章 数据定义与传送 4、其他传送指令 LDS、LES的功能分别是什么?指令格式是什么?影响标志位吗? CBW/CWD指令是对无符号数进行扩展呢还是对有符号数进行扩展?那么如何对无符号数进行扩展呢? MOVZX/MOVSX指令的功能和格式是什么?在汇编源程序中使用该指令时需要加入哪条伪指令? XCHG指令会改变源操作数和目的操作数内容吗?操作数可以是立即数吗?源操作数和目的操作数类型要求相同吗?源操作数和目的操作数可以同时为存储器数吗? XLAT指令有什么应用?
5、堆栈 如何定义堆栈段?堆栈段的用途及结构特点?如何取得堆栈段的栈顶物理地址? 第2章 数据定义与传送 5、堆栈 如何定义堆栈段?堆栈段的用途及结构特点?如何取得堆栈段的栈顶物理地址? 进栈/出栈操作对堆栈如何影响?进栈/出栈的数据可以是字节数据吗? PUSH指令格式?影响标志位吗? POP指令的操作数可以是立即数、CS寄存器吗?影响标志位吗? 如何使用PUSHF和POPF指令访问标志寄存器内容?