Alexandre Julliard : loader: Build the preloader for x86-64.

Alexandre Julliard julliard at winehq.org
Fri Dec 17 11:30:44 CST 2010


Module: wine
Branch: master
Commit: 0a0862001bb446e473324b121ae6e5a743fd96e0
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=0a0862001bb446e473324b121ae6e5a743fd96e0

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Thu Dec 16 16:54:15 2010 +0100

loader: Build the preloader for x86-64.

---

 .gitignore         |    1 +
 configure          |   11 ++--
 configure.ac       |   10 ++--
 loader/Makefile.in |    9 ++--
 loader/main.c      |    7 +++
 loader/preloader.c |  144 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 166 insertions(+), 16 deletions(-)

diff --git a/.gitignore b/.gitignore
index 16370d3..95b9fe9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -262,6 +262,7 @@ loader/wine
 loader/wine-installed
 loader/wine-preloader
 loader/wine64
+loader/wine64-preloader
 programs/Makeprog.rules
 programs/rpcss/epm.h
 programs/rpcss/epm_s.c
diff --git a/configure b/configure
index c1256ba..18ec4a7 100755
--- a/configure
+++ b/configure
@@ -12736,11 +12736,12 @@ MAIN_BINARY="wine"
 
 test "x$enable_win64" != "xyes" || MAIN_BINARY="wine64"
 
-case $host_cpu in
-  *i[3456789]86*)
-    case $host_os in
-      linux*)
-        EXTRA_BINARIES="wine-preloader"
+case $host_os in
+  linux*)
+    case $host_cpu in
+      *i[3456789]86*) EXTRA_BINARIES="wine-preloader"
+ ;;
+      x86_64*) EXTRA_BINARIES="wine64-preloader"
  ;;
     esac
     ;;
diff --git a/configure.ac b/configure.ac
index 71c14d3..012df93 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1863,11 +1863,11 @@ esac
 AC_SUBST(MAIN_BINARY,"wine")
 test "x$enable_win64" != "xyes" || MAIN_BINARY="wine64"
 
-case $host_cpu in
-  *i[[3456789]]86*)
-    case $host_os in
-      linux*)
-        AC_SUBST(EXTRA_BINARIES,"wine-preloader") ;;
+case $host_os in
+  linux*)
+    case $host_cpu in
+      *i[[3456789]]86*) AC_SUBST(EXTRA_BINARIES,"wine-preloader") ;;
+      x86_64*) AC_SUBST(EXTRA_BINARIES,"wine64-preloader") ;;
     esac
     ;;
 esac
diff --git a/loader/Makefile.in b/loader/Makefile.in
index 0ededde..ecaae76 100644
--- a/loader/Makefile.in
+++ b/loader/Makefile.in
@@ -9,9 +9,10 @@ EXTRA_BINARIES = @EXTRA_BINARIES@
 
 PROGRAMS = \
 	wine \
-	wine64 \
 	wine-installed \
-	wine-preloader
+	wine-preloader \
+	wine64 \
+	wine64-preloader
 
 MANPAGE = wine.man
 
@@ -32,8 +33,8 @@ all: $(MAIN_BINARY) wine-installed $(EXTRA_BINARIES)
 LIBPTHREAD  = @LIBPTHREAD@
 LDEXECFLAGS = @LDEXECFLAGS@
 
-wine-preloader: preloader.o Makefile.in
-	$(CC) -o $@ -static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7c000000 preloader.o $(LIBPORT) $(LDFLAGS)
+wine-preloader wine64-preloader: preloader.o Makefile.in
+	$(CC) -o $@ -static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7c400000 preloader.o $(LIBPORT) $(LDFLAGS)
 
 $(MAIN_BINARY): main.o Makefile.in
 	$(CC) -o $@ $(LDEXECFLAGS) main.o $(LIBWINE) $(LIBPORT) $(LIBPTHREAD) $(EXTRALIBS) $(LDFLAGS) $(LDRPATH_LOCAL)
diff --git a/loader/main.c b/loader/main.c
index 628a0fa..9fe5e59 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -164,6 +164,13 @@ static int pre_exec(void)
     return 1;
 }
 
