libvx32: build on x86-64 using gcc 4.3.2 - vx32 - Local 9vx git repository for patches.
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit ca1bfbd9fc9043c99d6c1d4f97caca6ac676bb70
 (DIR) parent 04c6b5b7c2535cf384926b6ccdce3dbeb0c78651
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Sun,  7 Dec 2008 20:18:46 -0800
       
       libvx32: build on x86-64 using gcc 4.3.2
       
       Diffstat:
         src/libvx32/Makefrag                |       1 -
         src/libvx32/asm.h                   |      25 -------------------------
         src/libvx32/elf.c                   |       6 ++++--
         src/libvx32/emu.c                   |       4 ++--
         src/libvx32/linux-asm.S             |      58 +++++++++++++++++++++++++++++--
         src/libvx32/linux.c                 |      54 ++++++++++++++++++++++++++++---
         src/libvx32/rts.S                   |       4 ++--
         src/libvx32/run32.S                 |       4 ++--
         src/libvx32/run64.S                 |       4 ++--
         src/libvx32/sig.c                   |       2 +-
         src/libvx32/vx32impl.h              |       2 ++
         src/libvx32/x86dis.c                |       6 +++---
       
       12 files changed, 124 insertions(+), 46 deletions(-)
       ---
 (DIR) diff --git a/src/libvx32/Makefrag b/src/libvx32/Makefrag
       @@ -52,4 +52,3 @@ libvx32/libvx32.a: $(VX32_OBJS)
        
        $(prefix)/lib/libvx32.a: libvx32/libvx32.a
                $(INSTALL) $< $@
       -
 (DIR) diff --git a/src/libvx32/asm.h b/src/libvx32/asm.h
       @@ -1,25 +0,0 @@
       -#define ASDF 12345
       -#define VXEMU_DATASEL 12
       -#define VXEMU_EMUSEL 16
       -#define VXEMU_EMUPTR 28
       -#define VXEMU_REG 32
       -#define VXEMU_EAX 32
       -#define VXEMU_ECX 36
       -#define VXEMU_EDX 40
       -#define VXEMU_EBX 44
       -#define VXEMU_ESP 48
       -#define VXEMU_EBP 52
       -#define VXEMU_ESI 56
       -#define VXEMU_EDI 60
       -#define VXEMU_EIP 64
       -#define VXEMU_EFLAGS 68
       -#define VXEMU_TRAPNO 80
       -#define VXEMU_JMPINFO 100
       -#define VXEMU_HOST_SS 124
       -#define VXEMU_HOST_DS 126
       -#define VXEMU_HOST_ES 128
       -#define VXEMU_HOST_VS 130
       -#define VXEMU_HOST_ESP 132
       -#define VXEMU_ETABLEN 152
       -#define VXEMU_ETABMASK 156
       -#define VXEMU_ETAB 164
 (DIR) diff --git a/src/libvx32/elf.c b/src/libvx32/elf.c
       @@ -153,10 +153,12 @@ static int elfloader(vxproc *proc,
                // For "big mem" we need more than 1/2 GB, but 64-bit Linux
                // has only about 1 GB of address space to give out with MAP_32BIT,
                // and we've used up some of it for the vxemu structure.  
       -        // Ask for (1<<30) - (1<<24), which should be close enough to 1GB
       +        // Used to ask for (1<<30) - (1<<24), which should be close enough to 1GB
                // to run the SPEC programs but leave enough for things like vxemu.
       +        // On Ubuntu 8.10, I get intermittent ouf of memory errors from this
       +        // mmap, so back off to 1<<29.
                if (vx_elfbigmem)
       -                size = (1<<30) - (1<<24);
       +                size = (1<<29);
        
                mm = NULL;
        
 (DIR) diff --git a/src/libvx32/emu.c b/src/libvx32/emu.c
       @@ -26,7 +26,7 @@
        
        // Special values for unused entries in entrypoint hash table
        #define NULLSRCEIP                ((uint32_t)-1)
       -#define NULLDSTEIP                ((uint32_t)vxrun_nullfrag);
       +#define NULLDSTEIP                ((uint32_t)(uintptr_t)vxrun_nullfrag);
        
        int vx32_debugxlate = 0;
        
       @@ -1904,6 +1904,6 @@ void vxprint(char *fmt, ...)
                va_start(arg, fmt);
                vsnprintf(buf, sizeof buf, fmt, arg);
                va_end(arg);
       -        write(2, buf, strlen(buf));
       +        USED(write(2, buf, strlen(buf)));
        }
        
 (DIR) diff --git a/src/libvx32/linux-asm.S b/src/libvx32/linux-asm.S
       @@ -6,6 +6,8 @@
        // notice also that unlike the linux getcontext,
        // we *do* copy the segment registers
        
       +#ifdef i386
       +
        .globl vx32_getcontext
        vx32_getcontext:
                movl 4(%esp), %eax
       @@ -33,8 +35,10 @@ vx32_getcontext:
                /* 56(%eax) is eip */
                movw %cs, %cx
                movl %ecx, 60(%eax)
       -        pushfl
       -        popl 64(%eax)
       +        pushf
       +        movl 0(%esp), %ecx
       +        popf
       +        movl %ecx, 64(%eax)
                /* 68(%eax) is another esp */
                movw %ss, %cx
                movl %ecx, 72(%eax)
       @@ -49,3 +53,53 @@ vx32_getcontext:
                movl $0, %eax
                ret
        
       +#else        /* x86-64 */
       +
       +.globl vx32_getcontext
       +vx32_getcontext:
       +        // mcontext_t pointer is in %rdi
       +        movq %r8, 0(%rdi)
       +        movq %r9, 8(%rdi)
       +        movq %r10, 16(%rdi)
       +        movq %r11, 24(%rdi)
       +        movq %r12, 32(%rdi)
       +        movq %r13, 40(%rdi)
       +        movq %r14, 48(%rdi)
       +        movq %r15, 56(%rdi)
       +        movq %rdi, 64(%rdi)
       +        movq %rsi, 72(%rdi)
       +        movq %rbp, 80(%rdi)
       +        movq %rbx, 88(%rdi)
       +        movq %rdx, 96(%rdi)
       +        movq $1, 104(%rdi)        /* %rax */
       +        movq %rcx, 112(%rdi)
       +        /* 120(%rdi) is rsp */
       +        leaq 8(%rsp), %rax
       +        movq %rax, 120(%rdi)
       +        /* 128(%rdi) is rip */
       +        movq 0(%rsp), %rax
       +        movq %rax, 128(%rdi)
       +        /* 136(%rdi) is eflags */
       +        pushf
       +        popq %rax
       +        movq %rax, 136(%rdi)
       +        /* 144(%rdi) is cs, gs, fs, pad */
       +        xorq %rax, %rax
       +        movw %fs, %ax
       +        shlq $16, %rax
       +        movw %gs, %ax
       +        shlq $16, %rax
       +        movw %cs, %ax
       +        movq %rax, 144(%rdi)
       +        /* 152(%rdi) is err */
       +        movq $0, 152(%rdi)
       +        /* 160(%rdi) is trapno */
       +        movq $0, 160(%rdi)
       +        /* 168(%rdi) is oldmask */
       +        movq $0, 168(%rdi)
       +        /* 176(%rdi) is cr2 */
       +        movq $0, 176(%rdi)
       +        movq $0, %rax
       +        ret
       +
       +#endif
 (DIR) diff --git a/src/libvx32/linux.c b/src/libvx32/linux.c
       @@ -8,6 +8,7 @@
        #include <ucontext.h>
        #include <sys/ucontext.h>
        #include <asm/ldt.h>
       +#include <errno.h>
        
        #include "vx32.h"
        #include "vx32impl.h"
       @@ -19,6 +20,7 @@ int vxemu_map(vxemu *emu, vxmmap *mm)
        {
                struct vxproc *vxp;
                struct user_desc desc;
       +        uint ldt[2];
        #ifdef __x86_64
                static int didflat;
        #endif
       @@ -73,13 +75,55 @@ int vxemu_map(vxemu *emu, vxmmap *mm)
                        desc.seg_not_present = 0;
                        desc.useable = 1;
        
       -                desc.entry_number = emu->runptr.sel / 8;
       +                desc.entry_number = FLATCODE / 8;
                        desc.base_addr = 0;
                        desc.limit = 0xfffff;
                        desc.contents = MODIFY_LDT_CONTENTS_CODE;
                        if (modify_ldt(1, &desc, sizeof(desc)) < 0)
                                return -1;
       -        
       +                
       +                /*
       +                 * Linux 2.6.27 has a bug: it does not load the L (long mode)
       +                 * bit from desc.lm when copying desc into its own
       +                 * copy of the LDT entry on the kernel stack.
       +                 * Instead, it leaves L uninitialized, picking up whatever
       +                 * random bit was left on the kernel stack by the
       +                 * previous call sequence.  We need L to be 0.
       +                 * If it ends up 1, the *ljmpq in run64.S will GP fault.
       +                 * Luckily, we can look for this by asking to read
       +                 * back the raw LDT bytes.  If we observe this problem,
       +                 * try to fix it by doing a modify_ldt with base = limit = 0,
       +                 * which clears the entire stack ldt structure, and then
       +                 * quickly do another modify_ldt with desc, hoping that
       +                 * the bit will still be zero when we get there for the
       +                 * second modify_ldt.  I wish I were making this up.
       +                 * This is fixed in Linus's git repository, but the Ubuntu
       +                 * git repositories are still out of date.  See for example
       +                 *         http://swtch.com/go/ubuntu-ldt
       +                 *        http://swtch.com/go/linus-ldt
       +                 *
       +                 * Remember, folks, Free Software is only free if your
       +                 * time has no value.
       +                 */
       +                if(modify_ldt(0, ldt, sizeof ldt) < 0)
       +                        return -1;
       +                if(ldt[1] & 0x00200000) {
       +                        if (vx32_debugxlate)
       +                                vxprint("FLATCODE LDT=%08x %08x; working around\n", ldt[0], ldt[1]);
       +                        desc.limit = 0;
       +                        modify_ldt(1, &desc, sizeof desc);
       +                        desc.limit = 0xfffff;
       +                        modify_ldt(1, &desc, sizeof desc);
       +                        modify_ldt(0, ldt, sizeof ldt);
       +                        if(ldt[1] & 0x00200000) {
       +                                vxprint("cannot work around Linux FLATCODE bug\n");
       +                                errno = EBADE;
       +                                return -1;
       +                        }
       +                        if (vx32_debugxlate)
       +                                vxprint("FLATCODE LDT=%08x %08x\n", ldt[0], ldt[1]);
       +                }
       +
                        desc.entry_number = FLATDATA / 8;
                        desc.base_addr = 0;
                        desc.limit = 0xfffff;
       @@ -179,6 +223,7 @@ int vx32_sighandler(int signo, siginfo_t *si, void *v)
                
                if(0) vxprint("vx32_sighandler signo=%d eip=%#x esp=%#x vs=%#x\n",
                        signo, ctx->ctxeip, ctx->esp, vs);
       +        if(0) dumpsigcontext(ctx);
        
                if ((vs & 15) != 15)        // 8 (emu), LDT, RPL=3
                        return 0;
       @@ -325,8 +370,9 @@ int vx32_sighandler(int signo, siginfo_t *si, void *v)
                        // But on a segmentation fault (as opposed to a paging fault),
                        // cr2 is not updated and the kernel sends an si_addr == 0.
                        // Be sure to use si_addr, not cr2.
       -                emu->cpu.trapva = (uint32_t)si->si_addr;
       -                memmove(mc->gregs, emu->trapenv->gregs, 19*4);
       +                emu->cpu.trapva = (uint32_t)(uintptr_t)si->si_addr;
       +                memmove(mc->gregs, emu->trapenv->gregs, sizeof emu->trapenv->gregs);
       +                
                        return 1;
                }
        
 (DIR) diff --git a/src/libvx32/rts.S b/src/libvx32/rts.S
       @@ -2,8 +2,8 @@
        // Assembly-language runtime support for translated vx32 code.
        //
        
       -#include "asm.h"
       -#include "os.h"
       +#include "libvx32/asm.h"
       +#include "libvx32/os.h"
        
        
        // The method we use to get back out to host code differs for 32/64-bit hosts.
 (DIR) diff --git a/src/libvx32/run32.S b/src/libvx32/run32.S
       @@ -2,8 +2,8 @@
        // Assembly-language support code for vx32-to-x86-32 translation
        //
        
       -#include "asm.h"
       -#include "os.h"
       +#include "libvx32/asm.h"
       +#include "libvx32/os.h"
        
                .text
        
 (DIR) diff --git a/src/libvx32/run64.S b/src/libvx32/run64.S
       @@ -2,8 +2,8 @@
        // Assembly-language support code for vx32-to-x86-64 translation
        //
        
       -#include "asm.h"
       -#include "os.h"
       +#include "libvx32/asm.h"
       +#include "libvx32/os.h"
        
                .text
        
 (DIR) diff --git a/src/libvx32/sig.c b/src/libvx32/sig.c
       @@ -69,7 +69,7 @@ int vxemu_sighandler(vxemu *emu, uint32_t trapeip)
                // In vx32 runtime code (rts.S, run32/64.S), the registers are in flux.
                // Single-step until we can get out; then they'll be safe to look at.
                // This only makes sense if the trap is an external trap like a timer.
       -        char *eip = (char*)trapeip;
       +        char *eip = (char*)(uintptr_t)trapeip;
                if ((emu->cpu_trap&VXTRAP_CATEGORY) != VXTRAP_CPU){
                        // The check for run32/64.S doesn't look for the entire file.
                        // Instead it looks for anywhere in the file except
 (DIR) diff --git a/src/libvx32/vx32impl.h b/src/libvx32/vx32impl.h
       @@ -251,5 +251,7 @@ void        vxprint(char*, ...);
        int        vx32_sighandler(int, siginfo_t*, void*);
        int        vxemu_sighandler(vxemu*, uint32_t);
        
       +#define USED(x) if(x){}        /* shut up gcc not-used warning */
       +
        #endif  // VX32_IMPL_H
        
 (DIR) diff --git a/src/libvx32/x86dis.c b/src/libvx32/x86dis.c
       @@ -1700,11 +1700,11 @@ fmtarg(char *p, char *ep, xdarg *da, uint32_t npc)
                        break;
                case DA_REL:
                        addr = da->disp + npc;
       -                if (addr == (uint32_t)vxrun_gentrap)
       +                if (addr == (uint32_t)(uintptr_t)vxrun_gentrap)
                                p += snprintf(p, ep-p, "vxrun_gentrap");
       -                else if (addr == (uint32_t)vxrun_lookup_backpatch)
       +                else if (addr == (uint32_t)(uintptr_t)vxrun_lookup_backpatch)
                                p += snprintf(p, ep-p, "vxrun_lookup_backpatch");
       -                else if (addr == (uint32_t)vxrun_lookup_indirect)
       +                else if (addr == (uint32_t)(uintptr_t)vxrun_lookup_indirect)
                                p += snprintf(p, ep-p, "vxrun_lookup_indirect");
                        else
                                p += snprintf(p, ep-p, "%#x", da->disp + npc);