[英]Inline Assembly Jump Error
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
}
}
据我所记得,有两个问题:
jmp
指令执行的操作不正确,您应该使用ret
指令跳转到下一行代码。 另外,不要从内联程序集中调用ret指令,否则您将跳过编译器在函数末尾放置的Epilog代码以清理堆栈。
我的第一个答案如下:
也许您的GDT描述符(gp)初始化错误。
当执行跳转指令时,处理器将尝试切换到保护模式,然后需要GDT。 如果GDT设置不正确,则会崩溃。
gp的前16位是gdt的大小(此处3 * 8 = 24字节),其后的32个字节是gdt的地址(此处&gdt [0])。
另外,在调用lgdt之前,请确保ds寄存器为空:指令使用该寄存器。
您将堆栈从堆栈中移出-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的函数调用之后的指令,但是主知道接下来会发生什么。
尝试在结构定义的前后放置以下杂注:
#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_entry
这些指令会更改gdt_ptr
结构的内存布局。 编译器的默认行为是在32位上对齐结构元素。 因此,先前的定义将等效于:
struct gdt_ptr
{
unsigned short limit;
unsigned short unused;
unsigned int base;
};
从处理器的角度来看这是无效的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.