Martin Storsjö : loader: Add support for ARM linux in the preloader.

Alexandre Julliard julliard at winehq.org
Thu Aug 5 16:13:40 CDT 2021


Module: wine
Branch: master
Commit: 29922c22765bb65352d48a3922c8fc07eebe7353
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=29922c22765bb65352d48a3922c8fc07eebe7353

Author: Martin Storsjö <martin at martin.st>
Date:   Tue Aug  3 23:24:12 2021 +0300

loader: Add support for ARM linux in the preloader.

Since 28fe84da45bea7de56539b50eac8ebcec54342de, the main exe image
must be mappable at its desired base address, which essentially
requires the preloader.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51539
Signed-off-by: Martin Storsjö <martin at martin.st>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 configure                |   4 +-
 configure.ac             |   4 +-
 dlls/ntdll/unix/loader.c |   6 +--
 loader/preloader.c       | 124 ++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 128 insertions(+), 10 deletions(-)

diff --git a/configure b/configure
index d3c60b4ff4c..1be0aa9d217 100755
--- a/configure
+++ b/configure
@@ -9473,7 +9473,7 @@ fi
       WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7d400000"
 
       case $host_cpu in
-        *i[3456789]86* | x86_64 | *aarch64*)
+        *i[3456789]86* | x86_64 | *aarch64* | arm*)
           { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-Ttext-segment=0x7bc00000" >&5
 $as_echo_n "checking whether the compiler supports -Wl,-Ttext-segment=0x7bc00000... " >&6; }
 if ${ac_cv_cflags__Wl__Ttext_segment_0x7bc00000+:} false; then :
@@ -18025,7 +18025,7 @@ esac
 case $host_os in
   linux*)
     case $host_cpu in
-      *i[3456789]86*|x86_64*|*aarch64*)
+      *i[3456789]86*|x86_64*|*aarch64*|arm*)
         test "$wine_binary" = wine || wine_fn_append_file CONFIGURE_TARGETS "loader/wine-preloader"
         WINELOADER_PROGRAMS="$WINELOADER_PROGRAMS $wine_binary-preloader"
         ;;
diff --git a/configure.ac b/configure.ac
index 5d9ca31099e..69e27147088 100644
--- a/configure.ac
+++ b/configure.ac
@@ -940,7 +940,7 @@ case $host_os in
       WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7d400000"
 
       case $host_cpu in
-        *i[[3456789]]86* | x86_64 | *aarch64*)
+        *i[[3456789]]86* | x86_64 | *aarch64* | arm*)
           WINE_TRY_CFLAGS([-Wl,-Ttext-segment=0x7bc00000],
                           [case $host_os in
                            freebsd* | kfreebsd*-gnu) WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -Wl,-Ttext-segment=0x60000000" ;;
@@ -2161,7 +2161,7 @@ esac
 case $host_os in
   linux*)
     case $host_cpu in
-      *i[[3456789]]86*|x86_64*|*aarch64*)
+      *i[[3456789]]86*|x86_64*|*aarch64*|arm*)
         test "$wine_binary" = wine || WINE_IGNORE_FILE("loader/wine-preloader")
         WINELOADER_PROGRAMS="$WINELOADER_PROGRAMS $wine_binary-preloader"
         ;;
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 8888376f2f0..55fc73d2d06 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -2155,11 +2155,7 @@ static int pre_exec(void)
     int temp;
 
     check_vmsplit( &temp );
-#ifdef __i386__
-    return 1;  /* we have a preloader on x86 */
-#else
-    return 0;
-#endif
+    return 1;  /* we have a preloader on x86/arm */
 }
 
 #elif defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__))
