]> xenbits.xensource.com Git - xtf.git/commitdiff
Memory operand and segment emulation tests
authorAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 26 Oct 2017 10:31:31 +0000 (11:31 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 16 Feb 2018 20:19:13 +0000 (20:19 +0000)
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
docs/all-tests.dox
tests/memop-seg/Makefile [new file with mode: 0644]
tests/memop-seg/asm.S [new file with mode: 0644]
tests/memop-seg/main.c [new file with mode: 0644]
tests/memop-seg/test.h [new file with mode: 0644]

index 6acddd0531f1d52c7e41b5da6cc1ec598a673e86..355cb800caf7d445e0dafa796f4785db96d9ea32 100644 (file)
@@ -26,6 +26,8 @@ and functionality.
 
 @subpage test-livepatch-priv-check - Live Patch Privilege Check.
 
+@subpage test-memop-seg - Memory operand and segment interaction test.
+
 @subpage test-nmi-taskswitch-priv - Task Gate handling of interrupts.
 
 @subpage test-pv-iopl - IOPL emulation for PV guests.
diff --git a/tests/memop-seg/Makefile b/tests/memop-seg/Makefile
new file mode 100644 (file)
index 0000000..1251094
--- /dev/null
@@ -0,0 +1,9 @@
+include $(ROOT)/build/common.mk
+
+NAME      := memop-seg
+CATEGORY  := functional
+TEST-ENVS := pv32pae pv64 hvm32pae hvm64
+
+obj-perenv += main.o asm.o
+
+include $(ROOT)/build/gen.mk
diff --git a/tests/memop-seg/asm.S b/tests/memop-seg/asm.S
new file mode 100644 (file)
index 0000000..6986614
--- /dev/null
@@ -0,0 +1,191 @@
+#include <xtf/asm_macros.h>
+#include <xtf/extable.h>
+#include <arch/segment.h>
+
+        .section .text.user, "ax", @progbits
+
+.macro GEN_ABS_STUB seg load_seg
+
+ENTRY(stub_\seg\()_abs) /* exinfo_t stub_\seg_abs(unsigned long addr) */
+#ifdef __i386__
+        /*
+         * Switch segment if necessary.  The old segment is preserved on the
+         * stack for the duration of the test.
+         */
+        .local stack_adj
+        stack_adj = 0
+
+        .if \load_seg
+            .ifeqs "\seg", "none"
+                push %ds
+                push $(GDTE_AVAIL1 << 3 | 3)
+                pop  %ds
+            .else
+                push %\seg
+                push $(GDTE_AVAIL1 << 3 | 3)
+                pop  %\seg
+            .endif
+            stack_adj = 1
+        .endif
+#endif
+
+        /* No exception if we don't fault.  Also reused by the 64bit case. */
+        xor %eax, %eax
+
+        /* The bottom bit of 'addr' encodes FEP. */
+#ifdef __i386__
+        testb $1, (1 + stack_adj)*4(%esp)
+#else
+        testb $1, %dil
+#endif
+        jz 1f
+
+        _ASM_XEN_FEP
+        .ifeqs "\seg", "none"
+#ifdef __i386__
+1:          movb $0, 0xc0000000
+#else
+1:          movabsb %al, 0x8000000040000000
+#endif
+        .else
+#ifdef __i386__
+1:          movb $0, %\seg:0xc0000000
+#else
+1:          movabsb %al, %\seg:0x8000000040000000
+#endif
+        .endif
+
+2:
+#ifdef __i386__
+        /* Restore the old segment if necessary. */
+        .if \load_seg
+            .ifeqs "\seg", "none"
+                pop  %ds
+            .else
+                pop  %\seg
+            .endif
+        .endif
+#endif
+
+        ret
+
+        _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+ENDFUNC(stub_\seg\()_abs)
+.endm
+
+.macro GEN_REG_STUB seg reg load_seg preserve_reg
+
+ENTRY(stub_\seg\()_\reg) /* exinfo_t stub_\seg_\reg(unsigned long addr) */
+
+#ifdef __i386__
+        /*
+         * Switch segment if necessary.  The old segment is preserved on the
+         * stack for the duration of the test.
+         */
+        .local stack_adj
+        stack_adj = 0
+
+        .if \load_seg
+            .ifeqs "\seg", "none"
+                push %ds
+                push $(GDTE_AVAIL1 << 3 | 3)
+                pop  %ds
+            .else
+                push %\seg
+                push $(GDTE_AVAIL1 << 3 | 3)
+                pop  %\seg
+            .endif
+            stack_adj = 1
+        .endif
+#endif
+
+        /* Preserve the subject register if necessary. */
+        .if \preserve_reg
+            mov %\reg, %_ASM_CX
+        .endif
+
+        /* Move 'addr' into \reg */
+#ifdef __i386__
+        mov (1 + stack_adj)*4(%esp), %\reg
+#else
+        mov %rdi, %\reg
+#endif
+
+        /* The bottom bit of 'addr' encodes FEP. */
+        test $1, %\reg
+        jz 1f
+
+        _ASM_XEN_FEP
+        .ifeqs "\seg", "none"
+1:          movb $0, (%\reg)
+        .else
+1:          movb $0, %\seg:(%\reg)
+        .endif
+
+        /* No exception if we didn't fault. */
+        xor %eax, %eax
+2:
+        /* Restore the register if necessary. */
+        .if \preserve_reg
+            mov %_ASM_CX, %\reg
+        .endif
+
+#ifdef __i386__
+        /* Restore the old segment if necessary. */
+        .if \load_seg
+            .ifeqs "\seg", "none"
+                pop  %ds
+            .else
+                pop  %\seg
+            .endif
+        .endif
+#endif
+
+        ret
+
+        _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+ENDFUNC(stub_\seg\()_\reg)
+.endm
+
+/*
+ * Instantiate `GEN_ABS_STUB foreach segment` and `GEN_REG_STUB foreach
+ * segment, foreach register`, calculaing whether the segment needs loading
+ * (implicit %ds, explicit %{e,d,f,g}s), and whether the register needs
+ * preserving (depends on the calling ABI).
+ */
+.local seg_mask, seg_idx, reg_mask, reg_idx
+#ifdef __i386__
+    seg_mask = 0b1100111
+#else
+    seg_mask = 0
+#endif
+    seg_idx  = 6
+
+.irp seg, none, es, cs, ss, ds, fs, gs
+
+    GEN_ABS_STUB \seg, (seg_mask & (1 << seg_idx))
+
+#ifdef __i386__
+    reg_mask = 0b00011111
+    reg_idx  = 7
+    .irp reg, eax, ecx, edx, ebx, esp, ebp, esi, edi
+#else
+    reg_mask = 0b0001110000001111
+    reg_idx  = 15
+    .irp reg, rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15
+#endif
+
+        GEN_REG_STUB \seg, \reg, (seg_mask & (1 << seg_idx)), (reg_mask & (1 << reg_idx))
+        reg_idx = reg_idx - 1
+
+    .endr
+    seg_idx = seg_idx - 1
+
+.endr
+
+/*
+ * Local variables:
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tests/memop-seg/main.c b/tests/memop-seg/main.c
new file mode 100644 (file)
index 0000000..c9b885e
--- /dev/null
@@ -0,0 +1,320 @@
+/**
+ * @file tests/memop-seg/main.c
+ * @ref test-memop-seg
+ *
+ * @page test-memop-seg Memory operand and segment emulation
+ *
+ * All memory operands operate through a segment.  Several factors control
+ * which segment is actually used.
+ *
+ * 1. If the memory operand is encoded with a base register of @%rbp or @%rsp,
+ *    the default segment is @%ss.  Otherwise, @%ds is the default.  (String
+ *    instructions with two memory operands use @%es for their second
+ *    operand.)
+
+ * 2. Instructions encoded with an explicit segment override prefix will use
+ *    the specified segment for their operand.  However, in 64bit mode with
+ *    deprecated most of the segmentation model, the @%es, @%cs, @%ss and @%ds
+ *    segment overrides are ignored and have no effect.
+ *
+ * This test uses the fact that @%ss can be distinguished from other segments
+ * because it yields @#SS[0] on a segmentation fault, rather than @#GP[0].  We
+ * construct a scenario in userspace which intends to suffer a segmentation
+ * based fault.
+ *
+ * Tests are run for each explicit segment override prefix as well as no
+ * prefix, and for each memory operand encoding of a base register, as well as
+ * an absolute operand.  The resulting fault is used to check that the
+ * expected segment is being used.
+ *
+ * @see tests/memop-seg/main.c
+ */
+#include <xtf.h>
+
+#include "test.h"
+
+const char test_title[] = "Memory operand and segment emulation tests";
+
+static const struct test
+{
+    unsigned long (*fn)(unsigned long);
+    const char *name;
+    exinfo_t exp;
+} tests[] =
+{
+#define GP EXINFO_SYM(GP, 0)
+#define SS EXINFO_SYM(SS, 0)
+
+#ifdef __i386__
+
+    { stub_none_abs, "abs",    GP },
+    { stub_none_eax, "(%eax)", GP },
+    { stub_none_ecx, "(%ecx)", GP },
+    { stub_none_edx, "(%edx)", GP },
+    { stub_none_ebx, "(%ebx)", GP },
+    { stub_none_esp, "(%esp)", SS },
+    { stub_none_ebp, "(%ebp)", SS },
+    { stub_none_esi, "(%esi)", GP },
+    { stub_none_edi, "(%edi)", GP },
+
+    { stub_es_abs, "%es:abs",    GP },
+    { stub_es_eax, "%es:(%eax)", GP },
+    { stub_es_ecx, "%es:(%ecx)", GP },
+    { stub_es_edx, "%es:(%edx)", GP },
+    { stub_es_ebx, "%es:(%ebx)", GP },
+    { stub_es_esp, "%es:(%esp)", GP },
+    { stub_es_ebp, "%es:(%ebp)", GP },
+    { stub_es_esi, "%es:(%esi)", GP },
+    { stub_es_edi, "%es:(%edi)", GP },
+
+    { stub_cs_abs, "%cs:abs",    GP },
+    { stub_cs_eax, "%cs:(%eax)", GP },
+    { stub_cs_ecx, "%cs:(%ecx)", GP },
+    { stub_cs_edx, "%cs:(%edx)", GP },
+    { stub_cs_ebx, "%cs:(%ebx)", GP },
+    { stub_cs_esp, "%cs:(%esp)", GP },
+    { stub_cs_ebp, "%cs:(%ebp)", GP },
+    { stub_cs_esi, "%cs:(%esi)", GP },
+    { stub_cs_edi, "%cs:(%edi)", GP },
+
+    { stub_ss_abs, "%ss:abs",    SS },
+    { stub_ss_eax, "%ss:(%eax)", SS },
+    { stub_ss_ecx, "%ss:(%ecx)", SS },
+    { stub_ss_edx, "%ss:(%edx)", SS },
+    { stub_ss_ebx, "%ss:(%ebx)", SS },
+    { stub_ss_esp, "%ss:(%esp)", SS },
+    { stub_ss_ebp, "%ss:(%ebp)", SS },
+    { stub_ss_esi, "%ss:(%esi)", SS },
+    { stub_ss_edi, "%ss:(%edi)", SS },
+
+    { stub_ds_abs, "%ds:abs",    GP },
+    { stub_ds_eax, "%ds:(%eax)", GP },
+    { stub_ds_ecx, "%ds:(%ecx)", GP },
+    { stub_ds_edx, "%ds:(%edx)", GP },
+    { stub_ds_ebx, "%ds:(%ebx)", GP },
+    { stub_ds_esp, "%ds:(%esp)", GP },
+    { stub_ds_ebp, "%ds:(%ebp)", GP },
+    { stub_ds_esi, "%ds:(%esi)", GP },
+    { stub_ds_edi, "%ds:(%edi)", GP },
+
+    { stub_fs_abs, "%fs:abs",    GP },
+    { stub_fs_eax, "%fs:(%eax)", GP },
+    { stub_fs_ecx, "%fs:(%ecx)", GP },
+    { stub_fs_edx, "%fs:(%edx)", GP },
+    { stub_fs_ebx, "%fs:(%ebx)", GP },
+    { stub_fs_esp, "%fs:(%esp)", GP },
+    { stub_fs_ebp, "%fs:(%ebp)", GP },
+    { stub_fs_esi, "%fs:(%esi)", GP },
+    { stub_fs_edi, "%fs:(%edi)", GP },
+
+    { stub_gs_abs, "%gs:abs",    GP },
+    { stub_gs_eax, "%gs:(%eax)", GP },
+    { stub_gs_ecx, "%gs:(%ecx)", GP },
+    { stub_gs_edx, "%gs:(%edx)", GP },
+    { stub_gs_ebx, "%gs:(%ebx)", GP },
+    { stub_gs_esp, "%gs:(%esp)", GP },
+    { stub_gs_ebp, "%gs:(%ebp)", GP },
+    { stub_gs_esi, "%gs:(%esi)", GP },
+    { stub_gs_edi, "%gs:(%edi)", GP },
+
+#else
+
+    { stub_none_abs, "abs",    GP },
+    { stub_none_rax, "(%rax)", GP },
+    { stub_none_rcx, "(%rcx)", GP },
+    { stub_none_rdx, "(%rdx)", GP },
+    { stub_none_rbx, "(%rbx)", GP },
+    { stub_none_rsp, "(%rsp)", SS },
+    { stub_none_rbp, "(%rbp)", SS },
+    { stub_none_rsi, "(%rsi)", GP },
+    { stub_none_rdi, "(%rdi)", GP },
+    { stub_none_r8,  "(%r8)",  GP },
+    { stub_none_r9,  "(%r9)",  GP },
+    { stub_none_r10, "(%r10)", GP },
+    { stub_none_r11, "(%r11)", GP },
+    { stub_none_r12, "(%r12)", GP },
+    { stub_none_r13, "(%r13)", GP },
+    { stub_none_r14, "(%r14)", GP },
+    { stub_none_r15, "(%r15)", GP },
+
+    { stub_es_abs, "%es:abs",    GP },
+    { stub_es_rax, "%es:(%rax)", GP },
+    { stub_es_rcx, "%es:(%rcx)", GP },
+    { stub_es_rdx, "%es:(%rdx)", GP },
+    { stub_es_rbx, "%es:(%rbx)", GP },
+    { stub_es_rsp, "%es:(%rsp)", SS },
+    { stub_es_rbp, "%es:(%rbp)", SS },
+    { stub_es_rsi, "%es:(%rsi)", GP },
+    { stub_es_rdi, "%es:(%rdi)", GP },
+    { stub_es_r8,  "%es:(%r8)",  GP },
+    { stub_es_r9,  "%es:(%r9)",  GP },
+    { stub_es_r10, "%es:(%r10)", GP },
+    { stub_es_r11, "%es:(%r11)", GP },
+    { stub_es_r12, "%es:(%r12)", GP },
+    { stub_es_r13, "%es:(%r13)", GP },
+    { stub_es_r14, "%es:(%r14)", GP },
+    { stub_es_r15, "%es:(%r15)", GP },
+
+    { stub_cs_abs, "%cs:abs",    GP },
+    { stub_cs_rax, "%cs:(%rax)", GP },
+    { stub_cs_rcx, "%cs:(%rcx)", GP },
+    { stub_cs_rdx, "%cs:(%rdx)", GP },
+    { stub_cs_rbx, "%cs:(%rbx)", GP },
+    { stub_cs_rsp, "%cs:(%rsp)", SS },
+    { stub_cs_rbp, "%cs:(%rbp)", SS },
+    { stub_cs_rsi, "%cs:(%rsi)", GP },
+    { stub_cs_rdi, "%cs:(%rdi)", GP },
+    { stub_cs_r8,  "%cs:(%r8)",  GP },
+    { stub_cs_r9,  "%cs:(%r9)",  GP },
+    { stub_cs_r10, "%cs:(%r10)", GP },
+    { stub_cs_r11, "%cs:(%r11)", GP },
+    { stub_cs_r12, "%cs:(%r12)", GP },
+    { stub_cs_r13, "%cs:(%r13)", GP },
+    { stub_cs_r14, "%cs:(%r14)", GP },
+    { stub_cs_r15, "%cs:(%r15)", GP },
+
+    { stub_ss_abs, "%ss:abs",    GP },
+    { stub_ss_rax, "%ss:(%rax)", GP },
+    { stub_ss_rcx, "%ss:(%rcx)", GP },
+    { stub_ss_rdx, "%ss:(%rdx)", GP },
+    { stub_ss_rbx, "%ss:(%rbx)", GP },
+    { stub_ss_rsp, "%ss:(%rsp)", SS },
+    { stub_ss_rbp, "%ss:(%rbp)", SS },
+    { stub_ss_rsi, "%ss:(%rsi)", GP },
+    { stub_ss_rdi, "%ss:(%rdi)", GP },
+    { stub_ss_r8,  "%ss:(%r8)",  GP },
+    { stub_ss_r9,  "%ss:(%r9)",  GP },
+    { stub_ss_r10, "%ss:(%r10)", GP },
+    { stub_ss_r11, "%ss:(%r11)", GP },
+    { stub_ss_r12, "%ss:(%r12)", GP },
+    { stub_ss_r13, "%ss:(%r13)", GP },
+    { stub_ss_r14, "%ss:(%r14)", GP },
+    { stub_ss_r15, "%ss:(%r15)", GP },
+
+    { stub_ds_abs, "%ds:abs",    GP },
+    { stub_ds_rax, "%ds:(%rax)", GP },
+    { stub_ds_rcx, "%ds:(%rcx)", GP },
+    { stub_ds_rdx, "%ds:(%rdx)", GP },
+    { stub_ds_rbx, "%ds:(%rbx)", GP },
+    { stub_ds_rsp, "%ds:(%rsp)", SS },
+    { stub_ds_rbp, "%ds:(%rbp)", SS },
+    { stub_ds_rsi, "%ds:(%rsi)", GP },
+    { stub_ds_rdi, "%ds:(%rdi)", GP },
+    { stub_ds_r8,  "%ds:(%r8)",  GP },
+    { stub_ds_r9,  "%ds:(%r9)",  GP },
+    { stub_ds_r10, "%ds:(%r10)", GP },
+    { stub_ds_r11, "%ds:(%r11)", GP },
+    { stub_ds_r12, "%ds:(%r12)", GP },
+    { stub_ds_r13, "%ds:(%r13)", GP },
+    { stub_ds_r14, "%ds:(%r14)", GP },
+    { stub_ds_r15, "%ds:(%r15)", GP },
+
+    { stub_fs_abs, "%fs:abs",    GP },
+    { stub_fs_rax, "%fs:(%rax)", GP },
+    { stub_fs_rcx, "%fs:(%rcx)", GP },
+    { stub_fs_rdx, "%fs:(%rdx)", GP },
+    { stub_fs_rbx, "%fs:(%rbx)", GP },
+    { stub_fs_rsp, "%fs:(%rsp)", GP },
+    { stub_fs_rbp, "%fs:(%rbp)", GP },
+    { stub_fs_rsi, "%fs:(%rsi)", GP },
+    { stub_fs_rdi, "%fs:(%rdi)", GP },
+    { stub_fs_r8,  "%fs:(%r8)",  GP },
+    { stub_fs_r9,  "%fs:(%r9)",  GP },
+    { stub_fs_r10, "%fs:(%r10)", GP },
+    { stub_fs_r11, "%fs:(%r11)", GP },
+    { stub_fs_r12, "%fs:(%r12)", GP },
+    { stub_fs_r13, "%fs:(%r13)", GP },
+    { stub_fs_r14, "%fs:(%r14)", GP },
+    { stub_fs_r15, "%fs:(%r15)", GP },
+
+    { stub_gs_abs, "%gs:abs",    GP },
+    { stub_gs_rax, "%gs:(%rax)", GP },
+    { stub_gs_rcx, "%gs:(%rcx)", GP },
+    { stub_gs_rdx, "%gs:(%rdx)", GP },
+    { stub_gs_rbx, "%gs:(%rbx)", GP },
+    { stub_gs_rsp, "%gs:(%rsp)", GP },
+    { stub_gs_rbp, "%gs:(%rbp)", GP },
+    { stub_gs_rsi, "%gs:(%rsi)", GP },
+    { stub_gs_rdi, "%gs:(%rdi)", GP },
+    { stub_gs_r8,  "%gs:(%r8)",  GP },
+    { stub_gs_r9,  "%gs:(%r9)",  GP },
+    { stub_gs_r10, "%gs:(%r10)", GP },
+    { stub_gs_r11, "%gs:(%r11)", GP },
+    { stub_gs_r12, "%gs:(%r12)", GP },
+    { stub_gs_r13, "%gs:(%r13)", GP },
+    { stub_gs_r14, "%gs:(%r14)", GP },
+    { stub_gs_r15, "%gs:(%r15)", GP },
+
+#endif
+
+#undef SS
+#undef GP
+};
+
+void test_main(void)
+{
+    /* Top bit set + 1GB.  Yields a non canonical address in 64bit. */
+    unsigned long addr = (~0ul & ~(~0ul >> 1)) + GB(1);
+    unsigned int i;
+
+    /* For 32bit, use segments with a limit of 2GB. */
+    if ( IS_DEFINED(CONFIG_32BIT) )
+    {
+        user_desc code = INIT_GDTE_SYM(0, 0x7ffff, COMMON, CODE, DPL3, R, D);
+        user_desc data = INIT_GDTE_SYM(0, 0x7ffff, COMMON, DATA, DPL3, B, W);
+
+        if ( IS_DEFINED(CONFIG_HVM) )
+        {
+            gdt[GDTE_AVAIL0] = code;
+            gdt[GDTE_AVAIL1] = data;
+        }
+        else
+        {
+            int rc = hypercall_update_descriptor(virt_to_maddr(
+                                                     &gdt[GDTE_AVAIL0]), code);
+
+            if ( !rc )
+                rc = hypercall_update_descriptor(virt_to_maddr(
+                                                     &gdt[GDTE_AVAIL1]), data);
+
+            if ( rc )
+                return xtf_error("Error: Update descriptor failed: %d\n", rc);
+        }
+
+        exec_user_cs = GDTE_AVAIL0 << 3 | 3;
+        exec_user_ss = GDTE_AVAIL1 << 3 | 3;
+    }
+
+    for ( i = 0; i < ARRAY_SIZE(tests); ++i )
+    {
+        const struct test *t = &tests[i];
+        exinfo_t res;
+
+        res = exec_user_param(t->fn, addr);
+        if ( res != t->exp )
+            xtf_failure("Fail: Testing '%s'\n"
+                        "  expected %pe, got %pe\n",
+                        t->name, _p(t->exp), _p(res));
+
+        if ( !xtf_has_fep )
+            continue;
+
+        res = exec_user_param(t->fn, addr | 1);
+        if ( res != t->exp )
+            xtf_failure("Fail: Testing emulated '%s'\n"
+                        "  expected %pe, got %pe\n",
+                        t->name, _p(t->exp), _p(res));
+    }
+
+    xtf_success(NULL);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tests/memop-seg/test.h b/tests/memop-seg/test.h
new file mode 100644 (file)
index 0000000..bfadcd3
--- /dev/null
@@ -0,0 +1,201 @@
+#ifdef __i386__
+
+extern unsigned long stub_none_abs(unsigned long);
+extern unsigned long stub_none_eax(unsigned long);
+extern unsigned long stub_none_ecx(unsigned long);
+extern unsigned long stub_none_edx(unsigned long);
+extern unsigned long stub_none_ebx(unsigned long);
+extern unsigned long stub_none_esp(unsigned long);
+extern unsigned long stub_none_ebp(unsigned long);
+extern unsigned long stub_none_esi(unsigned long);
+extern unsigned long stub_none_edi(unsigned long);
+
+extern unsigned long stub_es_abs(unsigned long);
+extern unsigned long stub_es_eax(unsigned long);
+extern unsigned long stub_es_ecx(unsigned long);
+extern unsigned long stub_es_edx(unsigned long);
+extern unsigned long stub_es_ebx(unsigned long);
+extern unsigned long stub_es_esp(unsigned long);
+extern unsigned long stub_es_ebp(unsigned long);
+extern unsigned long stub_es_esi(unsigned long);
+extern unsigned long stub_es_edi(unsigned long);
+
+extern unsigned long stub_cs_abs(unsigned long);
+extern unsigned long stub_cs_eax(unsigned long);
+extern unsigned long stub_cs_ecx(unsigned long);
+extern unsigned long stub_cs_edx(unsigned long);
+extern unsigned long stub_cs_ebx(unsigned long);
+extern unsigned long stub_cs_esp(unsigned long);
+extern unsigned long stub_cs_ebp(unsigned long);
+extern unsigned long stub_cs_esi(unsigned long);
+extern unsigned long stub_cs_edi(unsigned long);
+
+extern unsigned long stub_ss_abs(unsigned long);
+extern unsigned long stub_ss_eax(unsigned long);
+extern unsigned long stub_ss_ecx(unsigned long);
+extern unsigned long stub_ss_edx(unsigned long);
+extern unsigned long stub_ss_ebx(unsigned long);
+extern unsigned long stub_ss_esp(unsigned long);
+extern unsigned long stub_ss_ebp(unsigned long);
+extern unsigned long stub_ss_esi(unsigned long);
+extern unsigned long stub_ss_edi(unsigned long);
+
+extern unsigned long stub_ds_abs(unsigned long);
+extern unsigned long stub_ds_eax(unsigned long);
+extern unsigned long stub_ds_ecx(unsigned long);
+extern unsigned long stub_ds_edx(unsigned long);
+extern unsigned long stub_ds_ebx(unsigned long);
+extern unsigned long stub_ds_esp(unsigned long);
+extern unsigned long stub_ds_ebp(unsigned long);
+extern unsigned long stub_ds_esi(unsigned long);
+extern unsigned long stub_ds_edi(unsigned long);
+
+extern unsigned long stub_fs_abs(unsigned long);
+extern unsigned long stub_fs_eax(unsigned long);
+extern unsigned long stub_fs_ecx(unsigned long);
+extern unsigned long stub_fs_edx(unsigned long);
+extern unsigned long stub_fs_ebx(unsigned long);
+extern unsigned long stub_fs_esp(unsigned long);
+extern unsigned long stub_fs_ebp(unsigned long);
+extern unsigned long stub_fs_esi(unsigned long);
+extern unsigned long stub_fs_edi(unsigned long);
+
+extern unsigned long stub_gs_abs(unsigned long);
+extern unsigned long stub_gs_eax(unsigned long);
+extern unsigned long stub_gs_ecx(unsigned long);
+extern unsigned long stub_gs_edx(unsigned long);
+extern unsigned long stub_gs_ebx(unsigned long);
+extern unsigned long stub_gs_esp(unsigned long);
+extern unsigned long stub_gs_ebp(unsigned long);
+extern unsigned long stub_gs_esi(unsigned long);
+extern unsigned long stub_gs_edi(unsigned long);
+
+#else
+
+extern unsigned long stub_none_abs(unsigned long);
+extern unsigned long stub_none_rax(unsigned long);
+extern unsigned long stub_none_rcx(unsigned long);
+extern unsigned long stub_none_rdx(unsigned long);
+extern unsigned long stub_none_rbx(unsigned long);
+extern unsigned long stub_none_rsp(unsigned long);
+extern unsigned long stub_none_rbp(unsigned long);
+extern unsigned long stub_none_rsi(unsigned long);
+extern unsigned long stub_none_rdi(unsigned long);
+extern unsigned long stub_none_r8 (unsigned long);
+extern unsigned long stub_none_r9 (unsigned long);
+extern unsigned long stub_none_r10(unsigned long);
+extern unsigned long stub_none_r11(unsigned long);
+extern unsigned long stub_none_r12(unsigned long);
+extern unsigned long stub_none_r13(unsigned long);
+extern unsigned long stub_none_r14(unsigned long);
+extern unsigned long stub_none_r15(unsigned long);
+
+extern unsigned long stub_es_abs(unsigned long);
+extern unsigned long stub_es_rax(unsigned long);
+extern unsigned long stub_es_rcx(unsigned long);
+extern unsigned long stub_es_rdx(unsigned long);
+extern unsigned long stub_es_rbx(unsigned long);
+extern unsigned long stub_es_rsp(unsigned long);
+extern unsigned long stub_es_rbp(unsigned long);
+extern unsigned long stub_es_rsi(unsigned long);
+extern unsigned long stub_es_rdi(unsigned long);
+extern unsigned long stub_es_r8 (unsigned long);
+extern unsigned long stub_es_r9 (unsigned long);
+extern unsigned long stub_es_r10(unsigned long);
+extern unsigned long stub_es_r11(unsigned long);
+extern unsigned long stub_es_r12(unsigned long);
+extern unsigned long stub_es_r13(unsigned long);
+extern unsigned long stub_es_r14(unsigned long);
+extern unsigned long stub_es_r15(unsigned long);
+
+extern unsigned long stub_cs_abs(unsigned long);
+extern unsigned long stub_cs_rax(unsigned long);
+extern unsigned long stub_cs_rcx(unsigned long);
+extern unsigned long stub_cs_rdx(unsigned long);
+extern unsigned long stub_cs_rbx(unsigned long);
+extern unsigned long stub_cs_rsp(unsigned long);
+extern unsigned long stub_cs_rbp(unsigned long);
+extern unsigned long stub_cs_rsi(unsigned long);
+extern unsigned long stub_cs_rdi(unsigned long);
+extern unsigned long stub_cs_r8 (unsigned long);
+extern unsigned long stub_cs_r9 (unsigned long);
+extern unsigned long stub_cs_r10(unsigned long);
+extern unsigned long stub_cs_r11(unsigned long);
+extern unsigned long stub_cs_r12(unsigned long);
+extern unsigned long stub_cs_r13(unsigned long);
+extern unsigned long stub_cs_r14(unsigned long);
+extern unsigned long stub_cs_r15(unsigned long);
+
+extern unsigned long stub_ss_abs(unsigned long);
+extern unsigned long stub_ss_rax(unsigned long);
+extern unsigned long stub_ss_rcx(unsigned long);
+extern unsigned long stub_ss_rdx(unsigned long);
+extern unsigned long stub_ss_rbx(unsigned long);
+extern unsigned long stub_ss_rsp(unsigned long);
+extern unsigned long stub_ss_rbp(unsigned long);
+extern unsigned long stub_ss_rsi(unsigned long);
+extern unsigned long stub_ss_rdi(unsigned long);
+extern unsigned long stub_ss_r8 (unsigned long);
+extern unsigned long stub_ss_r9 (unsigned long);
+extern unsigned long stub_ss_r10(unsigned long);
+extern unsigned long stub_ss_r11(unsigned long);
+extern unsigned long stub_ss_r12(unsigned long);
+extern unsigned long stub_ss_r13(unsigned long);
+extern unsigned long stub_ss_r14(unsigned long);
+extern unsigned long stub_ss_r15(unsigned long);
+
+extern unsigned long stub_ds_abs(unsigned long);
+extern unsigned long stub_ds_rax(unsigned long);
+extern unsigned long stub_ds_rcx(unsigned long);
+extern unsigned long stub_ds_rdx(unsigned long);
+extern unsigned long stub_ds_rbx(unsigned long);
+extern unsigned long stub_ds_rsp(unsigned long);
+extern unsigned long stub_ds_rbp(unsigned long);
+extern unsigned long stub_ds_rsi(unsigned long);
+extern unsigned long stub_ds_rdi(unsigned long);
+extern unsigned long stub_ds_r8 (unsigned long);
+extern unsigned long stub_ds_r9 (unsigned long);
+extern unsigned long stub_ds_r10(unsigned long);
+extern unsigned long stub_ds_r11(unsigned long);
+extern unsigned long stub_ds_r12(unsigned long);
+extern unsigned long stub_ds_r13(unsigned long);
+extern unsigned long stub_ds_r14(unsigned long);
+extern unsigned long stub_ds_r15(unsigned long);
+
+extern unsigned long stub_fs_abs(unsigned long);
+extern unsigned long stub_fs_rax(unsigned long);
+extern unsigned long stub_fs_rcx(unsigned long);
+extern unsigned long stub_fs_rdx(unsigned long);
+extern unsigned long stub_fs_rbx(unsigned long);
+extern unsigned long stub_fs_rsp(unsigned long);
+extern unsigned long stub_fs_rbp(unsigned long);
+extern unsigned long stub_fs_rsi(unsigned long);
+extern unsigned long stub_fs_rdi(unsigned long);
+extern unsigned long stub_fs_r8 (unsigned long);
+extern unsigned long stub_fs_r9 (unsigned long);
+extern unsigned long stub_fs_r10(unsigned long);
+extern unsigned long stub_fs_r11(unsigned long);
+extern unsigned long stub_fs_r12(unsigned long);
+extern unsigned long stub_fs_r13(unsigned long);
+extern unsigned long stub_fs_r14(unsigned long);
+extern unsigned long stub_fs_r15(unsigned long);
+
+extern unsigned long stub_gs_abs(unsigned long);
+extern unsigned long stub_gs_rax(unsigned long);
+extern unsigned long stub_gs_rcx(unsigned long);
+extern unsigned long stub_gs_rdx(unsigned long);
+extern unsigned long stub_gs_rbx(unsigned long);
+extern unsigned long stub_gs_rsp(unsigned long);
+extern unsigned long stub_gs_rbp(unsigned long);
+extern unsigned long stub_gs_rsi(unsigned long);
+extern unsigned long stub_gs_rdi(unsigned long);
+extern unsigned long stub_gs_r8 (unsigned long);
+extern unsigned long stub_gs_r9 (unsigned long);
+extern unsigned long stub_gs_r10(unsigned long);
+extern unsigned long stub_gs_r11(unsigned long);
+extern unsigned long stub_gs_r12(unsigned long);
+extern unsigned long stub_gs_r13(unsigned long);
+extern unsigned long stub_gs_r14(unsigned long);
+extern unsigned long stub_gs_r15(unsigned long);
+
+#endif