C程序如何在后台传递参数?

C程序如何在后台传递参数?,c,assembly,compilation,stack,pdp-11,C,Assembly,Compilation,Stack,Pdp 11,这是PDP-11代码混合C和汇编。在下图中,u.u_rsav是一个数组指针 savu(u.ursav) 此函数的汇编代码为 _savu: bis $340,PS mov (sp)+,r1 mov (sp),r0 mov sp,(r0)+ mov r5,(r0)+ bic $340,PS

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

savu(u.ursav)

此函数的汇编代码为

_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(堆栈指针)不会恢复到原始值。它仍然指向参数存储在堆栈中的位置。

它不是C,而是约定(通常有多个语言实现或编译器遵循同一ABI,过去在同一系统上有多个具有不同ABI约定的编译器)。它是特定于体系结构和操作系统的。顺便说一句,你是ABI的一部分

例如,请参见

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

我的难题是,在汇编代码跳回调用点之前,sp(堆栈指针)不会恢复到原始值

某些ABI或调用约定要求被调用函数还原堆栈指针。其他人希望调用函数来实现这一点。

它不是C,而是约定(通常有多个语言实现或编译器遵循相同的ABI,过去在同一系统上有多个具有不同ABI约定的编译器)。它是特定于体系结构和操作系统的。顺便说一句,你是ABI的一部分

例如,请参见

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

我的难题是,在汇编代码跳回调用点之前,sp(堆栈指针)不会恢复到原始值


某些ABI或调用约定要求被调用函数还原堆栈指针。其他人希望调用函数能够做到这一点。

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

int printf();
int printf(fmt)

char *fmt;

{
    /* function body */
}
定义是这样开始的:

int printf();
int printf(fmt)

char *fmt;

{
    /* function body */
}
然后调用方就可以执行(例如)

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

为了让事情更清楚,这不仅仅是变量函数,在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;
}

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

int printf();
int printf(fmt)

char *fmt;

{
    /* function body */
}
定义是这样开始的:

int printf();
int printf(fmt)

char *fmt;

{
    /* function body */
}
然后调用方就可以执行(例如)

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

为了让事情更清楚,这不仅仅是变量函数,在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;
}

每个架构都有自己的约定,记录在相应的ABI中。为您的案例找到一个。这是
调用
指令之前的原始位置。带有堆栈参数的C调用约定通常使用调用方pops约定。我肯定会在PDP-11上看到这一点,因为早期的C通常不使用原型,因此被调用方可以轻松地传递一个额外的参数(被调用方不知道如何弹出),而不会出现编译时错误。但是调用者pops约定对此没有问题,因此它们适用于
printf
和其他可变函数。除了Eugene Sh提到的ABI之外,对于某些CPU架构,调用函数和传递参数的约定甚至可能因编译器供应商而异。非主题,因为需要外部资源(PDP11的ABI约定)每个体系结构都有自己的约定,记录在相应的ABI中。为您的案例找到一个。这是
调用
指令之前的原始位置。带有堆栈参数的C调用约定通常使用调用方pops约定。我肯定会在PDP-11上看到这一点,因为早期的C通常不使用原型,所以callee可以很容易地传递一个额外的arg(被叫方不知道如何弹出)没有编译时错误。但是调用方pops约定没有问题,因此它们适用于
printf
和其他可变函数。除了Eugene Sh提到的ABI之外,对于某些CPU架构,调用函数和传递参数的约定甚至可能因编译器供应商而异。离题,since请求外部资源(PDP11的ABI约定)此答案不独立,并且不在不相关的ABI补充的顶部链接上。请修改以实际回答问题,或者作为评论发布。@fuz好的,问题是“C程序如何在引擎盖下传递参数?”还有什么要说的,因为这不是关于C,而是关于ABI。我不知道怎样才能更具体地给出答案。至于PDP-11是否有呼叫者/被呼叫者推送pop等,我确信RTFM中提到了为该硬件编译所需的任何恐龙编译器——无论谁对软件考古学感兴趣你可以自己去读。你上一篇补遗上写着“这取决于你找到你的答案。”