diff --git a/loader/preloader.c b/loader/preloader.c
index bb16ecd96a4..86308484182 100644
--- a/loader/preloader.c
+++ b/loader/preloader.c
@@ -111,7 +111,7 @@
 
 static struct wine_preload_info preload_info[] =
 {
-#ifdef __i386__
+#if defined(__i386__) || defined(__arm__)
     { (void *)0x00000000, 0x00010000 },  /* low 64k */
     { (void *)0x00010000, 0x00100000 },  /* DOS area */
     { (void *)0x00110000, 0x67ef0000 },  /* low memory area */
@@ -536,6 +536,125 @@ SYSCALL_NOERR( wld_geteuid, 175 /* SYS_geteuid */ );
 gid_t wld_getegid(void);
 SYSCALL_NOERR( wld_getegid, 177 /* SYS_getegid */ );
 
+#elif defined(__arm__)
+
+void *thread_data[256];
+
+/*
+ * 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,
+                  "mov r0, sp\n\t"
+                  "sub sp, sp, #144\n\t" /* allocate some space for extra aux values */
+                  "str r0, [sp]\n\t"     /* orig stack pointer */
+                  "ldr r0, =thread_data\n\t"
+                  "movw r7, #0x0005\n\t" /* __ARM_NR_set_tls */
+                  "movt r7, #0xf\n\t"    /* __ARM_NR_set_tls */
+                  "svc #0\n\t"
+                  "mov r0, sp\n\t"       /* ptr to orig stack pointer */
+                  "bl wld_start\n\t"
+                  "ldr r1, [sp]\n\t"     /* new stack pointer */
+                  "mov sp, r1\n\t"
+                  "mov lr, r0\n\t"
+                  "mov r0, #0\n\t"
+                  "mov r1, #0\n\t"
+                  "mov r2, #0\n\t"
+                  "mov r3, #0\n\t"
+                  "mov r12, #0\n\t"
+                  "bx lr\n\t"
+                  ".ltorg\n\t")
+
+#define SYSCALL_FUNC( name, nr ) \
+    __ASM_GLOBAL_FUNC( name, \
+                       "push {r4-r5,r7,lr}\n\t" \
+                       "ldr r4, [sp, #16]\n\t" \
+                       "ldr r5, [sp, #20]\n\t" \
+                       "mov r7, #" #nr "\n\t" \
+                       "svc #0\n\t" \
+                       "cmn r0, #4096\n\t" \
+                       "it hi\n\t" \
+                       "movhi r0, #-1\n\t" \
+                       "pop {r4-r5,r7,pc}\n\t" )
+
+#define SYSCALL_NOERR( name, nr ) \
+    __ASM_GLOBAL_FUNC( name, \
+                       "push {r7,lr}\n\t" \
+                       "mov r7, #" #nr "\n\t" \
+                       "svc #0\n\t" \
+                       "pop {r7,pc}\n\t" )
+
+void wld_exit( int code ) __attribute__((noreturn));
+SYSCALL_NOERR( wld_exit, 1 /* SYS_exit */ );
+
+ssize_t wld_read( int fd, void *buffer, size_t len );
+SYSCALL_FUNC( wld_read, 3 /* SYS_read */ );
+
+ssize_t wld_write( int fd, const void *buffer, size_t len );
+SYSCALL_FUNC( wld_write, 4 /* SYS_write */ );
+
+int wld_openat( int dirfd, const char *name, int flags );
+SYSCALL_FUNC( wld_openat, 322 /* SYS_openat */ );
+
+int wld_open( const char *name, int flags )
+{
+    return wld_openat(-100 /* AT_FDCWD */, name, flags);
+}
+
+int wld_close( int fd );
+SYSCALL_FUNC( wld_close, 6 /* SYS_close */ );
+
+void *wld_mmap2( void *start, size_t len, int prot, int flags, int fd, int offset );
+SYSCALL_FUNC( wld_mmap2, 192 /* SYS_mmap2 */ );
+
+void *wld_mmap( void *start, size_t len, int prot, int flags, int fd, off_t offset )
+{
+    return wld_mmap2(start, len, prot, flags, fd, offset >> 12);
+}
+
+int wld_mprotect( const void *addr, size_t len, int prot );
+SYSCALL_FUNC( wld_mprotect, 125 /* SYS_mprotect */ );
+
+int wld_prctl( int code, long arg );
+SYSCALL_FUNC( wld_prctl, 172 /* SYS_prctl */ );
+
+uid_t wld_getuid(void);
+SYSCALL_NOERR( wld_getuid, 24 /* SYS_getuid */ );
+
+gid_t wld_getgid(void);
+SYSCALL_NOERR( wld_getgid, 47 /* SYS_getgid */ );
+
+uid_t wld_geteuid(void);
+SYSCALL_NOERR( wld_geteuid, 49 /* SYS_geteuid */ );
+
+gid_t wld_getegid(void);
+SYSCALL_NOERR( wld_getegid, 50 /* SYS_getegid */ );
+
+unsigned long long __aeabi_uidivmod(unsigned int num, unsigned int den)
+{
+    unsigned int bit = 1;
+    unsigned int quota = 0;
+    if (!den)
+        wld_exit(1);
+    while (den < num && !(den & 0x80000000)) {
+        den <<= 1;
+        bit <<= 1;
+    }
+    do {
+        if (den <= num) {
+            quota |= bit;
+            num   -= den;
+        }
+        bit >>= 1;
+        den >>= 1;
+    } while (bit);
+    return ((unsigned long long)num << 32) | quota;
+}
+
 #else
 #error preloader not implemented for this CPU
 #endif
@@ -809,6 +928,9 @@ static void map_so_lib( const char *name, struct wld_link_map *l)
 #elif defined(__aarch64__)
     if( header->e_machine != EM_AARCH64 )
         fatal_error("%s: not an aarch64 ELF binary... don't know how to load it\n", name );
+#elif defined(__arm__)
+    if( header->e_machine != EM_ARM )
+        fatal_error("%s: not an arm ELF binary... don't know how to load it\n", name );
 #endif
 
     if (header->e_phnum > sizeof(loadcmds)/sizeof(loadcmds[0]))




More information about the wine-cvs mailing list