这是汇编代码:
ldc 5 // a
ldc 12 // b
bsr sumsquare
ajs -2 // delete parameters
ldr RR // result on the stack
stl 1 // store in a variable
....
sumsquare:
link 1 // 1 local variable
ldl -3 // a
ldl -3 // a
mul // a*a
ldl -2 // b
ldl -2 // b
mul // b*b
add // a*a + b*b
stl 1 // x
ldl 1 // x
str RR // store in RR (=result register)
unlink 1
ret
我想更改这段代码,以便将方法 sumsquare 的结果传递回堆栈。如果我是对的,我所要做的就是不将其存储在 RR 上,而是立即将其存储在变量 a 和 b 所在的堆栈上。所以我必须使用其他东西来代替 str RR。
指令集
最佳答案
调用者压入5
,然后压入12
,然后是返回地址,然后将控制权转移到sumsquare
,它使用形参 MP-3 处的 a
(实际值 5
)和 MP-2 处的 b
(实际值 12
)位于堆栈后面返回地址为 MP-1。从被调用者返回到调用者会将返回地址从堆栈中弹出,将实际参数 5
和 12
留在堆栈上,然后调用者将其从堆栈中弹出。
至少有三种可能的方法:
一种方法是让被调用者(函数)在函数结束时重新调整第一个形式参数的用途,方法是将返回值存储到 -3 处的形式参数 a
中,然后将调用者仅从堆栈中弹出第二个实际参数,而不是两个实际参数,将返回值留在堆栈上以供正常使用(即通过表达式求值,例如通过算术或赋值)。这种方法需要对零参数函数进行特殊处理。
下一个方法是传递一个虚拟参数,为返回值保留空间。虚拟参数将首先在 5
和 12
之前传递。被调用者不会将返回值存储到 -3 处的形参 a
中,而是将其存储到 -4 处的虚拟参数中。然后,调用者将按照原始参数将实际参数 5
和 12
从堆栈中弹出(但通常会消耗现在保存返回值的虚拟参数)。这种方法的优点是它更加常规(允许零参数函数像所有其他函数一样工作)。
另一种方法是更改调用约定,以便被调用者(函数)从堆栈中删除自己的形式参数,只将返回值留在堆栈上。为了做到这一点,它必须 (1) 将返回值存储在形式参数 a
的 -3 处,然后 (2) 将返回地址从当前位置 -1 移动到b
的位置为 -2,然后 (3) 将返回地址的旧副本从堆栈中弹出,并返回给调用者(弹出返回地址的新副本(又名 b
)离开堆栈,只将返回值留在堆栈上)。在这种情况下,调用者不会弹出实际参数,因为这是由被调用者完成的。这种形式要求函数在其末端做一些工作,但节省了调用站点的空间;这可以通过观察通常比函数本身更多的函数调用(函数由多个调用者调用)来合理化。 (有时会提供特殊的堆栈指令来更直接地执行此操作。)但是,这种形式对可变参数( variadic functions )不利(如果不知道任何给定函数是否可以是可变参数,则将无法工作)。
这种改组是通过共享单个堆栈来进行表达式求值和函数链接所必需的。
在不同的体系结构中,两个独立的堆栈将允许在表达式堆栈上保留返回值,同时仍然能够弹出链接以返回给调用者 - 尽管两个堆栈会增加硬件的其他开销。
在另一种架构方法中,会有一个寄存器或累加器,这就是返回值所在的地方。
关于assembly - 在汇编编程中如何将方法的结果传递回堆栈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58011178/