From patchwork Sat Jun 29 15:41:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Chen X-Patchwork-Id: 1124798 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-103358-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=andestech.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="rKwwPodT"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45bdF03jpYz9s4V for ; Sun, 30 Jun 2019 01:42:44 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-type; q=dns; s=default; b=matJ9 7OvwEs+wWqwhNtMG8QSpfoLO77ImVOVsDTVqwfI1bBSoyQrtFfDDaL8jyb+SRwhc iT160WelBP4hUE8pZNrpVm0wdc7m/xWnxvx8ZoUBwL53g59ZkUoy/y5be+NAsKF7 KHkzBCvjju0ozDWtQnm3AK25K+aYIqTXqUyMEA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-type; s=default; bh=9KpW8zI7kfm PpWKfve22naIvna0=; b=rKwwPodTktTekTcsYINekrluCSBYSymtOgJMfisc2pb Wxv9iKHjkPFFd0C9Wnn1Ffm3vcAbpxc0mIiHGnhyp3tcZxECIrbwljeqCDvXswdE o117StwNLwEYVRmHbLObDrixHpO6LHeDlTcQVTKenAnsX5rdxSesCle9sKux6Cf8 = Received: (qmail 97498 invoked by alias); 29 Jun 2019 15:42:15 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 97437 invoked by uid 89); 29 Jun 2019 15:42:14 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-22.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, KAM_STOCKGEN, RDNS_DYNAMIC, SPF_PASS, TVD_RCVD_IP autolearn=ham version=3.3.1 spammy=Identify, rel, lw, sw X-HELO: ATCSQR.andestech.com From: Vincent Chen To: , CC: , , Vincent Chen Subject: [PATCH v6 04/11] nds32: Startup and Dynamic Loader Date: Sat, 29 Jun 2019 23:41:23 +0800 Message-ID: <1561822890-23219-5-git-send-email-vincentc@andestech.com> In-Reply-To: <1561822890-23219-1-git-send-email-vincentc@andestech.com> References: <1561822890-23219-1-git-send-email-vincentc@andestech.com> MIME-Version: 1.0 X-DNSRBL: X-MAIL: ATCSQR.andestech.com x5TFXvDr032330 This patch contains crti.S, crtn.S and the dynamic loader for nds32 system. 2019-06-29 Vincent Chen 2019-06-29 CheWei Chuang * sysdeps/nds32/dl-machine.h: New file. * sysdeps/nds32/dl-sysdep.h: Likewise. * sysdeps/nds32/dl-trampoline.S: Likewise. * sysdeps/nds32/ldsodefs.h: Likewise. * sysdeps/nds32/start.S: Likewise. * sysdeps/unix/sysv/linux/nds32/dl-static.c: Likewise. * sysdeps/unix/sysv/linux/nds32/ldconfig.h: Likewise. * sysdeps/unix/sysv/linux/nds32/ldsodefs.h: Likewise. --- sysdeps/nds32/dl-machine.h | 404 ++++++++++++++++++++++++++++++ sysdeps/nds32/dl-sysdep.h | 22 ++ sysdeps/nds32/dl-trampoline.S | 164 ++++++++++++ sysdeps/nds32/ldsodefs.h | 44 ++++ sysdeps/nds32/start.S | 124 +++++++++ sysdeps/unix/sysv/linux/nds32/dl-static.c | 84 +++++++ sysdeps/unix/sysv/linux/nds32/ldconfig.h | 27 ++ sysdeps/unix/sysv/linux/nds32/ldsodefs.h | 33 +++ 8 files changed, 902 insertions(+) create mode 100644 sysdeps/nds32/dl-machine.h create mode 100644 sysdeps/nds32/dl-sysdep.h create mode 100644 sysdeps/nds32/dl-trampoline.S create mode 100644 sysdeps/nds32/ldsodefs.h create mode 100644 sysdeps/nds32/start.S create mode 100644 sysdeps/unix/sysv/linux/nds32/dl-static.c create mode 100644 sysdeps/unix/sysv/linux/nds32/ldconfig.h create mode 100644 sysdeps/unix/sysv/linux/nds32/ldsodefs.h diff --git a/sysdeps/nds32/dl-machine.h b/sysdeps/nds32/dl-machine.h new file mode 100644 index 0000000..c418b34 --- /dev/null +++ b/sysdeps/nds32/dl-machine.h @@ -0,0 +1,404 @@ +/* Machine-dependent ELF dynamic relocation inline functions. + Andes nds32 version. + Copyright (C) 2018-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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 + . */ + +#ifndef dl_machine_h +#define dl_machine_h + +#define ELF_MACHINE_NAME "NDS32" + +#include +#include +#include + +/* Return nonzero iff ELF header is compatible with the running host. */ +static inline int __attribute__ ((unused)) +elf_machine_matches_host (const ElfW(Ehdr) *ehdr) +{ + return ehdr->e_machine == EM_NDS32; +} + + +/* Return the link-time address of _DYNAMIC. Conveniently, this is the + first element of the GOT, a special entry that is never relocated. */ +static inline ElfW(Addr) __attribute__ ((unused, const)) +elf_machine_dynamic (void) +{ + /* This produces a GOTOFF reloc that resolves to some offset 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. */ + extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden; + return _GLOBAL_OFFSET_TABLE_[0]; +} + +/* Return the run-time load address of the shared object. */ +static inline ElfW(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. */ + extern ElfW(Dyn) bygotoff[] asm ("_DYNAMIC") attribute_hidden; + return (ElfW(Addr)) &bygotoff - elf_machine_dynamic (); +} + + + +/* Set up the loaded object described by L so its unrelocated PLT + entries will jump to the on-demand fixup code in dl-runtime.c. */ + +static inline int __attribute__ ((unused, always_inline)) +elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) +{ + ElfW(Addr) *got; + extern void _dl_runtime_resolve (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_profile (ElfW(Word)) attribute_hidden; + + if (l->l_info[DT_JMPREL] && lazy) + { + /* The GOT entries for functions in the PLT have not yet been filled + in. Their initial contents will arrange when called to push an + offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1], + and then jump to _GLOBAL_OFFSET_TABLE[2]. */ + got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]); + /* If a library is prelinked but we have to relocate anyway, + we have to be able to undo the prelinking of .got.plt. + The prelinker saved us here address of .plt + 0x28. */ + if (got[1]) + { + l->l_mach.plt = got[1] + l->l_addr; + l->l_mach.gotplt = (ElfW(Addr)) &got[3]; + } + got[1] = (ElfW(Addr)) l; /* Identify this shared object. */ + + /* The got[2] entry contains the address of a function which gets + called to get the address of a so far unresolved function and + jump to it. The profiling extension of the dynamic linker allows + to intercept the calls to collect information. In this case we + don't store the address in the GOT so that all future calls also + end in this function. */ + if (__builtin_expect (profile, 0)) + { + got[2] = (ElfW(Addr)) &_dl_runtime_profile; + + if (GLRO(dl_profile) != NULL && _dl_name_match_p (GLRO(dl_profile), l)) + /* This is the object we are looking for. Say that we really + want profiling and the timers are started. */ + GL(dl_profile_map) = l; + } + else + /* This function will get called to fix up the GOT entry indicated by + the offset on the stack, and then jump to the resolved address. */ + got[2] = (ElfW(Addr)) &_dl_runtime_resolve; + } + + return lazy; +} + +/* Initial entry point code for the dynamic linker. + The C function `_dl_start' is the real entry point; + its return value is the user program's entry point. */ +#define RTLD_START asm (" \ + .text \n\ + .globl _start \n\ + .align 4 \n\ +_start: \n\ + /* We are PIC code, so get global offset table. */ \n\ + mfusr $r15, $PC \n\ + sethi $gp, HI20(_GLOBAL_OFFSET_TABLE_ + 4) \n\ + ori $gp, $gp, LO12(_GLOBAL_OFFSET_TABLE_ + 8) \n\ + add $gp, $r15, $gp \n\ + \n\ + /* At start time, all the args are on the stack. */ \n\ + addi $r0, $sp, 0 \n\ + bal _dl_start@PLT \n\ + /* Save user entry point in $r6 which is callee saved. */ \n\ + addi $r6, $r0, 0 \n\ + /* See if we were run as a command with the executable file \n\ + name as an extra leading argument. \n\ + skip these arguments. */ \n\ + l.w $r2, _dl_skip_args@GOTOFF \n\ + bnez $r2, 2f \n\ + /* Prepare args to call _dl_init. */ \n\ + /* Get argv. */ \n\ + addi $r2, $sp, 4 \n\ +1: \n\ + l.w $r0, _rtld_local@GOTOFF \n\ + /* Get argc. */ \n\ + lwi $r1, [$sp+0] \n\ + /* envp =sp +argc * 4 + 8. */ \n\ + slli $r3, $r1, 2 \n\ + addi $r3, $r3, 8 \n\ + /* Get envp. */ \n\ + add $r3, $r3, $sp \n\ + bal _dl_init@PLT \n\ + \n\ + /* Load address of _dl_fini finalizer function. */ \n\ + la $r5, _dl_fini@GOTOFF \n\ + /* Jump to the user_s entry point. */ \n\ + jr $r6 \n\ +2: \n\ + lwi $r0, [$sp+0] \n\ + /* Offset for new $sp. */ \n\ + slli $r1, $r2, 2 \n\ + /* Adjust sp to skip args. */ \n\ + add $sp, $sp, $r1 \n\ + /* Set and save new argc. */ \n\ + sub $r0, $r0, $r2 \n\ + swi $r0, [$sp+0] \n\ + andi $r0, $sp, 7 \n\ + beqz $r0, 1b \n\ + \n\ + /* Make stack 8-byte aligned. */ \n\ + bitci $sp, $sp, 7 \n\ + move $r2, $sp \n\ +3: /* argc and argv. */ \n\ + lwi $r0, [$r2+4] \n\ + smw.bim $r0,[$r2],$r0,#0 \n\ + bnez $r0, 3b \n\ + \n\ +3: /* envp. */ \n\ + lwi $r0, [$r2+4] \n\ + smw.bim $r0,[$r2],$r0,#0 \n\ + bnez $r0, 3b \n\ + \n\ +3: /* auxv. */ \n\ + lmw.ai $r0,[$r2],$r1,#0 \n\ + smw.bim $r0,[$r2],$r1,#0 \n\ + bnez $r0, 3b \n\ + \n\ + /* Update _dl_argv. */ \n\ + addi $r2, $sp, 4 \n\ + s.w $r2, _dl_argv@GOTOFF \n\ + j 1b \n\ + .previous \n\ +"); + +# define elf_machine_type_class(type) \ + (((((type) == R_NDS32_JMP_SLOT) \ + || ((type)== R_NDS32_TLS_TPOFF) \ + || ((type)== R_NDS32_TLS_DESC)) * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_NDS32_COPY) * ELF_RTYPE_CLASS_COPY) \ + | (((type) == R_NDS32_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA)) + + +/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */ +#define ELF_MACHINE_JMP_SLOT R_NDS32_JMP_SLOT + +/* nds32 uses ElfW(Rela) no ElfW(Rel). */ +#define ELF_MACHINE_NO_REL 1 +#define ELF_MACHINE_NO_RELA 0 + +/* We define an initialization functions. This is called very early in + _dl_sysdep_start. */ +#define DL_PLATFORM_INIT dl_platform_init () + +static inline void __attribute__ ((unused)) +dl_platform_init (void) +{ + /* Avoid an empty string which would disturb us. */ + if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0') + GLRO(dl_platform) = NULL; +} + +/* Fixup a PLT entry to bounce directly to the function at VALUE. */ +static inline ElfW(Addr) +elf_machine_fixup_plt (struct link_map *map, lookup_t t, + const ElfW(Sym) *refsym, const ElfW(Sym) *sym, + const ElfW(Rela) *reloc, + ElfW(Addr) *reloc_addr, ElfW(Addr) value) +{ + return *reloc_addr = value; +} + +static inline ElfW(Addr) +elf_machine_plt_value (struct link_map *map, const ElfW(Rela) *reloc, + ElfW(Addr) value) +{ + return value + reloc->r_addend ; +} + +/* Names of the architecture-specific auditing callback functions. */ +#define ARCH_LA_PLTENTER nds32_gnu_pltenter +#define ARCH_LA_PLTEXIT nds32_gnu_pltexit + +#endif /* dl_machine_h. */ + + +#ifdef RESOLVE_MAP + +# define COPY_UNALIGNED_WORD(swp, twp) \ + { \ + unsigned int __tmp = __builtin_nds32_unaligned_load_w (swp); \ + __builtin_nds32_unaligned_store_w (twp, __tmp); \ + } +/* Perform the relocation specified by RELOC and SYM (which is fully resolved). + MAP is the object containing the reloc. */ + +auto inline void +elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, + const ElfW(Sym) *sym, const struct r_found_version *version, + void *const reloc_addr_arg, int skip_ifunc) +{ + + ElfW(Addr) *const reloc_addr = reloc_addr_arg; + const unsigned int r_type = ELF32_R_TYPE (reloc->r_info); + ElfW(Addr) value = 0; + + const ElfW(Sym) *const refsym = sym; + struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); + if (sym_map != NULL) + value = SYMBOL_ADDRESS (sym_map, sym, true) + reloc->r_addend; + switch (r_type) + { + case R_NDS32_COPY: + if (__glibc_unlikely (sym == NULL)) + /* This can happen in trace mode if an object could not be + found. */ + break; + if (sym->st_size > refsym->st_size + || (sym->st_size < refsym->st_size && GLRO(dl_verbose))) + { + const char *strtab; + + strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]); + _dl_error_printf ("\ + %s: Symbol `%s' has different size in shared object, consider re-linking\n", + rtld_progname ?: "", + strtab + refsym->st_name); + } + memcpy (reloc_addr_arg, (void *) value, + MIN (sym->st_size, refsym->st_size)); + break; + case R_NDS32_GLOB_DAT: + case R_NDS32_JMP_SLOT: + *reloc_addr = value; + break; + case R_NDS32_32_RELA: + COPY_UNALIGNED_WORD (&value, reloc_addr); + break; + case R_NDS32_TLS_TPOFF: + { +# ifdef RTLD_BOOTSTRAP + *reloc_addr = map->l_tls_offset + sym->st_value + reloc->r_addend; +# else + if (sym != NULL) + { + CHECK_STATIC_TLS (map, sym_map); + *reloc_addr = sym_map->l_tls_offset + sym->st_value + reloc->r_addend; + } + else + _dl_error_printf ("sym is NULL in R_NDS32_TLS_TPOFF\n"); +# endif + } + break; + + case R_NDS32_TLS_DESC: + { + struct tlsdesc volatile *td = (struct tlsdesc volatile *) reloc_addr; +# ifndef RTLD_BOOTSTRAP + if (!sym) + { + td->argument.value = reloc->r_addend; + td->entry = _dl_tlsdesc_undefweak; + } + else +# endif /* !RTLD_BOOTSTRAP */ + { + value = sym->st_value + reloc->r_addend; +# ifndef RTLD_BOOTSTRAP +# ifndef SHARED + CHECK_STATIC_TLS (map, sym_map); +# else + if (!TRY_STATIC_TLS (map, sym_map)) + { + td->argument.pointer + = _dl_make_tlsdesc_dynamic (sym_map, value); + td->entry = _dl_tlsdesc_dynamic; + } + else +# endif /* SHARED */ +# endif /* !RTLD_BOOTSTRAP */ + { + td->argument.value = value + sym_map->l_tls_offset; + td->entry = _dl_tlsdesc_return; + } + } + } + break; +# if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC + case R_NDS32_RELATIVE: + { +# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC +# ifndef SHARED + weak_extern (_dl_rtld_map); +# endif + /* Already done in rtld itself. */ + if (map != &GL(dl_rtld_map)) +# endif + *reloc_addr = map->l_addr + reloc->r_addend; + } +# endif + case R_NDS32_NONE: + break; + default: + _dl_reloc_bad_type (map, r_type, 0); + break; + } +} + +auto inline void +__attribute__ ((always_inline)) +elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc, + void *const reloc_addr_arg) +{ + ElfW(Addr) value; + + if (reloc->r_addend) + value = l_addr + reloc->r_addend; + else + { + COPY_UNALIGNED_WORD (reloc_addr_arg, &value); + value += l_addr; + } + COPY_UNALIGNED_WORD (&value, reloc_addr_arg); + +# undef COPY_UNALIGNED_WORD +} + +auto inline void +__attribute__ ((always_inline)) +elf_machine_lazy_rel (struct link_map *map, + ElfW(Addr) l_addr, const ElfW(Rela) *reloc, int skip_ifunc) +{ + ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset); + /* Check for unexpected PLT reloc type. */ + if (ELF32_R_TYPE (reloc->r_info) == R_NDS32_JMP_SLOT) + { + if (__builtin_expect (map->l_mach.plt, 0) == 0) + *reloc_addr += l_addr; + else + *reloc_addr = + map->l_mach.plt + + (((ElfW(Addr)) reloc_addr) - map->l_mach.gotplt) * 6; + } + else if (ELF32_R_TYPE (reloc->r_info) != R_NDS32_NONE) + _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1); +} +#endif /* RESOLVE_MAP */ + diff --git a/sysdeps/nds32/dl-sysdep.h b/sysdeps/nds32/dl-sysdep.h new file mode 100644 index 0000000..c7fc3d0 --- /dev/null +++ b/sysdeps/nds32/dl-sysdep.h @@ -0,0 +1,22 @@ +/* System-specific settings for dynamic linker code. Andes nds32 version. + Copyright (C) 2018-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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 + . */ + +#include_next + +#define DL_ARGV_NOT_RELRO 1 +#define DL_EXTERN_PROTECTED_DATA diff --git a/sysdeps/nds32/dl-trampoline.S b/sysdeps/nds32/dl-trampoline.S new file mode 100644 index 0000000..ccd0a6e --- /dev/null +++ b/sysdeps/nds32/dl-trampoline.S @@ -0,0 +1,164 @@ +/* PLT trampolines. Andes nds32 version. + Copyright (C) 2018-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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 + . */ + +#include +#include + +ENTRY (_dl_runtime_resolve) + + /* We get called with: + $lp contains the return address from this call. + $r16 contains offset to target reloc entry. + $r17 contains GOT[1] (identity of taget lib). + $r15 is GOT[2] (starting address of _dl_runtime_resolve). */ + + /* Save arguments $r0 - $r3. */ + smw.adm $r0, [$sp], $r5, 6 + .cfi_adjust_cfa_offset 32 + .cfi_rel_offset lp, 28 + .cfi_rel_offset gp, 24 + + GET_GTABLE ($gp) + + move $r0, $r17 + /* Sizeof (ElfW(Rela)) is 12. */ + slli $r1, $r16, 2 + slli $r16, $r16, 3 + add $r1, $r1, $r16 + addi $r2, $lp, 0 + bal _dl_fixup + /* Save the return. */ + addi $r15, $r0, 0 + + lmw.bim $r0, [$sp], $r5, 6 + .cfi_adjust_cfa_offset -32 + .cfi_restore lp + .cfi_restore gp + + /* Jump to the newly found address. */ + jr $r15 +END (_dl_runtime_resolve) +ENTRY (_dl_runtime_profile) + + /* We get called with: + $lp contains the return address from this call. + $r16 contains offset to target reloc entry. + $r17 contains GOT[1] (identity of taget lib). + $r15 is GOT[2] (starting address of this function). + + Stack layout: + 12 - La_nds32_regs (9 registers). + 4 - Saved two arguments to _dl_profile_fixup. + 0 - framesize returned from pltenter. */ + + /* Save La_nds32_regs arguments: $r0 - $r5, $gp, $lp, $sp. */ + move $r15, $sp + smw.adm $r0, [$r15], $r5, 7 + move $sp, $r15 + .cfi_adjust_cfa_offset 36 + .cfi_rel_offset gp, 24 + .cfi_rel_offset lp, 28 + + GET_GTABLE ($gp) + + addi $r0, $r17, 0 + slli $r1, $r16, 2 + slli $r16, $r16, 3 + add $r1, $r1, $r16 + + smw.adm $r0, [$sp], $r1, 0 + .cfi_adjust_cfa_offset 4 + + xor $r4, $r4, $r4 + push $r4 + + move $r2, $lp + addi $r3, $sp, 12 + move $r4, $sp + + bal _dl_profile_fixup + lw $r2, [$sp] + sw $r0, [$sp] + bgez $r2, 1f + cfi_remember_state + + addi $r15, $sp, 12 + lmw.bim $r0, [$r15], $r5, 7 + .cfi_adjust_cfa_offset -48 + .cfi_restore gp + .cfi_restore lp + lwi $r15, [$sp + (-48)] + + /* Jump to the newly found address. */ + jr $r15 +1: + /* The new frame size is in $r2. + + New stack layout: + 16 - La_nds32_regs (9 registers). + 8 - Saved two arguments to _dl_profile_fixup. + 4 - Saved result of _dl_profile_fixup. + 0 - saved $r6. */ + + cfi_restore_state + push $r6 + + /* Make new frame size 8-byte aligned. */ + bitci $r6, $r2, 7 + + + /* Copy stack argument. */ + sub $r0, $sp, $r6 + addi $r1, $sp, 48 + bal memcpy + + /* Jump to the newly found address. */ + addi $r15, $sp, 16 + lmw.bim $r0, [$r15], $r5, 0 + lwi $r15, [$sp +4] + sub $sp, $sp, $r6 + jral $r15 + add $sp, $sp, $r6 + pop $r6 + cfi_def_cfa_register (sp) + /* New stack layout: + 24 - La_nds32_regs (9 registers). + 16 - Saved two arguments to _dl_profile_fixup. + 12 - Saved result of _dl_profile_fixup. + 8 - one dummy word for stack aligned. + 0 - La_nds32_retval. */ + + /* Push $r0, $r1 for La_nds32_retval. */ + /* Push $r2 for dummy word. */ + smw.adm $r0, [$sp], $r2 + .cfi_adjust_cfa_offset 12 + addi $r15, $sp, 16 + lmw.bim $r0, [$r15], $r1 + addi $r2, $sp, 24 + /* $r3 contains outregs. */ + move $r3, $sp + bal _dl_call_pltexit + + lmw.bim $r0, [$sp], $r1 + addi $r15, $sp, 24 + lmw.bim $r2, [$r15], $r5, 7 + .cfi_adjust_cfa_offset -48 + .cfi_restore gp + .cfi_restore lp + ret +END (_dl_runtime_profile) diff --git a/sysdeps/nds32/ldsodefs.h b/sysdeps/nds32/ldsodefs.h new file mode 100644 index 0000000..8df2ac8 --- /dev/null +++ b/sysdeps/nds32/ldsodefs.h @@ -0,0 +1,44 @@ +/* Run-time dynamic linker data structures for loaded ELF shared objects. + Copyright (C) 2018-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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 + . */ + + +#ifndef _NDS32_LDSODEFS_H +#define _NDS32_LDSODEFS_H 1 + +#include + +struct La_nds32_regs; +struct La_nds32_retval; + +#define ARCH_PLTENTER_MEMBERS \ + ElfW(Addr) (*nds32_gnu_pltenter) (ElfW(Sym) *, unsigned int, \ + uintptr_t *, uintptr_t *, \ + struct La_nds32_regs *, \ + unsigned int *, const char *name, \ + long int *framesizep) + +#define ARCH_PLTEXIT_MEMBERS \ + unsigned int (*nds32_gnu_pltexit) (ElfW(Sym) *, unsigned int, \ + uintptr_t *, uintptr_t *, \ + const struct La_nds32_regs *, \ + struct La_nds32_retval *, \ + const char *) + +#include_next + +#endif /* _NDS32_LDSODEFS_H. */ diff --git a/sysdeps/nds32/start.S b/sysdeps/nds32/start.S new file mode 100644 index 0000000..3135c10 --- /dev/null +++ b/sysdeps/nds32/start.S @@ -0,0 +1,124 @@ +/* Startup code compliant to the ELF nds32 ABI. + Copyright (C) 2018-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file with other + programs, and to distribute those programs without any restriction + coming from the use of this file. (The GNU Lesser General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into another program.) + + Note that people who make modified versions of this file are not + obligated to grant this special exception for their modified + versions; it is their choice whether to do so. The GNU Lesser + General Public License gives permission to release a modified + version without this exception; this exception also makes it + possible to release a modified version which carries forward this + exception. + + 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 + . */ + +/* This is the canonical entry point, usually the first thing in the text + segment. + + Note that the code in the .init section has already been run. + This includes _init and _libc_init + + + At this entry point, most registers' values are unspecified, except: + + $r5 Contains a function pointer to be registered with `atexit'. + This is how the dynamic linker arranges to have DT_FINI + functions called for shared libraries that have been loaded + before this code runs. + + sp The stack contains the arguments and environment: + 0(sp) argc + 4(sp) argv[0] + ... + (4*argc)(sp) NULL + (4*(argc+1))(sp) envp[0] + ... + NULL +*/ +#include + .text + .align 4 + .globl _start + .type _start, @function +#ifdef SHARED + .pic +#endif +_start: + /* clear FP. */ + movi $fp, 0 + /* $r1 = argc. */ + lwi $r1, [$sp + 0] + /* $r2 = argv. */ + addi $r2, $sp, 4 + + /* align sp to 8-byte boundary. */ + movi $r0, -8 + and $sp, $sp, $r0 + /* $r6 = stack top. */ + addi $r6, $sp, 0 + +#ifdef SHARED + /* set $gp register. */ + GET_GTABLE ($gp) + + la $r3, __libc_csu_init@GOTOFF + la $r4, __libc_csu_fini@GOTOFF + la $r0, main@GOT + + /* push everything to stack. + $r5 is rtld_fini, $r7 is used to keep stack align. */ + pushm $r0, $r7 + + /* now start it up. */ + bal __libc_start_main@PLT + + /* should never get here. */ + bal abort@PLT +#else + /* init $gp for small data access. */ + la $gp, _SDA_BASE_ + + la $r3, __libc_csu_init + la $r4, __libc_csu_fini + la $r0, main + + /* push everything to stack, $r5 is rtld_fini, $r7 is dummy a word. */ + pushm $r0, $r7 + + /* now start it up. */ + bal __libc_start_main + + /* should never get here. */ + bal abort +#endif /* !SHARED */ + + ret + + /* Define a symbol for the first piece of initialized data. */ + .data + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start diff --git a/sysdeps/unix/sysv/linux/nds32/dl-static.c b/sysdeps/unix/sysv/linux/nds32/dl-static.c new file mode 100644 index 0000000..09864a7 --- /dev/null +++ b/sysdeps/unix/sysv/linux/nds32/dl-static.c @@ -0,0 +1,84 @@ +/* Variable initialization, Andes nds32 version. + Copyright (C) 2018-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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 + . */ + +#include + +#ifdef SHARED + +void +_dl_var_init (void *array[]) +{ + /* It has to match "variables" below. */ + enum + { + DL_PAGESIZE = 0 + }; + + GLRO(dl_pagesize) = *((size_t *) array[DL_PAGESIZE]); +} + +#else + +static void *variables[] = +{ + &GLRO(dl_pagesize) +}; + +static void +_dl_unprotect_relro (struct link_map *l) +{ + ElfW(Addr) start = ((l->l_addr + l->l_relro_addr) + & ~(GLRO(dl_pagesize) - 1)); + ElfW(Addr) end = ((l->l_addr + l->l_relro_addr + l->l_relro_size) + & ~(GLRO(dl_pagesize) - 1)); + + if (start != end) + __mprotect ((void *) start, end - start, PROT_READ | PROT_WRITE); +} + +void +_dl_static_init (struct link_map *l) +{ + struct link_map *rtld_map = l; + struct r_scope_elem **scope; + const ElfW(Sym) *ref = NULL; + lookup_t loadbase; + void (*f) (void *[]); + size_t i; + + loadbase = _dl_lookup_symbol_x ("_dl_var_init", l, &ref, l->l_local_scope, + NULL, 0, 1, NULL); + + for (scope = l->l_local_scope; *scope != NULL; scope++) + for (i = 0; i < (*scope)->r_nlist; i++) + if ((*scope)->r_list[i] == loadbase) + { + rtld_map = (*scope)->r_list[i]; + break; + } + + if (ref != NULL) + { + f = (void (*) (void *[])) DL_SYMBOL_ADDRESS (loadbase, ref); + _dl_unprotect_relro (rtld_map); + f (variables); + _dl_protect_relro (rtld_map); + } +} + +#endif diff --git a/sysdeps/unix/sysv/linux/nds32/ldconfig.h b/sysdeps/unix/sysv/linux/nds32/ldconfig.h new file mode 100644 index 0000000..51e567e --- /dev/null +++ b/sysdeps/unix/sysv/linux/nds32/ldconfig.h @@ -0,0 +1,27 @@ +/* ldconfig default paths and libraries, Andes Linux/nds32 version. + Copyright (C) 2018-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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 + . */ + +#include + + +#define SYSDEP_KNOWN_INTERPRETER_NAMES \ + { "/lib/ld-linux-nds32le.so.1", FLAG_ELF_LIBC6 } + +#define SYSDEP_KNOWN_LIBRARY_NAMES \ + { "libc.so.6", FLAG_ELF_LIBC6 }, \ + { "libm.so.6", FLAG_ELF_LIBC6 }, diff --git a/sysdeps/unix/sysv/linux/nds32/ldsodefs.h b/sysdeps/unix/sysv/linux/nds32/ldsodefs.h new file mode 100644 index 0000000..435e0e3 --- /dev/null +++ b/sysdeps/unix/sysv/linux/nds32/ldsodefs.h @@ -0,0 +1,33 @@ +/* Andes nds32 dynamic linker data structures for loaded ELF shared objects. + Copyright (C) 2018-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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 + . */ + +#ifndef _LDSODEFS_H + + +/* Get the real definitions. */ +#include_next + +/* Now define our stuff. */ + +/* We need special support to initialize DSO loaded for statically linked + binaries. */ +extern void _dl_static_init (struct link_map *map); +#undef DL_STATIC_INIT +#define DL_STATIC_INIT(map) _dl_static_init (map) + +#endif /* _LDSODEFS_H */