+#elif defined(__linux__) && defined(__x86_64__)
+
+static int pre_exec(void)
+{
+    return 1;  /* we have a preloader on x86-64 */
+}
+
 #elif defined(__FreeBSD__) && defined(__i386__)
 
 static int pre_exec(void)
diff --git a/loader/preloader.c b/loader/preloader.c
index b14d94e..995cf59 100644
--- a/loader/preloader.c
+++ b/loader/preloader.c
@@ -108,10 +108,17 @@
 
 static struct wine_preload_info preload_info[] =
 {
+#ifdef __i386__
     { (void *)0x00000000, 0x00010000 },  /* low 64k */
     { (void *)0x00010000, 0x00100000 },  /* DOS area */
     { (void *)0x00110000, 0x67ef0000 },  /* low memory area */
     { (void *)0x7f000000, 0x03000000 },  /* top-down allocations + shared heap + virtual heap */
+#else
+    { (void *)0x000000010000, 0x00100000 },  /* DOS area */
+    { (void *)0x000000110000, 0x67ef0000 },  /* low memory area */
+    { (void *)0x00007ff00000, 0x000f0000 },  /* shared user data */
+    { (void *)0x7ffffe000000, 0x01ff0000 },  /* top-down allocations + virtual heap */
+#endif
     { 0, 0 },                            /* PE exe range set with WINEPRELOADRESERVE */
     { 0, 0 }                             /* end of list */
 };
@@ -166,6 +173,8 @@ void *__stack_chk_guard = 0;
 void __stack_chk_fail_local(void) { return; }
 void __stack_chk_fail(void) { return; }
 
+#ifdef __i386__
+
 /* data for setting up the glibc-style thread-local storage in %gs */
 
 static int thread_data[256];
@@ -333,6 +342,126 @@ static inline int wld_prctl( int code, long arg )
     return SYSCALL_RET(ret);
 }
 
