在64位环0环境中,我想切换到环3,工具链:x86-64 gcc 4.6.3,为2.22。相关代码:
#define SHELL64_PHY_BASE (12 * 1024 * 1024)
#define SHELL64_VIRT_BASE 0x10000000000
#define SHELL64_MAP_SIZE (4 * 1024 * 1024)
// selector for ring 3 app on 64-bit OS
#define SEL_SHELL64_CODE (0 | 4 | 3)
#define SEL_SHELL64_DATA (8 | 4 | 3)
size_t kernel64(size_t par)
{
map_info_t minfo;
prints(white, "-------------------------\n");
prints(OS_INFO "Hello, 64-bit OS!\n");
// prepare GDT/LDT/TSS/IDT
update_gdt();
setup_descriptors();
// Shell64: 64-bit shell app, map config
minfo.vaddr = SHELL64_VIRT_BASE;
minfo.paddr = SHELL64_PHY_BASE;
minfo.bytes = SHELL64_MAP_SIZE;
minfo.psize = 0x1000;
minfo.attr = PATTR_WB | PATTR_U_RW_EX | PATTR_EXIST;
paging_construct(&minfo);
dcache_flush();
sector_read((void *)SHELL64_VIRT_BASE, shell64_sec_start, shell64_sec_count);
prints(OS_INFO "Will switch to 64-bit shell\n");
dcache_flush();
switch_to_shell();
return 0;
}
void switch_to_shell(void)
{
__asm volatile
(
"sub rsp, 32\n\t"
"mov qword ptr [rsp + 24], %0\n\t"
"mov qword ptr [rsp + 16], %1\n\t"
"mov qword ptr [rsp + 8], %2\n\t"
"mov qword ptr [rsp], %3\n\t"
"mov rbp, [rsp + 16]\n\t"
"mov ds, %4\n\t"
"mov es, %4\n\t"
"mov fs, %4\n\t"
"mov gs, %4\n\t"
"retf 0"
: : "i"(SEL_SHELL64_DATA), "r"(SHELL64_VIRT_BASE + SHELL64_MAP_SIZE),
"i"(SEL_SHELL64_CODE), "r"(SHELL64_VIRT_BASE), "a"(SEL_SHELL64_DATA)
);
}
GDT信息:
+0 null desc
+8 64-bit code desc, non-conforming, DPL 0, for os
+16 data desc, DPL 0, for os
+24 LDT desc
+40 TSS desc
LDT信息:
+0 64-bit code desc, non-conforming, DPL 3, for app
+8 data desc, DPL 3, for app
+... the other desc
执行远程返回指令(retf)时,处理器输入异常。如果运行debug命令'c',则会出现大量错误并崩溃。
调试后,我发现异常向量为13,#GP fault。 输入异常时,堆栈信息:
[rsp + 0x00]:00000000 00000100 // error code
[rsp + 0x08]:ffff8000 00001b58 // old RIP
[rsp + 0x10]:00000000 00000008 // old CS
[rsp + 0x18]:00000000 00010082 // RFLAGS
[rsp + 0x20]:ffff8000 000221d0 // old RSP
[rsp + 0x28]:00000000 00000010 // old SS
bochs 2.6.2,Windows版本。主机操作系统是Win8.1
相关的崩溃信息:http://pan.baidu.com/s/1kT0qr4r
答案 0 :(得分:1)
问题是as
没有为REX
指令生成RETF
前缀。因此,您的代码以32位操作数大小执行,并且假设堆栈包含值为SHELL64_VIRT_BASE
的{{1}},则它将被解释为32位0x10000000000
= CS:EIP
。在您的问题的上一版本中,您声明0x100:0x00000000
会出现以下错误:
bochs
知道那里的数字是十六进制的,00012169062e[CPU0] fetch_raw_desciptor: GDT: index (107) 20 > limit (37)
的段选择器确实会尝试访问字节0x100
,并且会有索引0x107
。
解决方案:在intel语法中,您必须手动将前缀指定为0x20
或rex64 retf
。使用at& t语法,您可以使用将自动生成前缀的rex.w retf
助记符。