1

这是 PDP-11 代码混合 C 和汇编。在下面,u.u_rsav 是一个数组指针,

savu(u.u_rsav);

这个函数的汇编代码是

_savu:        bis     $340,PS
              mov     (sp)+,r1
              mov     (sp),r0
              mov     sp,(r0)+
              mov     r5,(r0)+
              bic     $340,PS
              jmp     (r1)

似乎在进入过程之前,它首先推送参数,然后推送返回点 PC 值。因此,r1 存储 PC,r0 存储参数。我的困惑是 sp(堆栈指针)在汇编代码跳回调用点之前没有恢复到原始值。它仍然指向参数存储在堆栈中的位置。

4

2 回答 2

6

在 C 中,尤其是任何 PDP-11 编译器都可能使用的 K&R C 中,被调用函数无法知道调用函数在堆栈上放置了多少参数。这就是 var args 函数过去的工作方式。例如,printf将这样声明stdio.h

int printf();

定义是这样开始的:

int printf(fmt)

char *fmt;

{
    /* function body */
}

然后调用者可以做(例如)

printf("%d %d\n", a, b);

因此,从堆栈中删除参数必须是调用函数的责任,而不是被调用函数。

为了让事情更清楚,它不仅仅是可变参数函数,在 K&R C 中,以下是完全合法的并且会打印 3。

int add();

int main()
{
    int sum;
    sum = add(1, 2, 3, 4);
    printf("%d\n", sum);
    return 0;
}

int add(a, b)
int a;
int b;
{
    return a + b;
}
于 2018-03-14T16:36:16.680 回答
-1

它不是 C,而是应用程序二进制接口约定(您通常有几种语言实现或编译器遵循相同的ABI,并且过去您确实在同一系统上拥有具有不同ABI 约定的各种编译器)。它是特定于体系结构和操作系统的。顺便说一句,调用约定是 ABI 的一部分。

例如,请参阅与 x86 相关的示例

您可以自行决定考古 PDP11 计算机(以及编译器和操作系统)的 ABI 约定,例如参见PDP11 FAQC 调用约定。一些 ABI 使用堆栈,在寄存器上有各种调用者安全/被调用者安全约定。

我的困惑是 sp(堆栈指针)在汇编代码跳回调用点之前没有恢复到原始值。

一些 ABI 或调用约定要求被调用函数恢复堆栈指针。其他人希望调用函数来做到这一点。

于 2018-03-14T14:57:27.113 回答