汇编Ch.5 & Ch.6笔记

Chapter V: 程序设计

躺雷记录:

关于汇编中大小写的问题:

  • 各条指令不区分大小写
  • 但是用户定义的各个变量, 标号等, 将区分大小写

关于汇编中的中括号:

对于MOV:

num 	dword 2
mov 	eax,2
mov 	ebx,num
mov 	ecx,[num]	
;执行完ebx==ecx==2
;证明了对于变量, 加不加[]得到的都是符号地址中储存的值
;想要获得符号地址的地址, 需要用LEA, 或者是offset前缀
mov 	ebx,eax	
;ebx==2
;将eax中的值传递给ebx中
mov 	ecx,[eax]
;报错,因为这里翻译成汇编是mov ecx,DS:[eax]
;证明了对于寄存器, 不加[]取的是寄存器中的储存的值
;而加[]是将其中的值解释为地址
;(BX)=1F23H
;(1F23H)=3
;(BL)=23
MOV 	[BX], BL
;执行后(1F23H)=BL=23
;即将BX中的值解释为地址 并将BL的值传递给该地址

对于LEA:

mov eax,2
lea ebx,[eax]
;执行后ebx=2
mov ebx,eax
;等同于上句
lea ebx,eax
;编译器报错: error A2070: invalid instruction operands
;证明了lea指令对于寄存器, 加[]取得是寄存器中的值
num dword 2
lea ebx,num
lea eax,[num]
; eax为num的地址,而ebx==eax
;证明了lea指令对于符号地址, 加不加[]效果相同 

关于汇编中的立即数:

  • 汇编中默认的立即数为10进制, 使用16进制需要特别声明
  • 而针对16进制, 当首位为字母时, 需要在前头补0

如:

MOV	AL, 0ABCDH	;必须加0, 否则报错

关于串处理指令:

由于串处理指令中使用的默认寄存器是:
SRC string: DS:SI
DST string: ES:DI
注意此处的DST使用的是ES前缀, 所以必须要设置ES
即将DST定义的segment name存到ES中

DATA 	SEGMENT
	S1 		DB		'personal computer'
	S2 		DB 		'personal computer'
	MESS1	DB		'match.$'
	MESS2	DB		'no match.$'
DATA 	ENDS
...
	MOV		AX, DATA
	MOV 	DS, AX
	MOV 	ES, AX		;需要单独操作

关于Debug的应用:

Debug 是实模式(i7 8086K 8086模式)程序的调试工具。
使用它,可以查看 CPU 各种寄存器中的内容、内存的情况和在机器码级跟踪程序的运行。
Debug 的常用功能:
R 命令:查看、改变 CPU 寄存器的内容;
D 命令:显示寄存器中的内容;
E 命令:改写内存中的内容;
U 命令:将内存中的机器指令翻译成汇编指令;
T 命令:执行一条机器指令;
(只会用这个)
A 命令:以汇编指令的格式在内存中写入一条机器指令


汇编程序基础模板:

;******************
DATAS SEGMENT
;数据段, 用于变量的定义
DATAS ENDS
;******************
STACKS SEGMENT
;堆栈段, 当前程序暂时没有用到
STACKS ENDS
;******************
CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS	;assume只起声明的作用, 并不真正操作
START:
    MOV AX,DATAS	;将DATAS送ds寄存器, 才有用
    MOV DS,AX	
;******************

;主程序编写部分

;******************
    MOV AX, 4C00H	;相当于main函数最后的return
    INT 21H			;只有在程序需要结束时才使用, 平时使用int 21时并不需要
CODES ENDS
    END START		;标准格式

循环结构:

循环程序由三部分组成:

  • 设置循环的初始条件
  • 循环体
  • 循环控制部分:
    计数控制、特征值控制、地址边界控制

单循环:

循环输出BX内储存的值:

		MOV CH, 4		;循环控制
