X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felfnn-riscv.c;h=7b1ca47083c69d88c4ec04f28c893cb9da7d0021;hb=09897e3330d41699b6146f9b8767734f92587dcc;hp=931bd1d89d5cf74a2deb784805bc3b1469bb0cce;hpb=2a0d98534964649bc6884b7833c6c4089159a6df;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 931bd1d89d..7b1ca47083 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -121,12 +121,13 @@ struct riscv_elf_link_hash_table (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ == RISCV_ELF_DATA ? ((struct riscv_elf_link_hash_table *) ((p)->hash)) : NULL) -static void -riscv_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, +static bfd_boolean +riscv_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) { - cache_ptr->howto = riscv_elf_rtype_to_howto (ELFNN_R_TYPE (dst->r_info)); + cache_ptr->howto = riscv_elf_rtype_to_howto (abfd, ELFNN_R_TYPE (dst->r_info)); + return cache_ptr->howto != NULL; } static void @@ -424,7 +425,7 @@ riscv_elf_record_tls_type (bfd *abfd, struct elf_link_hash_entry *h, if ((*new_tls_type & GOT_NORMAL) && (*new_tls_type & ~GOT_NORMAL)) { (*_bfd_error_handler) - (_("%B: `%s' accessed both as normal and thread local symbol"), + (_("%pB: `%s' accessed both as normal and thread local symbol"), abfd, h ? h->root.root.string : ""); return FALSE; } @@ -467,11 +468,13 @@ riscv_elf_record_got_reference (bfd *abfd, struct bfd_link_info *info, static bfd_boolean bad_static_reloc (bfd *abfd, unsigned r_type, struct elf_link_hash_entry *h) { + reloc_howto_type * r = riscv_elf_rtype_to_howto (abfd, r_type); + (*_bfd_error_handler) - (_("%B: relocation %s against `%s' can not be used when making a shared " + (_("%pB: relocation %s against `%s' can not be used when making a shared " "object; recompile with -fPIC"), - abfd, riscv_elf_rtype_to_howto (r_type)->name, - h != NULL ? h->root.root.string : "a local symbol"); + abfd, r ? r->name : _(""), + h != NULL ? h->root.root.string : "a local symbol"); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -510,7 +513,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) { - (*_bfd_error_handler) (_("%B: bad symbol index: %d"), + (*_bfd_error_handler) (_("%pB: bad symbol index: %d"), abfd, r_symndx); return FALSE; } @@ -624,9 +627,11 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, may need to keep relocations for symbols satisfied by a dynamic library if we manage to avoid copy relocs for the symbol. */ + reloc_howto_type * r = riscv_elf_rtype_to_howto (abfd, r_type); + if ((bfd_link_pic (info) && (sec->flags & SEC_ALLOC) != 0 - && (! riscv_elf_rtype_to_howto (r_type)->pc_relative + && ((r != NULL && ! r->pc_relative) || (h != NULL && (! info->symbolic || h->root.type == bfd_link_hash_defweak @@ -696,7 +701,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, } p->count += 1; - p->pc_count += riscv_elf_rtype_to_howto (r_type)->pc_relative; + p->pc_count += r == NULL ? 0 : r->pc_relative; } break; @@ -996,7 +1001,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) else { s->size += RISCV_ELF_WORD_BYTES; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)) + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h) + && ! UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) htab->elf.srelgot->size += sizeof (ElfNN_External_Rela); } } @@ -1035,7 +1041,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (eh->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak) { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) eh->dyn_relocs = NULL; /* Make sure undefined weak symbols are output as a dynamic @@ -1109,7 +1116,7 @@ maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) info->flags |= DF_TEXTREL; info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), + (_("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"), sec->owner, h->root.root.string, sec); /* Not an error, just cut short the traversal. */ @@ -1724,10 +1731,12 @@ riscv_elf_relocate_section (bfd *output_bfd, bfd_boolean unresolved_reloc, is_ie = FALSE; bfd_vma pc = sec_addr (input_section) + rel->r_offset; int r_type = ELFNN_R_TYPE (rel->r_info), tls_type; - reloc_howto_type *howto = riscv_elf_rtype_to_howto (r_type); + reloc_howto_type *howto = riscv_elf_rtype_to_howto (input_bfd, r_type); const char *msg = NULL; + bfd_boolean resolved_to_zero; - if (r_type == R_RISCV_GNU_VTINHERIT || r_type == R_RISCV_GNU_VTENTRY) + if (howto == NULL + || r_type == R_RISCV_GNU_VTINHERIT || r_type == R_RISCV_GNU_VTENTRY) continue; /* This is a final link. */ @@ -1779,6 +1788,9 @@ riscv_elf_relocate_section (bfd *output_bfd, name = bfd_section_name (input_bfd, sec); } + resolved_to_zero = (h != NULL + && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); + switch (r_type) { case R_RISCV_NONE: @@ -1888,9 +1900,11 @@ riscv_elf_relocate_section (bfd *output_bfd, howto, input_bfd); r_type = ELFNN_R_TYPE (rel->r_info); - howto = riscv_elf_rtype_to_howto (r_type); - if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, - relocation, absolute)) + howto = riscv_elf_rtype_to_howto (input_bfd, r_type); + if (howto == NULL) + r = bfd_reloc_notsupported; + else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, + relocation, absolute)) r = bfd_reloc_overflow; break; @@ -1917,8 +1931,24 @@ riscv_elf_relocate_section (bfd *output_bfd, } break; - case R_RISCV_CALL_PLT: case R_RISCV_CALL: + /* Handle a call to an undefined weak function. This won't be + relaxed, so we have to handle it here. */ + if (h != NULL && h->root.type == bfd_link_hash_undefweak + && h->plt.offset == MINUS_ONE) + { + /* We can use x0 as the base register. */ + bfd_vma insn = bfd_get_32 (input_bfd, + contents + rel->r_offset + 4); + insn &= ~(OP_MASK_RS1 << OP_SH_RS1); + bfd_put_32 (input_bfd, insn, contents + rel->r_offset + 4); + /* Set the relocation value so that we get 0 after the pc + relative adjustment. */ + relocation = sec_addr (input_section) + rel->r_offset; + } + /* Fall through. */ + + case R_RISCV_CALL_PLT: case R_RISCV_JAL: case R_RISCV_RVC_JUMP: if (bfd_link_pic (info) && h != NULL && h->plt.offset != MINUS_ONE) @@ -1984,10 +2014,12 @@ riscv_elf_relocate_section (bfd *output_bfd, howto, input_bfd); r_type = ELFNN_R_TYPE (rel->r_info); - howto = riscv_elf_rtype_to_howto (r_type); - if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, - relocation + rel->r_addend, - absolute)) + howto = riscv_elf_rtype_to_howto (input_bfd, r_type); + if (howto == NULL) + r = bfd_reloc_notsupported; + else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, + relocation + rel->r_addend, + absolute)) r = bfd_reloc_overflow; break; @@ -2022,7 +2054,8 @@ riscv_elf_relocate_section (bfd *output_bfd, if ((bfd_link_pic (info) && (h == NULL - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + && !resolved_to_zero) || h->root.type != bfd_link_hash_undefweak) && (! howto->pc_relative || !SYMBOL_CALLS_LOCAL (info, h))) @@ -2213,10 +2246,11 @@ riscv_elf_relocate_section (bfd *output_bfd, rel->r_offset) != (bfd_vma) -1) { (*_bfd_error_handler) - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), + (_("%pB(%pA+%#" PRIx64 "): " + "unresolvable %s relocation against symbol `%s'"), input_bfd, input_section, - rel->r_offset, + (uint64_t) rel->r_offset, howto->name, h->root.root.string); continue; @@ -2345,7 +2379,8 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd, } if (h->got.offset != (bfd_vma) -1 - && !(riscv_elf_hash_entry (h)->tls_type & (GOT_TLS_GD | GOT_TLS_IE))) + && !(riscv_elf_hash_entry (h)->tls_type & (GOT_TLS_GD | GOT_TLS_IE)) + && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) { asection *sgot; asection *srela; @@ -2504,7 +2539,7 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd, if (bfd_is_abs_section (output_section)) { (*_bfd_error_handler) - (_("discarded output section: `%A'"), htab->elf.sgotplt); + (_("discarded output section: `%pA'"), htab->elf.sgotplt); return FALSE; } @@ -2582,7 +2617,7 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0) { (*_bfd_error_handler) - (_("%B: ABI is incompatible with that of the selected emulation:\n" + (_("%pB: ABI is incompatible with that of the selected emulation:\n" " target emulation `%s' does not match `%s'"), ibfd, bfd_get_target (ibfd), bfd_get_target (obfd)); return FALSE; @@ -2602,7 +2637,15 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) if ((old_flags ^ new_flags) & EF_RISCV_FLOAT_ABI) { (*_bfd_error_handler) - (_("%B: can't link hard-float modules with soft-float modules"), ibfd); + (_("%pB: can't link hard-float modules with soft-float modules"), ibfd); + goto fail; + } + + /* Disallow linking RVE and non-RVE. */ + if ((old_flags ^ new_flags) & EF_RISCV_RVE) + { + (*_bfd_error_handler) + (_("%pB: can't link RVE with other target"), ibfd); goto fail; } @@ -2654,10 +2697,16 @@ riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count, /* If the symbol *spans* the bytes we just deleted (i.e. its *end* is in the moved bytes but its *start* isn't), then we - must adjust its size. */ - if (sym->st_value <= addr - && sym->st_value + sym->st_size > addr - && sym->st_value + sym->st_size <= toaddr) + must adjust its size. + + This test needs to use the original value of st_value, otherwise + we might accidentally decrease size when deleting bytes right + before the symbol. But since deleted relocs can't span across + symbols, we can't have both a st_value and a st_size decrease, + so it is simpler to just use an else. */ + else if (sym->st_value <= addr + && sym->st_value + sym->st_size > addr + && sym->st_value + sym->st_size <= toaddr) sym->st_size -= count; } } @@ -2675,9 +2724,12 @@ riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count, call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference the same symbol (which is __wrap_SYMBOL), but still exist as two different symbols in 'sym_hashes', we don't want to adjust - the global symbol __wrap_SYMBOL twice. - This check is only relevant when symbols are being wrapped. */ - if (link_info->wrap_hash != NULL) + the global symbol __wrap_SYMBOL twice. */ + /* The same problem occurs with symbols that are versioned_hidden, as + foo becomes an alias for foo@BAR, and hence they need the same + treatment. */ + if (link_info->wrap_hash != NULL + || sym_hash->versioned == versioned_hidden) { struct elf_link_hash_entry **cur_sym_hashes; @@ -2705,9 +2757,9 @@ riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count, sym_hash->root.u.def.value -= count; /* As above, adjust the size if needed. */ - if (sym_hash->root.u.def.value <= addr - && sym_hash->root.u.def.value + sym_hash->size > addr - && sym_hash->root.u.def.value + sym_hash->size <= toaddr) + else if (sym_hash->root.u.def.value <= addr + && sym_hash->root.u.def.value + sym_hash->size > addr + && sym_hash->root.u.def.value + sym_hash->size <= toaddr) sym_hash->size -= count; } } @@ -3110,10 +3162,11 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec, /* Make sure there are enough NOPs to actually achieve the alignment. */ if (rel->r_addend < nop_bytes) { - (*_bfd_error_handler) - (_("%B(%A+0x%lx): %d bytes required for alignment " - "to %d-byte boundary, but only %d present"), - abfd, sym_sec, rel->r_offset, nop_bytes, alignment, rel->r_addend); + _bfd_error_handler + (_("%pB(%pA+%#" PRIx64 "): %" PRId64 " bytes required for alignment " + "to %" PRId64 "-byte boundary, but only %" PRId64 " present"), + abfd, sym_sec, (uint64_t) rel->r_offset, + (int64_t) nop_bytes, (int64_t) alignment, (int64_t) rel->r_addend); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -3177,10 +3230,10 @@ _bfd_riscv_relax_pc (bfd *abfd, symval = hi_reloc.hi_addr; sym_sec = hi_reloc.sym_sec; if (!riscv_use_pcgp_hi_reloc(pcgp_relocs, hi->hi_sec_off)) - (*_bfd_error_handler) - (_("%B(%A+0x%lx): Unable to clear RISCV_PCREL_HI20 reloc" - "for cooresponding RISCV_PCREL_LO12 reloc"), - abfd, sec, rel->r_offset); + _bfd_error_handler + (_("%pB(%pA+%#" PRIx64 "): Unable to clear RISCV_PCREL_HI20 reloc " + "for corresponding RISCV_PCREL_LO12 reloc"), + abfd, sec, (uint64_t) rel->r_offset); } break; @@ -3399,8 +3452,14 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, { BFD_ASSERT (isym->st_shndx < elf_numsections (abfd)); sym_sec = elf_elfsections (abfd)[isym->st_shndx]->bfd_section; +#if 0 + /* The purpose of this code is unknown. It breaks linker scripts + for embedded development that place sections at address zero. + This code is believed to be unnecessary. Disabling it but not + yet removing it, in case something breaks. */ if (sec_addr (sym_sec) == 0) continue; +#endif symval = sec_addr (sym_sec) + isym->st_value; } }