This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH v4 04/11] nds32: Startup and Dynamic Loader
- From: Vincent Chen <vincentc at andestech dot com>
- To: <libc-alpha at sourceware dot org>, <joseph at codesourcery dot com>
- Cc: <deanbo422 at gmail dot com>, <cnoize at andestech dot com>, <vincentc at andestech dot com>
- Date: Wed, 5 Jun 2019 19:56:48 +0800
- Subject: [PATCH v4 04/11] nds32: Startup and Dynamic Loader
- References: <1559735815-20093-1-git-send-email-vincentc@andestech.com>
This patch contains crti.S, crtn.S and the dynamic loader
for nds32 system.
2019-06-03 Vincent Chen <vincentc@andestech.com>
2019-06-03 CheWei Chuang <cnoize@andestech.com>
* 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 | 405 ++++++++++++++++++++++++++++++
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 | 32 +++
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..21ba52a
--- /dev/null
+++ b/sysdeps/nds32/dl-machine.h
@@ -0,0 +1,405 @@
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef dl_machine_h
+#define dl_machine_h
+
+#define ELF_MACHINE_NAME "NDS32"
+
+#include <tls.h>
+#include <dl-tlsdesc.h>
+#include <ldsodefs.h>
+
+/* 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)
+{
+
+ if (l->l_info[DT_JMPREL] && lazy)
+ {
+ ElfW(Addr) *got;
+ extern void _dl_runtime_resolve (ElfW(Word)) attribute_hidden;
+ extern void _dl_runtime_profile (ElfW(Word)) attribute_hidden;
+ /* 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 /* Args to skip. */ \n\
+ bnez $r2, 2f \n\
+ /* Prepare args to call _dl_init. */ \n\
+ addi $r2, $sp, 4 /* argv. */ \n\
+1: \n\
+ l.w $r0, _rtld_local@GOTOFF \n\
+ lwi $r1, [$sp+0] /* argc. */ \n\
+ /* envp =sp +argc * 4 + 8. */ \n\
+ slli $r3, $r1, 2 \n\
+ addi $r3, $r3, 8 \n\
+ add $r3, $r3, $sp /* envp. */ \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] /* Original argc. */ \n\
+ /* Offset for new $sp. */ \n\
+ slli $r1, $r2, 2 \n\
+ /* Adjust sp to skip args. */ \n\
+ add $sp, $sp, $r1 \n\
+ sub $r0, $r0, $r2 /* Set new argc. */ \n\
+ swi $r0, [$sp+0] /* Save new argc. */ \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 /* Args to skip. */ \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)
+{
+ if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
+ /* Avoid an empty string which would disturb us. */
+ 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 ?: "<program name unknown>",
+ 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:
+ /* These addresses are always aligned. */
+ *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
+ {
+ 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
+# endif
+ {
+ 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
+ /* This is defined in rtld.c, but nowhere in the static libc.a;
+ make the reference weak so static programs can still link.
+ This declaration cannot be done when compiling rtld.c
+ (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
+ common defn for _dl_rtld_map, which is incompatible with a
+ weak decl in the same file. */
+# ifndef SHARED
+ weak_extern (_dl_rtld_map);
+# endif
+ if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
+# 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) {
+ }
+ else
+ _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
+ <http://www.gnu.org/licenses/>. */
+
+#include_next <dl-sysdep.h>
+
+#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..3b7a4ea
--- /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
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+#include <libc-symbols.h>
+
+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
+ <http://www.gnu.org/licenses/>. */
+
+
+#ifndef _NDS32_LDSODEFS_H
+#define _NDS32_LDSODEFS_H 1
+
+#include <elf.h>
+
+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 <ldsodefs.h>
+
+#endif /* _NDS32_LDSODEFS_H. */
diff --git a/sysdeps/nds32/start.S b/sysdeps/nds32/start.S
new file mode 100644
index 0000000..4b8cae6
--- /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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 <sysdep.h>
+ .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
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <ldsodefs.h>
+
+#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..cef84ec
--- /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
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdeps/generic/ldconfig.h>
+
+
+#define SYSDEP_KNOWN_INTERPRETER_NAMES \
+ { "ld-linux-nds32.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..01d6d77
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/nds32/ldsodefs.h
@@ -0,0 +1,32 @@
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LDSODEFS_H
+
+/* Get the real definitions. */
+#include_next <ldsodefs.h>
+
+/* 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. */
--
1.9.5