rotate:	
		MOV CL, 4		;每次移位次数为4
		ROL	BX, CL		;移位指令
		MOV	AL, BL		;将移位后BX的第8位赋给AL
		AND AL, 0FH		;将AH置零, 由于计算机最低只能进行字节操作, 这里需要4bit操作, 所以这么整
		ADD AL, 30H		;转换为ASCII码
		CMP AL, 3AH		;将小写a~f转化为大写A~F
		JL	printit		;跳转指令
		ADD AL, 7		;如果为a~f, 则转化为大写
printit:
		MOV DL, AL		;显示输出的入口参数
		MOV AH, 02H		;显示输出的功能号
		INT	21H			;CPU中断
		DEC CH			;循环控制
		JNZ	rotate		;跳回程序, 完成循环

把Y中1的个数存入COUNT单元中

;***************
DATAS 	SEGMENT
	number 		dw 	78a4h	;这玩意就是Y
	address 	dw 	number
	count 		dw 	?
DATAS 	ENDS
;***************
CODES 	SEGMENT
	ASSUME 	CS:CODES, DS:DATAS
START:
	MOV 	AX, DATAS
	MOV 	DS, AX
;***************
	MOV 	CX, 0			;重置CX,用于后头的计数
	MOV 	BX, address		;将address中的值传给BX
	MOV 	BX, [BX]		;将BX中的值指向的内存空间中的值传递给BX
	;执行后(BX)=78a4H
REPEAT1:	
	TEST 	BX, 0FFFFH		;AND一下, 主要是刷新FLAGS, 用于后头的判定
	JZ		EXIT1			;检测BX中的1是否全都移出了, 满足则代表循环结束
	JNS 	SHIFT			;通过符号位判定最高位是否为1
	INC 	CX				;如果为1, 则CX++
SHIFT:	
	SHL 	BX, 1			;逻辑左移1位
	JMP 	REPEAT1			;建立循环
EXIT1:	
	MOV 	CX, count		;最后将CX中的结果装入count中
;***************
	MOV		AX, 4C00H
	INT  	21H
CODES 	ENDS
	END START

插入排序:

;***************
DATAS 	SEGMENT
	X			DW	?			;-1
	ARRAY_HEAD 	DW 	3,5,15,23,37,49,52,65,78,99
	ARRAY_END 	DW 	105
	N 			DW	32
DATAS 	ENDS
;***************
CODES 	SEGMENT
	ASSUME 	CS:CODES, DS:DATAS
START:
	MOV 	AX, DATAS
	MOV 	DS, AX				;基本操作
;***************
	MOV 	AX,N				
	MOV 	X,-1				;执行后(X)=0FFFFH
	MOV 	SI,0				;初始化下标
COMPARE:
	CMP 	ARRAY_END[SI],AX	;将array中的数从后往前与N比较
	JLE 	INSERT				;如果array[si]<N, 则插入N
	MOV 	BX,ARRAY_END[SI]	;否则将array[si]后移动一位
	MOV 	ARRAY_END[SI+2],BX	
	SUB 	SI,2				;改变下标, array是DW,所以SI-=2
	JMP 	COMPARE				;跳转达成循环
INSERT:
	MOV 	ARRAY_END[SI+2],AX	;在已经空出的位置插入N
;****************
	MOV		AX, 4C00H
	INT  	21H
CODES 	ENDS
	END START

多重循环:

冒泡排序:

//CPP实现
    for (i=0; i<n-1; ++i)  //比较n-1轮
 	{
        for (j=0; j<n-1-i; ++j)  //每轮比较n-1-i次,
        {
            if (a[j] < a[j+1])
            {
                buf = a[j];
                a[j] = a[j+1];
                a[j+1] = buf;
            }
        }
    }
;***************
DATAS 	SEGMENT
	A 	DW  	5, 8, 16, 32, 84
	N  	DW 		5
DATAS 	ENDS
;***************
CODES 	SEGMENT
	ASSUME 	CS:CODES, DS:DATAS
;***************
START:
	MOV 	AX, DATAS
	MOV 	DS, AX				;基本操作
;***************
	MOV 	CX,N		;将数组元素个数存放到CX
	DEC 	CX			;CX--
