... почему вызов 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 тоже могли бы сделать это по-другому.