Как создать процесс, который запускает подпрограмму с переменным количеством параметров?

Я знаю, что здесь много вопросов о функциях, которые принимают переменное число аргументов. Я также знаю, что есть много документов о 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 делает что-то очень похожее на то, что я хочу сделать, но я изо всех сил пытался понять код и не добился успеха. Я расшифрую очень упрощенную версию Xinu's 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 ответ

Если вы пишете операционную систему, вы также определяете соглашение о вызовах правильно? Установите для аргументов размеры sizeof(void*) и pad, если необходимо.

Другие вопросы по тегам