LOOPOUT:				;外层循环
	MOV 	DI,CX		;在DI中暂存外层循环数
	MOV 	BX,0		;BX作为数组下标, 初始为0
LOOPIN:					;内层循环	
	MOV	 	AX,A[BX]	;将数组的A[I]装入AX
	CMP	 	AX,A[BX+2]	;A[I]与A[I+1]比较
	JGE 	CONTINUE	;如果A[I]>=A[I+1]则跳过交换的步骤
	XCHG 	AX,A[BX+2]	;交换数组两个元素的值
	MOV 	A[BX],AX	;交换数组两个元素的值
CONTINUE:
	ADD 	BX,2		;循环控制: 下标++
	LOOP 	LOOPIN		;每次LOOP都使CX--
	MOV 	CX,DI		;重置CX, 即外层循环数
	LOOP 	LOOPOUT		;每次LOOP都使CX--
;***************
	MOV		AX, 4C00H
	INT  	21H
CODES 	ENDS
	END START

汇编附加段:

附加段用于数据的定义
但是实际上在8086中, 数据定义在附加段和数据段的作用是相同的, 只需要在使用时整对段地址就好, 即

;将对应的段地址存到段地址寄存器
MOV AX, DATA
MOV DS, AX
MOV AX, EXTRA
MOV ES, AX

但通常在附加段中保存大数据, 如串和数组

汇编的标号&标识符:

  1. 标号:
    为指令的符号地址
    长度限制31个字符

  2. 标识符:
    为变量, 常量等的符号地址
    长度通常也是31个字符




后头将Ch.6




Chapter VI: 子程序

躺雷记录:

过程定义伪操作PROC:

用于定义子程序(就是函数)

标准格式:

label PROC [attributes] [USES reglist], parameter_list
	...
label ENDP
  • label: 作为符号地址保存子程序的段地址
    与其他标识符的定义有相同的要求
  • PROC: 伪操作标志
  • ENDP伪操作结束标志
  • attributes: 子程序属性, 具体可以是以下任意内容
[distance] [langtype] [visibility] [prologuearg]

在这里插入图片描述

但是通常使用的只有distance:

  1. NEAR:
    提供段内调用
    当子程序与调用点定义在同一个段中时使用
  2. FAR:
    提供段间调用
    当子程序与调用点定义在不同的段中时使用
    但是当定义在同一个段中时也可以使用
    所以这是一个通用的选择

注意这两个控制的都是RET指令的返回方式

关于汇编中的start:

start为程序的入口, 程序加载到内存之后CS:IP会指向这个标号, 从START指向的指令开始运行

同时, start只是一个标号, 并没有强制的语法特定, 使用其他也可以…
如改成FUCK也是可以运行的…

子程序的定义位置:

由于上头的start程序入口的问题, 所以子程序不能定义在start & END start中

可以定义的位置有两个:

  1. 与start & END start定义在同一代码段中, 但是需要定义在其之前或其之后
    (类似于main与其他函数的关系)
  2. 可以定义在其他代码段

子程序的传参&返回值:

  1. 寄存器传参:
    类似于形参传递.寄存器法

    寄存器法就是将入口参数和出口参数存放在约定的寄存器中。

    • 优点:数据传递书读快、编程较方便、节省内存单元。

    • 缺点:当传递参数过多时候,由于寄存器个数有限,及寄存器的频繁使用,将导致寄存器不足。

    • 适用:参数较少的子程序

  2. 储存单元传参:
    类似于函数使用全局变量

    把入口参数和出口参数都放在既定的储存单元中

    • 优点:不占用寄存器、参数个数任意、每个子程序要处理的数据和送出的结构都有独立的存储单元

    • 缺点:但用一定数量的存储单元,增加编程中对变量定义的难度

  3. 堆栈传参:
    类似于传递变量指针

    堆栈法是利用堆栈来传递参数
    通常将变量的地址保存到堆栈中

    • 优点:参数不占用寄存器,和存储单元。参数存放在公共堆栈区,处理完后客恢复。参数个数一般不限

    • 缺点:由于参数和子程序混杂在一起,存取参数时候必须小心计算它在堆栈中的位置。要注意断点的保存和恢复

  4. 地址表传参:
    类似于传递变量指针

    这种方法是把参数组成的一张参数表放在某个存储区中,然后只要主程序和子程序约定好这个存储区的首地址和存放的内容,在主程序中将参数传递给地址表,在子程序中根据地址表给定的参数就可以完成操作。

