From bfac60bfebb0e072d12630c42dbfac58a7da4949 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 22 Jun 2004 02:42:05 +0000 Subject: [PATCH] Do direct Linux system calls in the preloader to avoid trouble with some broken static libcs. --- configure | 50 --------------- configure.ac | 1 - loader/Makefile.in | 2 +- loader/preloader.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 161 insertions(+), 75 deletions(-) diff --git a/configure b/configure index 9294d0046ad..cdbc458f150 100755 --- a/configure +++ b/configure @@ -14607,56 +14607,6 @@ esac case $host_os in linux*) - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -static" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 - (eval $ac_link) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { echo "$as_me:$LINENO: error: You need to install the static version of glibc to build Wine." >&5 -echo "$as_me: error: You need to install the static version of glibc to build Wine." >&2;} - { (exit 1); exit 1; }; } -fi -rm -f conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved WINE_BINARIES="wine-glibc wine-kthread wine-pthread wine-preloader" MAIN_BINARY="wine-glibc" diff --git a/configure.ac b/configure.ac index 2cb240700fb..27be0d13284 100644 --- a/configure.ac +++ b/configure.ac @@ -989,7 +989,6 @@ esac case $host_os in linux*) - WINE_TRY_CFLAGS([-static],,AC_MSG_ERROR([You need to install the static version of glibc to build Wine.])) AC_SUBST(WINE_BINARIES,"wine-glibc wine-kthread wine-pthread wine-preloader") AC_SUBST(MAIN_BINARY,"wine-glibc") ;; diff --git a/loader/Makefile.in b/loader/Makefile.in index 5a5fb303c46..0167fb3313b 100644 --- a/loader/Makefile.in +++ b/loader/Makefile.in @@ -28,7 +28,7 @@ wine-glibc: glibc.o Makefile.in $(CC) -o $@ glibc.o $(LIBWINE) $(LIBPORT) $(LIBPTHREAD) $(EXTRALIBS) $(LDFLAGS) wine-preloader: preloader.o Makefile.in - $(CC) -o $@ -static -nostartfiles -Wl,-Ttext=0x78000000 preloader.o $(LIBPORT) $(LDFLAGS) + $(CC) -o $@ -static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x78000000 preloader.o $(LIBPORT) $(LDFLAGS) wine-kthread: $(KTHREAD_OBJS) Makefile.in $(CC) -o $@ $(LDEXECFLAGS) $(KTHREAD_OBJS) $(LIBWINE) $(LIBPORT) $(EXTRALIBS) $(LDFLAGS) diff --git a/loader/preloader.c b/loader/preloader.c index 85dbd9cc535..7bdf83d86e4 100644 --- a/loader/preloader.c +++ b/loader/preloader.c @@ -73,6 +73,9 @@ #ifdef HAVE_SYS_MMAN_H # include #endif +#ifdef HAVE_SYS_SYSCALL_H +# include +#endif #ifdef HAVE_UNISTD_H # include #endif @@ -156,6 +159,140 @@ __ASM_GLOBAL_FUNC(_start, "\txor %edx,%edx\n" "\tret\n") +/* wrappers for Linux system calls */ + +#define SYSCALL_RET(ret) (((ret) < 0 && (ret) > -4096) ? -1 : (ret)) + +static inline __attribute__((noreturn)) void wld_exit( int code ) +{ + for (;;) /* avoid warning */ + __asm__ __volatile__( "int $0x80" : : "a" (SYS_exit), "b" (code) ); +} + +static inline int wld_open( const char *name, int flags ) +{ + int ret; + __asm__ __volatile__( "int $0x80" : "=a" (ret) : "0" (SYS_open), "b" (name), "c" (flags) ); + return SYSCALL_RET(ret); +} + +static inline int wld_close( int fd ) +{ + int ret; + __asm__ __volatile__( "int $0x80" : "=a" (ret) : "0" (SYS_close), "b" (fd) ); + return SYSCALL_RET(ret); +} + +static inline ssize_t wld_read( int fd, void *buffer, size_t len ) +{ + int ret; + __asm__ __volatile__( "int $0x80" : "=a" (ret) + : "0" (SYS_read), "b" (fd), "c" (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__( "int $0x80" : "=a" (ret) + : "0" (SYS_write), "b" (fd), "c" (buffer), "d" (len) ); + return SYSCALL_RET(ret); +} + +static inline int wld_mprotect( const void *addr, size_t len, int prot ) +{ + int ret; + __asm__ __volatile__( "int $0x80" : "=a" (ret) : "0" (SYS_mprotect), "b" (addr), "c" (len), "d" (prot) ); + return SYSCALL_RET(ret); +} + +static void *wld_mmap( void *start, size_t len, int prot, int flags, int fd, off_t offset ) +{ + int ret; + + struct + { + void *addr; + unsigned int length; + unsigned int prot; + unsigned int flags; + unsigned int fd; + unsigned int offset; + } args; + + args.addr = start; + args.length = len; + args.prot = prot; + args.flags = flags; + args.fd = fd; + args.offset = offset; + __asm__ __volatile__( "int $0x80" : "=a" (ret) : "0" (SYS_mmap), "b" (&args) : "memory" ); + return (void *)SYSCALL_RET(ret); +} + +static inline uid_t wld_getuid(void) +{ + uid_t ret; + __asm__( "int $0x80" : "=a" (ret) : "0" (SYS_getuid) ); + return ret; +} + +static inline uid_t wld_geteuid(void) +{ + uid_t ret; + __asm__( "int $0x80" : "=a" (ret) : "0" (SYS_geteuid) ); + return ret; +} + +static inline gid_t wld_getgid(void) +{ + gid_t ret; + __asm__( "int $0x80" : "=a" (ret) : "0" (SYS_getgid) ); + return ret; +} + +static inline gid_t wld_getegid(void) +{ + gid_t ret; + __asm__( "int $0x80" : "=a" (ret) : "0" (SYS_getegid) ); + return ret; +} + + +/* replacement for libc functions */ + +static int wld_strcmp( const char *str1, const char *str2 ) +{ + while (*str1 && (*str1 == *str2)) { str1++; str2++; } + return *str1 - *str2; +} + +static int wld_strncmp( const char *str1, const char *str2, size_t len ) +{ + if (len <= 0) return 0; + while ((--len > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; } + return *str1 - *str2; +} + +static inline void *wld_memset( void *dest, int val, size_t len ) +{ + char *dst = dest; + while (len--) *dst++ = val; + return dest; +} + +static inline void *wld_memmove( void *dest, const void *src, size_t len ) +{ + const char *s = src; + char *d = dest; + int i; + + if (d < s) for (i = 0; i < len; i++) d[i] = s[i]; + else for (i = len - 1; i >= 0; i--) d[i] = s[i]; + return dest; +} + /* * wld_printf - just the basics * @@ -202,10 +339,10 @@ static void wld_printf(const char *fmt, ... ) va_start( args, fmt ); wld_vsprintf(buffer, fmt, args ); va_end( args ); - write(2, buffer, strlen(buffer)); + wld_write(2, buffer, strlen(buffer)); } -static void fatal_error(const char *fmt, ... ) +static __attribute__((noreturn)) void fatal_error(const char *fmt, ... ) { va_list args; char buffer[256]; @@ -213,8 +350,8 @@ static void fatal_error(const char *fmt, ... ) va_start( args, fmt ); wld_vsprintf(buffer, fmt, args ); va_end( args ); - write(2, buffer, strlen(buffer)); - _exit(1); + wld_write(2, buffer, strlen(buffer)); + wld_exit(1); } #ifdef DUMP_AUX_INFO @@ -278,7 +415,7 @@ static void set_auxiliary_values( ElfW(auxv_t) *av, const ElfW(auxv_t) *new_av, if (new_count) /* need to make room for the extra values */ { char *new_stack = (char *)*stack - new_count * sizeof(*av); - memmove( new_stack, *stack, (char *)(av + av_count) - (char *)*stack ); + wld_memmove( new_stack, *stack, (char *)(av + av_count) - (char *)*stack ); *stack = new_stack; av -= new_count; } @@ -337,10 +474,10 @@ static void map_so_lib( const char *name, struct wld_link_map *l) } loadcmds[16], *c; size_t nloadcmds = 0, maplength; - fd = open( name, O_RDONLY ); + fd = wld_open( name, O_RDONLY ); if (fd == -1) fatal_error("%s: could not open\n", name ); - if (read( fd, buf, sizeof(buf) ) != sizeof(buf)) + if (wld_read( fd, buf, sizeof(buf) ) != sizeof(buf)) fatal_error("%s: failed to read ELF header\n", name); phdr = (void*) (((unsigned char*)buf) + header->e_phoff); @@ -452,7 +589,7 @@ static void map_so_lib( const char *name, struct wld_link_map *l) - MAP_BASE_ADDR (l)); /* Remember which part of the address space this object uses. */ - l->l_map_start = (ElfW(Addr)) mmap ((void *) mappref, maplength, + l->l_map_start = (ElfW(Addr)) wld_mmap ((void *) mappref, maplength, c->prot, MAP_COPY | MAP_FILE, fd, c->mapoff); /* wld_printf("set : offset = %x\n", c->mapoff); */ @@ -461,7 +598,7 @@ static void map_so_lib( const char *name, struct wld_link_map *l) l->l_map_end = l->l_map_start + maplength; l->l_addr = l->l_map_start - c->mapstart; - mprotect ((caddr_t) (l->l_addr + c->mapend), + wld_mprotect ((caddr_t) (l->l_addr + c->mapend), loadcmds[nloadcmds - 1].allocend - c->mapend, PROT_NONE); goto postmap; @@ -485,7 +622,7 @@ static void map_so_lib( const char *name, struct wld_link_map *l) { if (c->mapend > c->mapstart) /* Map the segment contents from the file. */ - mmap ((void *) (l->l_addr + c->mapstart), + wld_mmap ((void *) (l->l_addr + c->mapstart), c->mapend - c->mapstart, c->prot, MAP_FIXED | MAP_COPY | MAP_FILE, fd, c->mapoff); @@ -526,18 +663,18 @@ static void map_so_lib( const char *name, struct wld_link_map *l) if ((c->prot & PROT_WRITE) == 0) { /* Dag nab it. */ - mprotect ((caddr_t) (zero & ~page_mask), page_size, c->prot|PROT_WRITE); + wld_mprotect ((caddr_t) (zero & ~page_mask), page_size, c->prot|PROT_WRITE); } - memset ((void *) zero, '\0', zeropage - zero); + wld_memset ((void *) zero, '\0', zeropage - zero); if ((c->prot & PROT_WRITE) == 0) - mprotect ((caddr_t) (zero & ~page_mask), page_size, c->prot); + wld_mprotect ((caddr_t) (zero & ~page_mask), page_size, c->prot); } if (zeroend > zeropage) { /* Map the remaining zero pages in from the zero fill FD. */ caddr_t mapat; - mapat = mmap ((caddr_t) zeropage, zeroend - zeropage, + mapat = wld_mmap ((caddr_t) zeropage, zeroend - zeropage, c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); } @@ -551,7 +688,7 @@ static void map_so_lib( const char *name, struct wld_link_map *l) l->l_phdr = (void *)((ElfW(Addr))l->l_phdr + l->l_addr); l->l_entry += l->l_addr; - close( fd ); + wld_close( fd ); } @@ -607,7 +744,7 @@ static void *find_symbol( const ElfW(Phdr) *phdr, int num, char *var ) for (i = 0; i < symtabend; i++) { if( ( ELF32_ST_BIND(symtab[i].st_info) == STT_OBJECT ) && - ( 0 == strcmp( strings+symtab[i].st_name, var ) ) ) + ( 0 == wld_strcmp( strings+symtab[i].st_name, var ) ) ) { #ifdef DUMP_SYMS wld_printf("Found %s -> %x\n", strings+symtab[i].st_name, symtab[i].st_value ); @@ -694,7 +831,7 @@ void* wld_start( void **stack ) while (*p) { static const char res[] = "WINEPRELOADRESERVE="; - if (!strncmp( *p, res, sizeof(res)-1 )) reserve = *p + sizeof(res) - 1; + if (!wld_strncmp( *p, res, sizeof(res)-1 )) reserve = *p + sizeof(res) - 1; p++; } @@ -714,8 +851,8 @@ void* wld_start( void **stack ) /* reserve memory that Wine needs */ if (reserve) preload_reserve( reserve ); for (i = 0; preload_info[i].size; i++) - mmap( preload_info[i].addr, preload_info[i].size, - PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0 ); + wld_mmap( preload_info[i].addr, preload_info[i].size, + PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0 ); /* load the main binary */ map_so_lib( argv[1], &main_binary_map ); @@ -738,10 +875,10 @@ void* wld_start( void **stack ) SET_NEW_AV( 4, AT_BASE, ld_so_map.l_addr ); SET_NEW_AV( 5, AT_FLAGS, get_auxiliary( av, AT_FLAGS, 0 ) ); SET_NEW_AV( 6, AT_ENTRY, main_binary_map.l_entry ); - SET_NEW_AV( 7, AT_UID, get_auxiliary( av, AT_UID, getuid() ) ); - SET_NEW_AV( 8, AT_EUID, get_auxiliary( av, AT_EUID, geteuid() ) ); - SET_NEW_AV( 9, AT_GID, get_auxiliary( av, AT_GID, getgid() ) ); - SET_NEW_AV(10, AT_EGID, get_auxiliary( av, AT_EGID, getegid() ) ); + SET_NEW_AV( 7, AT_UID, get_auxiliary( av, AT_UID, wld_getuid() ) ); + SET_NEW_AV( 8, AT_EUID, get_auxiliary( av, AT_EUID, wld_geteuid() ) ); + SET_NEW_AV( 9, AT_GID, get_auxiliary( av, AT_GID, wld_getgid() ) ); + SET_NEW_AV(10, AT_EGID, get_auxiliary( av, AT_EGID, wld_getegid() ) ); #undef SET_NEW_AV /* get rid of first argument */ -- 2.11.4.GIT