loader: Build the preloader for ARM
André Hentschel
nerv at dawncrow.de
Mon Jan 31 16:13:51 CST 2011
it took me long, it was hard work, but here it is :)
i know the modulo stuff is not the nicest way, but there's no other chance...
---
configure.ac | 1 +
loader/main.c | 4 +-
loader/preloader.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 147 insertions(+), 5 deletions(-)
diff --git a/configure.ac b/configure.ac
index 1a8c5b0..967ee76 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1887,6 +1887,7 @@ case $host_os in
linux*)
case $host_cpu in
*i[[3456789]]86*) AC_SUBST(EXTRA_BINARIES,"wine-preloader") ;;
+ arm*) AC_SUBST(EXTRA_BINARIES,"wine-preloader") ;;
x86_64*) AC_SUBST(EXTRA_BINARIES,"wine64-preloader") ;;
esac
;;
diff --git a/loader/main.c b/loader/main.c
index 8434d81..daf302b 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -167,11 +167,11 @@ static int pre_exec(void)
return 1;
}
-#elif defined(__linux__) && defined(__x86_64__)
+#elif defined(__linux__) && (defined(__x86_64__) || defined(__ARM_EABI__))
static int pre_exec(void)
{
- return 1; /* we have a preloader on x86-64 */
+ return 1; /* we have a preloader */
}
#elif (defined(__FreeBSD__) || defined (__FreeBSD_kernel__)) && defined(__i386__)
diff --git a/loader/preloader.c b/loader/preloader.c
index e1c2276..412bd2f 100644
--- a/loader/preloader.c
+++ b/loader/preloader.c
@@ -108,7 +108,7 @@
static struct wine_preload_info preload_info[] =
{
-#ifdef __i386__
+#if defined(__i386__) || defined(__ARM_EABI__)
{ (void *)0x00000000, 0x00010000 }, /* low 64k */
{ (void *)0x00010000, 0x00100000 }, /* DOS area */
{ (void *)0x00110000, 0x67ef0000 }, /* low memory area */
@@ -430,6 +430,125 @@ SYSCALL_NOERR( wld_geteuid, 107 /* SYS_geteuid */ );
gid_t wld_getegid(void);
SYSCALL_NOERR( wld_getegid, 108 /* SYS_getegid */ );
+#elif defined(__ARM_EABI__)
+
+/*
+ * 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, #136\n\t" /* allocate some space for extra aux values */
+ "push {r0}\n\t" /* orig stack pointer */
+ "mov r0, sp\n\t" /* ptr to orig stack pointer */
+ "mov r6, r0\n\t"
+ "bl wld_start\n\t"
+ "mov sp, r6\n\t"
+ "pop {r1}\n\t"
+ "mov sp, r1\n\t"
+ "push {r0}\n\t"
+ "mov r0, #0\n\t"
+ "mov r1, #0\n\t"
+ "mov r2, #0\n\t"
+ "mov r3, #0\n\t"
+ "mov r4, #0\n\t"
+ "mov r5, #0\n\t"
+ "mov r6, #0\n\t"
+ "mov r7, #0\n\t"
+ "mov r8, #0\n\t"
+ "mov r9, #0\n\t"
+ "mov r10, #0\n\t"
+ "mov r11, #0\n\t"
+ "mov r12, #0\n\t"
+ "pop {PC}\n\t")
+
+#define SYSCALL_FUNC( name, nr ) \
+ __ASM_GLOBAL_FUNC( name, \
+ "push {LR}\n\t" \
+ "push {r7}\n\t" \
+ "mov r7, #" #nr "\n\t" \
+ "swi #0\n\t" \
+ "pop {r7}\n\t" \
+ "cmp r0, #0\n\t" \
+ "bge.n 1f\n\t" \
+ "mov r1, #0x1000\n\t" \
+ "sub r1, r1, #2\n\t" \
+ "eor r1, r1, #-1\n\t" \
+ "cmp r0, r1\n\t" \
+ "blt.n 1f\n\t" \
+ "mov.w r0, #-1\n\t" \
+ "1: pop {PC}\n\t" )
+
+#define SYSCALL_NOERR( name, nr ) \
+ __ASM_GLOBAL_FUNC( name, \
+ "push {r7,LR}\n\t" \
+ "mov r7, #" #nr "\n\t" \
+ "swi #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_open( const char *name, int flags );
+SYSCALL_FUNC( wld_open, 5 /* SYS_open */ );
+
+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, off_t pgoffset );
+ __ASM_GLOBAL_FUNC( wld_mmap2,
+ "mov ip, sp\n\t"
+ "stmfd sp!, {r4, r5, r6, r7, LR}\n\t"
+ "mov r7, #192\n\t" /* SYS_mmap2 */
+ "ldmfd ip, {r4, r5, r6}\n\t"
+ "mov r5, r6\n\t"
+ "swi 0x0\n\t"
+ "cmp r0, #0\n\t"
+ "bge.n 1f\n\t"
+ "mov r1, #0x1000\n\t"
+ "sub r1, r1, #2\n\t"
+ "eor r1, r1, #-1\n\t"
+ "cmp r0, r1\n\t"
+ "blt.n 1f\n\t"
+ "mov.w r0, #-1\n\t"
+ "1: ldmfd sp!, {r4, r5, r6, r7, PC}\n\t" )
+
+void *wld_mmap( void *start, size_t len, int prot, int flags, int fd, off_t offset )
+{
+ /* On ARM EABI we don't have mmap, so recalculate the offset into pages and use mmap2 */
+ offset /= 0x1000;
+ return wld_mmap2(start, len, prot, flags, fd, offset);
+}
+
+int wld_mprotect( const void *addr, size_t len, int prot );
+SYSCALL_FUNC( wld_mprotect, 125 /* SYS_mprotect */ );
+
+int wld_prctl( int code, int 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 */ );
+
#else
#error preloader not implemented for this CPU
#endif
@@ -457,6 +576,25 @@ static inline void *wld_memset( void *dest, int val, size_t len )
}
/*
+ * wld_modulo
+ *
+ * on ARM, gcc tries to link to __aeabi_uidivmod for modulo
+ * that function is a workaround for that problem
+ */
+unsigned int wld_modulo( const unsigned int a, const Elf32_Word b )
+{
+#ifdef __ARM_EABI__
+ unsigned int i;
+ if(b > a) return a;
+ for(i = 0; i * b < a + b; i++)
+ if(i * b > a - b) return (a - i * b);
+ return 0;
+#else
+ return a % b;
+#endif
+}
+
+/*
* wld_printf - just the basics
*
* %x prints a hex number
@@ -700,6 +838,9 @@ static void map_so_lib( const char *name, struct wld_link_map *l)
#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 );
+#elif defined(__ARM_EABI__)
+ 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]))
@@ -985,7 +1126,7 @@ static void *find_symbol( const ElfW(Phdr) *phdr, int num, const char *var, int
const Elf32_Word *buckets = (const Elf32_Word *)(bitmask + nwords);
const Elf32_Word *chains = buckets + nbuckets - symbias;
- if (!(idx = buckets[hash % nbuckets])) return NULL;
+ if (!(idx = buckets[wld_modulo(hash, nbuckets)])) return NULL;
do
{
if ((chains[idx] & ~1u) == (hash & ~1u) &&
@@ -1001,7 +1142,7 @@ static void *find_symbol( const ElfW(Phdr) *phdr, int num, const char *var, int
const Elf_Symndx *buckets = hashtab + 2;
const Elf_Symndx *chains = buckets + nbuckets;
- for (idx = buckets[hash % nbuckets]; idx != STN_UNDEF; idx = chains[idx])
+ for (idx = buckets[wld_modulo(hash, nbuckets)]; idx != STN_UNDEF; idx = chains[idx])
{
if (symtab[idx].st_info == ELF32_ST_INFO( STB_GLOBAL, type ) &&
!wld_strcmp( strings + symtab[idx].st_name, var ))
--
Best Regards, André Hentschel
More information about the wine-patches
mailing list