伪操作equ:

EQU 伪指令把一个符号名称与一个整数表达式或一个任意文本连接起来
可以理解为define宏定义, 功能与其相似

格式:

name EQU expression
name EQU symbol
name EQU <text>
  • 第一种, expression 必须是一个有效整数表达式
  • 第二种, symbol 是一个已存在的符号名称,已经用 = 或 EQU 定义过了
  • 第三种, 任何文本都可以岀现在<…>内。当汇编器在程序后面遇到 name 时,它就用整数值或文本来代替符号。

例如:

//将几个DOS标志号和助记符相绑定
display 	equ 2h	
key_in 		equ 1h
doscall 	equ 21h

10进制到16进制的转换程序:

DECIHEX 	SEGMENT
	ASSUME 	CS: DECIHEX
;******************
DECIBIN 	PROC 	NEAR	;负责从键盘读取10进制数值
	MOV 	BX, 00H
NEWCHAR:
	MOV		AH, 01H		;DOS调用,键盘输入值
	INT 	21H
	SUB 	AL, 30H		;将读取的ASCII转化为数值
	JL 		EXIT		;如果小于30H,则代表不是0~9,直接退出
	CMP 	AL, 09H		;与09H比较
	JG 		EXIT		;如果大于09H,则代表输入的不是0~9,直接退出
	CBW					;将AL拓展到AX
	XCHG 	AX, BX		;将AX中新输入的数与BX中原有的结果交换
	MOV 	CX, 10		;将乘数存入CX预备
	MUL  	CX			;将AX中原有的数*10
	XCHG 	AX, BX		;将*10后的结果与BX交换,
	ADD 	BX, AX		;将新输入的值加到原有的值上
	JMP 	NEWCHAR		;输入新字符, 达成循环
EXIT:
	RET
DECIBIN 	ENDP
;******************
BINIHEX 	PROC 	NEAR	;负责将10进制转化为16进制并输出
	MOV 	CH, 4		
ROTATE:	
	MOV 	CL, 4		;设定ROL的移位次数为4
	ROL 	BX, CL		;将BX中的数循环左移4位, MSB的4位出现在LSB的4位中
	MOV 	AL, BL		;将BL转移到AL中用于后头计算
	AND 	AL, 0FH		;掩码覆盖MSB4位
	ADD 	AL, 30H		;将数值转化为相应的ASCII码
	CMP 	AL, 3AH		;检测是否大于9
	JL 		PRINTIT		;如果大于9,则为A~F
	ADD  	AL, 7		;转化为A~F
PRINTIT:
	MOV 	DL, AL		;将AL输出
	MOV 	AH, 02H
	INT 	21H
	DEC 	CH			;循环控制
	JNZ 	ROTATE		;跳回达成循环, 如果CH==0,则退出循环
	RET
BINIHEX 	ENDP
;******************
CRLF 		PROC 	NEAR 	;格式控制,输出回车与换行</br>
	MOV 	DL, 0DH		
	MOV 	AH, 02H
	INT  	21H
	MOV 	DL, 0AH
	MOV 	AH, 02H
	INT  	21H
	RET
CRLF 		ENDP
;******************
MAIN 	PROC 	FAR		;MAIN主程序
	PUSH 	DS			;由于是DOS调用Main,所以需要保存寄存器
	SUB 	AX, AX
	PUSH 	AX
	CALL 	DECIBIN		;执行几个子程序
	CALL 	CRLF
	CALL 	BINIHEX
	CALL 	CRLF
	RET
