【汇编语言与计算机系统结构笔记15】子程序设计:调用与返回,保护与恢复寄存器,子程序的参数传递,堆栈平衡,结构伪操作 STRUC
本次笔记内容:
20.子程序设计-1-1
21.子程序设计-1-2
22.子程序设计-1-3
注:我找到了对应内容的课件,请见我于{GitHub的CS笔记仓库](https://github.com/PiperLiu/CS-courses-notes)。因此,为了节省时间,我只记录老师上课强调的内容与对应ppt页码。
本节课对应幻灯片:汇编语言程序设计-循环与分支,第1页起。
上节课第 5 章刚刚结束,进入第 6 章“子程序结构”。视频一共三节课,第一节30分钟。其中,第一节老师讲了讲高级的汇编语言规则(高版本汇编器识别),包括标号的作用域、循环伪指令等等。
如图,并没有 ppt ,课件资源里也没有,因此本节的前 1/3 只能选择性跳过。
前1/3内容如标号决定作用域:过程、全局还是其他
等等。
文章目录
P2 主要内容
- 过程定义伪操作
- 子程序的调用与返回
- 保存与恢复寄存器
- 子程序的参数传送
(汇编语言来讲,参数传递我们亲自来做)
- 子程序的嵌套与
递归(比高级语言麻烦一些)
P3- 过程定义伪操作
(1)NEAR属性:调用程序和子程序在同一代码段中(段内调用)
(2)FAR属性:调用程序和子程序不在同一代码段中(段间调用)
如上,我们定义的过程名字是我们自己写的。习惯上,将主程序命名为 main
。注意段内调用与段间调用的区别。段间调用,定义了两个 segment 。
P5 子程序的调用与返回
段间调用,因为短地址改变了,一定是先压入段地址,之后再压IP。
ret 后可以是立即数:
- 对于实模式,必须是偶数;
- 对于保护模式,4、8、12这种。
- 后面会讨论具体什么意思。
P6 保存与恢复寄存器
一般,要把用到的寄存器保存起来。push和pop都成对的。
P7 子程序的参数传递
- (1) 通过寄存器传送参数
- (2) 通过存储器传送参数
- (3) 通过地址表传送参数地址
- (4) 通过堆栈传送参数或参数地址
- (5) 多个模块之间的参数传送
P8- 例:十进制到十六进制的转换(通过寄存器传送参数)
P10- 例:十六进制到十进制的转换(通过寄存器传送参数)
P12- 例:累加数组中的元素(通过存储器传送参数)
注意,基本不用这种方法,因为不可复用。
因此引出下面的,地址表传参
的例子。
P14- 例:累加数组中的元素(通过地址表传送参数地址)
如上,应该把地址表的地址给bx,再调用某个数时,就不用“直呼其名”了。
如上是子程序与内存中的样子。
P16 通过堆栈传送参数或参数地址
实际上,用的多的,也是用堆栈传参
。堆栈其实也是内存的一块区域。高级语言用的也是堆栈传参。
下面,举个例子看看堆栈段
传参。
P17- 例:累加数组中的元素(通过堆栈传送参数地址)
如上,在汇编中,可以先用,后定义。
在堆栈段中,要了 200 个字节。st
初值00c8
。
一般来说,一段程序里,有几个 push,就应该有几个 pop 。红字上面的两个 push ,对应 push ds 与 push 0,是与 ret 对应的(一般来说,ret相当于两个 pop)。
但是红字额外多了3个push?看起来,没弹出去?实际上,可以在proadd这个过程中弹出去。
如上,出现了一个代立即数的返回:
- 调用 ret 前,指向 ip 的位置;
- ret 是两个 pop,pop掉了 ip 与 cs ;
- ret 6 表示,自动跳过 6 个字节(
0000, 0014, 0016
)。
如果就写了 ret ,那这 3 个字,则交给主程序处理。
这个叫堆栈平衡
,不同模式下,堆栈平衡由不同程序处理。
此外,老师又举了不少例子;没有ppt,有些无奈。
P20- 结构伪操作 STRUC
定义一种可包含不同类型数据的结构模式。
如上,并没有用子程序定义变量。
接下来举了一个例子,累加数组中的元素(通过堆栈传送参数地址)。
如上,可以不用[bp+0ah]
这种形式,可以使用[bp].par3_addr
这种形式。
这适于下节课的递归中的“帧”内容,其调用时递归的,有规律的。