Assembly 从64位调用门远返回

Assembly 从64位调用门远返回,assembly,x86,64-bit,Assembly,X86,64 Bit,在64位环0环境中,我想切换到环3,工具链:x86-64 gcc 4.6.3,as 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_C

在64位环0环境中,我想切换到环3,工具链:x86-64 gcc 4.6.3,as 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)时,处理器进入异常。如果运行调试命令“c”,将出现大量错误并崩溃

调试之后,我发现异常向量是13,#GP fault。 输入exception时,堆栈信息:

[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


相关的崩溃信息:

问题在于
,因为
没有为
RETF
指令生成
REX
前缀。同样地,您的代码是以32位操作数大小执行的,并且假定堆栈包含值为0x1000000000的
SHELL64\u VIRT\u BASE
,它将被解释为32位
CS:EIP
=
0x100:0x00000000
。在问题的上一版本中,您指出
bochs
打印以下错误:

00012169062e[CPU0] fetch_raw_desciptor: GDT: index (107) 20 > limit (37)
知道那里的数字是十六进制的,
0x100
的段选择器实际上会尝试访问多达字节
0x107
,并且会有索引
0x20


解决方案:在英特尔语法中,您必须手动将前缀指定为
rex64-retf
rex.w-retf
。使用at&t语法,您可以使用将自动生成前缀的
lretq
助记符。

检查另一个vm(如qemu)中的代码,看看它是否可能是bochs中的错误。您也可以查阅bochs源代码以了解它正在做什么,甚至可以使用gdb对其进行调试。我已经签入qemu(从下载),也会崩溃。也许这些x86模拟器不支持64位far return?您能提供完整的可运行代码吗?我现在只能提供上述代码。