Я пытаюсь реализовать обработчик системных вызовов в Pintos. Перед вызовом прерывания аргументы для системных вызовов помещаются следующим образом:
/* Invokes syscall NUMBER, passing argument ARG0, and returns the
return value as an `int'. */
#define syscall1(NUMBER, ARG0) \
({ \
int retval; \
asm volatile \
("pushl %[arg0]; pushl %[number]; int $0x30; addl $8, %%esp" \
: "=a" (retval) \
: [number] "i" (NUMBER), \
[arg0] "g" (ARG0) \
: "memory"); \
retval; \
})
/* Invokes syscall NUMBER, passing arguments ARG0 and ARG1, and
returns the return value as an `int'. */
#define syscall2(NUMBER, ARG0, ARG1) \
({ \
int retval; \
asm volatile \
("pushl %[arg1]; pushl %[arg0]; " \
"pushl %[number]; int $0x30; addl $12, %%esp" \
: "=a" (retval) \
: [number] "i" (NUMBER), \
[arg0] "g" (ARG0), \
[arg1] "g" (ARG1) \
: "memory"); \
retval; \
})
/* Invokes syscall NUMBER, passing arguments ARG0, ARG1, and
ARG2, and returns the return value as an `int'. */
#define syscall3(NUMBER, ARG0, ARG1, ARG2) \
({ \
int retval; \
asm volatile \
("pushl %[arg2]; pushl %[arg1]; pushl %[arg0]; " \
"pushl %[number]; int $0x30; addl $16, %%esp" \
: "=a" (retval) \
: [number] "i" (NUMBER), \
[arg0] "g" (ARG0), \
[arg1] "g" (ARG1), \
[arg2] "g" (ARG2) \
: "memory"); \
retval; \
})
У меня есть структура, содержащая все отправленные регистры, а также указатель на стек пользовательского уровня (в который были помещены номер системного вызова и аргументы).
/* Interrupt stack frame. */
struct intr_frame
{
/* Pushed by intr_entry in intr-stubs.S.
These are the interrupted task's saved registers. */
uint32_t edi; /* Saved EDI. */
uint32_t esi; /* Saved ESI. */
uint32_t ebp; /* Saved EBP. */
uint32_t esp_dummy; /* Not used. */
uint32_t ebx; /* Saved EBX. */
uint32_t edx; /* Saved EDX. */
uint32_t ecx; /* Saved ECX. */
uint32_t eax; /* Saved EAX. */
uint16_t gs, :16; /* Saved GS segment register. */
uint16_t fs, :16; /* Saved FS segment register. */
uint16_t es, :16; /* Saved ES segment register. */
uint16_t ds, :16; /* Saved DS segment register. */
/* Pushed by intrNN_stub in intr-stubs.S. */
uint32_t vec_no; /* Interrupt vector number. */
/* Sometimes pushed by the CPU,
otherwise for consistency pushed as 0 by intrNN_stub.
The CPU puts it just under `eip', but we move it here. */
uint32_t error_code; /* Error code. */
/* Pushed by intrNN_stub in intr-stubs.S.
This frame pointer eases interpretation of backtraces. */
void *frame_pointer; /* Saved EBP (frame pointer). */
/* Pushed by the CPU.
These are the interrupted task's saved registers. */
void (*eip) (void); /* Next instruction to execute. */
uint16_t cs, :16; /* Code segment for eip. */
uint32_t eflags; /* Saved CPU flags. */
void *esp; /* Saved stack pointer. */
uint16_t ss, :16; /* Data segment for esp. */
};
Теперь я хочу получить эти аргументы. Все указатели в стеке имеют размер 4 байта, поэтому я подумал, что могу просто привести аргумент (разыменованный указатель) к соответствующему типу, затем увеличить указатель стека на 4 и привести следующий указатель.
У меня следующий вопрос:
Инструкция pushl правильно помещает значения в стек? Итак, я должен иметь возможность получить эти значения, просто разыменовав указатель на стек? Например, чтобы получить первый аргумент (при условии, что это int), я бы использовал (int) *(f->esp + 4), где f — указатель на структуру intr_frame, и я добавляю 4, потому что номер системного вызова является первым элемент в стеке. Теперь проблема в том, что арифметика указателей на пустых указателях не разрешена в C, и аргументы могут быть разных типов, поэтому может ли кто-нибудь дать какие-либо предложения о том, как вытолкнуть эти аргументы из стека?
g
допускаетesp
относительных операндов, что было бы явно неправильным из-за вашихpush
инструкций, изменяющихesp
до того, как все операнды будут обработаны. - person Jester   schedule 03.09.2019