From 4194bc660f0768b1e0999f4e0a7723a35b00953c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Apr 1998 19:08:46 +0000 Subject: [PATCH] * elf/dl-runtime.c (fixup, profile_fixup): The final arg to _dl_lookup_*symbol is DL_LOOKUP_NOPLT not ELF_MACHINE_JMP_SLOT. * elf/elf.h (EM_SPARC64): Remove. (EM_SPARC32PLUS, EM_SPARCV9): Add. (HWCAP_SPARC_V9): Add. * elf/ldsodefs.h (_dl_hwcap): Declare. * sysdeps/sparc/sparc32/dl-machine.h (_dl_hwcap, _dl_hwcap_mask): Weaken so dlopen from static progies works. (WEAKADDR): New macro. (elf_machine_matches_host): Accept EM_SPARC32PLUS on a v9 cpu. (LD_SO_PRELOAD): New macro. (elf_machine_fixup_plt): Cope with weak _dl_hwcap. (elf_machine_rela): Weaken _dl_rtld_map. * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Rename __libc_clone to __clone, and remove the later's alias. * sysdeps/unix/sysv/linux/sparc/sparc64/clone.S: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c: Copy to/from the kernel's structure. 1998-04-06 Jakub Jelinek * elf/dl-runtime.c (fixup, profile_fixup): The final arg to _dl_lookup_*symbol is DL_LOOKUP_NOPLT not ELF_MACHINE_JMP_SLOT. * elf/elf.h (EM_SPARC64): Remove. (EM_SPARC32PLUS, EM_SPARCV9): Add. (HWCAP_SPARC_V9): Add. * elf/ldsodefs.h (_dl_hwcap): Declare. * sysdeps/sparc/sparc32/dl-machine.h (_dl_hwcap, _dl_hwcap_mask): Weaken so dlopen from static progies works. (WEAKADDR): New macro. (elf_machine_matches_host): Accept EM_SPARC32PLUS on a v9 cpu. (LD_SO_PRELOAD): New macro. (elf_machine_fixup_plt): Cope with weak _dl_hwcap. (elf_machine_rela): Weaken _dl_rtld_map. * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Rename __libc_clone to __clone, and remove the later's alias. * sysdeps/unix/sysv/linux/sparc/sparc64/clone.S: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c: Copy to/from the kernel's structure. * sysdeps/generic/libc-start.c: Allow init and fini to be null. --- ChangeLog | 27 ++++ elf/dl-runtime.c | 8 +- elf/elf.h | 8 +- elf/ldsodefs.h | 3 + sysdeps/generic/libc-start.c | 18 ++- sysdeps/sparc/sparc32/dl-machine.h | 55 +++++-- sysdeps/unix/sysv/linux/sparc/sparc32/clone.S | 43 +++--- .../unix/sysv/linux/sparc/sparc32/sigaction.c | 145 ++++++------------ .../unix/sysv/linux/sparc/sparc32/socket.S | 2 +- sysdeps/unix/sysv/linux/sparc/sparc64/clone.S | 13 +- 10 files changed, 172 insertions(+), 150 deletions(-) diff --git a/ChangeLog b/ChangeLog index 93fc41c3dc..1d6a9946e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,32 @@ +1998-04-06 Jakub Jelinek + + * elf/dl-runtime.c (fixup, profile_fixup): The final arg to + _dl_lookup_*symbol is DL_LOOKUP_NOPLT not ELF_MACHINE_JMP_SLOT. + + * elf/elf.h (EM_SPARC64): Remove. + (EM_SPARC32PLUS, EM_SPARCV9): Add. + (HWCAP_SPARC_V9): Add. + + * elf/ldsodefs.h (_dl_hwcap): Declare. + * sysdeps/sparc/sparc32/dl-machine.h (_dl_hwcap, _dl_hwcap_mask): + Weaken so dlopen from static progies works. + (WEAKADDR): New macro. + (elf_machine_matches_host): Accept EM_SPARC32PLUS on a v9 cpu. + (LD_SO_PRELOAD): New macro. + (elf_machine_fixup_plt): Cope with weak _dl_hwcap. + (elf_machine_rela): Weaken _dl_rtld_map. + + * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Rename __libc_clone + to __clone, and remove the later's alias. + * sysdeps/unix/sysv/linux/sparc/sparc64/clone.S: Likewise. + + * sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c: Copy to/from + the kernel's structure. + 1998-04-06 Richard Henderson + * sysdeps/generic/libc-start.c: Allow init and fini to be null. + * sysdeps/sparc/sparc32/elf.S: Rewrite for __libc_start_main. * sysdeps/sparc/sparc64/elf.S: Likewise. diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c index 53601b809f..10daa98c06 100644 --- a/elf/dl-runtime.c +++ b/elf/dl-runtime.c @@ -128,13 +128,13 @@ fixup ( { value = _dl_lookup_versioned_symbol(strtab + sym->st_name, &sym, scope, l->l_name, - version, ELF_MACHINE_JMP_SLOT); + version, DL_LOOKUP_NOPLT); break; } } case 0: value = _dl_lookup_symbol (strtab + sym->st_name, &sym, scope, - l->l_name, ELF_MACHINE_JMP_SLOT); + l->l_name, DL_LOOKUP_NOPLT); } /* Currently value contains the base load address of the object @@ -205,13 +205,13 @@ profile_fixup ( value = _dl_lookup_versioned_symbol(strtab + sym->st_name, &sym, scope, l->l_name, version, - ELF_MACHINE_JMP_SLOT); + DL_LOOKUP_NOPLT); break; } } case 0: value = _dl_lookup_symbol (strtab + sym->st_name, &sym, scope, - l->l_name, ELF_MACHINE_JMP_SLOT); + l->l_name, DL_LOOKUP_NOPLT); } /* Currently value contains the base load address of the object diff --git a/elf/elf.h b/elf/elf.h index 037ababf70..fcc8a5384a 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -162,11 +162,14 @@ typedef struct #define EM_S370 9 /* Amdahl */ #define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ -#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */ - #define EM_PARISC 15 /* HPPA */ + +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ + #define EM_PPC 20 /* PowerPC */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ + /* If it is necessary to assign new unofficial EM_* values, please pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision with official or non-GNU unofficial values. */ @@ -808,6 +811,7 @@ typedef struct #define HWCAP_SPARC_STBAR 2 #define HWCAP_SPARC_SWAP 4 #define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */ /* MIPS R3000 specific definitions. */ diff --git a/elf/ldsodefs.h b/elf/ldsodefs.h index 39f28332c6..19d931fd4e 100644 --- a/elf/ldsodefs.h +++ b/elf/ldsodefs.h @@ -140,6 +140,9 @@ extern int _dl_debug_files; /* Expect cache ID. */ extern int _dl_correct_cache_id; +/* Mask for hardware capabilities that are available. */ +extern unsigned long int _dl_hwcap; + /* Mask for important hardware capabilities we honour. */ extern unsigned long int _dl_hwcap_mask; diff --git a/sysdeps/generic/libc-start.c b/sysdeps/generic/libc-start.c index 2e777a84d2..3225a7ce5d 100644 --- a/sysdeps/generic/libc-start.c +++ b/sysdeps/generic/libc-start.c @@ -40,13 +40,13 @@ __libc_start_main (int (*main) (int, char **, char **), int argc, __libc_multiple_libcs = dummy_addr && !_dl_starting_up; #endif + /* Set the global _environ variable correctly. */ + __environ = &argv[argc + 1]; + /* Register the destructor of the dynamic linker if there is any. */ if (rtld_fini != NULL) atexit (rtld_fini); - /* Set the global _environ variable correctly. */ - __environ = &argv[argc + 1]; - /* Call the initializer of the libc. */ #ifdef PIC if (_dl_debug_impcalls) @@ -54,15 +54,17 @@ __libc_start_main (int (*main) (int, char **, char **), int argc, #endif __libc_init_first (argc, argv, __environ); - /* Call the initializer of the program. */ + /* Register the destructor of the program, if any. */ + if (fini) + atexit (fini); + + /* Call the initializer of the program, if any. */ #ifdef PIC if (_dl_debug_impcalls) _dl_debug_message (1, "\ninitialize program: ", argv[0], "\n\n", NULL); #endif - (*init) (); - - /* Register the destructor of the program. */ - atexit (fini); + if (init) + (*init) (); #ifdef PIC if (_dl_debug_impcalls) diff --git a/sysdeps/sparc/sparc32/dl-machine.h b/sysdeps/sparc/sparc32/dl-machine.h index 224c6bafff..1931c0caa7 100644 --- a/sysdeps/sparc/sparc32/dl-machine.h +++ b/sysdeps/sparc/sparc32/dl-machine.h @@ -21,8 +21,8 @@ #include #include -#include #include +#include /* Some SPARC opcodes we need to use for self-modifying code. */ @@ -33,11 +33,36 @@ #define OPCODE_SAVE_SP 0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */ +/* To allow static progies to link properly, define these as weak. */ +weak_extern(_dl_hwcap); +weak_extern(_dl_hwcap_mask); + + +/* Protect some broken versions of gcc from misinterpreting weak addresses. */ +#define WEAKADDR(x) ({ __typeof(x) *_px = &x; \ + __asm ("" : "=r" (_px) : "0" (_px)); \ + _px }) + + +/* Use a different preload file when running in 32-bit emulation mode + on a 64-bit host. */ +#define LD_SO_PRELOAD ((_dl_hwcap & HWCAP_SPARC_V9) ? "/etc/ld.so.preload32" \ + : "/etc/ld.so.preload") + + /* Return nonzero iff E_MACHINE is compatible with the running host. */ static inline int elf_machine_matches_host (Elf32_Half e_machine) { - return e_machine == EM_SPARC; + if (e_machine == EM_SPARC) + return 1; + else if (e_machine == EM_SPARC32PLUS) + { + unsigned long *hwcap = WEAKADDR(_dl_hwcap); + return hwcap && (*hwcap & _dl_hwcap_mask & HWCAP_SPARC_V9); + } + else + return 0; } @@ -240,7 +265,14 @@ static inline void elf_machine_fixup_plt (struct link_map *map, const Elf32_Rela *reloc, Elf32_Addr *reloc_addr, Elf32_Addr value) { - extern unsigned long _dl_hwcap; +#ifndef RTLD_BOOTSTRAP + /* Note that we don't mask the hwcap here, as the flush is essential to + functionality on those cpu's that implement it. */ + unsigned long *hwcap = WEAKADDR(_dl_hwcap); + int do_flush = (!hwcap || (*hwcap & HWCAP_SPARC_FLUSH)); +#else + int do_flush = 0; +#endif /* For thread safety, write the instructions from the bottom and flush before we overwrite the critical "b,a". This of course @@ -248,16 +280,12 @@ elf_machine_fixup_plt (struct link_map *map, const Elf32_Rela *reloc, But we also can't tell if we _can_ use flush, so don't. */ reloc_addr[2] = OPCODE_JMP_G1 | (value & 0x3ff); -#ifndef RTLD_BOOTSTRAP - if (_dl_hwcap & HWCAP_SPARC_FLUSH) + if (do_flush) __asm __volatile ("flush %0+8" : : "r"(reloc_addr)); -#endif reloc_addr[1] = OPCODE_SETHI_G1 | (value >> 10); -#ifndef RTLD_BOOTSTRAP - if (_dl_hwcap & HWCAP_SPARC_FLUSH) + if (do_flush) __asm __volatile ("flush %0+4" : : "r"(reloc_addr)); -#endif } /* Return the final value of a plt relocation. */ @@ -278,6 +306,15 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, const Elf32_Sym *sym, const struct r_found_version *version, Elf32_Addr *const reloc_addr) { +#ifndef RTLD_BOOTSTRAP + /* This is defined in rtld.c, but nowhere in the static libc.a; make the + reference weak so static programs can still link. This declaration + cannot be done when compiling rtld.c (i.e. #ifdef RTLD_BOOTSTRAP) + because rtld.c contains the common defn for _dl_rtld_map, which is + incompatible with a weak decl in the same file. */ + weak_extern (_dl_rtld_map); +#endif + if (ELF32_R_TYPE (reloc->r_info) == R_SPARC_RELATIVE) { #ifndef RTLD_BOOTSTRAP diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S index 64735e9dbc..e053569650 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. Contributed by Richard Henderson (rth@tamu.edu). The GNU C Library is free software; you can redistribute it and/or @@ -26,21 +26,18 @@ .text .align 4 - .globl __libc_clone - .type __libc_clone,@function - .weak clone - __clone = __libc_clone - clone = __libc_clone + .globl __clone + .type __clone,@function -__libc_clone: +__clone: save %sp,-96,%sp /* sanity check arguments */ tst %i0 - be __clone_syscall_error - tst %i1 - be __clone_syscall_error - nop + be .Lerror + tst %i1 + be .Lerror + nop /* Do the system call */ mov %i1,%o1 @@ -48,23 +45,31 @@ __libc_clone: set __NR_clone,%g1 ta 0x10 bcs __clone_syscall_error - tst %o1 + tst %o1 bne __thread_start - nop + nop mov %o0,%i0 ret - restore + restore -__clone_syscall_error: +.Lerror: call __errno_location - set EINVAL,%i0 + set EINVAL,%i0 st %i0,[%o0] mov -1,%i0 ret - restore + restore + + .size __clone, .-__clone + + .type __thread_start,@function __thread_start: call %i0 - mov %i3,%o0 + mov %i3,%o0 call _exit,0 - nop + nop + + .size __thread_start, .-__thread_start + +weak_alias(__clone, clone) diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c b/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c index 0fab662064..b9c20ddcd0 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c @@ -21,120 +21,65 @@ #include #include #include +#include /* The variable is shared between all wrappers around signal handling functions which have RT equivalents. */ int __libc_missing_rt_sigs; -/* Commented out while I figure out what the fuck goes on */ -long ____sig_table [NSIG]; -#if 0 - -/* The kernel will deliver signals in the old way if the signal - number is a positive number. The kernel will deliver a signal - with the new stack layout if the signal number is a negative number. - - Our sigaction code takes care of selecting the type of kernel we are - using at runtime. */ - -extern void ____sparc_signal_trampoline (int); - int -__trampoline_sigaction (int sig, struct sigaction *new, struct sigaction *old) -{ - int ret; - int need_to_hide_trick = 0; - __sighandler_t old_sh; - - if (new) - { - if (new->sa_handler != SIG_DFL && new->sa_handler != SIG_IGN) - { - old_sh = ____sig_table[sig]; - ____sig_table[sig] = (long int) new->sa_handler; - new->sa_handler = ____sparc_signal_trampoline; - need_to_hide_trick = 1; - } - } - __asm__("or %%g0,%0,%%g1\n\t" - "or %%g0,%1,%%o0\n\t" - "or %%g0,%2,%%o1\n\t" - "or %%g0,%3,%%o2\n\t" - "t 0x10\n\t" - "bcc 1f\n\t" - "or %%o0, %%g0, %0\n\t" - "sub %%g0, %%o0, %0\n\t" - "1:" - : "=r" (ret), "=r" ((long int) sig), "=r" ((long int) new), - "=r" ((long int) old) - : "0" (__NR_sigaction), "1" (sig), "2" (new), "3" (old) - : "g1", "o0", "o1", "o2"); - - if (ret >= 0) - { - if (old && old->sa_handler == ____sparc_signal_trampoline) - { - if (need_to_hide_trick) - old->sa_handler = old_sh; - else - old->sa_handler = ____sig_table[sig]; - } - if (need_to_hide_trick) - new->sa_handler = ____sig_table[sig]; - return 0; - } - __set_errno (-ret); - return -1; -} -#else -# define __new_sigaction __sigaction -#endif - -int -__new_sigaction (int sig, __const struct sigaction *new, struct sigaction *old) +__sigaction (int sig, __const struct sigaction *act, struct sigaction *oact) { int ret; + struct kernel_sigaction k_sigact, k_osigact; + /* Magic to tell the kernel we are using "new-style" signals, in that + the signal table is not kept in userspace. Not the same as the + really-new-style rt signals. */ sig = -sig; - __asm__("or %%g0,%0,%%g1\n\t" - "or %%g0,%1,%%o0\n\t" - "or %%g0,%2,%%o1\n\t" - "or %%g0,%3,%%o2\n\t" - "t 0x10\n\t" - "bcc 1f\n\t" - "or %%o0, %%g0, %0\n\t" - "sub %%g0,%%o0,%0\n\t" - "1:" - : "=r" (ret), "=r" ((long int) sig), "=r" ((long int) new), - "=r" ((long int) old) - : "0" (__NR_sigaction), "1" (sig), "2" (new), "3" (old) - : "g1", "o0", "o1", "o2"); + if (act) + { + k_sigact.sa_handler = act->sa_handler; + k_sigact.sa_mask = act->sa_mask.__val[0]; + k_sigact.sa_flags = act->sa_flags; + } + + { + register int r_syscallnr __asm__("%g1") = __NR_sigaction; + register int r_sig __asm__("%o0") = sig; + register struct kernel_sigaction *r_act __asm__("%o1"); + register struct kernel_sigaction *r_oact __asm__("%o2"); + + r_act = act ? &k_sigact : NULL; + r_oact = oact ? &k_osigact : NULL; + + __asm__ __volatile__("t 0x10\n\t" + "bcc 1f\n\t" + " nop\n\t" + " sub %%g0,%%o0,%%o0\n" + "1:" + : "=r"(r_sig) + : "r"(r_syscallnr), "r"(r_act), "r"(r_oact), + "0"(r_sig)); + + ret = r_sig; + } + if (ret >= 0) - return 0; + { + if (oact) + { + oact->sa_handler = k_osigact.sa_handler; + oact->sa_mask.__val[0] = k_osigact.sa_mask; + oact->sa_flags = k_osigact.sa_flags; + oact->sa_restorer = NULL; + } + return 0; + } + __set_errno (-ret); return -1; } -#if 0 -int -__sigaction (int sig, __const struct sigaction *new, struct sigaction *old) -{ - static (*sigact_routine) (int, __const struct sigaction *, struct sigaction *); - int ret; - struct sigaction sa; - - if (sigact_routine) - return (*sigact_routine) (sig, new, old); - - ret = __new_sigaction (1, NULL, &sa); - if (ret == -1) - sigact_routine = __trampoline_sigaction; - else - sigact_routine = __new_sigaction; - - return __sigaction (sig, new, old); -} -#endif - weak_alias (__sigaction, sigaction); diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/socket.S b/sysdeps/unix/sysv/linux/sparc/sparc32/socket.S index 8d6fd77c10..a6cb324363 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/socket.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/socket.S @@ -1,4 +1,4 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. +/* Copyright (C) 1997, 1998 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Miguel de Icaza , 1997. diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S index a16f9b7c9b..6c619fcdc3 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S @@ -26,13 +26,10 @@ .text .align 4 - .globl __libc_clone - .type __libc_clone,@function - .weak clone - __clone = __libc_clone - clone = __libc_clone + .globl __clone + .type __clone,@function -__libc_clone: +__clone: save %sp,-160,%sp /* sanity check arguments */ @@ -77,7 +74,7 @@ __libc_clone: mov -1,%i0 ret restore - .size __libc_clone, .-__libc_clone + .size __clone, .-__clone .type __thread_start,@function __thread_start: @@ -88,3 +85,5 @@ __thread_start: call _exit,0 nop .size __thread_start, .-__thread_start + +weak_alias(__clone, clone)