Crazyharp

竖琴


  1. 1. 二进制运算
  2. 2. 寄存器
    1. 2.1. 通用寄存器:寄存运行时产生的数字
    2. 2.2. 16位寄存器:常做地址相关
    3. 2.3. 常见的内存类型记号
  3. 3. MOV指令
    1. 3.1. 形式化指令格式
    2. 3.2. 寻址方式
    3. 3.3. 段与偏移量
    4. 3.4. 命名
    5. 3.5. 写法
  4. 4. 栈相关指令
    1. 4.1. PUSH
    2. 4.2. POP
    3. 4.3. AD命令:全部寄存器出入栈
  5. 5. 累加器指令
  • Home
  • About
  •   

© 2025 Crazyharp

Theme Typography by Makito

Developed by Crazy_Harp

Proudly published with Hexo

汇编学习

Posted at 2025-09-17 Comments 学习 

本文共2k字,阅读需要约7分钟

本学期的内容其实都是挺新鲜的知识,秉持着不听课的优良传统看书自学。但是汇编的书编写的太过分了,头次看实在难以直观的看到重点和思考角度,复习也没法一目了然的看到知识结构。于是顺手就写了。

二进制运算

学了无数遍了好烦啊,回头看考研课的时候统一写一下吧。

寄存器

常见的寄存器如下:

通用寄存器:寄存运行时产生的数字

AX,BX,CX,DX,他们全是16位,支持双字读取,也支持单字节读取,这时写为AH,AL表示高位,低位。
这几个寄存器又有各自的特殊作用复用:
A(accumulate)用作累加器,IO功能使用
B(base)常用作基址寄存器
C(count)保存计数值,计数器
D(data)双字长运算的时候做高位,做IO端口地址
在四个通用寄存器复用中,BX寄存器可以作为基址寄存器是架构上的允许特性,其他三个则是约定俗成的规则,不具有硬性约束力。

16位寄存器:常做地址相关

SP,BP,SI,DI:他们也是16位,不同于其他通用寄存器,没有单字访问的能力。因此常用于表示地址相关的内容,具体如下
SP(stack pointer)堆栈指针
BP (base pointer)基址指针
DI (destination index)目的变址寄存器
SI (sourse index)源变址寄存器
IP(instraction pointer)指令指针寄存器,指向下一条指令的偏移量
他们往往配合以下段寄存器使用
CS:代码段寄存器,与IP连用获得下一条指令的位置
DS:数据段寄存器,指向数据段头与DI,SI连用,表达数据段中内存位置。
SS:堆栈段寄存器,与SP连用表示堆栈中内存位置。
ES:额外段寄存器,与DI连用,指向额外数据段。
es寄存器有很多位,功能各不相同,需要时查表吧。
还有一个表示状态的特殊寄存器
FLAG:表示程序状态的寄存器,位数同样很多而且各有作用。

命名好乱……背后定有历史包袱。

常见的内存类型记号

教材这里写的超级晚……附录也没声明,想找还是散装的……

mem:储存元件
reg:寄存器
ac:累加器
segreg:段寄存器

MOV指令

书上写了一大堆屋檐了,穷举了一堆之后才给形式化声明,简直倒反天罡。

形式化指令格式

$$
MOV ,DST , SRC
$$
将SRC内容塞进DST里面
其中DST:mem,reg,ac,segreg,
SRC:mem,reg,data,segreg

寻址方式

