2015-04-13 4 views
3

Я работаю с операционной системой xv6, и мой класс работает над внедрением сигналов для него.Машинный код в стеке пользователя - Операционные системы

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

Программа вызывает функцию сигнала, которая выглядит, как этот

signal(int signum, void (*handler)(int)) 

Программа пользователя, скажем, alarmtest3.c, передает свою пользовательскую функцию в качестве второго аргумента:

signal (14, snooze); // 14 is the signum for alarm 

Что мне нужно чтобы разобраться, один раз в сигнале, как заставить ядро ​​вызвать другой системный вызов sigret(). Я считаю, что этот системный вызов необходим для хранения копии ловушки для стека ядра. Дело в том, чтобы вернуться к пользовательскому пространству после того, как все произошло.

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

|other stack frames| 
|a few bytes of machine code to call sys_sigret| 
|signum parameter for the handler function| 
|address of the first byte of the code above| 

Я знаю, что машинный код для хранения, я нашел его в файле сборки. Я просто не знаю, что подразумевается под «несколькими байтами машинного кода для вызова sys_sigret». Как сохранить этот машинный код в стеке?

Благодарим за помощь!

ответ

0

Хранение кода в стеке не обязательно является хорошей идеей, но если вам необходимо это сделать, пусть будет так. Что касается того, как: просто создайте указанный машинный код в своей памяти ядра, просто скопируйте его в стек пользователя вместе со своим собственным адресом, чтобы он выполнялся, когда обработчик сигнала возвращается.

Это как Linux делает это:

static const struct { 
     u16 poplmovl; 
     u32 val; 
     u16 int80; 
} __attribute__((packed)) retcode = { 
     0xb858,   /* popl %eax; movl $..., %eax */ 
     __NR_sigreturn, 
     0x80cd,   /* int $0x80 */ 
}; 

/* 
* This is popl %eax ; movl $__NR_sigreturn, %eax ; int $0x80 
* 
* WE DO NOT USE IT ANY MORE! It's only left here for historical 
* reasons and because gdb uses it as a signature to notice 
* signal handler stack frames. 
*/ 
err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode); 
+0

«просто создать указанный машинный код в памяти ядра» - Так что, если у меня уже есть машинный код, который должен быть выполнен (поскольку это система я нашел машинный код для sys_sigret() в файле .asm), тогда я бы просто инициализировал соответствующие области структуры соответствующим частям машинного кода? –

+0

'sys_sigret' является фактическим обработчиком ядра для системного вызова, я полагаю. ** Вы не хотите этого **. Вам нужен фрагмент кода, который вызывает этот системный вызов, каким бы то ни было образом вашей ОС. В linux это был вызов 'int 0x80' после того, как' eax' был установлен на номер системы. – Jester

+0

У меня 8 байтов машинного кода, я думал, вместо 'u32 val; u16 int80; ' (Я не совсем уверен, что делают переменные внутри структуры) могу ли я сохранить мой машинный код на два ints? Кроме того, если sys_sigret вызывает sigret(), это обязательно плохо. Я должен спросить, потому что иначе я не пойму. –

Смежные вопросы