MAIN 	ENDP
;******************
DECIHEX 	ENDS
	END 	MAIN		;程序结尾必有的东西

输入16进制输出10进制:

程序框架:

本程序在main中调用各个子程序, 而main与几个子程序定义在同一个代码段中, 所以其他子程序为near

DISPLAY 	EQU	2H
KEY_IN 		EQU 1H
DOSCALL 	EQU 21H
;******************
HEXIDEC 	SEGMENT
;******************
MAIN	PROC 	FAR		;MAIN主程序
	ASSUME 	CS: HEXIDEC
START:
	PUSH 	DS			;由于是DOS调用Main,所以需要保存寄存器
	SUB 	AX, AX
	PUSH 	AX
	CALL	HEXIBIN		;执行几个子程序
	CALL 	CRLF
	CALL 	BINIDEC
	CALL 	CRLF
	JMP 	MAIN		;跳回MAIN达成死循环
	RET
MAIN 	ENDP
;*******************
HEXIBIN 	PROC 	NEAR;输入16进制ASCII字符并转化为16进制数值储存

	MOV 	BX, 0		;初始化BX
NEWCHAR:
	MOV 	AH, KEY_IN	;键盘输入
	INT 	DOSCALL
;0~9 ?	
	SUB 	AL, 30H		;判定输入的值是否在数字之前
	JL 		EXIT		;ASCII在数字之前, 直接结束循环
	CMP 	AL, 10D		;判定输入的值是否在数字之后
	JL 		ADD_TO		;如果小于10,则是0~9
;a~f ?
	SUB 	AL, 27H		;如果输入大于9,则跳转到字符a开始
	CMP 	AL, 0AH		;边界值a
	JL  	EXIT		;ASCII在a~f之前, 直接结束循环
	CMP 	AL, 10H		;边界值f
	JGE 	EXIT		;ASCII在a~f之后, 直接结束循环
	
;(BX)<-(BX)*16+(AX)
ADD_TO:	
	MOV 	CL, 4		;设置SHL移位次数
	SHL 	BX, CL		;逻辑左移
	MOV 	AH, 0		;AX高位置零
	ADD 	BX, AX		;将BX左移后空出的4位填入新输入的数值
;完成循环
	JMP 	NEWCHAR		;输入新字符,直到最后一个不满足条件才跳出
EXIT:
	RET
HEXIBIN 	ENDP
;*********************
;将BX中的数转换为10进制并输出
;按位取并转化为ACSII输出
BINIDEC 	PROC 	NEAR
	MOV 	CX, 10000D	
	CALL 	DEC_DIV		
	MOV 	CX, 1000D	
	CALL 	DEC_DIV		
	MOV 	CX, 100D	
	CALL 	DEC_DIV		
	MOV 	CX, 10D		
	CALL 	DEC_DIV		
	MOV 	CX, 1D		
	CALL 	DEC_DIV		
	RET
BINIDEC 	ENDP
;****************

;****************
;被除数		BX
;除数		CX
;商			AX 	
;余数		DX 
DEC_DIV 	PROC 	NEAR
	MOV 	AX, BX			;将被除数拷贝到AX中执行运算
	MOV 	DX, 0			;DX初始化
	DIV 	CX				;除以CX,按位取出BX中的10进制数
	MOV 	BX, DX			;将余数丢到BX中重新作为除数
	MOV 	DL, AL			;将商丢到DL中
	ADD 	DL, 30H			;转化为ASCII数字
	MOV 	AH, DISPLAY		;召唤DOS显示
	INT 	DOSCALL
	RET
DEC_DIV 	ENDP
;*****************
CRLF 		PROC 	NEAR 	;格式控制,输出回车与换行</br>
	MOV 	DL, 0DH		
	MOV 	AH, 02H
	INT  	21H
	MOV 	DL, 0AH
	MOV 	AH, 02H
	INT  	21H
	RET
CRLF 		ENDP
;******************
HEXIDEC 	ENDS
;******************
	END 	START