要说mov,对于学习者最重要的就是理解汇编的内存寻址方式,因为汇编是非常底层的语言,可以按照物理地址来选定内存。寻址方式如下:
实际上,汇编的寻址方式和C语言十分类似。采用基准+偏移量的形式寻找,类比到C语言中,就是指针访问数组与下标访问等价,a[5]== *(a+5)
对于指定定点,有如下表示方法:

  1. 直接指定常量(不调用内存而是记录常量)
  2. 寄存器:寄存器是有名字的内存,可以直接指名访问
  3. 基址+(变址*比例因子)+位移量
    其中最后一种较为常见,对以下术语做出阐释
    基址:指定的其实位置,可以是段/寄存器等,放在基址寄存器里(类比数组名)
    比例因子:扩大访问范围的缩放因子,可以一定程度上扩大16位的限制。
    变址:也就是所谓的偏移量(类比下标)
    位移量:查询的数据字长,指定位0,8,16(16位),0,8,32(32位)(类比数据类型)
  • 必须明白的事实:每一个程序包括的寄存器一般是独立的(系统足够复杂的情况下),于是各有自己的指令域,数据域,堆栈
    因此,所有的位移量都是在DS(数据段寄存器)作为默认基址的前提下进行的。如果基址不是DS,可以显式的指定为其他的段寄存器。如ES:2000H即表示在ES作为基址的前提下偏移2000H个字长。
  • 基址寄存器(有默认)+(变址寄存器)*(比例因子)+(指定偏移常量)+(指定位移量)

段与偏移量

8086只有16位字长,也就是说对于最多访问2e16的内存,也就是64K的内存单元,但是这样显然不够,因此,对于1M的内存单元,将其拆为64K份,每一份称为段。所以段的定义就是内存的种寻址上的单位,因为1M=2e20=2e16*2e4,所以一个段内有16位,这样,使用两个16位数就可以指出更多内存单元,计算公式为物理地址=段首地址<<4+偏移量。当然,这样可能会出现一个内存单元有多种表示的问题,这是完全合法的。
因此,对于一个内存就有了新的存取单位和表示方法,所以设置寄存器记录段首位置,一个寄存器计算偏移量。

命名

存在变址寄存器:在名字里加一个“变址”
存在常量偏移量:在名字里加一个“相对”
只有一个常量偏移:直接寻址
存在基址+变址的格式:基址变址寻址
换言之,“直接”就是指定明确的位置,以当前数据段为基准的偏移,”相对“就是依照某个变址寄存器的位置作为偏移基准的常量偏移。两者的分别是以谁为基准。可以类比数轴。
特殊的,如果没有常量偏移量,只有两个寄存器之间运算,则是单独命名为”基址变址寻址“,此时再加入常量偏移,则引入了”相对“。
还有一种80086不支持的比例写法,就是引入上述的“比例因子”,这里8086不支持乘法,但是依然介绍,在名字里引入“比例”

写法

这里注意一个运算符号“[]”
在汇编中,这个符号表示:括号内部的内容看作内存地址。(类比C中的指针解引用)

  • 有两种等价写法:[A][B][C]== [A+B+C]
  • 对于8086,[]不支持三运算符,所以最多COUNT[BX][DI]的两寄存器常数的形式。
  • 括号内寄存器仅限基址和变址寄存器

栈相关指令

PUSH

形式化格式: PUSH SRC
SRC:mem reg segreg data
将SRC进栈,值得一说的是,汇编中的栈入栈顺序是由高位到低位,即完成以下步骤:
sp<- sp-2
sp+1,sp <- src
可见栈方向由高到低

POP

形式化格式: POP DST
DST: mem reg seg

  • 不允许立即直接寻址
  • 出于保护程序的目的,当DST是segreg时,不能为CS
    这里包括了取得栈顶元素并弹出两个步骤。
    等价到CPP是如下代码
stack<T> st;
st.push(x)
T temp=st.head();
st.pop()

AD命令:全部寄存器出入栈

仅作标记存在。

累加器指令

IN 输入
OUT 输出
XLAT(translate) 换码
形式化格式
$$
\begin{align}
IN ,,, AX/AL ,,, PORT \newline
OUT ,,, PORT,,, AX/AL
\end{align}
$$
两者都用来进行IO操作
XLAT指令用于多种编码格式之间的相互转换,诸如2进制转ACSII等,需要提前存在一个对照表。
形式化指令格式:XLAT
实际操作: AL <- ((BX)+(AL))
BX,AL是指定实际存在的两具体寄存器,等于查表。

实际上可以等价于若干条MOV指令

下一篇: LEA等地址运算

Share 

 Previous post: 漫展小游戏页面 Next post: Go语言语法学习 

© 2025 Crazyharp

Theme Typography by Makito

Developed by Crazy_Harp

Proudly published with Hexo