diff options
Diffstat (limited to 'ldso')
47 files changed, 1689 insertions, 278 deletions
diff --git a/ldso/include/dl-auxvt.h b/ldso/include/dl-auxvt.h new file mode 100644 index 000000000..29eda6eb3 --- /dev/null +++ b/ldso/include/dl-auxvt.h @@ -0,0 +1,9 @@ +#ifndef _DL_AUXVT_H +#define _DL_AUXVT_H + +#define AUX_MAX_AT_ID 40 +extern ElfW(auxv_t) _dl_auxvt[AUX_MAX_AT_ID]; /* Cache frequently accessed auxiliary vector entries */ +extern ElfW(auxv_t) *_dl_auxv_start; /* Start of the auxiliary vector */ + +#endif /* _DL_AUXVT_H */ + diff --git a/ldso/include/dl-defs.h b/ldso/include/dl-defs.h index f27112a11..e900640bb 100644 --- a/ldso/include/dl-defs.h +++ b/ldso/include/dl-defs.h @@ -72,7 +72,7 @@ typedef struct { #endif #ifdef _LIBC -#ifndef __ARCH_HAS_NO_SHARED__ +#ifndef __ARCH_HAS_NO_LDSO__ /* arch specific defines */ #include <dl-sysdep.h> #endif diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h index 2b99958d9..832f6b1dd 100644 --- a/ldso/include/dl-elf.h +++ b/ldso/include/dl-elf.h @@ -250,5 +250,46 @@ unsigned int __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info (((X) & PF_W) ? PROT_WRITE : 0) | \ (((X) & PF_X) ? PROT_EXEC : 0)) +/* FDPIC ABI don't use relative relocations */ +#if !defined(__FDPIC__) +/* Apply relocations in DT_RELR format */ +#define DL_DO_RELOCATE_RELR(load_addr, relr_start, relr_end) \ + do { \ + const ElfW(Relr) *relr = 0; \ + ElfW(Addr) *relr_reloc_addr = 0; \ + for (relr = relr_start; relr < relr_end; relr++) { \ + ElfW(Relr) relr_entry = *relr; \ + if (!(relr_entry & 1)) \ + { \ + relr_reloc_addr = (ElfW(Addr) *)DL_RELOC_ADDR(load_addr, relr_entry); \ + *relr_reloc_addr = (ElfW(Addr))DL_RELOC_ADDR(load_addr, relr_reloc_addr); \ + relr_reloc_addr++; \ + } \ + else \ + { \ + for (long int i = 0; (relr_entry >>= 1) != 0; ++i) { \ + if ((relr_entry & 1) != 0) \ + relr_reloc_addr[i] = (ElfW(Addr))DL_RELOC_ADDR(load_addr, relr_reloc_addr[i]); \ + } \ + relr_reloc_addr += CHAR_BIT * sizeof(ElfW(Relr)) - 1; \ + } \ + } \ + } while (0) + +/* The macro to prepare data for the above DL_DO_RELOCATE_RELR */ +#define DL_RELOCATE_RELR(dyn) \ + do { \ + if (dyn->dynamic_info[DT_RELRENT]) \ + _dl_assert(dyn->dynamic_info[DT_RELRENT] == sizeof(ElfW(Relr))); \ + if (dyn->dynamic_info[DT_RELR] && \ + dyn->dynamic_info[DT_RELRSZ]) { \ + ElfW(Relr) *relr_start = (ElfW(Relr) *)((ElfW(Addr))dyn->loadaddr + (ElfW(Addr))dyn->dynamic_info[DT_RELR]); \ + ElfW(Relr) *relr_end = (ElfW(Relr) *)((const char *)relr_start + dyn->dynamic_info[DT_RELRSZ]); \ + _dl_if_debug_dprint("Relocating DT_RELR in %s: start:%p, end:%p\n", \ + dyn->libname, (void *)relr_start, (void *)relr_end); \ + DL_DO_RELOCATE_RELR(dyn->loadaddr, relr_start, relr_end); \ + } \ + } while (0) +#endif /* __FDPIC__ */ #endif /* _DL_ELF_H */ diff --git a/ldso/include/dl-string.h b/ldso/include/dl-string.h index bf6997188..4a66161e0 100644 --- a/ldso/include/dl-string.h +++ b/ldso/include/dl-string.h @@ -103,7 +103,7 @@ static __always_inline char * _dl_strstr(const char *s1, const char *s2) do { if (!*p) - return (char *) s1;; + return (char *) s1; if (*p == *s) { ++p; ++s; @@ -257,7 +257,7 @@ static __always_inline char * _dl_simple_ltoahex(char *local, unsigned long i) /* On some (wierd) arches, none of this stuff works at all, so * disable the whole lot... */ /* The same applies for ARM FDPIC at least for the moment. */ -#if defined(__mips__) || (__FDPIC__) +#if defined(__mips__) || defined(__FDPIC__) # define SEND_STDERR(X) # define SEND_ADDRESS_STDERR(X, add_a_newline) diff --git a/ldso/include/dl-syscall.h b/ldso/include/dl-syscall.h index 2e8bb3630..c143b8d45 100644 --- a/ldso/include/dl-syscall.h +++ b/ldso/include/dl-syscall.h @@ -11,8 +11,13 @@ * been dynamicly linked in yet. */ #include "sys/syscall.h" extern int _dl_errno; + +#ifdef UCLIBC_LDSO #undef __set_errno #define __set_errno(X) {(_dl_errno) = (X);} +#endif + +#include <linux/version.h> /* Pull in the arch specific syscall implementation */ #include <dl-syscalls.h> @@ -20,7 +25,7 @@ extern int _dl_errno; #define _SYS_MMAN_H 1 #include <bits/mman.h> -#ifdef __ARCH_HAS_DEPRECATED_SYSCALLS__ +#if defined(__ARCH_HAS_DEPRECATED_SYSCALLS__) && (!defined(__UCLIBC_USE_TIME64__) || defined(__sparc__)) /* Pull in whatever this particular arch's kernel thinks the kernel version of * struct stat should look like. It turns out that each arch has a different * opinion on the subject, and different kernel revs use different names... */ @@ -116,7 +121,7 @@ static __always_inline _syscall3(unsigned long, _dl_read, int, fd, static __always_inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, len, int, prot) -#if defined __NR_fstatat64 && !defined __NR_stat +#if defined __NR_fstatat64 && !defined __NR_stat && (!defined(__UCLIBC_USE_TIME64__) || defined(__sparc__)) # define __NR__dl_fstatat64 __NR_fstatat64 static __always_inline _syscall4(int, _dl_fstatat64, int, fd, const char *, fn, struct stat *, stat, int, flags) @@ -126,7 +131,7 @@ static __always_inline int _dl_stat(const char *file_name, { return _dl_fstatat64(AT_FDCWD, file_name, buf, 0); } -#elif defined __NR_newfstatat && !defined __NR_stat +#elif defined __NR_newfstatat && !defined __NR_stat && (!defined(__UCLIBC_USE_TIME64__) || defined(__sparc__)) # define __NR__dl_newfstatat __NR_newfstatat static __always_inline _syscall4(int, _dl_newfstatat, int, fd, const char *, fn, struct stat *, stat, int, flags) @@ -136,7 +141,7 @@ static __always_inline int _dl_stat(const char *file_name, { return _dl_newfstatat(AT_FDCWD, file_name, buf, 0); } -#elif defined __NR_stat +#elif defined __NR_stat && (!defined(__UCLIBC_USE_TIME64__) || defined(__sparc__) || (LINUX_VERSION_CODE <= KERNEL_VERSION(5,1,0))) # define __NR__dl_stat __NR_stat static __always_inline _syscall2(int, _dl_stat, const char *, file_name, struct stat *, buf) @@ -160,15 +165,15 @@ static __always_inline int _dl_stat(const char *file_name, } #endif -#if defined __NR_fstat64 && !defined __NR_fstat +#if defined __NR_fstat64 && !defined __NR_fstat && (!defined(__UCLIBC_USE_TIME64__) || defined(__sparc__)) # define __NR__dl_fstat __NR_fstat64 static __always_inline _syscall2(int, _dl_fstat, int, fd, struct stat *, buf) -#elif defined __NR_fstat +#elif defined __NR_fstat && !defined __UCLIBC_USE_TIME64__ || defined(__sparc__) # define __NR__dl_fstat __NR_fstat static __always_inline _syscall2(int, _dl_fstat, int, fd, struct stat *, buf) #elif defined __NR_statx && defined __UCLIBC_HAVE_STATX__ # define __NR__dl_fstatx __NR_statx -static __always_inline _syscall5(int, _dl_fstatx, int, fd, const char *, file_name, int, flags, unsigned int, mask, struct stat *, buf); +static __always_inline _syscall5(int, _dl_fstatx, int, fd, const char *, file_name, int, flags, unsigned int, mask, struct statx *, buf); static __always_inline int _dl_fstat(int fd, struct stat *buf) diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h index f19957d1d..061d8a536 100644..100755 --- a/ldso/include/ldso.h +++ b/ldso/include/ldso.h @@ -48,7 +48,7 @@ /* Pull in the MIN macro */ #include <sys/param.h> /* Pull in the ldso syscalls and string functions */ -#ifndef __ARCH_HAS_NO_SHARED__ +#if !defined(__ARCH_HAS_NO_SHARED__) || !defined(__ARCH_HAS_NO_LDSO__) #include <dl-syscall.h> #include <dl-string.h> /* Now the ldso specific headers */ @@ -109,6 +109,7 @@ extern char *_dl_debug_reloc; extern char *_dl_debug_detail; extern char *_dl_debug_nofixups; extern char *_dl_debug_bindings; +extern char *_dl_debug_vdso; extern int _dl_debug_file; # define __dl_debug_dprint(fmt, args...) \ _dl_dprintf(_dl_debug_file, "%s:%i: " fmt, __func__, __LINE__, ## args); @@ -148,6 +149,7 @@ extern int _dl_debug_file; #define NULL ((void *) 0) #endif + extern void *_dl_malloc(size_t size); extern void *_dl_calloc(size_t __nmemb, size_t __size); extern void *_dl_realloc(void *__ptr, size_t __size); @@ -176,7 +178,7 @@ extern void _dl_dprintf(int, const char *, ...); #endif extern void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, - ElfW(auxv_t) auxvt[AT_EGID + 1], char **envp, char **argv + char **envp, char **argv DL_GET_READY_TO_RUN_EXTRA_PARMS); #ifdef HAVE_DL_INLINES_H @@ -185,6 +187,12 @@ extern void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE loa #else /* __ARCH_HAS_NO_SHARED__ */ #include <dl-defs.h> +#include <dl-elf.h> + #endif +#include <dl-auxvt.h> + +void load_vdso(void *sys_info_ehdr, char **envp ); + #endif /* _LDSO_H */ diff --git a/ldso/ldso/Makefile.in b/ldso/ldso/Makefile.in index 4f2a18454..0f8ed140d 100644 --- a/ldso/ldso/Makefile.in +++ b/ldso/ldso/Makefile.in @@ -19,6 +19,11 @@ ifeq ($(TARGET_ARCH),arm) CFLAGS-rtld += -fno-unwind-tables -fno-asynchronous-unwind-tables endif +ifeq ($(TARGET_ARCH),bfin) +# for gcc 10.5.0 and above we need to use -ffreestanding +CFLAGS-rtld += -ffreestanding +endif + CFLAGS-rtld += -I$(top_srcdir)ldso/ldso/$(TARGET_ARCH) -I$(top_srcdir)ldso/include -I$(top_srcdir)ldso/ldso CFLAGS-rtld += -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" -DUCLIBC_LDSO=\"$(UCLIBC_LDSO)\" @@ -38,7 +43,8 @@ CFLAGS-ldso.c += -DLDSO_MULTILIB_DIR=\"$(MULTILIB_DIR)\" endif ifeq ($(TARGET_ARCH),arc) -CFLAGS-ldso.c += -mno-long-calls +$(eval $(call check-gcc-var,-mno-long-calls)) +CFLAGS-ldso.c += $(CFLAGS_-mno-long-calls) endif LDFLAGS-$(UCLIBC_FORMAT_DSBT_ELF)-$(UCLIBC_LDSO_NAME).so := -Wl,--dsbt-index=1 @@ -62,14 +68,15 @@ ldso_FULL_NAME := $(UCLIBC_LDSO_NAME)-$(VERSION).so $(UCLIBC_LDSO_NAME)_DIR := $(top_srcdir)ldso/ldso $(UCLIBC_LDSO_NAME)_OUT := $(top_builddir)ldso/ldso -$(UCLIBC_LDSO_NAME)_CSRC := $($(UCLIBC_LDSO_NAME)_DIR)/ldso.c +$(UCLIBC_LDSO_NAME)_CSRC := $($(UCLIBC_LDSO_NAME)_DIR)/ldso.c $($(UCLIBC_LDSO_NAME)_DIR)/dl-vdso.c # prerequesites $($(UCLIBC_LDSO_NAME)_OUT)/ldso.o $($(UCLIBC_LDSO_NAME)_OUT)/ldso.oS: \ $($(UCLIBC_LDSO_NAME)_DIR)/dl-debug.c \ $($(UCLIBC_LDSO_NAME)_DIR)/dl-startup.c \ $($(UCLIBC_LDSO_NAME)_DIR)/dl-array.c \ $($(UCLIBC_LDSO_NAME)_DIR)/dl-hash.c \ - $($(UCLIBC_LDSO_NAME)_DIR)/dl-elf.c + $($(UCLIBC_LDSO_NAME)_DIR)/dl-elf.c \ + $($(UCLIBC_LDSO_NAME)_DIR)/dl-vdso.c $(UCLIBC_LDSO_NAME)_COBJ := $(patsubst $($(UCLIBC_LDSO_NAME)_DIR)/%.c,$($(UCLIBC_LDSO_NAME)_OUT)/%.o,$($(UCLIBC_LDSO_NAME)_CSRC)) $(UCLIBC_LDSO_NAME)_SSRC := $(wildcard $($(UCLIBC_LDSO_NAME)_DIR)/$(TARGET_ARCH)/*.S) diff --git a/ldso/ldso/aarch64/dl-syscalls.h b/ldso/ldso/aarch64/dl-syscalls.h index f40c4fd31..7f3566d6b 100644 --- a/ldso/ldso/aarch64/dl-syscalls.h +++ b/ldso/ldso/aarch64/dl-syscalls.h @@ -1 +1,38 @@ -/* stub for arch-specific syscall issues */ +/* stub for arch-specific syscall issues/specific implementations */ +#ifndef _DL_SYSCALLS_H +#define _DL_SYSCALLS_H + +#ifdef __ARCH_VDSO_GETTIMEOFDAY_NAME +#undef __ARCH_VDSO_GETTIMEOFDAY_NAME +#endif + +#ifdef __ARCH_VDSO_CLOCK_GETTIME_NAME +#undef __ARCH_VDSO_CLOCK_GETTIME_NAME +#endif + +#define __ARCH_VDSO_GETTIMEOFDAY_NAME "__kernel_gettimeofday" +#define __ARCH_VDSO_CLOCK_GETTIME_NAME "__kernel_clock_gettime" + +#if defined(__VDSO_SUPPORT__) && !defined(UCLIBC_LDSO) + +#include "../dl-vdso-calls.h" + +static int __attribute__ ((used)) __aarch64_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp); +static int __attribute__ ((used)) __aarch64_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + return __generic_vdso_clock_gettime(clock_id, tp); +} + +static int __attribute__ ((used)) __aarch64_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz); +static int __attribute__ ((used)) __aarch64_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz) +{ + return __generic_vdso_gettimeofday(tv, tz); +} + +#define ARCH_VDSO_GETTIMEOFDAY(tv, tz) __aarch64_vdso_gettimeofday(tv, tz) +#define ARCH_VDSO_CLOCK_GETTIME(clock_id, tp) __aarch64_vdso_clock_gettime(clock_id, tp) + +#endif /* defined(__VDSO_SUPPORT__) && !defined(UCLIBC_LDSO) */ + +#endif /* _DL_SYSCALLS_H */ + diff --git a/ldso/ldso/aarch64/dl-sysdep.h b/ldso/ldso/aarch64/dl-sysdep.h index 6d9d2c1fb..3466920d9 100644 --- a/ldso/ldso/aarch64/dl-sysdep.h +++ b/ldso/ldso/aarch64/dl-sysdep.h @@ -54,28 +54,21 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); || (type) == R_AARCH64_TLSDESC) * ELF_RTYPE_CLASS_PLT) \ | (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY)) -/* Return the link-time address of _DYNAMIC. Conveniently, this is the - first element of the GOT. */ -extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden; -static __always_inline ElfW(Addr) __attribute__ ((unused)) -elf_machine_dynamic (void) -{ - return _GLOBAL_OFFSET_TABLE_[0]; -} - /* Return the run-time load address of the shared object. */ static __always_inline ElfW(Addr) __attribute__ ((unused)) elf_machine_load_address (void) { - /* To figure out the load address we use the definition that for any symbol: - dynamic_addr(symbol) = static_addr(symbol) + load_addr - - _DYNAMIC sysmbol is used here as its link-time address stored in - the special unrelocated first GOT entry. */ + extern const ElfW(Ehdr) __ehdr_start attribute_hidden; + return (ElfW(Addr)) &__ehdr_start; +} - extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; - return (ElfW(Addr)) &_DYNAMIC - elf_machine_dynamic (); +/* Return the link-time address of _DYNAMIC. */ +static __always_inline ElfW(Addr) __attribute__ ((unused)) +elf_machine_dynamic (void) +{ + extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; + return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address (); } static __always_inline void diff --git a/ldso/ldso/aarch64/elfinterp.c b/ldso/ldso/aarch64/elfinterp.c index adabafaad..9365569cc 100644 --- a/ldso/ldso/aarch64/elfinterp.c +++ b/ldso/ldso/aarch64/elfinterp.c @@ -238,6 +238,12 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, } } break; + case R_AARCH64_TLS_DTPMOD: + *reloc_addr = tls_tpnt->l_tls_modid; + break; + case R_AARCH64_TLS_DTPREL: + *reloc_addr = symbol_addr + rpnt->r_addend; + break; #endif default: return -1; /*call _dl_exit(1) */ @@ -253,6 +259,8 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, return 0; } +#undef __AARCH64_LAZY_RELOC_WORKS +#ifdef __AARCH64_LAZY_RELOC_WORKS static int _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) @@ -303,11 +311,17 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, return 0; } +#endif void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size) { +#ifdef __AARCH64_LAZY_RELOC_WORKS (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); +#else + _dl_parse_relocation_information(rpnt, &_dl_loaded_modules->symbol_scope, + rel_addr, rel_size); +#endif } int _dl_parse_relocation_information(struct dyn_elf *rpnt, diff --git a/ldso/ldso/arc/dl-sysdep.h b/ldso/ldso/arc/dl-sysdep.h index ed8b37205..c8915511a 100644 --- a/ldso/ldso/arc/dl-sysdep.h +++ b/ldso/ldso/arc/dl-sysdep.h @@ -75,6 +75,9 @@ do { \ #elif defined(__HS__) #define MAGIC1 EM_ARCV2 #define ELF_TARGET "ARCv2" /* For error messages */ +#elif defined(__ARC64_ARCH32__) +#define MAGIC1 EM_ARCV3_32 +#define ELF_TARGET "ARCv3_32" /* For error messages */ #endif #undef MAGIC2 diff --git a/ldso/ldso/arc/resolve.S b/ldso/ldso/arc/resolve.S index 891f66b97..2b66c69cb 100644 --- a/ldso/ldso/arc/resolve.S +++ b/ldso/ldso/arc/resolve.S @@ -4,6 +4,7 @@ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. */ +#include <asm.h> #include <sysdep.h> #include <sys/syscall.h> @@ -12,30 +13,30 @@ ; r10-r12 are already clobbered by PLTn, PLT0 thus neednot be saved .macro SAVE_CALLER_SAVED - push_s r0 - push_s r1 - push_s r2 - push_s r3 - st.a r4, [sp, -4] - st.a r5, [sp, -4] - st.a r6, [sp, -4] - st.a r7, [sp, -4] - st.a r8, [sp, -4] - st.a r9, [sp, -4] - push_s blink + PUSHR_S r0 + PUSHR_S r1 + PUSHR_S r2 + PUSHR_S r3 + PUSHR r4 + PUSHR r5 + PUSHR r6 + PUSHR r7 + PUSHR r8 + PUSHR r9 + PUSHR_S blink .endm .macro RESTORE_CALLER_SAVED_BUT_R0 - ld.ab blink,[sp, 4] - ld.ab r9, [sp, 4] - ld.ab r8, [sp, 4] - ld.ab r7, [sp, 4] - ld.ab r6, [sp, 4] - ld.ab r5, [sp, 4] - ld.ab r4, [sp, 4] - pop_s r3 - pop_s r2 - pop_s r1 + POPR blink + POPR r9 + POPR r8 + POPR r7 + POPR r6 + POPR r5 + POPR r4 + POPR_S r3 + POPR_S r2 + POPR_S r1 .endm ; Upon entry, PLTn, which led us here, sets up the following regs @@ -53,5 +54,5 @@ ENTRY(_dl_linux_resolve) RESTORE_CALLER_SAVED_BUT_R0 j_s.d [r0] ; r0 has resolved function addr - pop_s r0 ; restore first arg to resolved call + POPR_S r0 ; restore first arg to resolved call END(_dl_linux_resolve) diff --git a/ldso/ldso/arm/dl-startup.h b/ldso/ldso/arm/dl-startup.h index cacd461e1..d00e7b053 100644 --- a/ldso/ldso/arm/dl-startup.h +++ b/ldso/ldso/arm/dl-startup.h @@ -301,3 +301,5 @@ int raise(int sig) _dl_exit(1); } #endif /* __FDPIC__ */ + +#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR) diff --git a/ldso/ldso/arm/dl-syscalls.h b/ldso/ldso/arm/dl-syscalls.h index f40c4fd31..5f6f7a883 100644 --- a/ldso/ldso/arm/dl-syscalls.h +++ b/ldso/ldso/arm/dl-syscalls.h @@ -1 +1,28 @@ -/* stub for arch-specific syscall issues */ +/* stub for arch-specific syscall issues/specific implementations */ + +#ifndef _DL_SYSCALLS_H +#define _DL_SYSCALLS_H + +#if defined(__VDSO_SUPPORT__) && !defined(UCLIBC_LDSO) + +#include "../dl-vdso-calls.h" + +static int __attribute__ ((used)) __arm_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp); +static int __attribute__ ((used)) __arm_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + return __generic_vdso_clock_gettime(clock_id, tp); +} + +static int __attribute__ ((used)) __arm_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz); +static int __attribute__ ((used)) __arm_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz) +{ + return __generic_vdso_gettimeofday(tv, tz); +} + +#define ARCH_VDSO_GETTIMEOFDAY(tv, tz) __arm_vdso_gettimeofday(tv, tz) +#define ARCH_VDSO_CLOCK_GETTIME(clock_id, tp) __arm_vdso_clock_gettime(clock_id, tp) + +#endif /* defined(__VDSO_SUPPORT__) && !defined(UCLIBC_LDSO) */ + +#endif /* _DL_SYSCALLS_H */ + diff --git a/ldso/ldso/arm/dl-sysdep.h b/ldso/ldso/arm/dl-sysdep.h index 0f783e1c4..93e36b694 100644 --- a/ldso/ldso/arm/dl-sysdep.h +++ b/ldso/ldso/arm/dl-sysdep.h @@ -96,43 +96,6 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY)) #endif /* __FDPIC__ */ -/* Return the link-time address of _DYNAMIC. Conveniently, this is the - first element of the GOT. We used to use the PIC register to do this - without a constant pool reference, but GCC 4.2 will use a pseudo-register - for the PIC base, so it may not be in r10. */ -static __always_inline Elf32_Addr __attribute__ ((unused)) -elf_machine_dynamic (void) -{ - Elf32_Addr dynamic; -#if !defined __thumb__ - __asm__ ("ldr %0, 2f\n" - "1: ldr %0, [pc, %0]\n" - "b 3f\n" - "2: .word _GLOBAL_OFFSET_TABLE_ - (1b+8)\n" - "3:" : "=r" (dynamic)); -#else - int tmp; - __asm__ (".align 2\n" - "bx pc\n" - "nop\n" - ".arm\n" - "ldr %0, 2f\n" - "1: ldr %0, [pc, %0]\n" - "b 3f\n" - "2: .word _GLOBAL_OFFSET_TABLE_ - (1b+8)\n" - "3:" - ".align 2\n" - "orr %1, pc, #1\n" - "bx %1\n" - ".force_thumb\n" - : "=r" (dynamic), "=&r" (tmp)); -#endif - - return dynamic; -} - -extern char __dl_start[] __asm__("_dl_start"); - #ifdef __FDPIC__ /* We must force strings used early in the bootstrap into the data segment. */ @@ -148,28 +111,16 @@ extern char __dl_start[] __asm__("_dl_start"); static __always_inline Elf32_Addr __attribute__ ((unused)) elf_machine_load_address (void) { -#if defined(__FDPIC__) - return 0; -#else - Elf32_Addr got_addr = (Elf32_Addr) &__dl_start; - Elf32_Addr pcrel_addr; -#if defined __OPTIMIZE__ && !defined __thumb__ - __asm__ ("adr %0, _dl_start" : "=r" (pcrel_addr)); -#else - /* A simple adr does not work in Thumb mode because the offset is - negative, and for debug builds may be too large. */ - int tmp; - __asm__ ("adr %1, 1f\n\t" - "ldr %0, [%1]\n\t" - "add %0, %0, %1\n\t" - "b 2f\n\t" - ".align 2\n\t" - "1: .word _dl_start - 1b\n\t" - "2:" - : "=r" (pcrel_addr), "=r" (tmp)); -#endif - return pcrel_addr - got_addr; -#endif + extern const Elf32_Ehdr __ehdr_start attribute_hidden; + return (Elf32_Addr) &__ehdr_start; +} + +/* Return the link-time address of _DYNAMIC. */ +static __always_inline Elf32_Addr __attribute__ ((unused)) +elf_machine_dynamic (void) +{ + extern Elf32_Dyn _DYNAMIC[] attribute_hidden; + return (Elf32_Addr) _DYNAMIC - elf_machine_load_address (); } static __always_inline void diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c index 4c268356f..9c9a3e8ca 100644 --- a/ldso/ldso/arm/elfinterp.c +++ b/ldso/ldso/arm/elfinterp.c @@ -92,7 +92,7 @@ unsigned long _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_offet) *got_entry = funcval; #endif - return got_entry; + return (unsigned long)got_entry; } #else unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) @@ -362,7 +362,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope, unsigned long reloc_value = *reloc_addr; if (symbol_addr) - reloc_value = (unsigned long) _dl_funcdesc_for(symbol_addr + reloc_value, sym_ref.tpnt->loadaddr.got_value); + reloc_value = (unsigned long) _dl_funcdesc_for((void *)(symbol_addr + reloc_value), sym_ref.tpnt->loadaddr.got_value); else /* Relocation against an undefined weak symbol: @@ -429,7 +429,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, { struct funcdesc_value *dst = (struct funcdesc_value *) reloc_addr; - dst->entry_point = DL_RELOC_ADDR(tpnt->loadaddr, dst->entry_point); + dst->entry_point = (void *)DL_RELOC_ADDR(tpnt->loadaddr, dst->entry_point); dst->got_value = tpnt->loadaddr.got_value; } break; diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index 2bcfcda64..6656acb0f 100644 --- a/ldso/ldso/dl-elf.c +++ b/ldso/ldso/dl-elf.c @@ -182,7 +182,10 @@ search_for_named_library(const char *name, unsigned int rflags, const char *path } else { _dl_strcpy(mylibname, "."); } - _dl_strcat(mylibname, "/"); + plen = _dl_strlen(mylibname); + if ((plen == 0) || (mylibname[plen-1] != '/')) { + _dl_strcat(mylibname, "/"); + } _dl_strcat(mylibname, name); #ifdef __LDSO_SAFE_RUNPATH__ if (*mylibname == '/') @@ -897,7 +900,8 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned int rflags, _dl_memset(*rpnt, 0, sizeof(struct dyn_elf)); } #endif - (*rpnt)->dyn = tpnt; + if (*rpnt) + (*rpnt)->dyn = tpnt; tpnt->usage_count++; if (tpnt->rtld_flags & RTLD_NODELETE) tpnt->usage_count++; @@ -1024,6 +1028,11 @@ int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int now_flag) return goof; } +#if !defined(__FDPIC__) && !defined(__FRV_FDPIC__) && !defined(__DSBT__) + /* Process DT_RELR relative relocations */ + DL_RELOCATE_RELR(tpnt); +#endif + reloc_size = tpnt->dynamic_info[DT_RELOC_TABLE_SIZE]; /* On some machines, notably SPARC & PPC, DT_REL* includes DT_JMPREL in its range. Note that according to the ELF spec, this is completely legal! */ diff --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c index 24b046c62..ec6b72a39 100644 --- a/ldso/ldso/dl-startup.c +++ b/ldso/ldso/dl-startup.c @@ -98,6 +98,10 @@ extern ElfW(Addr) _begin[] attribute_hidden; #endif + +ElfW(auxv_t) _dl_auxvt[AUX_MAX_AT_ID]; +ElfW(auxv_t) *_dl_auxv_start; + #ifdef LDSO_NEED_DPNT ElfW(Dyn) *_dl_saved_dpnt = 0; #endif @@ -127,7 +131,8 @@ DL_START(unsigned long args) ElfW(Ehdr) *header; struct elf_resolve tpnt_tmp; struct elf_resolve *tpnt = &tpnt_tmp; - ElfW(auxv_t) auxvt[AT_EGID + 1]; + ElfW(auxv_t) _dl_auxvt_tmp[AUX_MAX_AT_ID]; + ElfW(auxv_t) *_dl_auxv_start_tmp; ElfW(Dyn) *dpnt; uint32_t *p32; @@ -158,17 +163,20 @@ DL_START(unsigned long args) /* Place -1 here as a checkpoint. We later check if it was changed * when we read in the auxvt */ - auxvt[AT_UID].a_type = -1; + _dl_auxvt_tmp[AT_UID].a_type = -1; /* The junk on the stack immediately following the environment is * the Auxiliary Vector Table. Read out the elements of the auxvt, * sort and store them in auxvt for later use. */ + _dl_auxv_start_tmp = (ElfW(auxv_t) *)aux_dat; while (*aux_dat) { ElfW(auxv_t) *auxv_entry = (ElfW(auxv_t) *) aux_dat; - if (auxv_entry->a_type <= AT_EGID) { - _dl_memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(ElfW(auxv_t))); + if (auxv_entry->a_type < AUX_MAX_AT_ID) { + _dl_memcpy(&(_dl_auxvt_tmp[auxv_entry->a_type]), auxv_entry, sizeof(ElfW(auxv_t))); } + + aux_dat += 2; } @@ -183,16 +191,16 @@ DL_START(unsigned long args) * We use it if the kernel is not passing a valid address through the auxvt. */ - if (!auxvt[AT_BASE].a_un.a_val) - auxvt[AT_BASE].a_un.a_val = (ElfW(Addr)) &_begin; + if (!_dl_auxvt_tmp[AT_BASE].a_un.a_val) + _dl_auxvt_tmp[AT_BASE].a_un.a_val = (ElfW(Addr)) &_begin; /* Note: if the dynamic linker itself is prelinked, the load_addr is 0 */ DL_INIT_LOADADDR_BOOT(load_addr, elf_machine_load_address()); #else - if (!auxvt[AT_BASE].a_un.a_val) - auxvt[AT_BASE].a_un.a_val = elf_machine_load_address(); - DL_INIT_LOADADDR_BOOT(load_addr, auxvt[AT_BASE].a_un.a_val); + if (!_dl_auxvt_tmp[AT_BASE].a_un.a_val) + _dl_auxvt_tmp[AT_BASE].a_un.a_val = elf_machine_load_address(); + DL_INIT_LOADADDR_BOOT(load_addr, _dl_auxvt_tmp[AT_BASE].a_un.a_val); #endif - header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_val; + header = (ElfW(Ehdr) *) _dl_auxvt_tmp[AT_BASE].a_un.a_val; /* Check the ELF header to make sure everything looks ok. */ if (!header || header->e_ident[EI_CLASS] != ELF_CLASS || @@ -255,12 +263,15 @@ DL_START(unsigned long args) PERFORM_BOOTSTRAP_GOT(tpnt); #endif -#if !defined(PERFORM_BOOTSTRAP_GOT) || defined(__avr32__) || defined(__mips__) - /* OK, now do the relocations. We do not do a lazy binding here, so that once we are done, we have considerably more flexibility. */ SEND_EARLY_STDERR_DEBUG("About to do library loader relocations\n"); +#if !defined(__FDPIC__) && !defined(__FRV_FDPIC__) && !defined(__DSBT__) + /* Process DT_RELR relative relocations */ + DL_RELOCATE_RELR(tpnt); +#endif + { int indx; #if defined(ELF_MACHINE_PLTREL_OVERLAP) @@ -337,7 +348,6 @@ DL_START(unsigned long args) #endif } } -#endif SEND_STDERR_DEBUG("Done relocating ldso; we can now use globals and make function calls!\n"); @@ -356,10 +366,19 @@ DL_START(unsigned long args) #endif __rtld_stack_end = (void *)(argv - 1); + /* + * now the globals work. so copy the aux vector + */ + _dl_memcpy( _dl_auxvt, _dl_auxvt_tmp, sizeof( ElfW(auxv_t) ) * AUX_MAX_AT_ID ); + _dl_auxv_start = _dl_auxv_start_tmp; + _dl_elf_main = (int (*)(int, char **, char **)) - _dl_get_ready_to_run(tpnt, load_addr, auxvt, envp, argv + _dl_get_ready_to_run(tpnt, load_addr, envp, argv DL_GET_READY_TO_RUN_EXTRA_ARGS); + + load_vdso((void *)_dl_auxvt[AT_SYSINFO_EHDR].a_un.a_val, envp); + /* Transfer control to the application. */ SEND_STDERR_DEBUG("transfering control to application @ "); SEND_ADDRESS_STDERR_DEBUG(_dl_elf_main, 1); diff --git a/ldso/ldso/dl-vdso-calls.h b/ldso/ldso/dl-vdso-calls.h new file mode 100644 index 000000000..c72f2dadf --- /dev/null +++ b/ldso/ldso/dl-vdso-calls.h @@ -0,0 +1,68 @@ +#ifndef _DL_VDSO_CALLS_H +#define _DL_VDSO_CALLS_H + +#include <sys/time.h> +#include <sys/syscall.h> +#include <errno.h> +#include <time.h> + +void __attribute__((weak)) *_get__dl__vdso_clock_gettime(void); +#if defined(__UCLIBC_USE_TIME64__) +#include "internal/time64_helpers.h" +void __attribute__((weak)) *_get__dl__vdso_clock_gettime64(void); +typedef int (*clock_gettime_func)(clockid_t clock_id, struct __ts64_struct *tp); +#else +typedef int (*clock_gettime_func)(clockid_t clock_id, struct timespec *tp); +#endif + +extern int __libc_clock_gettime(clockid_t clock_id, struct timespec *tp); + +static int __attribute__ ((used)) __generic_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp); +static int __attribute__ ((used)) __generic_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + void *impl = NULL; +#if defined(__UCLIBC_USE_TIME64__) + if (&_get__dl__vdso_clock_gettime64 && (impl = _get__dl__vdso_clock_gettime64())) { + struct __ts64_struct __ts64; + int __ret = ((clock_gettime_func)impl)(clock_id, &__ts64); + if (__ret != 0) { + __set_errno(-__ret); + return -1; + } + + if (tp) { + tp->tv_sec = __ts64.tv_sec; + tp->tv_nsec = __ts64.tv_nsec; + } + return 0; + } + + /* fallback to syscall */ + return __libc_clock_gettime(clock_id, tp); +#else + if (&_get__dl__vdso_clock_gettime && (impl = _get__dl__vdso_clock_gettime())) { + int __ret = ((clock_gettime_func)impl)(clock_id, tp); + if (__ret != 0) { + __set_errno(-__ret); + return -1; + } + + return 0; + } + + /* fallback to syscall */ + return __libc_clock_gettime(clock_id, tp); +#endif +} + +static int __attribute__ ((used)) __generic_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz) +{ + struct timespec ts; + int __res = __generic_vdso_clock_gettime(CLOCK_REALTIME, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = (suseconds_t)ts.tv_nsec / 1000; + + return __res; +} + +#endif /* _DL_VDSO_CALLS_H */
\ No newline at end of file diff --git a/ldso/ldso/dl-vdso.c b/ldso/ldso/dl-vdso.c new file mode 100755 index 000000000..01309011d --- /dev/null +++ b/ldso/ldso/dl-vdso.c @@ -0,0 +1,372 @@ + +#include <elf.h> +#include <string.h> +#include "sys/auxv.h" + +#define __ARCH_VDSO_GETTIMEOFDAY_NAME "__vdso_gettimeofday" +#define __ARCH_VDSO_CLOCK_GETTIME_NAME "__vdso_clock_gettime" + +#if defined(__UCLIBC_USE_TIME64__) +#define __ARCH_VDSO_CLOCK_GETTIME64_NAME "__vdso_clock_gettime64" +#endif + +/* Maybe override default vDSO functions names by arch-specific */ +#include "ldso.h" +#include "generated/autoconf.h" + +#ifndef ELF_BITS +# if ULONG_MAX > 0xffffffffUL +# define ELF_BITS 64 +# else +# define ELF_BITS 32 +# endif +#endif + +#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x +#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x) +#define ELF(x) ELF_BITS_XFORM(ELF_BITS, x) + + +#ifndef __VDSO_SUPPORT__ +void load_vdso( void *sys_info_ehdr attribute_unused, + char **envp attribute_unused ){ +#ifdef __SUPPORT_LD_DEBUG__ + if ( _dl_debug_vdso != 0 ){ + _dl_dprintf(2,"_dl_vdso support not enabled\n" ); + } +#endif +} +#else + +void *_dl__vdso_gettimeofday = 0; +void *_dl__vdso_clock_gettime = 0; + +#if defined(__UCLIBC_USE_TIME64__) +void *_dl__vdso_clock_gettime64 = 0; +#endif + +void *_get__dl__vdso_clock_gettime(void); +void *_get__dl__vdso_clock_gettime(void) +{ + return _dl__vdso_clock_gettime; +} + +#if defined(__UCLIBC_USE_TIME64__) +void *_get__dl__vdso_clock_gettime64(void); +void *_get__dl__vdso_clock_gettime64(void) +{ + return _dl__vdso_clock_gettime64; +} +#endif + +void *_get__dl__vdso_gettimeofday(void); +void *_get__dl__vdso_gettimeofday(void) +{ + return _dl__vdso_gettimeofday; +} + +typedef struct { + + void* base_addr; + + ELF(Ehdr) *hdr; + + char* section_header_strtab; + + ELF(Sym) *dynsym_table; + uint32_t dynsym_table_num; + + char* dynstr_table; + + uint16_t *versym_table; + + ELF(Verdef) *verdef_table; + uint32_t verdef_num; + + ELF(Dyn) *dynamic_section; + uint32_t dynamic_section_num; + + char* text_section; + + + char* vers_strings[10]; + + +} elf_infos; + +/* + * the raise() dummy function is needed because of divisons in this code + * but keep it hidden in this object + * + * fixes link error with gcc 12 for arm + */ +#pragma GCC visibility push(hidden) +int raise(int sig){ + sig = sig; + return 0; +} +#pragma GCC visibility pop + + +static int vdso_check_elf_header( elf_infos* elf ){ + + if ( 0 != _dl_memcmp( ELFMAG, elf->base_addr, 4 ) ){ + return 1; + } + + if (elf->hdr->e_ident[EI_CLASS] != (ELF_BITS == 32 ? ELFCLASS32 : ELFCLASS64)) { + _dl_dprintf(2,"vdso ELF Bits check error\n"); + return 1; /* Wrong ELF class -- check ELF_BITS */ + } + + return 0; +} + +static ELF(Shdr) *vdso_get_sec_header( elf_infos* elf, int index ){ + + return (ELF(Shdr) *) ( elf->base_addr + elf->hdr->e_shoff + ( index * sizeof( ELF(Shdr) )) ); + +} + +void load_vdso(void *sys_info_ehdr, char **envp ){ + + elf_infos vdso_infos; + + if ( sys_info_ehdr == 0 ){ +#ifdef __SUPPORT_LD_DEBUG__ + if ( _dl_debug_vdso != 0 ){ + _dl_dprintf(2,"_dl_vdso no vdso provied by kernel\n" ); + } +#endif + return; + + } + + char* _dl_vdso_disable = _dl_getenv("VDSO_DISABLE", envp); + if ( _dl_vdso_disable != 0 ){ +#ifdef __SUPPORT_LD_DEBUG__ + if ( _dl_debug_vdso != 0 ){ + _dl_dprintf(2,"_dl_vdso vdso support disabled\n" ); + } +#endif + return; + } + + _dl_memset( &vdso_infos, 0 , sizeof( elf_infos ) ); + + vdso_infos.base_addr = (void*)sys_info_ehdr; + vdso_infos.hdr = (ELF(Ehdr)*)vdso_infos.base_addr; + + if ( 0 != vdso_check_elf_header( &vdso_infos ) ){ + return; + } + + ELF(Shdr) *sec_header = vdso_get_sec_header( &vdso_infos, vdso_infos.hdr->e_shstrndx); + vdso_infos.section_header_strtab = ( vdso_infos.base_addr + sec_header->sh_offset ); + + /* + * + * load ELF section headers + * + */ + + for ( int i = 0 ; i < vdso_infos.hdr->e_shnum; i++ ){ + + sec_header = vdso_get_sec_header( &vdso_infos, i ); + + char* name = vdso_infos.section_header_strtab + sec_header->sh_name; + + if( ( SHT_DYNSYM == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".dynsym",name ) ) ){ + vdso_infos.dynsym_table = ( vdso_infos.base_addr + sec_header->sh_offset ); + vdso_infos.dynsym_table_num = sec_header->sh_size / sec_header->sh_entsize ; + continue; + } + + if( ( SHT_STRTAB == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".dynstr",name ) ) ){ + vdso_infos.dynstr_table = ( vdso_infos.base_addr + sec_header->sh_offset ); + continue; + } + + if( ( SHT_GNU_versym == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".gnu.version",name ) ) ){ + vdso_infos.versym_table = ( vdso_infos.base_addr + sec_header->sh_offset ); + continue; + } + + if( ( SHT_GNU_verdef == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".gnu.version_d",name ) ) ){ + vdso_infos.verdef_table = ( vdso_infos.base_addr + sec_header->sh_offset ); + continue; + } + + if( ( SHT_DYNAMIC == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".dynamic",name ) ) ){ + vdso_infos.dynamic_section = ( vdso_infos.base_addr + sec_header->sh_offset ); + vdso_infos.dynamic_section_num = sec_header->sh_size / sec_header->sh_entsize ; + continue; + } + + if( ( SHT_PROGBITS == sec_header->sh_type ) && ( 0 == _dl_strcmp( ".text",name ) ) ){ + vdso_infos.text_section = ( vdso_infos.base_addr + sec_header->sh_offset ); + continue; + } + + } + + + /* + * + * check section header -> dynamic table consistence + * + */ + + + for( int i = 0 ; i < vdso_infos.dynamic_section_num ; i++ ){ + ELF(Dyn) *dyn_sec = &vdso_infos.dynamic_section[i]; + if ( dyn_sec->d_tag == 0 ) continue; + + + if ( dyn_sec->d_tag == DT_STRTAB ){ + char* strtab = ( vdso_infos.base_addr + dyn_sec->d_un.d_ptr ); + if ( strtab != (char*) vdso_infos.dynstr_table ){ + _dl_dprintf(2,"vdso elf DT_STRTAB check error\n"); + return; + } + continue; + } + + if ( dyn_sec->d_tag == DT_SYMTAB ){ + char* symtab = ( vdso_infos.base_addr + dyn_sec->d_un.d_ptr ); + if ( symtab != (char*) vdso_infos.dynsym_table ){ + _dl_dprintf(2,"vdso elf DT_SYMTAB check error\n"); + return; + } + continue; + } + + if ( dyn_sec->d_tag == DT_VERDEF ){ + Elf32_Verdef* verdef = ( vdso_infos.base_addr + dyn_sec->d_un.d_ptr ); + if ( verdef != (Elf32_Verdef*) vdso_infos.verdef_table ){ + _dl_dprintf(2,"vdso elf DT_VERDEF check error\n"); + return; + } + continue; + } + + if ( dyn_sec->d_tag == DT_VERDEFNUM ){ + vdso_infos.verdef_num = dyn_sec->d_un.d_val; + continue; + } + + if ( dyn_sec->d_tag == DT_VERSYM ){ + uint16_t* versym = ( vdso_infos.base_addr + dyn_sec->d_un.d_ptr ); + if ( versym != vdso_infos.versym_table ){ + _dl_dprintf(2,"vdso elf DT_VERSYM check error\n"); + return; + } + continue; + } + + } + + /* + * + * load vdso version definition strings + * + */ + + ELF(Verdef) *vd = vdso_infos.verdef_table; + for( int i = 0 ; i < vdso_infos.verdef_num ; i++ ){ + + ELF(Verdaux) *vd_aux = (ELF(Verdaux) *)(( ( char*)vd ) + vd->vd_aux); + + vdso_infos.vers_strings[ vd->vd_ndx ] = vdso_infos.dynstr_table + vd_aux->vda_name; + + vd = ( ELF(Verdef) *)(( ( char*)vd ) + vd->vd_next); + + } + + /* + * + * load function from the vdso + * + */ +#ifdef __SUPPORT_LD_DEBUG__ + if ( _dl_debug_vdso != 0 ){ + int vdso_functions = 0; + for( int i = 0 ; i < vdso_infos.dynsym_table_num ; i++ ){ + ELF(Sym)* sym = &vdso_infos.dynsym_table[i]; + + if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) + continue; + + char* name = vdso_infos.dynstr_table + sym->st_name; + if ( name[0] == 0 ){ + continue; + } + + vdso_functions++; + } + _dl_dprintf(2,"_dl_vdso_load functions found : %d\n", vdso_functions ); + } + +#endif + + for( int i = 0 ; i < vdso_infos.dynsym_table_num ; i++ ){ + ELF(Sym)* sym = &vdso_infos.dynsym_table[i]; + + if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) + continue; + + char* name = vdso_infos.dynstr_table + sym->st_name; + void* func_addr = (void*)( vdso_infos.base_addr + sym->st_value ); + + // the function name is patched to zero if the kernel has no timer which is + // usable for the function + if ( name[0] == 0 ){ +#ifdef __SUPPORT_LD_DEBUG__ + if ( _dl_debug_vdso != 0 ){ + _dl_dprintf(2," function at address %p disabled by the kernel\n", sym->st_value ); + } +#endif + continue; + } + + if ( 0 == _dl_strcmp( name, __ARCH_VDSO_GETTIMEOFDAY_NAME ) ){ + _dl__vdso_gettimeofday = func_addr; +#ifdef __SUPPORT_LD_DEBUG__ + if ( _dl_debug_vdso != 0 ){ + _dl_dprintf(2," %s at address %p\n", name, func_addr ); + } +#endif + continue; + } + if ( 0 == _dl_strcmp( name, __ARCH_VDSO_CLOCK_GETTIME_NAME ) ){ + _dl__vdso_clock_gettime = func_addr; +#ifdef __SUPPORT_LD_DEBUG__ + if ( _dl_debug_vdso != 0 ){ + _dl_dprintf(2," %s at address %p\n", name, func_addr ); + } +#endif + continue; + } + +#if defined(__UCLIBC_USE_TIME64__) + if ( 0 == _dl_strcmp( name, __ARCH_VDSO_CLOCK_GETTIME64_NAME ) ){ + _dl__vdso_clock_gettime64 = func_addr; +#ifdef __SUPPORT_LD_DEBUG__ + if ( _dl_debug_vdso != 0 ){ + _dl_dprintf(2," %s at address %p\n", name, func_addr ); + } +#endif + continue; + } +#endif /* defined(__UCLIBC_USE_TIME64__) */ + +#ifdef __SUPPORT_LD_DEBUG__ + if ( _dl_debug_vdso != 0 ){ + _dl_dprintf(2," <%s> not handled\n", name ); + } +#endif + + } +} + +#endif // __VDSO_SUPPORT__ diff --git a/ldso/ldso/fdpic/dl-inlines.h b/ldso/ldso/fdpic/dl-inlines.h index 89e7a9a68..6a31ef3e6 100644 --- a/ldso/ldso/fdpic/dl-inlines.h +++ b/ldso/ldso/fdpic/dl-inlines.h @@ -102,7 +102,7 @@ __dl_update_loadaddr_hdr(struct elf32_fdpic_loadaddr loadaddr, void *addr, #if defined (__SUPPORT_LD_DEBUG__) if (_dl_debug) - _dl_dprintf(_dl_debug_file, "%i: changed mapping %x at %x (old %x), size %x\n", + _dl_dprintf(_dl_debug_file, "%i: changed mapping %x at %x (old %p), size %x\n", loadaddr.map->nsegs - 1, segdata->p_vaddr, segdata->addr, oldaddr, segdata->p_memsz); #endif @@ -177,7 +177,7 @@ _dl_funcdesc_for (void *entry_point, void *got_value) tpnt->funcdesc_ht = ht; } - entry = htab_find_slot(ht, entry_point, 1, hash_pointer, eq_pointer); + entry = (struct funcdesc_value **)htab_find_slot(ht, entry_point, 1, hash_pointer, eq_pointer); if (entry == NULL) _dl_exit(1); diff --git a/ldso/ldso/fdpic/dl-sysdep.h b/ldso/ldso/fdpic/dl-sysdep.h index 6ab303b37..81694dc76 100644 --- a/ldso/ldso/fdpic/dl-sysdep.h +++ b/ldso/ldso/fdpic/dl-sysdep.h @@ -108,7 +108,7 @@ struct funcdesc_ht; && ELF32_ST_TYPE((SYM)->st_info) == STT_FUNC \ ? _dl_funcdesc_for ((void *)DL_RELOC_ADDR ((TPNT)->loadaddr, (SYM)->st_value), \ (TPNT)->loadaddr.got_value) \ - : DL_RELOC_ADDR ((TPNT)->loadaddr, (SYM)->st_value)) + : (void*)DL_RELOC_ADDR ((TPNT)->loadaddr, (SYM)->st_value)) #define DL_GET_READY_TO_RUN_EXTRA_PARMS \ , struct elf32_fdpic_loadmap *dl_boot_progmap, Elf32_Addr dl_boot_got_pointer diff --git a/ldso/ldso/i386/dl-syscalls.h b/ldso/ldso/i386/dl-syscalls.h index f40c4fd31..8f144ee28 100644 --- a/ldso/ldso/i386/dl-syscalls.h +++ b/ldso/ldso/i386/dl-syscalls.h @@ -1 +1,29 @@ +/* stub for arch-specific syscall issues/specific implementations */ + +#ifndef _DL_SYSCALLS_H +#define _DL_SYSCALLS_H + +#if defined(__VDSO_SUPPORT__) && !defined(UCLIBC_LDSO) + +#include "../dl-vdso-calls.h" + +static int __attribute__ ((used)) __x86_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp); +static int __attribute__ ((used)) __x86_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + return __generic_vdso_clock_gettime(clock_id, tp); +} + +static int __attribute__ ((used)) __x86_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz); +static int __attribute__ ((used)) __x86_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz) +{ + return __generic_vdso_gettimeofday(tv, tz); +} + +#define ARCH_VDSO_GETTIMEOFDAY(tv, tz) __x86_vdso_gettimeofday(tv, tz) +#define ARCH_VDSO_CLOCK_GETTIME(clock_id, tp) __x86_vdso_clock_gettime(clock_id, tp) + +#endif /* defined(__VDSO_SUPPORT__) && !defined(UCLIBC_LDSO) */ + +#endif /* _DL_SYSCALLS_H */ + /* stub for arch-specific syscall issues */ diff --git a/ldso/ldso/i386/dl-sysdep.h b/ldso/ldso/i386/dl-sysdep.h index b95328df4..8fc80a145 100644 --- a/ldso/ldso/i386/dl-sysdep.h +++ b/ldso/ldso/i386/dl-sysdep.h @@ -35,28 +35,21 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent || (type) == R_386_TLS_TPOFF) * ELF_RTYPE_CLASS_PLT) \ | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY)) -/* Return the link-time address of _DYNAMIC. Conveniently, this is the - first element of the GOT, a special entry that is never relocated. */ -extern const Elf32_Addr _GLOBAL_OFFSET_TABLE_[] attribute_hidden; -static __always_inline Elf32_Addr __attribute__ ((unused, const)) -elf_machine_dynamic (void) -{ - /* This produces a GOTOFF reloc that resolves to zero at link time, so in - fact just loads from the GOT register directly. By doing it without - an asm we can let the compiler choose any register. */ - return _GLOBAL_OFFSET_TABLE_[0]; -} - -extern Elf32_Dyn bygotoff[] __asm__ ("_DYNAMIC") attribute_hidden; /* Return the run-time load address of the shared object. */ static __always_inline Elf32_Addr attribute_unused elf_machine_load_address (void) { - /* Compute the difference between the runtime address of _DYNAMIC as seen - by a GOTOFF reference, and the link-time address found in the special - unrelocated first GOT entry. */ - return (Elf32_Addr) &bygotoff - elf_machine_dynamic (); + extern const Elf32_Ehdr __ehdr_start attribute_hidden; + return (Elf32_Addr) &__ehdr_start; +} + +/* Return the link-time address of _DYNAMIC. */ +static __always_inline Elf32_Addr __attribute__ ((unused, const)) +elf_machine_dynamic (void) +{ + extern Elf32_Dyn _DYNAMIC[] attribute_hidden; + return (Elf32_Addr) _DYNAMIC - elf_machine_load_address (); } static __always_inline void diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c index b33547670..e866d6418 100644..100755 --- a/ldso/ldso/ldso.c +++ b/ldso/ldso/ldso.c @@ -73,6 +73,7 @@ char *_dl_debug_reloc = NULL; char *_dl_debug_detail = NULL; char *_dl_debug_nofixups = NULL; char *_dl_debug_bindings = NULL; +char *_dl_debug_vdso = NULL; int _dl_debug_file = 2; #endif @@ -350,10 +351,9 @@ static void trace_objects(struct elf_resolve *tpnt, char *str_name) static struct elf_resolve * add_ldso(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, ElfW(Addr) ldso_mapaddr, - ElfW(auxv_t) auxvt[AT_EGID + 1], struct dyn_elf *rpnt) { - ElfW(Ehdr) *epnt = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_val; + ElfW(Ehdr) *epnt = (ElfW(Ehdr) *) _dl_auxvt[AT_BASE].a_un.a_val; ElfW(Phdr) *myppnt = (ElfW(Phdr) *) DL_RELOC_ADDR(DL_GET_RUN_ADDR(load_addr, ldso_mapaddr), epnt->e_phoff); @@ -422,7 +422,7 @@ static void _dl_setup_progname(const char *argv0) } void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, - ElfW(auxv_t) auxvt[AT_EGID + 1], char **envp, char **argv + char **envp, char **argv DL_GET_READY_TO_RUN_EXTRA_PARMS) { ElfW(Addr) app_mapaddr = 0, ldso_mapaddr = 0; @@ -461,7 +461,7 @@ void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, _dl_memset(app_tpnt, 0, sizeof(*app_tpnt)); /* Store the page size for later use */ - _dl_pagesize = (auxvt[AT_PAGESZ].a_un.a_val) ? (size_t) auxvt[AT_PAGESZ].a_un.a_val : PAGE_SIZE; + _dl_pagesize = (_dl_auxvt[AT_PAGESZ].a_un.a_val) ? (size_t) _dl_auxvt[AT_PAGESZ].a_un.a_val : PAGE_SIZE; /* Make it so _dl_malloc can use the page of memory we have already * allocated. We shouldn't need to grab any more memory. This must * be first since things like _dl_dprintf() use _dl_malloc()... @@ -485,7 +485,7 @@ void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, #endif #ifndef __LDSO_STANDALONE_SUPPORT__ - if (_start == (void *) auxvt[AT_ENTRY].a_un.a_val) { + if (_start == (void *) _dl_auxvt[AT_ENTRY].a_un.a_val) { _dl_dprintf(2, "Standalone execution is not enabled\n"); _dl_exit(1); } @@ -504,10 +504,10 @@ void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, * Note that for SUID programs we ignore the settings in * LD_LIBRARY_PATH. */ - if ((auxvt[AT_UID].a_un.a_val == (size_t)-1 && _dl_suid_ok()) || - (auxvt[AT_UID].a_un.a_val != (size_t)-1 && - auxvt[AT_UID].a_un.a_val == auxvt[AT_EUID].a_un.a_val && - auxvt[AT_GID].a_un.a_val == auxvt[AT_EGID].a_un.a_val)) { + if ((_dl_auxvt[AT_UID].a_un.a_val == (size_t)-1 && _dl_suid_ok()) || + (_dl_auxvt[AT_UID].a_un.a_val != (size_t)-1 && + _dl_auxvt[AT_UID].a_un.a_val == _dl_auxvt[AT_EUID].a_un.a_val && + _dl_auxvt[AT_GID].a_un.a_val == _dl_auxvt[AT_EGID].a_un.a_val)) { _dl_secure = 0; #ifdef __LDSO_PRELOAD_ENV_SUPPORT__ _dl_preload = _dl_getenv("LD_PRELOAD", envp); @@ -546,7 +546,7 @@ void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, #endif #ifdef __LDSO_STANDALONE_SUPPORT__ - if (_start == (void *) auxvt[AT_ENTRY].a_un.a_val) { + if (_start == (void *) _dl_auxvt[AT_ENTRY].a_un.a_val) { ElfW(Addr) *aux_dat = (ElfW(Addr) *) argv; int argc = (int) aux_dat[-1]; @@ -643,11 +643,11 @@ of this helper program; chances are you did not intend to run this program.\n\ */ { unsigned int idx; - ElfW(Phdr) *phdr = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_val; + ElfW(Phdr) *phdr = (ElfW(Phdr) *) _dl_auxvt[AT_PHDR].a_un.a_val; - for (idx = 0; idx < auxvt[AT_PHNUM].a_un.a_val; idx++, phdr++) + for (idx = 0; idx < _dl_auxvt[AT_PHNUM].a_un.a_val; idx++, phdr++) if (phdr->p_type == PT_PHDR) { - DL_INIT_LOADADDR_PROG(app_tpnt->loadaddr, auxvt[AT_PHDR].a_un.a_val - phdr->p_vaddr); + DL_INIT_LOADADDR_PROG(app_tpnt->loadaddr, _dl_auxvt[AT_PHDR].a_un.a_val - phdr->p_vaddr); break; } @@ -662,8 +662,8 @@ of this helper program; chances are you did not intend to run this program.\n\ */ debug_addr = _dl_zalloc(sizeof(struct r_debug)); - ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_val; - for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) { + ppnt = (ElfW(Phdr) *) _dl_auxvt[AT_PHDR].a_un.a_val; + for (i = 0; i < _dl_auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) { if (ppnt->p_type == PT_GNU_RELRO) { relro_addr = ppnt->p_vaddr; relro_size = ppnt->p_memsz; @@ -682,11 +682,11 @@ of this helper program; chances are you did not intend to run this program.\n\ */ /* Now cover the application program. */ if (app_tpnt->dynamic_info[DT_TEXTREL]) { - int j; + unsigned int j; ElfW(Phdr) *ppnt_outer = ppnt; _dl_debug_early("calling mprotect on the application program\n"); - ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_val; - for (j = 0; j < auxvt[AT_PHNUM].a_un.a_val; j++, ppnt++) { + ppnt = (ElfW(Phdr) *) _dl_auxvt[AT_PHDR].a_un.a_val; + for (j = 0; j < _dl_auxvt[AT_PHNUM].a_un.a_val; j++, ppnt++) { if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) _dl_mprotect((void *) (DL_RELOC_ADDR(app_tpnt->loadaddr, ppnt->p_vaddr) & PAGE_ALIGN), (DL_RELOC_ADDR(app_tpnt->loadaddr, ppnt->p_vaddr) & ADDR_ALIGN) + @@ -713,8 +713,8 @@ of this helper program; chances are you did not intend to run this program.\n\ (unsigned long) DL_RELOC_ADDR(app_tpnt->loadaddr, ppnt->p_vaddr), ppnt->p_filesz); _dl_loaded_modules->libtype = elf_executable; - _dl_loaded_modules->ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_val; - _dl_loaded_modules->n_phent = auxvt[AT_PHNUM].a_un.a_val; + _dl_loaded_modules->ppnt = (ElfW(Phdr) *) _dl_auxvt[AT_PHDR].a_un.a_val; + _dl_loaded_modules->n_phent = _dl_auxvt[AT_PHNUM].a_un.a_val; _dl_symbol_tables = rpnt = _dl_zalloc(sizeof(struct dyn_elf)); rpnt->dyn = _dl_loaded_modules; app_tpnt->mapaddr = app_mapaddr; @@ -792,7 +792,7 @@ of this helper program; chances are you did not intend to run this program.\n\ if (_dl_debug) { if (_dl_strstr(_dl_debug, "all")) { _dl_debug_detail = _dl_debug_move = _dl_debug_symbols - = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = (void*)1; + = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = _dl_debug_vdso = (void*)1; } else { _dl_debug_detail = _dl_strstr(_dl_debug, "detail"); _dl_debug_move = _dl_strstr(_dl_debug, "move"); @@ -800,6 +800,7 @@ of this helper program; chances are you did not intend to run this program.\n\ _dl_debug_reloc = _dl_strstr(_dl_debug, "reloc"); _dl_debug_nofixups = _dl_strstr(_dl_debug, "nofix"); _dl_debug_bindings = _dl_strstr(_dl_debug, "bind"); + _dl_debug_vdso = _dl_strstr(_dl_debug, "vdso"); } } @@ -856,7 +857,7 @@ of this helper program; chances are you did not intend to run this program.\n\ } #endif - ldso_mapaddr = (ElfW(Addr)) auxvt[AT_BASE].a_un.a_val; + ldso_mapaddr = (ElfW(Addr)) _dl_auxvt[AT_BASE].a_un.a_val; /* * OK, fix one more thing - set up debug_addr so it will point * to our chain. Later we may need to fill in more fields, but this @@ -1046,7 +1047,7 @@ of this helper program; chances are you did not intend to run this program.\n\ if (!ldso_tpnt) { /* Insert the ld.so only once */ ldso_tpnt = add_ldso(tpnt, load_addr, - ldso_mapaddr, auxvt, rpnt); + ldso_mapaddr, rpnt); } else { ldso_tpnt->init_flag |= DL_OPENED2; } @@ -1148,7 +1149,7 @@ of this helper program; chances are you did not intend to run this program.\n\ * again once all libs are loaded. */ if (!ldso_tpnt) { - tpnt = add_ldso(tpnt, load_addr, ldso_mapaddr, auxvt, rpnt); + tpnt = add_ldso(tpnt, load_addr, ldso_mapaddr, rpnt); tpnt->usage_count++; nscope_elem++; } else @@ -1450,11 +1451,11 @@ of this helper program; chances are you did not intend to run this program.\n\ _dl_debug_state(); #ifdef __LDSO_STANDALONE_SUPPORT__ - if (_start == (void *) auxvt[AT_ENTRY].a_un.a_val) + if (_start == (void *) _dl_auxvt[AT_ENTRY].a_un.a_val) return (void *) app_tpnt->l_entry; else #endif - return (void *) auxvt[AT_ENTRY].a_un.a_val; + return (void *) _dl_auxvt[AT_ENTRY].a_un.a_val; } #include "dl-hash.c" diff --git a/ldso/ldso/m68k/dl-startup.h b/ldso/ldso/m68k/dl-startup.h index dfece443f..9c3285e27 100644 --- a/ldso/ldso/m68k/dl-startup.h +++ b/ldso/ldso/m68k/dl-startup.h @@ -55,6 +55,9 @@ _dl_start_user:\n\ * do something a little more subtle here. */ #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long *) ARGS) + 1) +/* We can't call functions earlier in the dl startup process */ +#define NO_FUNCS_BEFORE_BOOTSTRAP + /* Handle relocation of the symbols in the dynamic loader. */ static __always_inline void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr, diff --git a/ldso/ldso/m68k/dl-sysdep.h b/ldso/ldso/m68k/dl-sysdep.h index 21937b259..5d2d7a097 100644 --- a/ldso/ldso/m68k/dl-sysdep.h +++ b/ldso/ldso/m68k/dl-sysdep.h @@ -83,3 +83,5 @@ elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr, *reloc_addr = load_off + rpnt->r_addend; } while (--relative_count); } + +#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR) diff --git a/ldso/ldso/m68k/elfinterp.c b/ldso/ldso/m68k/elfinterp.c index 25ea23067..e7fa117da 100644 --- a/ldso/ldso/m68k/elfinterp.c +++ b/ldso/ldso/m68k/elfinterp.c @@ -193,7 +193,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, #endif #if defined (__SUPPORT_LD_DEBUG__) - old_val = *reloc_addr; + old_val = reloc_addr ? *reloc_addr : 0; #endif switch (reloc_type) { @@ -292,7 +292,7 @@ _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, reloc_type = ELF_R_TYPE(rpnt->r_info); #if defined (__SUPPORT_LD_DEBUG__) - old_val = *reloc_addr; + old_val = reloc_addr ? *reloc_addr : 0; #endif switch (reloc_type) { diff --git a/ldso/ldso/mips/dl-startup.h b/ldso/ldso/mips/dl-startup.h index 8026f1702..c2168d774 100644 --- a/ldso/ldso/mips/dl-startup.h +++ b/ldso/ldso/mips/dl-startup.h @@ -7,6 +7,7 @@ #include <sgidefs.h> +#ifndef L_rcrt1 __asm__("" " .text\n" " .globl _start\n" @@ -114,6 +115,7 @@ __asm__("" "\n\n" ".previous\n" ); +#endif /* * Get a pointer to the argv array. On many platforms this can be just @@ -191,6 +193,5 @@ do { \ case R_MIPS_NONE: \ break; \ default: \ - SEND_STDERR("Aiieeee!"); \ _dl_exit(1); \ } diff --git a/ldso/ldso/mips/dl-syscalls.h b/ldso/ldso/mips/dl-syscalls.h index f40c4fd31..d8407f17c 100644 --- a/ldso/ldso/mips/dl-syscalls.h +++ b/ldso/ldso/mips/dl-syscalls.h @@ -1 +1,28 @@ -/* stub for arch-specific syscall issues */ +/* stub for arch-specific syscall issues/specific implementations */ + +#ifndef _DL_SYSCALLS_H +#define _DL_SYSCALLS_H + +#if defined(__VDSO_SUPPORT__) && !defined(UCLIBC_LDSO) + +#include "../dl-vdso-calls.h" + +static int __attribute__ ((used)) __mips_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp); +static int __attribute__ ((used)) __mips_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + return __generic_vdso_clock_gettime(clock_id, tp); +} + +static int __attribute__ ((used)) __mips_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz); +static int __attribute__ ((used)) __mips_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz) +{ + return __generic_vdso_gettimeofday(tv, tz); +} + +#define ARCH_VDSO_GETTIMEOFDAY(tv, tz) __mips_vdso_gettimeofday(tv, tz) +#define ARCH_VDSO_CLOCK_GETTIME(clock_id, tp) __mips_vdso_clock_gettime(clock_id, tp) + +#endif /* defined(__VDSO_SUPPORT__) && !defined(UCLIBC_LDSO) */ + +#endif /* _DL_SYSCALLS_H */ + diff --git a/ldso/ldso/powerpc/dl-startup.h b/ldso/ldso/powerpc/dl-startup.h index 8b2a517e2..8503350c5 100644 --- a/ldso/ldso/powerpc/dl-startup.h +++ b/ldso/ldso/powerpc/dl-startup.h @@ -26,6 +26,10 @@ __asm__( " bl _GLOBAL_OFFSET_TABLE_-4@local\n" /* Put our GOT pointer in r31, */ " mflr 31\n" #endif +/* I'm quite sure this piece of code is always compiled as PIC but let's be sure */ +#if defined(PPC_HAS_SECUREPLT) && defined(__PIC__) + " mr 30,31\n" +#endif " addi 1,1,16\n" /* Restore SP */ " lwz 7,_dl_skip_args@got(31)\n" /* load EA of _dl_skip_args */ " lwz 7,0(7)\n" /* Load word from _dl_skip_args */ diff --git a/ldso/ldso/riscv32/dl-startup.h b/ldso/ldso/riscv32/dl-startup.h new file mode 100644 index 000000000..6f16918d6 --- /dev/null +++ b/ldso/ldso/riscv32/dl-startup.h @@ -0,0 +1,92 @@ +/* + * Architecture specific code used by dl-startup.c + * Copyright (C) 2024 Waldemar Brodkorb <wbx@uclibc-ng.org> + * Ported from GNU libc + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 2011-2019 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <features.h> +#include <sys/asm.h> + +#ifndef _RTLD_PROLOGUE +# define _RTLD_PROLOGUE(entry) \ + ".globl\t" __STRING (entry) "\n\t" \ + ".type\t" __STRING (entry) ", @function\n" \ + __STRING (entry) ":\n\t" +#endif + +#ifndef _RTLD_EPILOGUE +# define _RTLD_EPILOGUE(entry) \ + ".size\t" __STRING (entry) ", . - " __STRING (entry) "\n\t" +#endif + +#define STRINGXP(X) __STRING (X) + +__asm__(\ + ".text\n\ + " _RTLD_PROLOGUE (_start) "\ + mv a0, sp\n\ + jal _dl_start\n\ + # Stash user entry point in s0.\n\ + mv s0, a0\n\ + # See if we were run as a command with the executable file\n\ + # name as an extra leading argument.\n\ + lw a0, _dl_skip_args\n\ + # Load the original argument count.\n\ + " STRINGXP (REG_L) " a1, 0(sp)\n\ + # Subtract _dl_skip_args from it.\n\ + sub a1, a1, a0\n\ + # Adjust the stack pointer to skip _dl_skip_args words.\n\ + sll a0, a0, " STRINGXP (PTRLOG) "\n\ + add sp, sp, a0\n\ + # Save back the modified argument count.\n\ + " STRINGXP (REG_S) " a1, 0(sp)\n\ + # Pass our finalizer function to _start.\n\ + lla a0, _dl_fini\n\ + # Jump to the user entry point.\n\ + jr s0\n\ + " _RTLD_EPILOGUE (_start) "\ + .previous" \ +); + +/* Get a pointer to the argv array. On many platforms this can be just + * the address of the first argument, on other platforms we need to + * do something a little more subtle here. */ +#define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*)ARGS)+1) + +/* Function calls are not safe until the GOT relocations have been done. */ +#define NO_FUNCS_BEFORE_BOOTSTRAP + +/* Handle relocation of the symbols in the dynamic loader. */ +static __always_inline +void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, ElfW(Addr) *reloc_addr, + ElfW(Addr) symbol_addr, ElfW(Addr) load_addr, ElfW(Addr) *sym) +{ + switch (ELF_R_TYPE(rpnt->r_info)) { + case R_RISCV_NONE: + break; + case R_RISCV_JUMP_SLOT: + *reloc_addr = symbol_addr + rpnt->r_addend; + break; + default: + _dl_exit(1); + } +} + +#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR) diff --git a/ldso/ldso/riscv32/dl-syscalls.h b/ldso/ldso/riscv32/dl-syscalls.h new file mode 100644 index 000000000..f40c4fd31 --- /dev/null +++ b/ldso/ldso/riscv32/dl-syscalls.h @@ -0,0 +1 @@ +/* stub for arch-specific syscall issues */ diff --git a/ldso/ldso/riscv32/dl-sysdep.h b/ldso/ldso/riscv32/dl-sysdep.h new file mode 100644 index 000000000..02296b148 --- /dev/null +++ b/ldso/ldso/riscv32/dl-sysdep.h @@ -0,0 +1,89 @@ +/* + * Various assembly language/system dependent hacks that are required + * so that we can minimize the amount of platform specific code. + * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org> + * Copyright (C) 2024 by Waldemar Brodkorb <wbx@uclibc-ng.org> + * Ported from GNU C Library + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 2011-2019 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +/* Define this if the system uses RELOCA. */ +#define ELF_USES_RELOCA + +#include <elf.h> +#include <link.h> + +/* Initialization sequence for the GOT. */ +#define INIT_GOT(GOT_BASE,MODULE) \ +{ \ + GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \ + GOT_BASE[1] = (unsigned long) MODULE; \ +} + +/* Here we define the magic numbers that this dynamic loader should accept */ +#define MAGIC1 EM_RISCV +#undef MAGIC2 + +/* Used for error messages */ +#define ELF_TARGET "RISC-V" + +struct elf_resolve; +unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); + +#define ELF_MACHINE_JMP_SLOT R_RISCV_JUMP_SLOT + +#define elf_machine_type_class(type) \ + ((ELF_RTYPE_CLASS_PLT * ((type) == ELF_MACHINE_JMP_SLOT \ + || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_DTPREL32) \ + || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_DTPMOD32) \ + || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_TPREL32) \ + || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPREL64) \ + || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPMOD64) \ + || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_TPREL64))) \ + | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY))) + + +/* Return the run-time load address of the shared object. */ +static __always_inline ElfW(Addr) __attribute__ ((unused)) +elf_machine_load_address (void) +{ + extern const ElfW(Ehdr) __ehdr_start attribute_hidden; + return (ElfW(Addr)) &__ehdr_start; +} + +/* Return the link-time address of _DYNAMIC. */ +static inline ElfW(Addr) +elf_machine_dynamic (void) +{ + extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; + return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address (); +} + +static __always_inline void +elf_machine_relative(Elf32_Addr load_off, const Elf32_Addr rel_addr, + Elf32_Word relative_count) +{ + Elf32_Rela *rpnt = (Elf32_Rela*)rel_addr; + --rpnt; + do { + Elf32_Addr *const reloc_addr = (Elf32_Addr*)(load_off + (++rpnt)->r_offset); + + *reloc_addr = load_off + rpnt->r_addend; + } while (--relative_count); +} diff --git a/ldso/ldso/riscv32/elfinterp.c b/ldso/ldso/riscv32/elfinterp.c new file mode 100644 index 000000000..1a0d5d445 --- /dev/null +++ b/ldso/ldso/riscv32/elfinterp.c @@ -0,0 +1,295 @@ +/* RISCV ELF shared library loader suppport + * + * Copyright (C) 2001-2004 Erik Andersen + * Copyright (C) 2024 Waldemar Brodkorb <wbx@uclibc-ng.org> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the above contributors may not be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Program to load an ELF binary on a linux system, and run it. + References to symbols in sharable libraries can be resolved by either + an ELF sharable library or a linux style of shared library. */ + +#include "ldso.h" + +extern int _dl_linux_resolve(void); + +unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) +{ + ELF_RELOC *this_reloc; + char *strtab; + ElfW(Sym) *symtab; + int symtab_index; + char *rel_addr; + char *new_addr; + char **got_addr; + ElfW(Addr) instr_addr; + char *symname; + + rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL]; + this_reloc = (ELF_RELOC *)(rel_addr + reloc_entry); + symtab_index = ELF_R_SYM(this_reloc->r_info); + + symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB]; + strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; + symname = strtab + symtab[symtab_index].st_name; + + /* Address of jump instruction to fix up */ + instr_addr = (this_reloc->r_offset + tpnt->loadaddr); + got_addr = (char **)instr_addr; + + /* Get the address of the GOT entry */ + new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); + if (unlikely(!new_addr)) { + _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname); + _dl_exit(1); + } +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug_bindings) { + _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname); + if (_dl_debug_detail) _dl_dprintf(_dl_debug_file, + "\tpatched %x ==> %x @ %x", *got_addr, new_addr, got_addr); + } + if (!_dl_debug_nofixups) { + *got_addr = new_addr; + } +#else + *got_addr = new_addr; +#endif + return (unsigned long)new_addr; +} + +static int +_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope, + unsigned long rel_addr, unsigned long rel_size, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)) +{ + unsigned int i; + char *strtab; + ElfW(Sym) *symtab; + ELF_RELOC *rpnt; + int symtab_index; + + /* Parse the relocation information */ + rpnt = (ELF_RELOC *)rel_addr; + rel_size = rel_size / sizeof(ELF_RELOC); + + symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB]; + strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; + + for (i = 0; i < rel_size; i++, rpnt++) { + int res; + + symtab_index = ELF_R_SYM(rpnt->r_info); + + debug_sym(symtab, strtab, symtab_index); + debug_reloc(symtab, strtab, rpnt); + + res = reloc_fnc(tpnt, scope, rpnt, symtab, strtab); + + if (res==0) + continue; + + _dl_dprintf(2, "\n%s: ", _dl_progname); + + if (symtab_index) + _dl_dprintf(2, "symbol '%s': ", + strtab + symtab[symtab_index].st_name); + + if (unlikely(res < 0)) { + int reloc_type = ELF_R_TYPE(rpnt->r_info); + _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type); + _dl_exit(-res); + } else if (unlikely(res > 0)) { + _dl_dprintf(2, "can't resolve symbol\n"); + return res; + } + } + + return 0; +} + +static int +_dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) +{ + int reloc_type; + int symtab_index; + char *symname; +#if defined USE_TLS && USE_TLS + struct elf_resolve *tls_tpnt = NULL; +#endif + struct symbol_ref sym_ref; + ElfW(Addr) *reloc_addr; + ElfW(Addr) symbol_addr; +#if defined (__SUPPORT_LD_DEBUG__) + ElfW(Addr) old_val; +#endif + + reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); + sym_ref.sym = &symtab[symtab_index]; + sym_ref.tpnt = NULL; + symbol_addr = 0; + symname = strtab + sym_ref.sym->st_name; + + if (symtab_index) { + symbol_addr = (ElfW(Addr))_dl_find_hash(symname, scope, tpnt, + elf_machine_type_class(reloc_type), &sym_ref); + + /* + * We want to allow undefined references to weak symbols - this might + * have been intentional. We should not be linking local symbols + * here, so all bases should be covered. + */ + if (unlikely (!symbol_addr && + (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS) && + (ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK))) { + return 1; + } + if (_dl_trace_prelink) { + _dl_debug_lookup (symname, tpnt, &symtab[symtab_index], + &sym_ref, elf_machine_type_class(reloc_type)); + } +#if defined USE_TLS && USE_TLS + tls_tpnt = sym_ref.tpnt; +#endif + } else { + /* + * Relocs against STN_UNDEF are usually treated as using a + * symbol value of zero, and using the module containing the + * reloc itself. + */ + symbol_addr = sym_ref.sym->st_value; +#if defined USE_TLS && USE_TLS + tls_tpnt = tpnt; +#endif + } + +#if defined (__SUPPORT_LD_DEBUG__) + old_val = *reloc_addr; +#endif + + switch (reloc_type) { + case R_RISCV_NONE: + break; + case R_RISCV_32: /* REL_SYMBOLIC */ + case R_RISCV_JUMP_SLOT: /* REL_PLT */ + *reloc_addr = symbol_addr + rpnt->r_addend; + break; + case R_RISCV_RELATIVE: + *reloc_addr += tpnt->loadaddr + rpnt->r_addend; + break; + case R_RISCV_COPY: + if (symbol_addr) { + _dl_memcpy((char *)reloc_addr, (char *)symbol_addr, + sym_ref.sym->st_size); + } + break; +#if defined USE_TLS && USE_TLS + case R_RISCV_TLS_DTPMOD32: + *reloc_addr = tls_tpnt->l_tls_modid; + break; + case R_RISCV_TLS_DTPREL32: + *reloc_addr = symbol_addr -TLS_DTV_OFFSET + rpnt->r_addend; + break; + case R_RISCV_TLS_TPREL32: + CHECK_STATIC_TLS ((struct link_map *) tls_tpnt); + *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend; + break; +#endif + default: + return -1; /*call _dl_exit(1) */ + } + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug_reloc && _dl_debug_detail) { + _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", + old_val, *reloc_addr, reloc_addr); + } +#endif + + return 0; +} + +#undef __RISCV_LAZY_RELOC_WORKS +#ifdef __RISCV_LAZY_RELOC_WORKS +static int +_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) +{ + int reloc_type; + ElfW(Addr) *reloc_addr; +#if defined (__SUPPORT_LD_DEBUG__) + ElfW(Addr) old_val; +#endif + + (void)scope; + (void)strtab; + + reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); + +#if defined (__SUPPORT_LD_DEBUG__) + old_val = *reloc_addr; +#endif + + switch (reloc_type) { + case R_RISCV_NONE: + break; + case R_RISCV_JUMP_SLOT: + break; + default: + return -1; /*call _dl_exit(1) */ + } + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug_reloc && _dl_debug_detail) { + _dl_dprintf(_dl_debug_file, "\tpatched_lazy: %x ==> %x @ %x\n", + old_val, *reloc_addr, reloc_addr); + } +#endif + + return 0; +} +#endif + +void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, + unsigned long rel_addr, unsigned long rel_size) +{ +#ifdef __RISCV_LAZY_RELOC_WORKS + (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc); +#else + _dl_parse_relocation_information(rpnt, &_dl_loaded_modules->symbol_scope, + rel_addr, rel_size); +#endif +} + +int _dl_parse_relocation_information(struct dyn_elf *rpnt, + struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size) +{ + return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc); +} diff --git a/ldso/ldso/riscv32/resolve.S b/ldso/ldso/riscv32/resolve.S new file mode 100644 index 000000000..bfa91ecdb --- /dev/null +++ b/ldso/ldso/riscv32/resolve.S @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024 by Waldemar Brodkorb <wbx@uclibc-ng.org> + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + * ported from GNU libc + */ + +/* Copyright (C) 2017-2019 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + <https://www.gnu.org/licenses/>. */ + +#include <features.h> + +#include <sysdep.h> +#include <sys/asm.h> + +/* Assembler veneer called from the PLT header code for lazy loading. + The PLT header passes its own args in t0-t2. */ + +#ifdef __riscv_float_abi_soft +# define FRAME_SIZE (-((-10 * SZREG) & ALMASK)) +#else +# define FRAME_SIZE (-((-10 * SZREG - 8 * SZFREG) & ALMASK)) +#endif + +ENTRY (_dl_linux_resolve) + # Save arguments to stack. + addi sp, sp, -FRAME_SIZE + REG_S ra, 9*SZREG(sp) + REG_S a0, 1*SZREG(sp) + REG_S a1, 2*SZREG(sp) + REG_S a2, 3*SZREG(sp) + REG_S a3, 4*SZREG(sp) + REG_S a4, 5*SZREG(sp) + REG_S a5, 6*SZREG(sp) + REG_S a6, 7*SZREG(sp) + REG_S a7, 8*SZREG(sp) + +#ifndef __riscv_float_abi_soft + FREG_S fa0, (10*SZREG + 0*SZFREG)(sp) + FREG_S fa1, (10*SZREG + 1*SZFREG)(sp) + FREG_S fa2, (10*SZREG + 2*SZFREG)(sp) + FREG_S fa3, (10*SZREG + 3*SZFREG)(sp) + FREG_S fa4, (10*SZREG + 4*SZFREG)(sp) + FREG_S fa5, (10*SZREG + 5*SZFREG)(sp) + FREG_S fa6, (10*SZREG + 6*SZFREG)(sp) + FREG_S fa7, (10*SZREG + 7*SZFREG)(sp) +#endif + + # Update .got.plt and obtain runtime address of callee. + slli a1, t1, 1 + mv a0, t0 # link map + add a1, a1, t1 # reloc offset (== thrice the .got.plt offset) + la a2, _dl_fixup + jalr a2 + mv t1, a0 + + # Restore arguments from stack. + REG_L ra, 9*SZREG(sp) + REG_L a0, 1*SZREG(sp) + REG_L a1, 2*SZREG(sp) + REG_L a2, 3*SZREG(sp) + REG_L a3, 4*SZREG(sp) + REG_L a4, 5*SZREG(sp) + REG_L a5, 6*SZREG(sp) + REG_L a6, 7*SZREG(sp) + REG_L a7, 8*SZREG(sp) + +#ifndef __riscv_float_abi_soft + FREG_L fa0, (10*SZREG + 0*SZFREG)(sp) + FREG_L fa1, (10*SZREG + 1*SZFREG)(sp) + FREG_L fa2, (10*SZREG + 2*SZFREG)(sp) + FREG_L fa3, (10*SZREG + 3*SZFREG)(sp) + FREG_L fa4, (10*SZREG + 4*SZFREG)(sp) + FREG_L fa5, (10*SZREG + 5*SZFREG)(sp) + FREG_L fa6, (10*SZREG + 6*SZFREG)(sp) + FREG_L fa7, (10*SZREG + 7*SZFREG)(sp) +#endif + + addi sp, sp, FRAME_SIZE + + # Invoke the callee. + jr t1 +END (_dl_linux_resolve) + diff --git a/ldso/ldso/riscv64/dl-startup.h b/ldso/ldso/riscv64/dl-startup.h index dabe1bebd..82e525e66 100644 --- a/ldso/ldso/riscv64/dl-startup.h +++ b/ldso/ldso/riscv64/dl-startup.h @@ -88,3 +88,5 @@ void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, ElfW(Addr) *reloc_addr, _dl_exit(1); } } + +#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR) diff --git a/ldso/ldso/riscv64/dl-sysdep.h b/ldso/ldso/riscv64/dl-sysdep.h index 91a45af46..01f3e49bf 100644 --- a/ldso/ldso/riscv64/dl-sysdep.h +++ b/ldso/ldso/riscv64/dl-sysdep.h @@ -58,23 +58,20 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_TPREL64))) \ | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY))) - -/* Return the link-time address of _DYNAMIC. */ +/* Return the run-time load address of the shared object. */ static inline ElfW(Addr) -elf_machine_dynamic (void) +elf_machine_load_address (void) { - extern ElfW(Addr) _GLOBAL_OFFSET_TABLE_ __attribute__ ((visibility ("hidden"))); - return _GLOBAL_OFFSET_TABLE_; + extern const ElfW(Ehdr) __ehdr_start attribute_hidden; + return (ElfW(Addr)) &__ehdr_start; } - -/* Return the run-time load address of the shared object. */ -static __always_inline ElfW(Addr) __attribute__ ((unused)) -elf_machine_load_address (void) +/* Return the link-time address of _DYNAMIC. */ +static inline ElfW(Addr) +elf_machine_dynamic (void) { - ElfW(Addr) load_addr; - __asm__ ("lla %0, _DYNAMIC" : "=r" (load_addr)); - return load_addr - elf_machine_dynamic (); + extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; + return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address (); } static __always_inline void diff --git a/ldso/ldso/riscv64/elfinterp.c b/ldso/ldso/riscv64/elfinterp.c index 427e7b8fd..5266d96b2 100644 --- a/ldso/ldso/riscv64/elfinterp.c +++ b/ldso/ldso/riscv64/elfinterp.c @@ -214,11 +214,11 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, *reloc_addr = tls_tpnt->l_tls_modid; break; case R_RISCV_TLS_DTPREL64: - *reloc_addr = symbol_addr + rpnt->r_addend; + *reloc_addr = symbol_addr - TLS_DTV_OFFSET + rpnt->r_addend; break; case R_RISCV_TLS_TPREL64: CHECK_STATIC_TLS ((struct link_map *) tls_tpnt); - *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend - TLS_TCB_SIZE; + *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend; break; #endif default: diff --git a/ldso/ldso/x86_64/dl-syscalls.h b/ldso/ldso/x86_64/dl-syscalls.h index f40c4fd31..3f953aa83 100644 --- a/ldso/ldso/x86_64/dl-syscalls.h +++ b/ldso/ldso/x86_64/dl-syscalls.h @@ -1 +1,28 @@ -/* stub for arch-specific syscall issues */ +/* stub for arch-specific syscall issues/specific implementations */ + +#ifndef _DL_SYSCALLS_H +#define _DL_SYSCALLS_H + +#if defined(__VDSO_SUPPORT__) && !defined(UCLIBC_LDSO) + +#include "../dl-vdso-calls.h" + +static int __attribute__ ((used)) __x86_64_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp); +static int __attribute__ ((used)) __x86_64_vdso_clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + return __generic_vdso_clock_gettime(clock_id, tp); +} + +static int __attribute__ ((used)) __x86_64_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz); +static int __attribute__ ((used)) __x86_64_vdso_gettimeofday(struct timeval *tv, __timezone_ptr_t tz) +{ + return __generic_vdso_gettimeofday(tv, tz); +} + +#define ARCH_VDSO_GETTIMEOFDAY(tv, tz) __x86_64_vdso_gettimeofday(tv, tz) +#define ARCH_VDSO_CLOCK_GETTIME(clock_id, tp) __x86_64_vdso_clock_gettime(clock_id, tp) + +#endif /* defined(__VDSO_SUPPORT__) && !defined(UCLIBC_LDSO) */ + +#endif /* _DL_SYSCALLS_H */ + diff --git a/ldso/ldso/x86_64/dl-sysdep.h b/ldso/ldso/x86_64/dl-sysdep.h index ccf9a8851..58447a951 100644 --- a/ldso/ldso/x86_64/dl-sysdep.h +++ b/ldso/ldso/x86_64/dl-sysdep.h @@ -52,48 +52,21 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent * ELF_RTYPE_CLASS_PLT) \ | (((type) == R_X86_64_COPY) * ELF_RTYPE_CLASS_COPY)) -/* Return the link-time address of _DYNAMIC. Conveniently, this is the - first element of the GOT. This must be inlined in a function which - uses global data. */ -static __always_inline Elf64_Addr __attribute__ ((unused)) -elf_machine_dynamic (void) -{ - Elf64_Addr addr; - - /* This works because we have our GOT address available in the small PIC - model. */ - addr = (Elf64_Addr) &_DYNAMIC; - - return addr; -} - /* Return the run-time load address of the shared object. */ static __always_inline Elf64_Addr __attribute__ ((unused)) elf_machine_load_address (void) { - register Elf64_Addr addr, tmp; - - /* The easy way is just the same as on x86: - leaq _dl_start, %0 - leaq _dl_start(%%rip), %1 - subq %0, %1 - but this does not work with binutils since we then have - a R_X86_64_32S relocation in a shared lib. - - Instead we store the address of _dl_start in the data section - and compare it with the current value that we can get via - an RIP relative addressing mode. */ - - __asm__ ("movq 1f(%%rip), %1\n" - "0:\tleaq _dl_start(%%rip), %0\n\t" - "subq %1, %0\n\t" - ".section\t.data\n" - "1:\t.quad _dl_start\n\t" - ".previous\n\t" - : "=r" (addr), "=r" (tmp) : : "cc"); + extern const Elf64_Ehdr __ehdr_start attribute_hidden; + return (Elf64_Addr) &__ehdr_start; +} - return addr; +/* Return the link-time address of _DYNAMIC. */ +static __always_inline Elf64_Addr __attribute__ ((unused)) +elf_machine_dynamic (void) +{ + extern Elf64_Dyn _DYNAMIC[] attribute_hidden; + return (Elf64_Addr) _DYNAMIC - elf_machine_load_address (); } static __always_inline void diff --git a/ldso/ldso/xtensa/dl-inlines.h b/ldso/ldso/xtensa/dl-inlines.h new file mode 100644 index 000000000..8fdf6eb48 --- /dev/null +++ b/ldso/ldso/xtensa/dl-inlines.h @@ -0,0 +1 @@ +#include "../fdpic/dl-inlines.h" diff --git a/ldso/ldso/xtensa/dl-startup.h b/ldso/ldso/xtensa/dl-startup.h index db223fead..2a453752a 100644 --- a/ldso/ldso/xtensa/dl-startup.h +++ b/ldso/ldso/xtensa/dl-startup.h @@ -7,6 +7,69 @@ * Parts taken from glibc/sysdeps/xtensa/dl-machine.h. */ +#if defined(__FDPIC__) +__asm__ ( + " .text\n" + " .align 4\n" + " .literal_position\n" + " .global _start\n" + " .type _start, @function\n" + " .hidden _start\n" + "_start:\n" + " .begin no-transform\n" + " _call0 1f\n" + "2:\n" + " .end no-transform\n" + " .align 4\n" + "1:\n" +#if defined(__XTENSA_CALL0_ABI__) + " movi a15, 2b\n" + " sub a15, a0, a15\n" + + /* Save FDPIC pointers in callee-saved registers */ + " mov a12, a4\n" + " mov a13, a5\n" + " mov a14, a6\n" + + /* Call __self_reloc */ + " mov a2, a5\n" + " movi a3, __ROFIXUP_LIST__\n" + " add a3, a3, a15\n" + " movi a4, __ROFIXUP_END__\n" + " add a4, a4, a15\n" + " movi a0, __self_reloc\n" + " add a0, a0, a15\n" + " callx0 a0\n" + + /* call _dl_start */ + " mov a3, a12\n" + " mov a4, a13\n" + " mov a5, a14\n" + " mov a7, sp\n" + " addi sp, sp, -16\n" + " mov a6, sp\n" + " mov a11, a2\n" + /* a13, interpreter map is no longer needed, save interpreter GOT there */ + " mov a13, a2\n" + " movi a0, _dl_start\n" + " add a0, a0, a15\n" + " callx0 a0\n" + + /* call main */ + " l32i a0, sp, 0\n" + " l32i a11, sp, 4\n" + " addi sp, sp, 16\n" + " mov a4, a12\n" + " movi a5, _dl_fini@GOTOFFFUNCDESC\n" + " add a5, a5, a13\n" + " mov a6, a14\n" + " jx a0\n" +#else +#error Unsupported Xtensa ABI +#endif + ); +#else /* __FDPIC__ */ +#ifndef L_rcrt1 __asm__ ( " .text\n" " .align 4\n" @@ -81,6 +144,8 @@ __asm__ ( " addi a5, a5, 8\n" " bnez a6, 3b\n" " j .Lfixup_stack_ret"); +#endif +#endif /* __FDPIC__ */ /* Get a pointer to the argv value. */ #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long *) ARGS) + 1) @@ -88,12 +153,11 @@ __asm__ ( /* Function calls are not safe until the GOT relocations have been done. */ #define NO_FUNCS_BEFORE_BOOTSTRAP +#if defined(__ARCH_USE_MMU__) && !defined(__FDPIC__) #define PERFORM_BOOTSTRAP_GOT(tpnt) \ do { \ xtensa_got_location *got_loc; \ unsigned long l_addr = tpnt->loadaddr; \ - Elf32_Word relative_count; \ - unsigned long rel_addr; \ Elf32_Addr prev_got_start = 0, prev_got_end = 0; \ int x; \ \ @@ -125,13 +189,31 @@ do { \ prev_got_end - prev_got_start, \ PROT_READ | PROT_WRITE | PROT_EXEC); \ } \ -\ - /* The following is a stripped down version of the code following \ - the invocation of PERFORM_BOOTSTRAP_GOT in dl-startup.c. That \ - code is skipped when PERFORM_BOOTSTRAP_GOT is defined, so it has \ - to be done here instead. */ \ - relative_count = tpnt->dynamic_info[DT_RELCONT_IDX]; \ - rel_addr = tpnt->dynamic_info[DT_RELOC_TABLE_ADDR]; \ - if (rel_addr) \ - elf_machine_relative(load_addr, rel_addr, relative_count); \ } while (0) +#endif + +#ifdef __FDPIC__ +#undef DL_START +#define DL_START(X) \ +static void __attribute__ ((used)) \ +_dl_start (Elf32_Addr dl_boot_got_pointer, \ + struct elf32_fdpic_loadmap *dl_boot_progmap, \ + struct elf32_fdpic_loadmap *dl_boot_ldsomap, \ + Elf32_Dyn *dl_boot_ldso_dyn_pointer, \ + struct funcdesc_value *dl_main_funcdesc, \ + X) + +/* + * Transfer control to the user's application, once the dynamic loader + * is done. We return the address of the function's entry point to + * _dl_boot, see boot1_arch.h. + */ +#define START() do { \ + struct elf_resolve *exec_mod = _dl_loaded_modules; \ + dl_main_funcdesc->entry_point = _dl_elf_main; \ + while (exec_mod->libtype != elf_executable) \ + exec_mod = exec_mod->next; \ + dl_main_funcdesc->got_value = exec_mod->loadaddr.got_value; \ + return; \ +} while (0) +#endif /* __FDPIC__ */ diff --git a/ldso/ldso/xtensa/dl-sysdep.h b/ldso/ldso/xtensa/dl-sysdep.h index d308237d3..5aa3e177f 100644 --- a/ldso/ldso/xtensa/dl-sysdep.h +++ b/ldso/ldso/xtensa/dl-sysdep.h @@ -26,6 +26,7 @@ in l_info array. */ #define DT_XTENSA(x) (DT_XTENSA_##x - DT_LOPROC + DT_NUM + OS_NUM) +#ifndef __FDPIC__ typedef struct xtensa_got_location_struct { Elf32_Off offset; Elf32_Word length; @@ -86,6 +87,7 @@ typedef struct xtensa_got_location_struct { else if (dpnt->d_tag == DT_XTENSA_GOT_LOC_SZ) \ dynamic[DT_XTENSA (GOT_LOC_SZ)] = dpnt->d_un.d_val; \ } while (0) +#endif /* Here we define the magic numbers that this dynamic loader should accept. */ #define MAGIC1 EM_XTENSA @@ -94,9 +96,6 @@ typedef struct xtensa_got_location_struct { /* Used for error messages. */ #define ELF_TARGET "Xtensa" -/* Need bootstrap relocations */ -#define ARCH_NEEDS_BOOTSTRAP_RELOCS - struct elf_resolve; extern unsigned long _dl_linux_resolver (struct elf_resolve *, int); @@ -118,10 +117,41 @@ elf_machine_dynamic (void) return (Elf32_Addr) &_DYNAMIC; } +#ifdef __FDPIC__ + +#define DL_CHECK_LIB_TYPE(epnt, piclib, _dl_progname, libname) \ +do \ +{ \ + (piclib) = 2; \ +} \ +while (0) + +/* We must force strings used early in the bootstrap into the data + segment. */ +#undef SEND_EARLY_STDERR +#define SEND_EARLY_STDERR(S) \ + do { /* FIXME: implement */; } while (0) + +#undef INIT_GOT +#include "../fdpic/dl-sysdep.h" +#undef INIT_GOT +#define INIT_GOT(GOT_BASE,MODULE) \ +{ \ + (MODULE)->loadaddr.got_value = (GOT_BASE); \ + GOT_BASE[0] = ((unsigned long *)&_dl_linux_resolve)[0]; \ + GOT_BASE[1] = ((unsigned long *)&_dl_linux_resolve)[1]; \ + GOT_BASE[2] = (unsigned long) MODULE; \ +} + +#endif /* __FDPIC__ */ + /* Return the run-time load address of the shared object. */ static __always_inline Elf32_Addr elf_machine_load_address (void) { +#ifdef __FDPIC__ + return 0; +#else Elf32_Addr addr, tmp; /* At this point, the runtime linker is being bootstrapped and the GOT @@ -138,17 +168,48 @@ elf_machine_load_address (void) : "=a" (addr), "=a" (tmp)); return addr - 3; +#endif } +#ifdef __FDPIC__ + +/* Need bootstrap relocations */ +#define ARCH_NEEDS_BOOTSTRAP_RELOCS + +#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB) \ + switch (ELF_R_TYPE((RELP)->r_info)){ \ + case R_XTENSA_SYM32: \ + *(REL) = (SYMBOL) + (RELP)->r_addend; \ + break; \ + case R_XTENSA_RELATIVE: \ + case R_XTENSA_NONE: \ + default: \ + break; \ + } + static __always_inline void -elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr, +elf_machine_relative (DL_LOADADDR_TYPE load_off, const Elf32_Addr rel_addr, Elf32_Word relative_count) { Elf32_Rela *rpnt = (Elf32_Rela *) rel_addr; while (relative_count--) { + Elf32_Addr *const reloc_addr = (Elf32_Addr *) DL_RELOC_ADDR(load_off, rpnt->r_offset); + *reloc_addr = DL_RELOC_ADDR(load_off, *reloc_addr); + rpnt++; + } +} +#else +static __always_inline void +elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr, + Elf32_Word relative_count) +{ + Elf32_Rela *rpnt = (Elf32_Rela *) rel_addr; + while (relative_count--) + { Elf32_Addr *const reloc_addr = (Elf32_Addr *) (load_off + rpnt->r_offset); *reloc_addr += load_off + rpnt->r_addend; rpnt++; } } +#endif diff --git a/ldso/ldso/xtensa/dl-tlsdesc.S b/ldso/ldso/xtensa/dl-tlsdesc.S index 426f2180b..1a8eacff2 100644 --- a/ldso/ldso/xtensa/dl-tlsdesc.S +++ b/ldso/ldso/xtensa/dl-tlsdesc.S @@ -24,6 +24,9 @@ .text HIDDEN_ENTRY (_dl_tlsdesc_return) +#ifdef __FDPIC__ + l32i a2, a2, 4 +#endif rur.threadptr a3 add a2, a2, a3 abi_ret @@ -53,7 +56,9 @@ END (_dl_tlsdesc_return) */ HIDDEN_ENTRY (_dl_tlsdesc_dynamic) - +#ifdef __FDPIC__ + l32i a2, a2, 4 +#endif /* dtv_t *dtv = (dtv_t *)THREAD_DTV(); */ rur.threadptr a3 l32i a4, a3, 0 @@ -86,7 +91,8 @@ HIDDEN_ENTRY (_dl_tlsdesc_dynamic) #elif defined(__XTENSA_CALL0_ABI__) addi a1, a1, -16 s32i a0, a1, 0 - movi a0, __tls_get_addr + movi a0, JUMPTARGET(__tls_get_addr) + FDPIC_LOAD_JUMPTARGET(a0, a11, a0) callx0 a0 l32i a0, a1, 0 addi a1, a1, 16 diff --git a/ldso/ldso/xtensa/elfinterp.c b/ldso/ldso/xtensa/elfinterp.c index e38a02666..d97f23435 100644 --- a/ldso/ldso/xtensa/elfinterp.c +++ b/ldso/ldso/xtensa/elfinterp.c @@ -36,6 +36,13 @@ #include "tlsdeschtab.h" #endif +#ifdef __FDPIC__ +unsigned long +_dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry) +{ + return 0; +} +#else unsigned long _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry) { @@ -83,7 +90,7 @@ _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry) return (unsigned long) new_addr; } - +#endif static int _dl_parse (struct elf_resolve *tpnt, struct r_scope_elem *scope, @@ -145,8 +152,8 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, int reloc_type; int symtab_index; char *symname; -#if defined USE_TLS && USE_TLS - struct elf_resolve *tls_tpnt = NULL; +#if defined USE_TLS && USE_TLS || defined (__FDPIC__) + struct elf_resolve *def_mod = NULL; #endif struct symbol_ref sym_ref; ElfW(Addr) *reloc_addr; @@ -155,7 +162,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, ElfW(Addr) old_val; #endif - reloc_addr = (ElfW(Addr) *) (tpnt->loadaddr + rpnt->r_offset); + reloc_addr = (ElfW(Addr) *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset); reloc_type = ELF_R_TYPE (rpnt->r_info); symtab_index = ELF_R_SYM (rpnt->r_info); sym_ref.sym = &symtab[symtab_index]; @@ -164,9 +171,17 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, symname = strtab + sym_ref.sym->st_name; if (symtab_index) { - symbol_addr = (ElfW(Addr)) - _dl_find_hash (symname, scope, tpnt, - elf_machine_type_class (reloc_type), &sym_ref); + if (ELF_ST_BIND (sym_ref.sym->st_info) == STB_LOCAL) { + symbol_addr = (ElfW(Addr)) + DL_RELOC_ADDR(tpnt->loadaddr, + symtab[symtab_index].st_value); + sym_ref.tpnt = tpnt; + } else { + symbol_addr = (ElfW(Addr)) + _dl_find_hash (symname, scope, tpnt, + elf_machine_type_class (reloc_type), + &sym_ref); + } /* * We want to allow undefined references to weak symbols - this might @@ -182,13 +197,13 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, _dl_debug_lookup (symname, tpnt, &symtab[symtab_index], &sym_ref, elf_machine_type_class(reloc_type)); } -#if defined USE_TLS && USE_TLS - tls_tpnt = sym_ref.tpnt; +#if defined USE_TLS && USE_TLS || defined (__FDPIC__) + def_mod = sym_ref.tpnt; #endif } else { symbol_addr =symtab[symtab_index].st_value; -#if defined USE_TLS && USE_TLS - tls_tpnt = tpnt; +#if defined USE_TLS && USE_TLS || defined (__FDPIC__) + def_mod = tpnt; #endif } @@ -202,6 +217,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, case R_XTENSA_GLOB_DAT: case R_XTENSA_JMP_SLOT: + case R_XTENSA_SYM32: *reloc_addr = symbol_addr + rpnt->r_addend; break; @@ -219,19 +235,63 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, break; case R_XTENSA_RELATIVE: - *reloc_addr += tpnt->loadaddr + rpnt->r_addend; + *reloc_addr += DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_addend); break; +#ifdef __FDPIC__ + case R_XTENSA_FUNCDESC_VALUE: + { + struct funcdesc_value *dst = (struct funcdesc_value *) reloc_addr; + + dst->entry_point = (void *) (symbol_addr + rpnt->r_addend); + dst->got_value = def_mod->loadaddr.got_value; + } + break; + case R_XTENSA_FUNCDESC: + if (symbol_addr) + *reloc_addr = (unsigned long) + _dl_funcdesc_for((void *) (symbol_addr + rpnt->r_addend), + sym_ref.tpnt->loadaddr.got_value); + else + /* Relocation against an undefined weak symbol: + set funcdesc to zero. */ + *reloc_addr = 0; + break; + case R_XTENSA_TLS_TPOFF: + CHECK_STATIC_TLS((struct link_map *) def_mod); + *reloc_addr = symbol_addr + rpnt->r_addend + def_mod->l_tls_offset; + break; + case R_XTENSA_TLSDESC: + { + struct tlsdesc *td = (struct tlsdesc *) reloc_addr; +#ifndef SHARED + CHECK_STATIC_TLS((struct link_map *) def_mod); +#else + if (!TRY_STATIC_TLS ((struct link_map *) def_mod)) + { + td->entry = _dl_tlsdesc_dynamic; + td->argument = _dl_make_tlsdesc_dynamic((struct link_map *) def_mod, + symbol_addr + rpnt->r_addend); + } + else +#endif + { + td->entry = _dl_tlsdesc_return; + td->argument = (void *) (symbol_addr + rpnt->r_addend + def_mod->l_tls_offset); + } + } + break; +#else #if defined USE_TLS && USE_TLS case R_XTENSA_TLS_TPOFF: - CHECK_STATIC_TLS((struct link_map *) tls_tpnt); - *reloc_addr = symbol_addr + tls_tpnt->l_tls_offset + rpnt->r_addend; + CHECK_STATIC_TLS((struct link_map *) def_mod); + *reloc_addr = symbol_addr + rpnt->r_addend + def_mod->l_tls_offset; break; case R_XTENSA_TLSDESC_FN: #ifndef SHARED - CHECK_STATIC_TLS((struct link_map *) tls_tpnt); + CHECK_STATIC_TLS((struct link_map *) def_mod); #else - if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt)) + if (!TRY_STATIC_TLS ((struct link_map *) def_mod)) *reloc_addr = (ElfW(Addr)) _dl_tlsdesc_dynamic; else #endif @@ -239,25 +299,25 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, break; case R_XTENSA_TLSDESC_ARG: #ifndef SHARED - CHECK_STATIC_TLS((struct link_map *) tls_tpnt); + CHECK_STATIC_TLS((struct link_map *) def_mod); #else - if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt)) + if (!TRY_STATIC_TLS ((struct link_map *) def_mod)) *reloc_addr = (ElfW(Addr)) - _dl_make_tlsdesc_dynamic((struct link_map *) tls_tpnt, + _dl_make_tlsdesc_dynamic((struct link_map *) def_mod, symbol_addr + rpnt->r_addend); else #endif *reloc_addr = symbol_addr + rpnt->r_addend + - tls_tpnt->l_tls_offset; + def_mod->l_tls_offset; break; #endif - +#endif default: return -1; /* Calls _dl_exit(1). */ } #if defined (__SUPPORT_LD_DEBUG__) if (_dl_debug_reloc && _dl_debug_detail) - _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", + _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %p\n", old_val, *reloc_addr, reloc_addr); #endif @@ -275,7 +335,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, ElfW(Addr) old_val; #endif - reloc_addr = (ElfW(Addr) *) (tpnt->loadaddr + rpnt->r_offset); + reloc_addr = (ElfW(Addr) *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset); reloc_type = ELF_R_TYPE (rpnt->r_info); #if defined (__SUPPORT_LD_DEBUG__) @@ -286,7 +346,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, case R_XTENSA_JMP_SLOT: /* Perform a RELATIVE reloc on the GOT entry that transfers to the stub function. */ - *reloc_addr += tpnt->loadaddr; + *reloc_addr = DL_RELOC_ADDR(tpnt->loadaddr, *reloc_addr); break; case R_XTENSA_NONE: break; @@ -296,7 +356,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, #if defined (__SUPPORT_LD_DEBUG__) if (_dl_debug_reloc && _dl_debug_detail) - _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", + _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %p\n", old_val, *reloc_addr, reloc_addr); #endif return 0; @@ -320,3 +380,7 @@ _dl_parse_relocation_information (struct dyn_elf *rpnt, return _dl_parse (rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc); } + +#ifndef IS_IN_libdl +# include "../../libc/sysdeps/linux/xtensa/crtreloc.c" +#endif diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c index 37c4a876e..6e50cb087 100644 --- a/ldso/libdl/libdl.c +++ b/ldso/libdl/libdl.c @@ -972,11 +972,11 @@ static int do_dlclose(void *vhandle, int need_fini) end = (end + ADDR_ALIGN) & PAGE_ALIGN; start = start & ~ADDR_ALIGN; if (end > start) { - _dl_if_debug_print("unmapping: %s at %p with length: '%p' until %p\n", tpnt->libname, tpnt->mapaddr, end - start, tpnt->mapaddr + (end - start)); + _dl_if_debug_print("unmapping: %s at %p with length: '%p' until %p\n", tpnt->libname, (void *)tpnt->mapaddr, (void *)(end - start), (void *)(tpnt->mapaddr + (end - start))); DL_LIB_UNMAP (tpnt, end - start); } else { - _dl_if_debug_print("NOT unmapping: %s at %p. start<end ('%p'<'%p')", tpnt->libname, tpnt->mapaddr, start, end); + _dl_if_debug_print("NOT unmapping: %s at %p. start<end ('%p'<'%p')", tpnt->libname, (void *)tpnt->mapaddr, (void *)start, (void *)end); } /* Free elements in RTLD_LOCAL scope list */ for (runp = tpnt->rtld_local; runp; runp = tmp) { |