前言
本博文将讲解 80X86汇编中的 变址寻址,缘由是笔者对照 《80X86汇编语言程序设计_王元珍.pdf》学习时 遇到的困惑。比例因子 含义是啥 为啥要乘以它?
基本概念
相关概念和图片摘自《80X86汇编语言程序设计_王元珍.pdf》书中。
变址寻址:变址寻址方式的操作数放在主存储器中,其偏移地址EA是指令中指定寄存器的内容乘以比例因子后与给出的位移量之和。
笔者刚开始也不明白为啥要乘以比例因子F,反正就跟着书上例子代码敲敲 试试看!当然笔者出问题了。这里先抛结论,比例因子 意义是?笔者也是网络中找到的,感觉是那么回事。
就是用来寻址数组的,有些数组元素占用不止一个内存单元,所以在计算数组元素的地址时需要用这种方式来计算:
数组元素地址=数组首地址+元素索引 * 数组元素占用空间
比如一个字形的数组,它的首地址是6000H,那么它的第4个(索引从0开始)元素的地址就是:
6000H+4 * 2=6008H
在高级的CPU中,这种比例因子的寻址方式是在指令级别上提供支持的,所以可以直接用这种方式寻址:
mov ebx,offset a
mov edx,4
mov ax,[ebx+edx * 2]
示例程序
下面就是笔者 使用 书上的 例子2.2
【例 2.2】 某班 C 语言的考试成绩存放在以 CC 为首址的分数表中, 该班学生各门功课的考试成绩(总分)存放在以 TOTAL 为首址的总分表中, 设学生的学号分别为 0, 1, 2,3, …, 10H, 11H, …现要取出学号为 10H 的同学的 C 语言分数累加到它的总分中。 试用变址方式实现该程序。
下图为书上的伪代码。
下面代码是笔者 修改后的代码,可正常运行,注释写的很清楚。笔者这里改为取出3号同学的 C 语言分数累加到它的总分中。
; eg0213.asm in Windows Console
;某班 C 语言的考试成绩存放在以 CC 为首址的分数表中, 该班学生各门功
;课的考试成绩(总分)存放在以 TOTAL 为首址的总分表中, 设学生的学号分别为 0, 1, 2,
;3, …, 10H, 11H, …现要取出学号为 3 的同学的 C 语言分数累加到它的总分中。 试用
;变址方式实现该程序
include io32.inc
.data
cc dword 80,90,70,65 ; 0 ~ 3号 学生的各科C语言的成绩
total dword 5640,5000,4800,6000 ; 0 ~ 3号 学生的各科总成绩(不含C语言)
.code
start:
mov eax, 0 ;
; 书上写法,呵呵,一堆错误
;mov si, offset cc ; si为cc分数表指针
;mov di, offset total ; di为total分数表指针
;mov ax, 4*3[si] ; 取出3号的C语言的分数
;mov 4*3[di], ax ; 加到总分表中
; 修改后的写法
mov esi, offset cc ; esi为cc分数表指针
mov edi, offset total ; edi为total分数表指针
mov eax, [4*3][esi] ; 取出3号的C语言的分数 65-> 41H,常量乘法需要用[]包起来,这里实际上还是相对寻址,没有寄存器*比例因子。
add [4*3][edi], eax ; 加到总分表中,4*3:dword 4字节,3为学号为3
mov edx, [edi][4*3] ; 该总分也放到edx 方便确认
call disprd
sub [4*3][edi], eax ; 3号学生总分数据还原,方便对比!
; 我们换一种写法 变址寻址的方法
mov ecx, 3 ; 我们将学号放到寄存器中
mov eax, [ecx*4][esi] ; 取出3号的C语言的分数,ecx*4 + 偏移地址
add [ecx*4][edi], eax ; 加到总分表中 6065-> 17B1
mov edx, [ecx*4][edi] ; 该总分也放到edx 方便确认
call disprd
exit 0
end start