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

时间:2018-03-15 01:16:23

标签: 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个字节怎么办?但这只是第一个问题。我也不了解代码的下一行。

1 个答案:

答案 0 :(得分:0)

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