+#elif defined(__x86_64__)
+
+/*
+ * The _start function is the entry and exit point of this program
+ *
+ *  It calls wld_start, passing a pointer to the args it receives
+ *  then jumps to the address wld_start returns.
+ */
+void _start(void);
+extern char _end[];
+__ASM_GLOBAL_FUNC(_start,
+                  "movq %rsp,%rax\n\t"
+                  "leaq -144(%rsp),%rsp\n\t" /* allocate some space for extra aux values */
+                  "movq %rsp,%rdi\n\t"       /* ptr to orig stack pointer */
+                  "movq %rax,(%rdi)\n\t"     /* orig stack pointer */
+                  "call wld_start\n\t"
+                  "movq (%rsp),%rsp\n\t"     /* new stack pointer */
+                  "pushq %rax\n\t"           /* ELF interpreter entry point */
+                  "xorq %rax,%rax\n\t"
+                  "xorq %rcx,%rcx\n\t"
+                  "xorq %rdx,%rdx\n\t"
+                  "xorq %rsi,%rsi\n\t"
+                  "xorq %rdi,%rdi\n\t"
+                  "xorq %r8,%r8\n\t"
+                  "xorq %r9,%r9\n\t"
+                  "xorq %r10,%r10\n\t"
+                  "xorq %r11,%r11\n\t"
+                  "ret")
+
+#define SYSCALL_RET(ret) (((ret) < 0 && (ret) > -4096) ? -1 : (ret))
+
+static inline __attribute__((noreturn)) void wld_exit( int code )
+{
+    for (;;)  /* avoid warning */
+        __asm__ __volatile__( "syscall" : : "a" (SYS_exit), "D" (code) );
+}
+
+static inline int wld_open( const char *name, int flags )
+{
+    int ret;
+    __asm__ __volatile__( "syscall" : "=a" (ret) : "0" (SYS_open), "D" (name), "S" (flags) );
+    return SYSCALL_RET(ret);
+}
+
+static inline int wld_close( int fd )
+{
+    int ret;
+    __asm__ __volatile__( "syscall" : "=a" (ret) : "0" (SYS_close), "D" (fd) );
+    return SYSCALL_RET(ret);
+}
+
+static inline ssize_t wld_read( int fd, void *buffer, size_t len )
+{
+    int ret;
+    __asm__ __volatile__( "syscall"
+                          : "=a" (ret)
+                          : "0" (SYS_read), "D" (fd), "S" (buffer), "d" (len)
+                          : "memory" );
+    return SYSCALL_RET(ret);
+}
+
+static inline ssize_t wld_write( int fd, const void *buffer, size_t len )
+{
+    int ret;
+    __asm__ __volatile__( "syscall" : "=a" (ret) : "0" (SYS_write), "D" (fd), "S" (buffer), "d" (len) );
+    return SYSCALL_RET(ret);
+}
+
+static inline int wld_mprotect( const void *addr, size_t len, int prot )
+{
+    int ret;
+    __asm__ __volatile__( "syscall" : "=a" (ret) : "0" (SYS_mprotect), "D" (addr), "S" (len), "d" (prot) );
+    return SYSCALL_RET(ret);
+}
+
+void *wld_mmap( void *start, size_t len, int prot, int flags, int fd, off_t offset );
+__ASM_GLOBAL_FUNC( wld_mmap,
+                   "movq %rcx,%r10\n\t"
+                   "movq $9,%rax\n\t"  /* SYS_mmap */
+                   "syscall\n\t"
+                   "ret" );
+
+static inline uid_t wld_getuid(void)
+{
+    uid_t ret;
+    __asm__( "syscall" : "=a" (ret) : "0" (SYS_getuid) );
+    return ret;
+}
+
+static inline uid_t wld_geteuid(void)
+{
+    uid_t ret;
+    __asm__( "syscall" : "=a" (ret) : "0" (SYS_geteuid) );
+    return ret;
+}
+
+static inline gid_t wld_getgid(void)
+{
+    gid_t ret;
+    __asm__( "syscall" : "=a" (ret) : "0" (SYS_getgid) );
+    return ret;
+}
+
+static inline gid_t wld_getegid(void)
+{
+    gid_t ret;
+    __asm__( "syscall" : "=a" (ret) : "0" (SYS_getegid) );
+    return ret;
+}
+
+static inline int wld_prctl( int code, int arg )
+{
+    int ret;
+    __asm__ __volatile__( "syscall" : "=a" (ret) : "D" (SYS_prctl), "S" (code), "d" (arg) );
+    return SYSCALL_RET(ret);
+}
+
+#else
+#error preloader not implemented for this CPU
+#endif
 
 /* replacement for libc functions */
 
@@ -594,8 +723,13 @@ static void map_so_lib( const char *name, struct wld_link_map *l)
         ( header->e_ident[3] != 'F' ) )
         fatal_error( "%s: not an ELF binary... don't know how to load it\n", name );
 
+#ifdef __i386__
     if( header->e_machine != EM_386 )
         fatal_error("%s: not an i386 ELF binary... don't know how to load it\n", name );
+#elif defined(__x86_64__)
+    if( header->e_machine != EM_X86_64 )
+        fatal_error("%s: not an x86-64 ELF binary... don't know how to load it\n", name );
+#endif
 
     if (header->e_phnum > sizeof(loadcmds)/sizeof(loadcmds[0]))
         fatal_error( "%s: oops... not enough space for load commands\n", name );
@@ -1082,8 +1216,14 @@ void* wld_start( void **stack )
     if (reserve) preload_reserve( reserve );
     for (i = 0; preload_info[i].size; i++)
     {
-        if (wld_mmap( preload_info[i].addr, preload_info[i].size, PROT_NONE,
-                      MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0 ) == (void *)-1)
+        if ((char *)av >= (char *)preload_info[i].addr &&
+            (char *)pargc <= (char *)preload_info[i].addr + preload_info[i].size)
+        {
+            remove_preload_range( i );
+            i--;
+        }
+        else if (wld_mmap( preload_info[i].addr, preload_info[i].size, PROT_NONE,
+                           MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0 ) == (void *)-1)
         {
             /* don't warn for low 64k */
             if (preload_info[i].addr >= (void *)0x10000)




More information about the wine-cvs mailing list