Как этот Kernel Call узнает, как получить его из регистра счетчиков? - PullRequest
0 голосов
/ 11 апреля 2019

Я пытаюсь изучить ассемблер, и могу заставить работать несколько примеров, но это загадочно.

Как ядро ​​узнает, что захватывает то, что находится в регистре ecx, как указатель на пользователя-пространство памяти для отображения на stdout

mov edx,9       ;message length
mov ecx, name   ;message to write
mov ebx,1       ;file descriptor (stdout)
mov eax,4       ;system call number (sys_write)
int 0x80        ;call kernel

Если edx является универсальным регистром данных, а eax является универсальным входным выходом, почему вызов ядра ожидает данных / выходных данных в регистре ecx?

Ответы [ 2 ]

2 голосов
/ 11 апреля 2019

Расположение аргументов является частью ABI.По https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux#Making_a_syscall:

Параметры передаются путем установки регистров общего назначения следующим образом:

Syscall # | Param 1 | Param 2 | Param 3 | Param 4 | Param 5 | Param 6
eax       | ebx     | ecx     | edx     | esi     | edi     | ebp

Return value
eax
1 голос
/ 11 апреля 2019

... почему вызов Kernal ожидает данных / вывода в регистре ecx?

Прерывание - это особая форма подпрограммы, которая работает аналогично подпрограмме-программа, которую вы вызываете, используя инструкцию call.

Когда вводится прерывание, первое, что нужно сделать, это push всех регистров в стеке.Это означает, что все регистры будут храниться в оперативной памяти (поскольку стек является оперативной памятью).

В Linux функция, написанная на языке программирования C, будет вызываться из кода ассемблера.

InЯзык программирования C struct может использоваться для доступа к данным, хранящимся в ОЗУ, если известно, как хранятся данные.И поскольку мы знаем, в каком порядке мы написали push инструкции в нашем коде ассемблера, мы можем определить struct, который можно использовать для доступа к данным в стеке:

struct registers {
    unsigned long ebx;
    unsigned long ecx;
    unsigned long edx;
    ...
    unsigned long eax;
    unsigned long eip;
    ...
}

ВНаписанная на C функция в ядре, теперь мы можем получить доступ к этой структуре для считывания значений регистра:

void systemCall_4(struct registers * regs)
{
    kernelFile * f;
    int (*pWrite)(kernelFile *,const void *,int);

    /* Get the file from the file handle */
    f = getFileFromHandle(regs->ebx);

    /* No such file */
    if(f == NULL)
    {
        regs->eax = ERROR_INVALID_HANDLE;
    }
    /* Call the device driver */
    else
    {
        pWrite = f->writeFunction;
        regs->eax = pWrite(f, (const void *)(regs->ecx), regs->edx);
    }
}

Программисты ядра решили определить, что ecx указывает на данные, а edx - это длина.

В MS-DOS (например) это наоборот: ecx это длина, а edx указывает на данные.Итак, вы видите, что разработчики Linux тоже могли бы сделать это по-другому.

...