diff --git a/bfd/config.bfd b/bfd/config.bfd index a4c6c8e885..9edd7a0a15 100644 --- a/bfd/config.bfd +++ b/bfd/config.bfd @@ -238,6 +238,11 @@ esac case "${targ}" in # START OF targmatch.h #ifdef BFD64 + aarch64-*-solaris2*) + targ_defvec=aarch64_elf64_le_vec + targ_selvecs="aarch64_elf64_be_vec aarch64_elf32_le_vec aarch64_elf32_be_vec arm_elf32_le_vec arm_elf32_be_vec" + want64=true + ;; aarch64-*-darwin*) targ_defvec=aarch64_mach_o_vec targ_selvecs="arm_mach_o_vec mach_o_le_vec mach_o_be_vec mach_o_fat_vec" diff --git a/bfd/configure b/bfd/configure index 24531087d4..a0aed712a5 100755 --- a/bfd/configure +++ b/bfd/configure @@ -13757,6 +13757,9 @@ CORE_HEADER= TRAD_HEADER= if test "${target}" = "${host}"; then case "${host}" in + aarch64*-*-solaris*) + COREFILE='' + ;; alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu | alpha*-*-*vms*) COREFILE='' ;; @@ -13853,6 +13856,9 @@ if test "${target}" = "${host}"; then ns32k-*-netbsd* | ns32k-*-openbsd*) COREFILE=netbsd-core.lo ;; + riscv64-*-solaris*) + COREFILE='' + ;; rs6000-*-lynx*) COREFILE=lynx-core.lo ;; diff --git a/bfd/configure.ac b/bfd/configure.ac index 6146efb5ae..2f701a7f51 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -801,6 +801,9 @@ CORE_HEADER= TRAD_HEADER= if test "${target}" = "${host}"; then case "${host}" in + aarch64*-*-solaris*) + COREFILE='' + ;; alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu | alpha*-*-*vms*) COREFILE='' ;; @@ -921,6 +924,9 @@ changequote([,])dnl ns32k-*-netbsd* | ns32k-*-openbsd*) COREFILE=netbsd-core.lo ;; + riscv64-*-solaris*) + COREFILE='' + ;; rs6000-*-lynx*) COREFILE=lynx-core.lo ;; diff --git a/bfd/elflink.c b/bfd/elflink.c index 2b1450fa4e..5c51c67921 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -6954,6 +6954,11 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, for (n = t->deps; n != NULL; n = n->next) { + if (n->version_needed_name) { + info->callbacks->einfo(_("%Xversion `%s' is not found\n"), + n->version_needed_name); + } + BFD_ASSERT (n->version_needed_name == NULL); if (n->version_needed == NULL) { /* This can happen if there was an error in the @@ -7321,7 +7326,11 @@ NOTE: This behaviour is deprecated and will be removed in a future version of th if (!_bfd_elf_add_dynamic_entry (info, DT_FINI, 0)) return false; } - + if (info->rtldinfo) + { + if (!_bfd_elf_add_dynamic_entry (info, DT_SUNW_RTLDINF, 0)) + return false; + } s = bfd_get_section_by_name (output_bfd, ".preinit_array"); if (s != NULL && s->linker_has_input) { @@ -13182,7 +13191,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) relr_entsize = 0; } continue; - + case DT_SUNW_RTLDINF: + name = info->rtldinfo_name; + goto get_sym; case DT_INIT: name = info->init_function; goto get_sym; diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index 251a27edb5..827722e7ee 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -9989,6 +9989,59 @@ const struct elf_size_info elfNN_aarch64_size_info = bfd_elfNN_swap_reloca_out }; +static int +elfNN_aarch64_additional_program_headers (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + asection *s; + int count = 0; + + /* Check to see if we need a large readonly segment. */ + s = bfd_get_section_by_name (abfd, ".dtrace_data"); + if (s && (s->flags & SEC_LOAD)) + count++; + + return count; +} + +#define PT_SUNWDTRACE 0x6ffffffc +static bool +elfNN_aarch64_modify_segment_map (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + struct elf_segment_map *m; + asection *sec; + + sec = bfd_get_section_by_name (abfd, ".dtrace_data"); + if (sec != NULL && (sec->flags & SEC_LOAD) != 0) + { + m = elf_seg_map (abfd); + while (m && m->p_type != PT_SUNWDTRACE) + m = m->next; + + if (!m) + { + m = (struct elf_segment_map *) bfd_zalloc(abfd, sizeof (struct elf_segment_map)); + if (m == NULL) + return false; + m->p_type = PT_SUNWDTRACE; + m->count = 1; + m->sections[0] = sec; + m->next = elf_seg_map (abfd); + elf_seg_map (abfd) = m; + } + } + + return true; +} + +static const struct bfd_elf_special_section + elfNN_aarch64_special_sections[]= +{ + { STRING_COMMA_LEN (".dtrace_data"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_EXECINSTR}, + { NULL, 0, 0, 0, 0 } +}; + #define ELF_ARCH bfd_arch_aarch64 #define ELF_MACHINE_CODE EM_AARCH64 #define ELF_MAXPAGESIZE 0x10000 @@ -10104,6 +10157,15 @@ const struct elf_size_info elfNN_aarch64_size_info = #define elf_backend_merge_gnu_properties \ elfNN_aarch64_merge_gnu_properties +#define elf_backend_special_sections \ + elfNN_aarch64_special_sections + +#define elf_backend_modify_segment_map \ + elfNN_aarch64_modify_segment_map + +#define elf_backend_additional_program_headers \ + elfNN_aarch64_additional_program_headers + #define elf_backend_can_refcount 1 #define elf_backend_can_gc_sections 1 #define elf_backend_plt_readonly 1 diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 8f9f0d8a86..ec84f3e442 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -5169,9 +5169,16 @@ riscv_elf_additional_program_headers (bfd *abfd, if (bfd_get_section_by_name (abfd, RISCV_ATTRIBUTES_SECTION_NAME)) ++ret; + /* Check to see if we need a large readonly segment. */ + asection *s = bfd_get_section_by_name (abfd, ".dtrace_data"); + if (s && (s->flags & SEC_LOAD)) + ++ret; + return ret; } +#define PT_SUNWDTRACE 0x6ffffffc + static bool riscv_elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) @@ -5213,6 +5220,26 @@ riscv_elf_modify_segment_map (bfd *abfd, } } + asection *sec = bfd_get_section_by_name (abfd, ".dtrace_data"); + if (sec != NULL && (sec->flags & SEC_LOAD) != 0) + { + m = elf_seg_map (abfd); + while (m && m->p_type != PT_SUNWDTRACE) + m = m->next; + + if (!m) + { + m = (struct elf_segment_map *) bfd_zalloc(abfd, sizeof (struct elf_segment_map)); + if (m == NULL) + return false; + m->p_type = PT_SUNWDTRACE; + m->count = 1; + m->sections[0] = sec; + m->next = elf_seg_map (abfd); + elf_seg_map (abfd) = m; + } + } + return true; } @@ -5238,6 +5265,13 @@ riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, h->other |= STO_RISCV_VARIANT_CC; } +static const struct bfd_elf_special_section + riscv_elf_special_sections[]= +{ + { STRING_COMMA_LEN (".dtrace_data"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_EXECINSTR}, + { NULL, 0, 0, 0, 0 } +}; + #define TARGET_LITTLE_SYM riscv_elfNN_vec #define TARGET_LITTLE_NAME "elfNN-littleriscv" #define TARGET_BIG_SYM riscv_elfNN_be_vec @@ -5278,6 +5312,8 @@ riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, #define elf_backend_init_index_section _bfd_elf_init_1_index_section +#define elf_backend_special_sections riscv_elf_special_sections + #define elf_backend_can_gc_sections 1 #define elf_backend_can_refcount 1 #define elf_backend_want_got_plt 1 diff --git a/gas/configure.tgt b/gas/configure.tgt index 62f806bdfe..80e5a4d385 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -134,6 +134,7 @@ case ${generic_target} in aarch64*-linux-gnu_ilp32) arch=aarch64:32 ;; esac ;; aarch64*-*-netbsd*) fmt=elf em=nbsd;; + aarch64*-*-solaris*) fmt=elf em=solaris ;; alpha-*-*vms*) fmt=evax ;; alpha-*-osf*) fmt=ecoff ;; @@ -369,6 +370,7 @@ case ${generic_target} in pru-*-*) fmt=elf ;; + riscv64-*-solaris*) fmt=elf endian=little em=solaris ;; riscv*-*-haiku*) fmt=elf endian=little em=haiku ;; riscv*-*-*) fmt=elf ;; diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c index 961a3b9218..46d9212d38 100644 --- a/gas/dw2gencfi.c +++ b/gas/dw2gencfi.c @@ -257,7 +257,7 @@ get_debugseg_name (segT seg, const char *base_name) else name = dollar; - return concat (base_name, name, NULL); + return concat (base_name, name, (void *)0); } /* Allocate a dwcfi_seg_list structure. */ diff --git a/gdb/aarch64-sol2-nat.c b/gdb/aarch64-sol2-nat.c new file mode 100644 index 0000000000..527958d819 --- /dev/null +++ b/gdb/aarch64-sol2-nat.c @@ -0,0 +1,53 @@ +/* Native-dependent code for Solaris SPARC. + + Copyright (C) 2003-2014 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "regcache.h" + +#include +#include "gregset.h" + +#include "aarch64-tdep.h" +#include "aarch64-sol2-tdep.h" +#include "target.h" +#include "procfs.h" + +void +supply_gregset (struct regcache *regcache, const prgregset_t *gregs) +{ + regcache_supply_regset (&aarch64_sol2_gregset, regcache, -1, (const gdb_byte *) gregs, AARCH64_SOL2_SIZEOF_GREGSET); +} + +void +supply_fpregset (struct regcache *regcache, const prfpregset_t *fpregs) +{ + regcache_supply_regset (&aarch64_sol2_fpregset, regcache, -1, (const gdb_byte *) fpregs, AARCH64_SOL2_SIZEOF_FPREGSET); +} + +void +fill_gregset (const struct regcache *regcache, prgregset_t *gregs, int regnum) +{ + regcache_collect_regset (&aarch64_sol2_gregset, regcache, regnum, (gdb_byte *) gregs, AARCH64_SOL2_SIZEOF_GREGSET); +} + +void +fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs, int regnum) +{ + regcache_collect_regset (&aarch64_sol2_fpregset, regcache, regnum, (gdb_byte *) fpregs, AARCH64_SOL2_SIZEOF_FPREGSET); +} diff --git a/gdb/aarch64-sol2-tdep.c b/gdb/aarch64-sol2-tdep.c new file mode 100644 index 0000000000..7918e51f8d --- /dev/null +++ b/gdb/aarch64-sol2-tdep.c @@ -0,0 +1,253 @@ +/* Target-dependent code for Newlib AArch64. + + Copyright (C) 2011-2014 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "frame.h" +#include "frame-unwind.h" +#include "gdbarch.h" +#include "aarch64-tdep.h" +#include "aarch64-sol2-tdep.h" +#include "osabi.h" +#include "inferior.h" +#include "regcache.h" +#include "regset.h" +#include "solib-svr4.h" +#include "trad-frame.h" +#include "sol2-tdep.h" +#include "stap-probe.h" +#include "parser-defs.h" +#include "user-regs.h" +#include + +/* Register maps. */ + +static const struct regcache_map_entry aarch64_sol2_gregmap[] = + { + { 31, AARCH64_X0_REGNUM, 8 }, /* x0 ... x30 */ + { 1, AARCH64_SP_REGNUM, 8 }, + { 1, AARCH64_PC_REGNUM, 8 }, + { 1, AARCH64_CPSR_REGNUM, 8 }, + { 0 } + }; + +static const struct regcache_map_entry aarch64_sol2_fpregmap[] = + { + { 32, AARCH64_V0_REGNUM, 16 }, /* v0 ... v31 */ + { 1, AARCH64_FPCR_REGNUM, 4 }, + { 1, AARCH64_FPSR_REGNUM, 4 }, + { 0 } + }; + +/* Register set definitions. */ + +const struct regset aarch64_sol2_gregset = + { + aarch64_sol2_gregmap, + regcache_supply_regset, regcache_collect_regset + }; + +const struct regset aarch64_sol2_fpregset = + { + aarch64_sol2_fpregmap, + regcache_supply_regset, regcache_collect_regset + }; + +/* Implement the "regset_from_core_section" gdbarch method. */ + +static void +aarch64_sol2_iterate_over_regset_sections (struct gdbarch *gdbarch, + iterate_over_regset_sections_cb *cb, + void *cb_data, + const struct regcache *regcache) +{ + cb (".reg", AARCH64_SOL2_SIZEOF_GREGSET, AARCH64_SOL2_SIZEOF_GREGSET, &aarch64_sol2_gregset, + NULL, cb_data); + cb (".reg2", AARCH64_SOL2_SIZEOF_FPREGSET, AARCH64_SOL2_SIZEOF_FPREGSET, &aarch64_sol2_fpregset, + NULL, cb_data); +} + + +struct aarch64_frame_cache +{ + /* Base address. */ + CORE_ADDR base; + CORE_ADDR pc; + + /* Do we have a frame? */ + int frameless_p; + + /* The offset from the base register to the CFA. */ + int frame_offset; + + /* Mask of `local' and `in' registers saved in the register save area. */ + unsigned short int saved_regs_mask; + + /* Mask of `out' registers copied or renamed to their `in' sibling. */ + unsigned char copied_regs_mask; + + /* Do we have a Structure, Union or Quad-Precision return value? */ + int struct_return_p; + + /* Table of saved registers. */ + struct trad_frame_saved_reg *saved_regs; +}; + +static CORE_ADDR +aarch64_sol2_mcontext_addr (struct frame_info *this_frame) +{ + CORE_ADDR ucontext_addr; + + ucontext_addr = get_frame_register_unsigned (this_frame, AARCH64_X0_REGNUM + 2); + return ucontext_addr + 8 * 7; +} + +static struct aarch64_frame_cache * +aarch64_alloc_frame_cache (void) +{ + struct aarch64_frame_cache *cache; + + cache = FRAME_OBSTACK_ZALLOC (struct aarch64_frame_cache); + + /* Base address. */ + cache->base = 0; + cache->pc = 0; + + /* Frameless until proven otherwise. */ + cache->frameless_p = 1; + cache->frame_offset = 0; + cache->saved_regs_mask = 0; + cache->copied_regs_mask = 0; + cache->struct_return_p = 0; + + return cache; +} + +static struct aarch64_frame_cache * +aarch64_sol2_sigtramp_frame_cache (struct frame_info *this_frame, + void **this_cache) +{ + struct aarch64_frame_cache *cache; + CORE_ADDR mcontext_addr; + int regnum; + + if (*this_cache) + return (aarch64_frame_cache*)*this_cache; + + cache = aarch64_alloc_frame_cache (); + *this_cache = cache; + + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); + + mcontext_addr = aarch64_sol2_mcontext_addr (this_frame); + + for (regnum = 0; regnum < 31; regnum++) + cache->saved_regs[regnum].set_addr(mcontext_addr + regnum * 8); + cache->saved_regs[AARCH64_SP_REGNUM].set_addr(mcontext_addr + 31 * 8); // sp + cache->saved_regs[AARCH64_PC_REGNUM].set_addr(mcontext_addr + 32 * 8); // pc + cache->saved_regs[AARCH64_CPSR_REGNUM].set_addr(mcontext_addr + 33 * 8); // cpsr + + for (regnum = 0; regnum < 32; regnum++) + cache->saved_regs[regnum + AARCH64_V0_REGNUM].set_addr(mcontext_addr + 36 * 8 + regnum * 16); + + cache->saved_regs[AARCH64_FPCR_REGNUM].set_addr(mcontext_addr + 36 * 8 + 32 * 16); + cache->saved_regs[AARCH64_FPSR_REGNUM].set_addr(mcontext_addr + 36 * 8 + 32 * 16 + 4); + + return cache; +} + +static void +aarch64_sol2_sigtramp_frame_this_id (struct frame_info *this_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct aarch64_frame_cache *cache = + aarch64_sol2_sigtramp_frame_cache (this_frame, this_cache); + + (*this_id) = frame_id_build (cache->base, cache->pc); +} + +static struct value * +aarch64_sol2_sigtramp_frame_prev_register (struct frame_info *this_frame, + void **this_cache, + int regnum) +{ + struct aarch64_frame_cache *cache = + aarch64_sol2_sigtramp_frame_cache (this_frame, this_cache); + + struct value *ret = trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum); + return ret; +} + +static int +aarch64_sol2_sigtramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_cache) +{ + CORE_ADDR pc = get_frame_pc (this_frame); + const char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + return (name && (strcmp ("sigacthandler", name) == 0 || strcmp (name, "ucbsigvechandler") == 0)); +} + + +static const struct frame_unwind aarch64_sol2_sigtramp_frame_unwind = +{ + "aarch64 solaris sigtramp", + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + aarch64_sol2_sigtramp_frame_this_id, + aarch64_sol2_sigtramp_frame_prev_register, + NULL, + aarch64_sol2_sigtramp_frame_sniffer +}; + + +/* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ + +static void +aarch64_sol2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch); + + tdep->lowest_pc = 0x8000; + tdep->jb_pc = 11; + + frame_unwind_append_unwinder (gdbarch, &aarch64_sol2_sigtramp_frame_unwind); + sol2_init_abi (info, gdbarch); + + /* Solaris has SVR4-style shared libraries... */ + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); + set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets); + + /* Solaris has kernel-assisted single-stepping support. */ + /* Breakpoint manipulation. */ + set_gdbarch_software_single_step (gdbarch, NULL); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_aarch64_sol2_tdep; + +void +_initialize_aarch64_sol2_tdep (void) +{ + gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_SOLARIS, + aarch64_sol2_init_abi); +} diff --git a/gdb/aarch64-sol2-tdep.h b/gdb/aarch64-sol2-tdep.h new file mode 100644 index 0000000000..3592030fc6 --- /dev/null +++ b/gdb/aarch64-sol2-tdep.h @@ -0,0 +1,31 @@ +/* GNU/Linux on AArch64 target support, prototypes. + + Copyright (C) 2012-2014 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "regset.h" + +/* X0 - X31, SP, PC, PSR, TP */ +#define AARCH64_SOL2_SIZEOF_GREGSET (36 * X_REGISTER_SIZE) + +/* V0 - V31, FPCR, FPSR */ +#define AARCH64_SOL2_SIZEOF_FPREGSET (33 * V_REGISTER_SIZE) + +extern const struct regset aarch64_sol2_gregset; +extern const struct regset aarch64_sol2_fpregset; + diff --git a/gdb/config/aarch64/nm-sol2.h b/gdb/config/aarch64/nm-sol2.h new file mode 100644 index 0000000000..bee367004e --- /dev/null +++ b/gdb/config/aarch64/nm-sol2.h @@ -0,0 +1,26 @@ +/* Native-dependent definitions for Solaris AArch64. + + Copyright (C) 2003-2014 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef NM_SOL2_H +#define NM_SOL2_H + +#define GDB_GREGSET_T prgregset_t +#define GDB_FPREGSET_T prfpregset_t + +#endif /* nm-sol2.h */ diff --git a/gdb/config/riscv64/nm-sol2.h b/gdb/config/riscv64/nm-sol2.h new file mode 100644 index 0000000000..90c663de94 --- /dev/null +++ b/gdb/config/riscv64/nm-sol2.h @@ -0,0 +1,26 @@ +/* Native-dependent definitions for Solaris RISC-V. + + Copyright (C) 2003-2014 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef NM_SOL2_H +#define NM_SOL2_H + +#define GDB_GREGSET_T prgregset_t +#define GDB_FPREGSET_T prfpregset_t + +#endif /* nm-sol2.h */ diff --git a/gdb/configure.host b/gdb/configure.host index da71675b20..e98f88092f 100644 --- a/gdb/configure.host +++ b/gdb/configure.host @@ -81,6 +81,7 @@ case "${host}" in aarch64*-*-linux*) gdb_host=linux ;; aarch64*-*-freebsd*) gdb_host=fbsd ;; +aarch64*-*-solaris2.1[0-9]*) gdb_host=sol2 ;; alpha*-*-linux*) gdb_host=alpha-linux ;; alpha*-*-netbsdaout* | alpha*-*-knetbsdaout*-gnu) @@ -147,6 +148,7 @@ powerpc*-*-linux*) gdb_host=linux ;; riscv*-*-freebsd*) gdb_host=fbsd ;; riscv*-*-linux*) gdb_host=linux ;; +riscv*-*-solaris2.1[0-9]*) gdb_host=sol2 ;; s390*-*-linux*) gdb_host=linux ;; diff --git a/gdb/configure.nat b/gdb/configure.nat index d219d6a960..1177f3ad06 100644 --- a/gdb/configure.nat +++ b/gdb/configure.nat @@ -498,6 +498,16 @@ case ${gdb_host} in NAT_FILE='nm-sol2.h' NATDEPFILES="${NATDEPFILES} sparc-sol2-nat.o" ;; + aarch64) + # Host: Solaris AArch64 + NAT_FILE='nm-sol2.h' + NATDEPFILES="${NATDEPFILES} aarch64-sol2-nat.o" + ;; + riscv*) + # Host: Solaris RISC-V + NAT_FILE='nm-sol2.h' + NATDEPFILES="${NATDEPFILES} riscv-sol2-nat.o" + ;; esac ;; esac diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 0705ccf32b..ee59691912 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -144,6 +144,12 @@ aarch64*-*-linux*) symfile-mem.o linux-record.o" ;; +aarch64*-*-solaris2.1[0-9]*) + # Target: AArch64 Solaris + gdb_target_obs="aarch64-tdep.o aarch64-sol2-tdep.o arch/aarch64-insn.o arch/aarch64.o \ + sol2-tdep.o solib-svr4.o ravenscar-thread.o aarch64-ravenscar-thread.o" + ;; + alpha*-*-linux*) # Target: Little-endian Alpha running Linux gdb_target_obs="alpha-mdebug-tdep.o alpha-linux-tdep.o \ @@ -535,6 +541,12 @@ riscv*-*-linux*) linux-tdep.o solib-svr4.o symfile-mem.o linux-record.o" ;; +riscv*-*-solaris2.1[0-9]*) + # Target: RISC-V Solaris + gdb_target_obs="riscv-sol2-tdep.o \ + sol2-tdep.o solib-svr4.o" + ;; + riscv*-*-*) # Target: RISC-V architecture gdb_target_obs="" diff --git a/gdb/procfs.c b/gdb/procfs.c index ffb4d18029..b5bd8b24d6 100644 --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -2155,7 +2155,7 @@ procfs_target::wait (ptid_t ptid, struct target_waitstatus *status, } else { - int temp = ::wait (&wstat); + int temp = ::waitpid(pi->pid, &wstat, 0); /* FIXME: shouldn't I make sure I get the right event from the right process? If (for diff --git a/gdb/riscv-sol2-nat.c b/gdb/riscv-sol2-nat.c new file mode 100644 index 0000000000..bff150ee1f --- /dev/null +++ b/gdb/riscv-sol2-nat.c @@ -0,0 +1,57 @@ +/* Native-dependent code for Solaris SPARC. + + Copyright (C) 2003-2014 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "regcache.h" + +#include +#include "gregset.h" + +#include "riscv-tdep.h" +#include "riscv-sol2-tdep.h" +#include "target.h" +#include "procfs.h" + +void +supply_gregset (struct regcache *regcache, const prgregset_t *gregs) +{ + int xlen = register_size (regcache->arch(), RISCV_RA_REGNUM); + regcache_supply_regset (&riscv_sol2_gregset, regcache, -1, (const gdb_byte *) gregs, xlen * 32); +} + +void +supply_fpregset (struct regcache *regcache, const prfpregset_t *fpregs) +{ + int flen = register_size (regcache->arch(), RISCV_FIRST_FP_REGNUM); + regcache_supply_regset (&riscv_sol2_fpregset, regcache, -1, (const gdb_byte *) fpregs, flen * 32 + 8); +} + +void +fill_gregset (const struct regcache *regcache, prgregset_t *gregs, int regnum) +{ + int xlen = register_size (regcache->arch(), RISCV_RA_REGNUM); + regcache_collect_regset (&riscv_sol2_gregset, regcache, regnum, (gdb_byte *) gregs, xlen * 32); +} + +void +fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs, int regnum) +{ + int flen = register_size (regcache->arch(), RISCV_FIRST_FP_REGNUM); + regcache_collect_regset (&riscv_sol2_fpregset, regcache, regnum, (gdb_byte *) fpregs, flen * 32 + 8); +} diff --git a/gdb/riscv-sol2-tdep.c b/gdb/riscv-sol2-tdep.c new file mode 100644 index 0000000000..e827d743a0 --- /dev/null +++ b/gdb/riscv-sol2-tdep.c @@ -0,0 +1,248 @@ +/* Target-dependent code for Newlib AArch64. + + Copyright (C) 2011-2014 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "frame.h" +#include "frame-unwind.h" +#include "gdbarch.h" +#include "riscv-tdep.h" +#include "riscv-sol2-tdep.h" +#include "osabi.h" +#include "inferior.h" +#include "regcache.h" +#include "regset.h" +#include "solib-svr4.h" +#include "trad-frame.h" +#include "sol2-tdep.h" +#include "stap-probe.h" +#include "parser-defs.h" +#include "user-regs.h" +#include + +/* Register maps. */ + +static const struct regcache_map_entry riscv_sol2_gregmap[] = + { + { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */ + { 1, RISCV_PC_REGNUM, 0 }, + { 0 } +}; + +static const struct regcache_map_entry riscv_sol2_fpregmap[] = + { + { 32, RISCV_FIRST_FP_REGNUM, 0 }, + { 1, RISCV_CSR_FCSR_REGNUM, 0 }, + { 0 } +}; + +/* Register set definitions. */ + +const struct regset riscv_sol2_gregset = + { + riscv_sol2_gregmap, regcache_supply_regset, regcache_collect_regset + }; + +const struct regset riscv_sol2_fpregset = + { + riscv_sol2_fpregmap, + regcache_supply_regset, regcache_collect_regset + }; + +/* Implement the "regset_from_core_section" gdbarch method. */ + +static void +riscv_sol2_iterate_over_regset_sections (struct gdbarch *gdbarch, + iterate_over_regset_sections_cb *cb, + void *cb_data, + const struct regcache *regcache) +{ + cb (".reg", (32 * riscv_isa_xlen (gdbarch)), (32 * riscv_isa_xlen (gdbarch)), + &riscv_sol2_gregset, NULL, cb_data); + cb (".reg2", (32 * riscv_isa_flen (gdbarch)) + 8, + (32 * riscv_isa_flen (gdbarch)) + 8, + &riscv_sol2_fpregset, NULL, cb_data); +} + + +struct riscv_frame_cache +{ + /* Base address. */ + CORE_ADDR base; + CORE_ADDR pc; + + /* Do we have a frame? */ + int frameless_p; + + /* The offset from the base register to the CFA. */ + int frame_offset; + + /* Mask of `local' and `in' registers saved in the register save area. */ + unsigned short int saved_regs_mask; + + /* Mask of `out' registers copied or renamed to their `in' sibling. */ + unsigned char copied_regs_mask; + + /* Do we have a Structure, Union or Quad-Precision return value? */ + int struct_return_p; + + /* Table of saved registers. */ + struct trad_frame_saved_reg *saved_regs; +}; + +static CORE_ADDR +riscv_sol2_mcontext_addr (struct frame_info *this_frame) +{ + CORE_ADDR ucontext_addr; + + ucontext_addr = get_frame_register_unsigned (this_frame, RISCV_A0_REGNUM + 2); + return ucontext_addr + 8 * 7; +} + +static struct riscv_frame_cache * +riscv_alloc_frame_cache (void) +{ + struct riscv_frame_cache *cache; + + cache = FRAME_OBSTACK_ZALLOC (struct riscv_frame_cache); + + /* Base address. */ + cache->base = 0; + cache->pc = 0; + + /* Frameless until proven otherwise. */ + cache->frameless_p = 1; + cache->frame_offset = 0; + cache->saved_regs_mask = 0; + cache->copied_regs_mask = 0; + cache->struct_return_p = 0; + + return cache; +} + +static struct riscv_frame_cache * +riscv_sol2_sigtramp_frame_cache (struct frame_info *this_frame, + void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct riscv_frame_cache *cache; + CORE_ADDR mcontext_addr; + int regnum; + int xlen = riscv_isa_xlen (gdbarch); + int flen = riscv_isa_flen (gdbarch); + + if (*this_cache) + return (riscv_frame_cache*)*this_cache; + + cache = riscv_alloc_frame_cache (); + *this_cache = cache; + + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); + + mcontext_addr = riscv_sol2_mcontext_addr (this_frame); + + for (regnum = 0; regnum < 31; regnum++) + cache->saved_regs[regnum].set_addr(mcontext_addr + regnum * xlen); + cache->saved_regs[RISCV_PC_REGNUM].set_addr(mcontext_addr + 31 * xlen); // pc + + for (regnum = 0; regnum < 32; regnum++) + cache->saved_regs[regnum + RISCV_FIRST_FP_REGNUM].set_addr(mcontext_addr + 32 * xlen + regnum * flen); + + cache->saved_regs[RISCV_CSR_FCSR_REGNUM].set_addr(mcontext_addr + 32 * xlen + 32 * flen); + + return cache; +} + +static void +riscv_sol2_sigtramp_frame_this_id (struct frame_info *this_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct riscv_frame_cache *cache = + riscv_sol2_sigtramp_frame_cache (this_frame, this_cache); + + (*this_id) = frame_id_build (cache->base, cache->pc); +} + +static struct value * +riscv_sol2_sigtramp_frame_prev_register (struct frame_info *this_frame, + void **this_cache, + int regnum) +{ + struct riscv_frame_cache *cache = + riscv_sol2_sigtramp_frame_cache (this_frame, this_cache); + + struct value *ret = trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum); + return ret; +} + +static int +riscv_sol2_sigtramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_cache) +{ + CORE_ADDR pc = get_frame_pc (this_frame); + const char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + return (name && (strcmp ("sigacthandler", name) == 0 || strcmp (name, "ucbsigvechandler") == 0)); +} + + +static const struct frame_unwind riscv_sol2_sigtramp_frame_unwind = +{ + "riscv solaris sigtramp", + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + riscv_sol2_sigtramp_frame_this_id, + riscv_sol2_sigtramp_frame_prev_register, + NULL, + riscv_sol2_sigtramp_frame_sniffer +}; + + +/* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ + +static void +riscv_sol2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + frame_unwind_append_unwinder (gdbarch, &riscv_sol2_sigtramp_frame_unwind); + sol2_init_abi (info, gdbarch); + + /* Solaris has SVR4-style shared libraries... */ + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); + set_solib_svr4_fetch_link_map_offsets (gdbarch, + (riscv_isa_xlen (gdbarch) == 4 + ? svr4_ilp32_fetch_link_map_offsets + : svr4_lp64_fetch_link_map_offsets)); + + set_gdbarch_software_single_step (gdbarch, riscv_software_single_step); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_riscv_sol2_tdep; + +void +_initialize_riscv_sol2_tdep (void) +{ + gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_SOLARIS, + riscv_sol2_init_abi); +} diff --git a/gdb/riscv-sol2-tdep.h b/gdb/riscv-sol2-tdep.h new file mode 100644 index 0000000000..6900818df2 --- /dev/null +++ b/gdb/riscv-sol2-tdep.h @@ -0,0 +1,25 @@ +/* GNU/Linux on AArch64 target support, prototypes. + + Copyright (C) 2012-2014 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "regset.h" + +extern const struct regset riscv_sol2_gregset; +extern const struct regset riscv_sol2_fpregset; + diff --git a/gnulib/import/string.in.h b/gnulib/import/string.in.h index 33160b2525..6eafdf0b36 100644 --- a/gnulib/import/string.in.h +++ b/gnulib/import/string.in.h @@ -127,6 +127,8 @@ _GL_EXTERN_C void __cdecl free (void *); # else # if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) _GL_EXTERN_C void free (void *) throw (); +# elif defined __cplusplus && defined __sun__ && defined __GNUC__ +_GL_EXTERN_C void std::free (void *); # else _GL_EXTERN_C void free (void *); # endif @@ -138,6 +140,8 @@ _GL_EXTERN_C void __cdecl free (void *); # else # if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) _GL_EXTERN_C void free (void *) throw (); +# elif defined __cplusplus && defined __sun__ && defined __GNUC__ +_GL_EXTERN_C void std::free (void *); # else _GL_EXTERN_C void free (void *); # endif diff --git a/gnulib/import/wchar.in.h b/gnulib/import/wchar.in.h index 0d5c0b7abe..b19d917da1 100644 --- a/gnulib/import/wchar.in.h +++ b/gnulib/import/wchar.in.h @@ -190,6 +190,8 @@ _GL_EXTERN_C void __cdecl free (void *); # else # if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) _GL_EXTERN_C void free (void *) throw (); +# elif defined __cplusplus && defined __sun__ && defined __GNUC__ +_GL_EXTERN_C void std::free (void *); # else _GL_EXTERN_C void free (void *); # endif @@ -201,6 +203,8 @@ _GL_EXTERN_C void __cdecl free (void *); # else # if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) _GL_EXTERN_C void free (void *) throw (); +# elif defined __cplusplus && defined __sun__ && defined __GNUC__ +_GL_EXTERN_C void std::free (void *); # else _GL_EXTERN_C void free (void *); # endif diff --git a/include/bfdlink.h b/include/bfdlink.h index 09a3ec0168..c6e7465f90 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -554,6 +554,10 @@ struct bfd_link_info /* TRUE if commonpagesize is set on command-line. */ unsigned int commonpagesize_is_set : 1; + unsigned int rtldinfo: 1; + + char *rtldinfo_name; + /* Char that may appear as the first char of a symbol, but should be skipped (like symbol_leading_char) when looking up symbols in wrap_hash. Used by PowerPC Linux for 'dot' symbols. */ @@ -1038,6 +1042,7 @@ struct bfd_elf_version_deps struct bfd_elf_version_deps *next; /* The version which this version depends upon. */ struct bfd_elf_version_tree *version_needed; + const char *version_needed_name; }; /* A node in the version tree. */ diff --git a/include/elf/common.h b/include/elf/common.h index e4bc53e35b..8b57a949c6 100644 --- a/include/elf/common.h +++ b/include/elf/common.h @@ -1176,6 +1176,8 @@ #define DT_VERNEED 0x6ffffffe #define DT_VERNEEDNUM 0x6fffffff +#define DT_SUNW_RTLDINF 0x6000000e + /* This tag is a GNU extension to the Solaris version scheme. */ #define DT_VERSYM 0x6ffffff0 diff --git a/ld/configure.tgt b/ld/configure.tgt index 2bae9099b6..3d97c056e1 100644 --- a/ld/configure.tgt +++ b/ld/configure.tgt @@ -80,6 +80,8 @@ fi # Please try to keep this table more or less in alphabetic order - it # makes it much easier to lookup a specific archictecture. case "${targ}" in +aarch64-*-solaris2*) targ_emul=aarch64elf + targ_extra_emuls="aarch64elf32 aarch64elf32b aarch64elfb armelf armelfb" ;; aarch64_be-*-elf) targ_emul=aarch64elfb targ_extra_emuls="aarch64elf aarch64elf32 aarch64elf32b armelfb armelf" ;; @@ -811,6 +813,7 @@ riscv64be*-*-linux*) targ_emul=elf64briscv targ_extra_emuls="elf64briscv_lp64f elf64briscv_lp64 elf32briscv elf32briscv_ilp32f elf32briscv_ilp32 elf64lriscv elf64lriscv_lp64f elf64lriscv_lp64 elf32lriscv elf32lriscv_ilp32f elf32lriscv_ilp32" targ_extra_libpath=$targ_extra_emuls ;; +riscv64-*-solaris2*) targ_emul=elf64lriscv ;; riscv64*-*-linux*) targ_emul=elf64lriscv targ_extra_emuls="elf64lriscv_lp64f elf64lriscv_lp64 elf32lriscv elf32lriscv_ilp32f elf32lriscv_ilp32 elf64briscv elf64briscv_lp64f elf64briscv_lp64 elf32briscv elf32briscv_ilp32f elf32briscv_ilp32" targ_extra_libpath=$targ_extra_emuls diff --git a/ld/emulparams/aarch64elf.sh b/ld/emulparams/aarch64elf.sh index 8f68e517b4..92e5d1acda 100644 --- a/ld/emulparams/aarch64elf.sh +++ b/ld/emulparams/aarch64elf.sh @@ -12,16 +12,19 @@ NO_REL_RELOCS=yes TEMPLATE_NAME=elf EXTRA_EM_FILE=aarch64elf +# SEPARATE_CODE=yes + GENERATE_SHLIB_SCRIPT=yes GENERATE_PIE_SCRIPT=yes MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" +COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" ENTRY=_start EMBEDDED=yes SEPARATE_GOTPLT=24 IREL_IN_PLT= -TEXT_START_ADDR=0x00400000 +TEXT_START_ADDR="0x00400000 + SIZEOF_HEADERS" DATA_START_SYMBOLS="${CREATE_SHLIB+PROVIDE (}__data_start = .${CREATE_SHLIB+)};" @@ -34,6 +37,7 @@ OTHER_END_SYMBOLS="${CREATE_SHLIB+PROVIDE (}__end__ = .${CREATE_SHLIB+)};" OTHER_SECTIONS='.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }' ATTRS_SECTIONS='.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }' +PLT=".plt ${RELOCATING-0} : ALIGN(16) { *(.plt)${IREL_IN_PLT+ *(.iplt)} }" # This sets the stack to the top of the simulator memory (2^19 bytes). STACK_ADDR=0x80000 diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em index 1968f12cf2..097f967019 100644 --- a/ld/emultempl/aarch64elf.em +++ b/ld/emultempl/aarch64elf.em @@ -60,9 +60,92 @@ fragment <dynobj == NULL) + hash_table->dynobj = abfd; + + if (hash_table->dynstr == NULL) + { + hash_table->dynstr = _bfd_elf_strtab_init (); + if (hash_table->dynstr == NULL) + return false; + } + return true; +} + +static void +elf_add_dt_needed_tag (bfd *abfd, + struct bfd_link_info *info, + const char *soname, + bool do_it) +{ + struct elf_link_hash_table *hash_table; + bfd_size_type oldsize; + bfd_size_type strindex; + + if (!_bfd_elf_link_create_dynstrtab (abfd, info)) + return; + + hash_table = elf_hash_table (info); + oldsize = _bfd_elf_strtab_size (hash_table->dynstr); + strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, false); + if (strindex == (bfd_size_type) -1) + return; + + if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr)) + { + asection *sdyn; + const struct elf_backend_data *bed; + bfd_byte *extdyn; + + bed = get_elf_backend_data (hash_table->dynobj); + sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic"); + if (sdyn != NULL) + for (extdyn = sdyn->contents; + extdyn < sdyn->contents + sdyn->size; + extdyn += bed->s->sizeof_dyn) + { + Elf_Internal_Dyn dyn; + + bed->s->swap_dyn_in (hash_table->dynobj, extdyn, &dyn); + if (dyn.d_tag == DT_NEEDED + && dyn.d_un.d_val == strindex) + { + _bfd_elf_strtab_delref (hash_table->dynstr, strindex); + return; + } + } + } + + if (do_it) + { + if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info)) + return; + + if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex)) + return; + } + else + /* We were just checking for existence of the tag. */ + _bfd_elf_strtab_delref (hash_table->dynstr, strindex); + + return; +} static void aarch64_elf_before_allocation (void) { + struct bfd_link_needed_list *entry = force_needed_top; + while (entry) { + elf_add_dt_needed_tag (link_info.output_bfd, &link_info, entry->name, true); + entry = entry->next; + } /* We should be able to set the size of the interworking stub section. We can't do it until later if we have dynamic sections, though. */ if (! elf_hash_table (&link_info)->dynamic_sections_created) @@ -363,6 +446,7 @@ PARSE_AND_LIST_PROLOGUE=' #define OPTION_FIX_ERRATUM_835769 313 #define OPTION_FIX_ERRATUM_843419 314 #define OPTION_NO_APPLY_DYNAMIC_RELOCS 315 +#define OPTION_FORCE_ADD_NEEDED 316 ' PARSE_AND_LIST_SHORTOPTS=p @@ -376,6 +460,7 @@ PARSE_AND_LIST_LONGOPTS=' { "fix-cortex-a53-835769", no_argument, NULL, OPTION_FIX_ERRATUM_835769}, { "fix-cortex-a53-843419", optional_argument, NULL, OPTION_FIX_ERRATUM_843419}, { "no-apply-dynamic-relocs", no_argument, NULL, OPTION_NO_APPLY_DYNAMIC_RELOCS}, + { "force-add-needed", required_argument, NULL, OPTION_FORCE_ADD_NEEDED }, ' PARSE_AND_LIST_OPTIONS=' @@ -408,6 +493,7 @@ PARSE_AND_LIST_OPTIONS=' fprintf (file, _(" --no-apply-dynamic-relocs Do not apply link-time values for dynamic relocations\n")); fprintf (file, _(" -z force-bti Turn on Branch Target Identification mechanism and generate PLTs with BTI. Generate warnings for missing BTI on inputs\n")); fprintf (file, _(" -z pac-plt Protect PLTs with Pointer Authentication.\n")); + fprintf (file, _(" --force-add-needed= Force add needed\n")); ' PARSE_AND_LIST_ARGS_CASE_Z_AARCH64=' @@ -462,6 +548,25 @@ PARSE_AND_LIST_ARGS_CASES=' no_apply_dynamic_relocs = 1; break; + case OPTION_FORCE_ADD_NEEDED: + { + struct bfd_link_needed_list *new_entry = xmalloc (sizeof (struct bfd_link_needed_list)); + if (new_entry) { + new_entry->name = strdup(optarg); + new_entry->by = 0; + new_entry->next = 0; + struct bfd_link_needed_list *entry = force_needed_top;; + if (entry) { + while (entry->next) + entry = entry->next; + entry->next = new_entry; + } else { + force_needed_top = new_entry; + } + } + } + break; + case OPTION_STUBGROUP_SIZE: { const char *end; diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em index c52484f35d..16712d434c 100644 --- a/ld/emultempl/elf.em +++ b/ld/emultempl/elf.em @@ -737,6 +737,11 @@ fragment <dynobj == NULL) + hash_table->dynobj = abfd; + + if (hash_table->dynstr == NULL) + { + hash_table->dynstr = _bfd_elf_strtab_init (); + if (hash_table->dynstr == NULL) + return false; + } + return true; +} + +static void +elf_add_dt_needed_tag (bfd *abfd, + struct bfd_link_info *info, + const char *soname, + bool do_it) +{ + struct elf_link_hash_table *hash_table; + bfd_size_type oldsize; + bfd_size_type strindex; + + if (!_bfd_elf_link_create_dynstrtab (abfd, info)) + return; + + hash_table = elf_hash_table (info); + oldsize = _bfd_elf_strtab_size (hash_table->dynstr); + strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, false); + if (strindex == (bfd_size_type) -1) + return; + + if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr)) + { + asection *sdyn; + const struct elf_backend_data *bed; + bfd_byte *extdyn; + + bed = get_elf_backend_data (hash_table->dynobj); + sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic"); + if (sdyn != NULL) + for (extdyn = sdyn->contents; + extdyn < sdyn->contents + sdyn->size; + extdyn += bed->s->sizeof_dyn) + { + Elf_Internal_Dyn dyn; + + bed->s->swap_dyn_in (hash_table->dynobj, extdyn, &dyn); + if (dyn.d_tag == DT_NEEDED + && dyn.d_un.d_val == strindex) + { + _bfd_elf_strtab_delref (hash_table->dynstr, strindex); + return; + } + } + } + + if (do_it) + { + if (!_bfd_elf_link_create_dynamic_sections (hash_table->dynobj, info)) + return; + + if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex)) + return; + } + else + /* We were just checking for existence of the tag. */ + _bfd_elf_strtab_delref (hash_table->dynstr, strindex); + + return; +} + static void riscv_elf_before_allocation (void) { + struct bfd_link_needed_list *entry = force_needed_top; + while (entry) { + elf_add_dt_needed_tag (link_info.output_bfd, &link_info, entry->name, true); + entry = entry->next; + } gld${EMULATION_NAME}_before_allocation (); if (link_info.discard == discard_sec_merge) @@ -100,6 +184,43 @@ riscv_create_output_section_statements (void) EOF +# Define some shell vars to insert bits of code into the standard elf +# parse_args and list_options functions. +# +PARSE_AND_LIST_PROLOGUE=' +#define OPTION_FORCE_ADD_NEEDED 300 +' + +PARSE_AND_LIST_LONGOPTS=' + { "force-add-needed", required_argument, NULL, OPTION_FORCE_ADD_NEEDED }, +' + +PARSE_AND_LIST_OPTIONS=' + fprintf (file, _("\ + --force-add-needed= Force add needed\n")); +' + +PARSE_AND_LIST_ARGS_CASES=' + case OPTION_FORCE_ADD_NEEDED: + { + struct bfd_link_needed_list *new_entry = xmalloc (sizeof (struct bfd_link_needed_list)); + if (new_entry) { + new_entry->name = strdup(optarg); + new_entry->by = 0; + new_entry->next = 0; + struct bfd_link_needed_list *entry = force_needed_top;; + if (entry) { + while (entry->next) + entry = entry->next; + entry->next = new_entry; + } else { + force_needed_top = new_entry; + } + } + } + break; +' + LDEMUL_BEFORE_ALLOCATION=riscv_elf_before_allocation LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=riscv_create_output_section_statements diff --git a/ld/ldgram.y b/ld/ldgram.y index 3a904e3948..ea11373de4 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -154,7 +154,7 @@ static int error_index; %token LOG2CEIL FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL %token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START %token VERS_TAG VERS_IDENTIFIER -%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT +%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT SYMBOL_VERSION SYMBOL_SCOPE %token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL INPUT_SECTION_FLAGS ALIGN_WITH_INPUT %token EXCLUDE_FILE %token CONSTANT @@ -1381,6 +1381,18 @@ vers_node: { lang_register_vers_node (NULL, $2, NULL); } + | SYMBOL_SCOPE '{' vers_tag '}' ';' + { + lang_register_vers_node (NULL, $3, NULL); + } + | SYMBOL_VERSION VERS_TAG '{' vers_tag '}' ';' + { + lang_register_vers_node ($2, $4, NULL); + } + | SYMBOL_VERSION VERS_TAG '{' vers_tag '}' verdep ';' + { + lang_register_vers_node ($2, $4, $6); + } | VERS_TAG '{' vers_tag '}' ';' { lang_register_vers_node ($1, $3, NULL); diff --git a/ld/ldlang.c b/ld/ldlang.c index f12c09633a..4e4261f9f3 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -9465,9 +9465,41 @@ lang_register_vers_node (const char *name, else version->vernum = 0; + int vernum = version->vernum; + for (t = link_info.version_info; t != NULL; t = t->next) { + struct bfd_elf_version_deps *ver_deps = t->deps; + while (ver_deps) { + if (ver_deps->version_needed_name && + strcmp (ver_deps->version_needed_name, name) == 0) { + ver_deps->version_needed = version; + free(ver_deps->version_needed_name); + ver_deps->version_needed_name = NULL; + if (t->vernum < vernum) + vernum = t->vernum; + } + ver_deps = ver_deps->next; + } + } + for (pp = &link_info.version_info; *pp != NULL; pp = &(*pp)->next) - ; + ; *pp = version; + + while (vernum != version->vernum) { + for (pp = &link_info.version_info; *pp != NULL; pp = &(*pp)->next) { + if ((*pp)->next == version) { + t = *pp; + int v = t->vernum; + t->vernum = version->vernum; + version->vernum = v; + + t->next = version->next; + version->next = t; + *pp = version; + break; + } + } + } } /* This is called when we see a version dependency. */ @@ -9480,6 +9512,7 @@ lang_add_vers_depend (struct bfd_elf_version_deps *list, const char *name) ret = (struct bfd_elf_version_deps *) xmalloc (sizeof *ret); ret->next = list; + ret->version_needed_name = NULL; for (t = link_info.version_info; t != NULL; t = t->next) { @@ -9490,9 +9523,10 @@ lang_add_vers_depend (struct bfd_elf_version_deps *list, const char *name) } } - einfo (_("%X%P: unable to find version dependency `%s'\n"), name); +// einfo (_("%X%P: unable to find version dependency `%s'\n"), name); ret->version_needed = NULL; + ret->version_needed_name = strdup(name); return ret; } diff --git a/ld/ldlex.l b/ld/ldlex.l index c38b46b933..a18410f55f 100644 --- a/ld/ldlex.l +++ b/ld/ldlex.l @@ -444,6 +444,8 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* #.* { /* Eat up comments */ } +$mapfile_version.* { /* Eat up comments */ } + [:,;] { return *yytext; } global { RTOKEN(GLOBAL); } @@ -455,6 +457,10 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* {V_IDENTIFIER} { yylval.name = xstrdup (yytext); return VERS_IDENTIFIER; } +SYMBOL_VERSION { RTOKEN(SYMBOL_VERSION); } + +SYMBOL_SCOPE { RTOKEN(SYMBOL_SCOPE); } + {V_TAG} { yylval.name = xstrdup (yytext); return VERS_TAG; }