Masm到达jmp后,为什么这失败了?

struct gdt_entry
{
    unsigned short limit_low;
    unsigned short base_low;
    unsigned char base_middle;
    unsigned char access;
    unsigned char granularity;
    unsigned char base_high;
};

struct gdt_ptr
{
    unsigned short limit;
    unsigned int base;
};

struct gdt_entry gdt[3];
struct gdt_ptr gp;


void gdt_flush()
{
      __asm{
          lgdt [gp]

          mov ax, 0x10
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
          mov ss, ax

          ; push the address on the stack
          push 0x08
          mov eax, offset flush2
          push eax

          ; ret use the previous pushed address
          _emit 0xCB ; far return

      flush2:
          ;ret
   }
}


void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran)
{

    gdt[num].base_low = (base & 0xFFFF);
    gdt[num].base_middle = (base >> 16) & 0xFF;
    gdt[num].base_high = (base >> 24) & 0xFF;
    gdt[num].limit_low = (limit & 0xFFFF);
    gdt[num].granularity = ((limit >> 16) & 0x0F);
    gdt[num].granularity |= (gran & 0xF0);
    gdt[num].access = access;
}

void gdt_install()
{
    gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
    gp.base = (int)&gdt;
    gdt_set_gate(0, 0, 0, 0, 0);
    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
    gdt_flush();
}


`

最佳答案

新答案:

我已经有一段时间遇到这个问题了,我发现使用MASM内联汇编更新GDT的唯一方法是使用远返回指令,而不是远跳转指令。

struct gdt_entry gdt[3];
struct gdt_ptr gp;
void gdt_flush(){
    __asm{
          lgdt [gp]

          mov ax, 0x10
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
          mov ss, ax

          ; push the address on the stack
          push 0x08
          mov eax, offset flush2
          push eax

          ; ret use the previous pushed address
          _emit 0xCB ; far return

      flush2:
          ;ret
   }
}


据我所记得,有两个问题:


32位MASM内联汇编不能编译远指令,因此您必须发出操作码。
jmp指令执行的操作不正确,您应该使用ret指令跳转到下一行代码。


另外,不要从内联汇编中调用ret指令,否则您将跳过编译器在函数末尾放置的Epilog代码以清理堆栈。



我的第一个答案如下:

也许您的GDT描述符(gp)初始化错误。

当执行跳转指令时,处理器将尝试切换到保护模式,然后需要GDT。如果GDT设置不正确,则会崩溃。

gp的前16位是gdt的大小(此处3 * 8 = 24字节),其后的32个字节是gdt的地址(此处&gdt [0])。

另外,在调用lgdt之前,请确保ds寄存器为空:指令使用该寄存器。

09-25 22:07