从中断处理程序中的用户堆栈弹出值



我正在尝试在 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( *(f->esp + 4(,其中 f 是指向结构intr_frame的指针,我添加 4,因为系统调用号是堆栈上的第一个元素。现在的问题是 C 中不允许在 void 指针上使用指针算术,并且参数可以是不同类型的,所以任何人都可以就如何从堆栈中弹出这些参数给出任何建议吗?

是的,您可以通过取消引用用户来获取参数值,尤其是用户。与任何 void * 一样,在取消引用它或索引它之前,必须将其强制转换为合适的指针类型。在这种情况下,uint32_t * 是合适的,因此您将使用

*(((uint32_t *)f->esp) + 1)

请注意 +1 而不是 +4,因为索引按指向的对象的大小缩放。如果要使用实际的字节偏移量,则需要两个强制转换

*(uint32_t *)(((uint8_t *)f->esp) + 4)

相关内容

  • 没有找到相关文章

最新更新