[PATCH v3] loader: Add support for ARM linux in the preloader
Martin Storsjö
martin at martin.st
Tue Aug 3 15:24:12 CDT 2021
Since 28fe84da45bea7de56539b50eac8ebcec54342de, the main exe image
must be mappable at its desired base address, which essentially
requires the preloader.
This fixes the original issue that lead to
https://bugs.winehq.org/show_bug.cgi?id=51539.
Signed-off-by: Martin Storsjö <martin at martin.st>
---
v3: Provide a trivial implementation of __aeabi_uidivmod to avoid
relying on extra sources.
---
configure.ac | 4 +-
dlls/ntdll/unix/loader.c | 6 +-
loader/preloader.c | 124 ++++++++++++++++++++++++++++++++++++++-
3 files changed, 126 insertions(+), 8 deletions(-)
diff --git a/configure.ac b/configure.ac
index b5d3217f2a0..c018c89f748 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 0e580cd7556..14f26cbd520 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]))
--
2.25.1
More information about the wine-devel
mailing list