Pointers 中断处理程序内用户堆栈中的Pop值

Pointers 中断处理程序内用户堆栈中的Pop值,pointers,gcc,assembly,osdev,pintos,Pointers,Gcc,Assembly,Osdev,Pintos,我正在尝试为Pintos中的系统调用实现一个处理程序。在引发中断之前,系统调用的参数按以下方式推送: /* Invokes syscall NUMBER, passing argument ARG0, and returns the return value as an `int'. */ #define syscall1(NUMBER, ARG0) \ ({

我正在尝试为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是指向struct intr_框架的指针,我添加了4,因为系统调用号是堆栈上的第一个元素。现在的问题是C中不允许在void指针上使用指针算法,并且参数可以是不同的类型,所以有人能就如何从堆栈中弹出这些参数给出任何建议吗?

是的,您可以通过取消对用户esp的引用来获得参数值。就像任何void*,在对其取消引用或索引之前,必须将其强制转换为合适的指针类型。在本例中,uint32_t*将是合适的,因此您将使用

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

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

是的,您可以通过取消对用户esp的引用来获取参数值。与任何void*一样,您必须在取消对其引用或索引之前将其转换为合适的指针类型。在本例中,uint32_t*将是合适的,因此您将使用

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

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

您的代码已中断,因为g约束允许esp相对操作数,这显然是错误的,因为您的推送指令在处理所有操作数之前更改esp。您的代码已中断,因为g约束允许esp相对操作数,这显然是错误的,因为您的推送指令在处理所有操作数之前更改esp操作数已被处理。盲目地取消引用由非特权用户代码提供的指针将是一个安全漏洞。@Timothy,是的,很好,用户代码可以在系统调用之前将任何内容加载到esp中。盲目地取消引用由非特权用户代码提供的指针将是一个安全漏洞。@Timothy,是的,很好,用户代码可以在系统调用之前将任何内容加载到esp中。