题目说明:
调用
调用宏用于调用函数。它应该准备好调用的堆栈,
跳转到给定的函数标签,然后在调用后恢复状态。
在调用之前,可能会将零个或多个值放置在堆栈上。
占位符参数计数是参数的数量。
调用约定需要三个共享内存插槽:
ARGS = 1
当前函数参数的地址
LOCALS = 2
函数的本地存储地址
RETVAL = 6
从函数返回的临时值的插槽。
(这些插槽地址可以定义为共享常量以方便使用。)
步骤:
将ARGS的当前值推送到堆栈上
推送LOCALS的当前值。
推送跳转后的地址(返回地址)。
计算一个新的ARGS地址,即当前SP减去参数计数减去3
(因为我们刚刚将三个值推送到堆栈上)。
跳转到由functionName占位符给出的地址。
执行函数调用后,控制将返回到跳转后的标签。
将当前ARGS值存储在临时插槽中。
从堆栈中恢复LOCALS值
从堆栈中恢复ARGS值
将SP设置为先前的ARGS值
将RETVAL推送到堆栈上
level help:
函数可能是软件中最重要的抽象之一。
函数是一段代码单元,接受一些输入(称为参数),
具有用于处理的一些本地存储,并返回一个值。
函数可以从程序中的任何位置执行(调用)。
当调用函数时,调用的地址被存储在堆栈上,
当函数完成时,它返回到调用它的地址。
参数和本地存储也存储在堆栈上。
函数需要三个部分共同工作:
Call:从程序的某处调用函数。
Function:函数的起始点
Return:函数的结束点。
这三个单元需要根据一个共享约定一起工作,
用于确定数据如何进出函数。
代码和注释:
相对于参考代码,加了前面的5个DEFINE
DEFINE ARGS 1
DEFINE LOCALS 2
DEFINE RETVAL 6
DEFINE SP 0
DEFINE TEMP 3
PUSH_STATIC ARGS //将ARGS的当前值推送到堆栈上
PUSH_STATIC LOCALS //推送LOCALS的当前值
PUSH_VALUE RETADDR //推送跳转后的地址(返回地址)
A = SP
D = *A
A = 3 //栈内放了3个值
D = D - A //栈顶减3
A = argumentCount //参数个数
D = D - A
A = ARGS
*A = D
GOTO functionName //跳转到由functionName占位符给出的地址
RETADDR: //执行函数调用后,控制将返回到跳转后的标签
A = ARGS
D = *A
A = TEMP
*A = D //将当前ARGS值存储在临时插槽中
POP_STATIC LOCALS //从堆栈中恢复LOCALS值
POP_STATIC ARGS //从堆栈中恢复ARGS值
A = TEMP
D = *A
A = SP //将SP设置为先前的ARGS值
*A = D
PUSH_STATIC RETVAL //将RETVAL推送到堆栈上
实际通过gcc、vc之类的编译器可以得到c语言的汇编代码