c - 如何创建一个运行具有可变数量参数的例程的进程?

标签 c operating-system calling-convention process-management activation-record

我知道这里有很多关于采用可变数量参数的函数的问题。我还知道有很多关于 stdarg.h 及其宏的文档。我还知道类似 printf 的函数如何接受可变数量的参数。我已经尝试过所有这些替代方案,但它们对我没有帮助。因此,在将此问题标记为重复之前,请记住这一点。

我正在研究一个小型嵌入式操作系统的进程管理功能,并且一直致力于设计一个函数,该函数可以创建运行具有可变数量参数的函数的进程。以下是我希望 API 的简化版本:

// create a new process
// * function is a pointer to the routine the process will run
// * nargs is the number of arguments the routine takes
void create(void* function, uint8_t nargs, ...);

void f1();
void f2(int i);
void f3(float f, int i, const char* str);

int main()
{
    create(f1, 0);
    create(f2, 1, 9);
    create(f3, 3, 3.14f, 9, "string");

    return 0;
}

这是系统调用create实现相关部分的伪代码:

void create(void* function, uint8_t nargs, ...)
{
    process_stack = create_stack();
    first_arg = &nargs + 1;
    copy_args_list_to_process_stack(process_stack, first_arg);
}

当然,我需要知道调用约定,以便能够从 create 的激活记录复制到新的进程堆栈,但这不是问题。问题是我需要复制多少字节。尽管我知道需要复制多少个参数,但我不知道每个参数占用多少空间。所以我不知道什么时候停止复制。

Xinu Operating System做了与我想做的非常相似的事情,但我努力理解代码但没有成功。我将在这里记录 Xinu 的 create 函数的一个非常简化的版本。也许有人理解并帮助我。

pid32 create(void* procaddr, uint32 ssize, pri16 priority, char *name, int32 nargs, ...)
{
    int32        i;
    uint32      *a;     /* points to list of args   */
    uint32  *saddr;     /* stack address        */

    saddr = (uint32 *)getstk(ssize); // return a pointer to the new process's stack

    *saddr = STACKMAGIC; // STACKMAGIC is just a marker to detect stack overflow

    // this is the cryptic part
    /* push arguments */
    a = (uint32 *)(&nargs + 1);     /* start of args        */
    a += nargs -1;                  /* last argument        */
    for ( ; nargs > 4 ; nargs--)    /* machine dependent; copy args */
        *--saddr = *a--;            /* onto created process's stack */
    *--saddr = (long)procaddr;
    for(i = 11; i >= 4; i--)
        *--saddr = 0;
    for(i = 4; i > 0; i--) {
        if(i <= nargs)
            *--saddr = *a--;
        else
            *--saddr = 0;
    }
}

我被困在这一行:a += nargs -1;。这应该将指针 a 4*(nargs - 1) 在内存中向前移动,对吧?如果参数的大小不是 4 个字节怎么办?但这只是第一个问题。我也不明白接下来的代码行。

最佳答案

如果您正在编写操作系统,您还定义了调用约定,对吗?根据需要确定 sizeof(void*) 和 pad 的参数大小。

关于c - 如何创建一个运行具有可变数量参数的例程的进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49290078/

相关文章:

c++ - Makefile——高效编译

c - 程序不读取循环中的最后一个字符

c - 线程程序与Goto

memory - 编译器如何在内存中布局代码

linux - 堆管理

c - 程序可以在 Dev-C++ 上运行,但不能在 GCC 上运行

operating-system - Mellanox 中断 mlx4-async@pci :0000 . .. 是什么意思?

c++ - 如何指定 vc11 lambda 调用约定

c++ - `extern "C"`是函数类型的一部分吗?

pointers - 我们是否在 Go 中过度使用了传递指针?