ASCII码表:

在这里插入图片描述

上机程序分析:

都是之前的程序拼起来的

实验4:

DATA	SEGMENT
	CRLF_STR	DB	13,10,'$'
	X			DW	-1
	ARRAY_HEAD	DW	5H,10H,18H,22H,2AH,3CH,45H,58H
	ARRAY_END	DW	6FH
	N			DW	?
	COUNT		DW	10
DATA	ENDS
;*******************
CODE	SEGMENT
;*******************
MAIN		PROC	FAR
	ASSUME	CS:CODE,DS:DATA
	PUSH 	DS
	SUB 	AX, AX
	PUSH 	AX
	MOV		AX,DATA
	MOV		DS,AX
;*******************

	CALL	HEXIBIN
	CALL	CRLF
	CALL	INSERT_ARR
	CALL	PRINT_ARR
	MOV		AX,4C00H
	INT		21H
MAIN	ENDP
;*******************
HEXIBIN	PROC	NEAR	;输入16进制数值并转化为ASCII码
	MOV		BX,0
NEWCHAR:	
	MOV		AH,1H
	INT		21H
	SUB		AL,30H
	JL		EXIT
	CMP		AL,10D
	JL		ADD_TO
	SUB		AL,27H
	CMP		AL,0AH
	JL		EXIT
	CMP		AL,10H
	JGE		EXIT
ADD_TO:		
	MOV		CL,4
	SHL		BX,CL
	MOV		AH,0
	ADD		BX,AX
	JMP		NEWCHAR
EXIT:	
	RET
HEXIBIN	ENDP

;*******************
INSERT_ARR 	PROC	NEAR	
	MOV 	AX,BX				;
	MOV 	X,-1				;执行后(X)=0FFFFH
	MOV 	SI,0				;初始化下标
COMPARE:
	CMP 	ARRAY_END[SI],AX	;将array中的数从后往前与N比较
	JLE 	INSERT				;如果array[si]<N, 则插入N
	MOV 	BX,ARRAY_END[SI]	;否则将array[si]后移动一位
	MOV 	ARRAY_END[SI+2],BX	
	SUB 	SI,2				;改变下标, array是DW,所以SI-=2
	JMP 	COMPARE				;跳转达成循环
INSERT:
	MOV 	ARRAY_END[SI+2],AX	;在已经空出的位置插入N
	RET
INSERT_ARR 	ENDP
;*******************
PRINT_ARR 	PROC	NEAR
	MOV		CX,COUNT
	MOV		SI,0
OUTPUT:	
	MOV		BX,ARRAY_HEAD[SI]
	ADD		SI,2
	PUSH	CX
	CALL	BINIHEX
	MOV		DL,32
	MOV		AH,2
	INT		21H
	POP		CX
	DEC		CX
	JNZ		OUTPUT
	RET
PRINT_ARR	ENDP
;*******************
BINIHEX		PROC	NEAR
	MOV		CH,4
ROTATE:		
	MOV		CL,4
	ROL		BX,CL
	MOV		AL,BL
	AND		AL,0FH
	ADD		AL,30H
	CMP		AL,3AH
	JL		PRINTIT
	ADD		AL,7
PRINTIT:
	MOV		DL,AL
	MOV		AH,2
	INT		21H
	DEC		CH
	JNZ		ROTATE
	RET
BINIHEX	ENDP
;*******************
CRLF	PROC	NEAR
	MOV 	DL, 0DH		
	MOV 	AH, 02H
	INT  	21H
	MOV 	DL, 0AH
	MOV 	AH, 02H
	INT  	21H
	RET
	RET
CRLF	ENDP
;*******************
CODE	ENDS
;*******************
	END	MAIN

试卷组成:

填空 & 选择
每个2分, 总共50

程序填空
15空, 30分

编程题
2题10分
都是上课讲过的程序

刷题坑点整合:

80X86的数据储存方式:

80X86的CPU绝大多数是用小端模式进行存储
而ARM绝大多数都是大端存储

小端模式:

