从中断处理程序中的用户堆栈弹出值
Pop values from user stack inside interrupt handler
我正在尝试在 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 [=10=]x30; addl , %%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 [=10=]x30; addl , %%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 [=10=]x30; addl , %%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,因为系统调用number 是堆栈中的第一个元素。现在的问题是 C 中不允许对 void 指针进行指针运算,并且参数可以是不同的类型,所以有人可以就如何从堆栈中弹出这些参数提出任何建议吗?
是的,您可以通过取消引用用户 esp 来获取参数值。与任何 void * 一样,您必须在取消引用或索引之前将其转换为合适的指针类型。在这种情况下,uint32_t * 是合适的,因此您可以使用
*(((uint32_t *)f->esp) + 1)
请注意 +1 而不是 +4,因为索引是根据指向的对象的大小缩放的。如果你想使用实际的字节偏移量,你需要两次转换
*(uint32_t *)(((uint8_t *)f->esp) + 4)
我正在尝试在 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 [=10=]x30; addl , %%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 [=10=]x30; addl , %%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 [=10=]x30; addl , %%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,因为系统调用number 是堆栈中的第一个元素。现在的问题是 C 中不允许对 void 指针进行指针运算,并且参数可以是不同的类型,所以有人可以就如何从堆栈中弹出这些参数提出任何建议吗?
是的,您可以通过取消引用用户 esp 来获取参数值。与任何 void * 一样,您必须在取消引用或索引之前将其转换为合适的指针类型。在这种情况下,uint32_t * 是合适的,因此您可以使用
*(((uint32_t *)f->esp) + 1)
请注意 +1 而不是 +4,因为索引是根据指向的对象的大小缩放的。如果你想使用实际的字节偏移量,你需要两次转换
*(uint32_t *)(((uint8_t *)f->esp) + 4)