【问题标题】:Inline Assembly Jump Error内联汇编跳转错误
【发布时间】:2009-09-09 07:18:36
【问题描述】:

为什么这会失败,一旦 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();
}

`

【问题讨论】:

  • 奇怪..这应该可以工作。如果您能找到答案,请在此处发布。我也有点兴趣。 :-)
  • 如何初始化 GDT 描述符?
  • 我编辑了这个问题,这样你就可以看到代码现在的样子......虽然仍然失败......

标签: c visual-studio assembly nasm masm


【解决方案1】:

新答案:

前段时间我已经遇到过这个问题,我发现使用 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 寄存器为空:该寄存器被指令使用。

【讨论】:

  • 编译时没有错误,但调用 gdt_install() 时崩溃
【解决方案2】:

尝试在结构定义之前和之后放置以下 pragma:

#pragma pack(push,1)

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;
};

#pragma pack(pop)

虽然对gdt_entry没有影响,但这些指令改变了gdt_ptr结构的内存布局。编译器的默认行为是在 32 位上对齐结构元素。因此,前面的定义相当于:

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

从处理器的角度来看这是无效的。

【讨论】:

  • 无效...仍然崩溃...或者我应该在调用 gdt 之前激活某些东西吗?我正在 VirtualBox 上测试它
  • 我假设您正在编写内核并在 VirtualBox 上对其进行测试,我错了吗?您正在使用哪个引导加载程序,您的代码预计何时运行?
  • 我正在使用 isolinux.bin 和 mkisofs 工具...来启动我的内核,实际上我的代码在我使用 Nasm(在 Ubuntu 上)时正在运行,现在我想将它转换为 Masm 但卡住了在 IDT、GDT、ISR……嗯,你说的运行是什么意思?截止日期?
【解决方案3】:

您将堆栈从其下方移出 - ret 使用的 ip 现在指向某个非常疯狂的地方

[编辑]

你仍然破坏堆栈 - 与 VC 使用的相同。 VC 将更多的东西压入堆栈,而不仅仅是返回 IP。对源代码进行汇编列表,您会看到。

一种可能性是在您进行更改之前将返回地址从堆栈中复制出来,最后只跳转到它指向的位置。

创建一个带标签的dw来存储地址:

_asm {
    oldip dd ?      ;this is in cs
    pop eax         ;eip into eax
    push eax        ;leave stack as found
    mov oldip,eax    
    .
    ..your stuff
    .
    jmp far cs:[oldip]     
}

我可能在这里遗漏了一些东西,但是从您的代码的外观来看,您正在破坏除 cs 之外的所有段值,从而破坏了对先前声明的变量的所有访问,以及您放置在堆栈上的任何返回地址等程序...也许这就是您想要做的,跳到其他地方编写代码,孤立您当前的程序...

上面的片段应该让你回到使用 _asm 东西调用函数之后的指令,但是上帝知道接下来会发生什么。

【讨论】:

  • 远返回指令代替远跳转,不是函数返回语句。 2 个压入的值被远返回指令使用,之后堆栈被恢复。函数的返回留给编译器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
  • 2017-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-28
相关资源
最近更新 更多