将数据的高位放在低字节, 低位放在高字节
取数据时, 向低字节方向进行解析

大端模式:
和小端模式相反

将数据的高位放在高字节, 低位放在低字节
去数据时, 向高字节方向进行解析

所以有如下代码:|

DATA	SEGMENT
	TABLE   DW   10H,20H,30H,40H,50H,60H,70H,80H
	ENTRY      DW   5
DATA	ENDS
;*******************
CODE	SEGMENT
	ASSUME 	CS: CODE, DS: DATA
START:
	MOV 	AX, DATA
	MOV 	DS, AX
;*******************
	MOV  	BX, OFFSET  TABLE
	MOV 	CX, 10
RE:
	MOV  	AX, [BX]
	ADD  	BX, 1
	LOOP 	RE
;*******************
	MOV 	AX, 4C00H
	INT 	21H
CODE	ENDS
;*******************
	END	START

每次MOV AX, [BX]后, AX的值为:

0010, 2000, 0020, 3000, 0030, 4000 …

MOV补充:

MOV     [BX],10H 	;MOV实际上不支持这种操作, 但是在编译器中是可以通过的

;必须在前头说明地址的数据类型:
MOV		WORD PTR[BX], 1001H	;正确
;因为立即数无类型, 所以需要显式说明

实际上相当于DST为储存器寻址方式, SRC为立即数寻址方式

关于算数指令:

不可以使用立即数的指令:

  • 除法: DIV & IDIV
  • 乘法: MUL & IMUL

而加法和减法都可以使用立即数

关于数值回送操作符:

总之, 滚回去再看, 以为不考, 都忘了

SEG补充:

MOV BX , SEG oper1

其oper1只能是variable或label, 不能是其他的任何东西, 即使使用的是variable或label的地址也不行

如:

MOV 	AX, OFFSET ARR
MOV 	BX, SEG [AX]	;还是报错

关于寻址方式:

你以为不会考吗?
滚回去看!

关于双精度数的比较:

首先, 汇编中所有的数都默认当做是有符号数, 即使有无符号完全依靠程序员的解释

所以, 对于有符号双精度数的比较

  • 高位使用有符号的比较法
    LESS & GREATER 系列JMP
  • 低位使用无符号的比较法
    BELOW & ABOVE 系列的JMP

如:

	CMP 	DX, BX
	JL 		LABLE1	;符号位在高字节
	JG		LABLE2
	CMP 	AX, CX
	JB 		LABLE1	;低字节相当于无符号位
	JAE 	LABLE2

关于8086寻址:

注意, 之前给出的EA公式不是白给的!

EA(effective address) = 基址 + (变址 * 比例因子) + 位移量

8086几个地址要点:

  1. 最后得到的EA一定要是TMD20位, 否则就TM各种报错!

  2. 段地址一定要使用段寄存器段寄存器, 否则报错
    (包含隐藏的默认使用段寄存器的情况)
    如:

    MOV 	1234H:2H, 2	;报错
    
    ;而这种方法就OK:
    MOV 	AX, 1234H
    MOV 	DS, AX
    MOV 	DS:2H, 2
    
  3. 除了段寄存器中的段地址, 后头所有的都TM属于偏移地址
    而偏移地址都TM需要一个中括号[]

    而能够出现在中括号之中的, 只有那4个寄存器, 和立即数
    BX, BP, SI, DI, 立即数

    其他任何东西要是出现, 狗腿给你打断

  4. 各种隐含段寄存器的情况:
    主要用作计算物理地址的题

    • 访问指令时:
      默认的段寄存器为CS

    • 访问堆栈时:
      默认的段寄存器为SS

      注意, 当偏移地址中有BP时, 也视作访问堆栈, 其默认寄存器也是SS

    • 访问数据时:
      默认的段寄存器为DS

    • 访问目的串时:
      默认的段寄存器为ES

发布了17 篇原创文章 · 获赞 7 · 访问量 1353

猜你喜欢

转载自blog.csdn.net/qq_42683011/article/details/102792194