X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=bfd%2Felfnn-riscv.c;h=8f9f0d8a86a3a793b627b0de653b83a5df3338db;hb=a55939ca586b81c16cc95fa692a7862551cc6773;hp=ec8a3e73c8fb60dfe0f0c017cfaa17da7245206e;hpb=5a9f5403c75c8ae1f4935a9a0904949f52d9e3aa;p=binutils-gdb.git diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index ec8a3e73c8f..8f9f0d8a86a 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -1,5 +1,5 @@ /* RISC-V-specific support for NN-bit ELF. - Copyright (C) 2011-2021 Free Software Foundation, Inc. + Copyright (C) 2011-2022 Free Software Foundation, Inc. Contributed by Andrew Waterman (andrew@sifive.com). Based on TILE-Gx and MIPS targets. @@ -32,11 +32,8 @@ #include "elf/riscv.h" #include "opcode/riscv.h" #include "objalloc.h" -#include "cpu-riscv.h" -#ifdef HAVE_LIMITS_H #include -#endif #ifndef CHAR_BIT #define CHAR_BIT 8 #endif @@ -64,6 +61,8 @@ #define ELF_MAXPAGESIZE 0x1000 #define ELF_COMMONPAGESIZE 0x1000 +#define RISCV_ATTRIBUTES_SECTION_NAME ".riscv.attributes" + /* RISC-V ELF linker hash entry. */ struct riscv_elf_link_hash_entry @@ -104,7 +103,7 @@ struct _bfd_riscv_elf_obj_tdata && elf_tdata (bfd) != NULL \ && elf_object_id (bfd) == RISCV_ELF_DATA) -static bfd_boolean +static bool elfNN_riscv_mkobject (bfd *abfd) { return bfd_elf_allocate_object (abfd, @@ -131,6 +130,13 @@ struct riscv_elf_link_hash_table /* The index of the last unused .rel.iplt slot. */ bfd_vma last_iplt_index; + + /* The data segment phase, don't relax the section + when it is exp_seg_relro_adjust. */ + int *data_segment_phase; + + /* Relocations for variant CC symbols may be present. */ + int variant_cc; }; /* Instruction access functions. */ @@ -151,7 +157,7 @@ struct riscv_elf_link_hash_table && elf_hash_table_id (elf_hash_table (p)) == RISCV_ELF_DATA) \ ? (struct riscv_elf_link_hash_table *) (p)->hash : NULL) -static bfd_boolean +static bool riscv_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) @@ -173,7 +179,7 @@ riscv_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel) /* Return true if a relocation is modifying an instruction. */ -static bfd_boolean +static bool riscv_is_insn_reloc (const reloc_howto_type *howto) { /* Heuristic: A multibyte destination with a nontrivial mask @@ -205,7 +211,7 @@ riscv_is_insn_reloc (const reloc_howto_type *howto) /* Generate a PLT header. */ -static bfd_boolean +static bool riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr, uint32_t *entry) { @@ -217,7 +223,7 @@ riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr, { _bfd_error_handler (_("%pB: warning: RVE PLT generation not supported"), output_bfd); - return FALSE; + return false; } /* auipc t2, %hi(.got.plt) @@ -238,12 +244,12 @@ riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr, entry[6] = RISCV_ITYPE (LREG, X_T0, X_T0, RISCV_ELF_WORD_BYTES); entry[7] = RISCV_ITYPE (JALR, 0, X_T3, 0); - return TRUE; + return true; } /* Generate a PLT entry. */ -static bfd_boolean +static bool riscv_make_plt_entry (bfd *output_bfd, bfd_vma got, bfd_vma addr, uint32_t *entry) { @@ -252,7 +258,7 @@ riscv_make_plt_entry (bfd *output_bfd, bfd_vma got, bfd_vma addr, { _bfd_error_handler (_("%pB: warning: RVE PLT generation not supported"), output_bfd); - return FALSE; + return false; } /* auipc t3, %hi(.got.plt entry) @@ -265,7 +271,7 @@ riscv_make_plt_entry (bfd *output_bfd, bfd_vma got, bfd_vma addr, entry[2] = RISCV_ITYPE (JALR, X_T1, X_T3, 0); entry[3] = RISCV_NOP; - return TRUE; + return true; } /* Create an entry in an RISC-V ELF linker hash table. */ @@ -326,7 +332,7 @@ riscv_elf_local_htab_eq (const void *ptr1, const void *ptr2) static struct elf_link_hash_entry * riscv_elf_get_local_sym_hash (struct riscv_elf_link_hash_table *htab, bfd *abfd, const Elf_Internal_Rela *rel, - bfd_boolean create) + bool create) { struct riscv_elf_link_hash_entry eh, *ret; asection *sec = abfd->sections; @@ -418,7 +424,7 @@ riscv_elf_link_hash_table_create (bfd *abfd) /* Create the .got section. */ -static bfd_boolean +static bool riscv_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) { flagword flags; @@ -429,7 +435,7 @@ riscv_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) /* This function may be called more than once. */ if (htab->sgot != NULL) - return TRUE; + return true; flags = bed->dynamic_sec_flags; @@ -440,13 +446,13 @@ riscv_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) | SEC_READONLY)); if (s == NULL || !bfd_set_section_alignment (s, bed->s->log_file_align)) - return FALSE; + return false; htab->srelgot = s; s = s_got = bfd_make_section_anyway_with_flags (abfd, ".got", flags); if (s == NULL || !bfd_set_section_alignment (s, bed->s->log_file_align)) - return FALSE; + return false; htab->sgot = s; /* The first bit of the global offset table is the header. */ @@ -457,7 +463,7 @@ riscv_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); if (s == NULL || !bfd_set_section_alignment (s, bed->s->log_file_align)) - return FALSE; + return false; htab->sgotplt = s; /* Reserve room for the header. */ @@ -474,17 +480,17 @@ riscv_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) "_GLOBAL_OFFSET_TABLE_"); elf_hash_table (info)->hgot = h; if (h == NULL) - return FALSE; + return false; } - return TRUE; + return true; } /* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and .rela.bss sections in DYNOBJ, and set up shortcuts to them in our hash table. */ -static bfd_boolean +static bool riscv_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) { @@ -494,10 +500,10 @@ riscv_elf_create_dynamic_sections (bfd *dynobj, BFD_ASSERT (htab != NULL); if (!riscv_elf_create_got_section (dynobj, info)) - return FALSE; + return false; if (!_bfd_elf_create_dynamic_sections (dynobj, info)) - return FALSE; + return false; if (!bfd_link_pic (info)) { @@ -525,7 +531,7 @@ riscv_elf_create_dynamic_sections (bfd *dynobj, || (!bfd_link_pic (info) && (!htab->elf.srelbss || !htab->sdyntdata))) abort (); - return TRUE; + return true; } /* Copy the extra info we tack onto an elf_link_hash_entry. */ @@ -549,7 +555,7 @@ riscv_elf_copy_indirect_symbol (struct bfd_link_info *info, _bfd_elf_link_hash_copy_indirect (info, dir, ind); } -static bfd_boolean +static bool riscv_elf_record_tls_type (bfd *abfd, struct elf_link_hash_entry *h, unsigned long symndx, char tls_type) { @@ -561,12 +567,12 @@ riscv_elf_record_tls_type (bfd *abfd, struct elf_link_hash_entry *h, (*_bfd_error_handler) (_("%pB: `%s' accessed both as normal and thread local symbol"), abfd, h ? h->root.root.string : ""); - return FALSE; + return false; } - return TRUE; + return true; } -static bfd_boolean +static bool riscv_elf_record_got_reference (bfd *abfd, struct bfd_link_info *info, struct elf_link_hash_entry *h, long symndx) { @@ -576,13 +582,13 @@ riscv_elf_record_got_reference (bfd *abfd, struct bfd_link_info *info, if (htab->elf.sgot == NULL) { if (!riscv_elf_create_got_section (htab->elf.dynobj, info)) - return FALSE; + return false; } if (h != NULL) { h->got.refcount += 1; - return TRUE; + return true; } /* This is a global offset table entry for a local symbol. */ @@ -590,16 +596,16 @@ riscv_elf_record_got_reference (bfd *abfd, struct bfd_link_info *info, { bfd_size_type size = symtab_hdr->sh_info * (sizeof (bfd_vma) + 1); if (!(elf_local_got_refcounts (abfd) = bfd_zalloc (abfd, size))) - return FALSE; + return false; _bfd_riscv_elf_local_got_tls_type (abfd) = (char *) (elf_local_got_refcounts (abfd) + symtab_hdr->sh_info); } elf_local_got_refcounts (abfd) [symndx] += 1; - return TRUE; + return true; } -static bfd_boolean +static bool 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); @@ -613,14 +619,14 @@ bad_static_reloc (bfd *abfd, unsigned r_type, struct elf_link_hash_entry *h) abfd, r ? r->name : _(""), h != NULL ? h->root.root.string : "a local symbol"); bfd_set_error (bfd_error_bad_value); - return FALSE; + return false; } /* Look through the relocs for a section during the first phase, and allocate space in the global offset table or procedure linkage table. */ -static bfd_boolean +static bool riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, const Elf_Internal_Rela *relocs) { @@ -631,7 +637,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sreloc = NULL; if (bfd_link_relocatable (info)) - return TRUE; + return true; htab = riscv_elf_hash_table (info); symtab_hdr = &elf_tdata (abfd)->symtab_hdr; @@ -653,7 +659,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, { (*_bfd_error_handler) (_("%pB: bad symbol index: %d"), abfd, r_symndx); - return FALSE; + return false; } if (r_symndx < symtab_hdr->sh_info) @@ -662,14 +668,14 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd, r_symndx); if (isym == NULL) - return FALSE; + return false; /* Check relocation against local STT_GNU_IFUNC symbol. */ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { - h = riscv_elf_get_local_sym_hash (htab, abfd, rel, TRUE); + h = riscv_elf_get_local_sym_hash (htab, abfd, rel, true); if (h == NULL) - return FALSE; + return false; /* Fake STT_GNU_IFUNC global symbol. */ h->root.root.string = bfd_elf_sym_name (abfd, symtab_hdr, @@ -706,7 +712,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, executables. */ if (h->type == STT_GNU_IFUNC && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info)) - return FALSE; + return false; break; default: @@ -722,7 +728,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_RISCV_TLS_GD_HI20: if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_TLS_GD)) - return FALSE; + return false; break; case R_RISCV_TLS_GOT_HI20: @@ -730,13 +736,13 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, info->flags |= DF_STATIC_TLS; if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_TLS_IE)) - return FALSE; + return false; break; case R_RISCV_GOT_HI20: if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_NORMAL)) - return FALSE; + return false; break; case R_RISCV_CALL: @@ -872,10 +878,10 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, { sreloc = _bfd_elf_make_dynamic_reloc_section (sec, htab->elf.dynobj, RISCV_ELF_LOG_WORD_BYTES, - abfd, /*rela?*/ TRUE); + abfd, /*rela?*/ true); if (sreloc == NULL) - return FALSE; + return false; } /* If this is a global symbol, we count the number of @@ -895,7 +901,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd, r_symndx); if (isym == NULL) - return FALSE; + return false; s = bfd_section_from_elf_index (abfd, isym->st_shndx); if (s == NULL) @@ -912,7 +918,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, p = ((struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj, amt)); if (p == NULL) - return FALSE; + return false; p->next = *head; *head = p; p->sec = sec; @@ -928,12 +934,12 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_RISCV_GNU_VTINHERIT: if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) - return FALSE; + return false; break; case R_RISCV_GNU_VTENTRY: if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; + return false; break; default: @@ -941,7 +947,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, } } - return TRUE; + return true; } static asection * @@ -968,7 +974,7 @@ riscv_elf_gc_mark_hook (asection *sec, change the definition to something the rest of the link can understand. */ -static bfd_boolean +static bool riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h) { @@ -1010,7 +1016,7 @@ riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info, h->needs_plt = 0; } - return TRUE; + return true; } else h->plt.offset = (bfd_vma) -1; @@ -1024,7 +1030,7 @@ riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info, BFD_ASSERT (def->root.type == bfd_link_hash_defined); h->root.u.def.section = def->root.u.def.section; h->root.u.def.value = def->root.u.def.value; - return TRUE; + return true; } /* This is a reference to a symbol defined by a dynamic object which @@ -1035,18 +1041,18 @@ riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info, For such cases we need not do anything here; the relocations will be handled correctly by relocate_section. */ if (bfd_link_pic (info)) - return TRUE; + return true; /* If there are no references to this symbol that do not use the GOT, we don't need to generate a copy reloc. */ if (!h->non_got_ref) - return TRUE; + return true; /* If -z nocopyreloc was given, we won't generate them either. */ if (info->nocopyreloc) { h->non_got_ref = 0; - return TRUE; + return true; } /* If we don't find any dynamic relocs in read-only sections, then @@ -1054,7 +1060,7 @@ riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info, if (!_bfd_elf_readonly_dynrelocs (h)) { h->non_got_ref = 0; - return TRUE; + return true; } /* We must allocate the symbol in our .dynbss section, which will @@ -1099,7 +1105,7 @@ riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info, /* Allocate space in .plt, .got and associated reloc sections for dynamic relocs. */ -static bfd_boolean +static bool allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { struct bfd_link_info *info; @@ -1107,7 +1113,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) struct elf_dyn_relocs *p; if (h->root.type == bfd_link_hash_indirect) - return TRUE; + return true; info = (struct bfd_link_info *) inf; htab = riscv_elf_hash_table (info); @@ -1120,14 +1126,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) && htab->elf.dynamic_sections_created && strcmp (h->root.root.string, RISCV_GP_SYMBOL) == 0 && !bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; + return false; /* Since STT_GNU_IFUNC symbols must go through PLT, we handle them in the allocate_ifunc_dynrelocs and allocate_local_ifunc_dynrelocs, if they are defined and referenced in a non-shared object. */ if (h->type == STT_GNU_IFUNC && h->def_regular) - return TRUE; + return true; else if (htab->elf.dynamic_sections_created && h->plt.refcount > 0) { @@ -1137,7 +1143,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) && !h->forced_local) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; + return false; } if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) @@ -1169,6 +1175,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) h->root.u.def.section = s; h->root.u.def.value = h->plt.offset; } + + /* If the symbol has STO_RISCV_VARIANT_CC flag, then raise the + variant_cc flag of riscv_elf_link_hash_table. */ + if (h->other & STO_RISCV_VARIANT_CC) + htab->variant_cc = 1; } else { @@ -1185,7 +1196,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (h->got.refcount > 0) { asection *s; - bfd_boolean dyn; + bool dyn; int tls_type = riscv_elf_hash_entry (h)->tls_type; /* Make sure this symbol is output as a dynamic symbol. @@ -1194,7 +1205,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) && !h->forced_local) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; + return false; } s = htab->elf.sgot; @@ -1228,7 +1239,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) h->got.offset = (bfd_vma) -1; if (h->dyn_relocs == NULL) - return TRUE; + return true; /* In the shared -Bsymbolic case, discard space allocated for dynamic pc-relative relocs against symbols which turn out to be @@ -1268,7 +1279,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) && !h->forced_local) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; + return false; } } } @@ -1291,7 +1302,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) && !h->forced_local) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; + return false; } /* If that succeeded, we know we'll be keeping all the @@ -1312,20 +1323,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) sreloc->size += p->count * sizeof (ElfNN_External_Rela); } - return TRUE; + return true; } /* Allocate space in .plt, .got and associated reloc sections for ifunc dynamic relocs. */ -static bfd_boolean +static bool allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, void *inf) { struct bfd_link_info *info; if (h->root.type == bfd_link_hash_indirect) - return TRUE; + return true; if (h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; @@ -1341,14 +1352,14 @@ allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, PLT_ENTRY_SIZE, PLT_HEADER_SIZE, GOT_ENTRY_SIZE, - TRUE); - return TRUE; + true); + return true; } /* Allocate space in .plt, .got and associated reloc sections for local ifunc dynamic relocs. */ -static bfd_boolean +static int allocate_local_ifunc_dynrelocs (void **slot, void *inf) { struct elf_link_hash_entry *h @@ -1364,7 +1375,7 @@ allocate_local_ifunc_dynrelocs (void **slot, void *inf) return allocate_ifunc_dynrelocs (h, inf); } -static bfd_boolean +static bool riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { struct riscv_elf_link_hash_table *htab; @@ -1476,7 +1487,7 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) struct elf_link_hash_entry *got; got = elf_link_hash_lookup (elf_hash_table (info), "_GLOBAL_OFFSET_TABLE_", - FALSE, FALSE, FALSE); + false, false, false); /* Don't allocate .got.plt section if there are no GOT nor PLT entries and there is no refeence to _GLOBAL_OFFSET_TABLE_. */ @@ -1511,7 +1522,7 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) /* Strip this section if we don't need it; see the comment below. */ } - else if (strncmp (s->name, ".rela", 5) == 0) + else if (startswith (s->name, ".rela")) { if (s->size != 0) { @@ -1549,10 +1560,21 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) at the beginning, and we don't want garbage. */ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); if (s->contents == NULL) - return FALSE; + return false; + } + + /* Add dynamic entries. */ + if (elf_hash_table (info)->dynamic_sections_created) + { + if (!_bfd_elf_add_dynamic_tags (output_bfd, info, true)) + return false; + + if (htab->variant_cc + && !_bfd_elf_add_dynamic_entry (info, DT_RISCV_VARIANT_CC, 0)) + return false; } - return _bfd_elf_add_dynamic_tags (output_bfd, info, TRUE); + return true; } #define TP_OFFSET 0 @@ -1587,7 +1609,7 @@ riscv_global_pointer_value (struct bfd_link_info *info) { struct bfd_link_hash_entry *h; - h = bfd_link_hash_lookup (info->hash, RISCV_GP_SYMBOL, FALSE, FALSE, TRUE); + h = bfd_link_hash_lookup (info->hash, RISCV_GP_SYMBOL, false, false, true); if (h == NULL || h->type != bfd_link_hash_defined) return 0; @@ -1733,25 +1755,41 @@ perform_relocation (const reloc_howto_type *howto, typedef struct { + /* PC value. */ bfd_vma address; + /* Relocation value with addend. */ bfd_vma value; + /* Original reloc type. */ + int type; } riscv_pcrel_hi_reloc; typedef struct riscv_pcrel_lo_reloc { + /* PC value of auipc. */ + bfd_vma address; + /* Internal relocation. */ + const Elf_Internal_Rela *reloc; + /* Record the following information helps to resolve the %pcrel + which cross different input section. For now we build a hash + for pcrel at the start of riscv_elf_relocate_section, and then + free the hash at the end. But riscv_elf_relocate_section only + handles an input section at a time, so that means we can only + resolve the %pcrel_hi and %pcrel_lo which are in the same input + section. Otherwise, we will report dangerous relocation errors + for those %pcrel which are not in the same input section. */ asection *input_section; struct bfd_link_info *info; reloc_howto_type *howto; - const Elf_Internal_Rela *reloc; - bfd_vma addr; - const char *name; bfd_byte *contents; + /* The next riscv_pcrel_lo_reloc. */ struct riscv_pcrel_lo_reloc *next; } riscv_pcrel_lo_reloc; typedef struct { + /* Hash table for riscv_pcrel_hi_reloc. */ htab_t hi_relocs; + /* Linked list for riscv_pcrel_lo_reloc. */ riscv_pcrel_lo_reloc *lo_relocs; } riscv_pcrel_relocs; @@ -1762,14 +1800,14 @@ riscv_pcrel_reloc_hash (const void *entry) return (hashval_t)(e->address >> 2); } -static bfd_boolean +static int riscv_pcrel_reloc_eq (const void *entry1, const void *entry2) { const riscv_pcrel_hi_reloc *e1 = entry1, *e2 = entry2; return e1->address == e2->address; } -static bfd_boolean +static bool riscv_init_pcrel_relocs (riscv_pcrel_relocs *p) { p->lo_relocs = NULL; @@ -1793,14 +1831,13 @@ riscv_free_pcrel_relocs (riscv_pcrel_relocs *p) htab_delete (p->hi_relocs); } -static bfd_boolean +static bool riscv_zero_pcrel_hi_reloc (Elf_Internal_Rela *rel, struct bfd_link_info *info, bfd_vma pc, bfd_vma addr, bfd_byte *contents, - const reloc_howto_type *howto, - bfd *input_bfd ATTRIBUTE_UNUSED) + const reloc_howto_type *howto) { /* We may need to reference low addreses in PC-relative modes even when the PC is far away from these addresses. For example, undefweak references @@ -1810,66 +1847,68 @@ riscv_zero_pcrel_hi_reloc (Elf_Internal_Rela *rel, programs to work we simply convert the PC-relative auipc sequences to 0-relative lui sequences. */ if (bfd_link_pic (info)) - return FALSE; + return false; /* If it's possible to reference the symbol using auipc we do so, as that's more in the spirit of the PC-relative relocations we're processing. */ bfd_vma offset = addr - pc; if (ARCH_SIZE == 32 || VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (offset))) - return FALSE; + return false; /* If it's impossible to reference this with a LUI-based offset then don't bother to convert it at all so users still see the PC-relative relocation in the truncation message. */ if (ARCH_SIZE > 32 && !VALID_UTYPE_IMM (RISCV_CONST_HIGH_PART (addr))) - return FALSE; + return false; rel->r_info = ELFNN_R_INFO (addr, R_RISCV_HI20); bfd_vma insn = riscv_get_insn (howto->bitsize, contents + rel->r_offset); insn = (insn & ~MASK_AUIPC) | MATCH_LUI; riscv_put_insn (howto->bitsize, insn, contents + rel->r_offset); - return TRUE; + return true; } -static bfd_boolean -riscv_record_pcrel_hi_reloc (riscv_pcrel_relocs *p, bfd_vma addr, - bfd_vma value, bfd_boolean absolute) +static bool +riscv_record_pcrel_hi_reloc (riscv_pcrel_relocs *p, + bfd_vma addr, + bfd_vma value, + int type, + bool absolute) { bfd_vma offset = absolute ? value : value - addr; - riscv_pcrel_hi_reloc entry = {addr, offset}; + riscv_pcrel_hi_reloc entry = {addr, offset, type}; riscv_pcrel_hi_reloc **slot = (riscv_pcrel_hi_reloc **) htab_find_slot (p->hi_relocs, &entry, INSERT); BFD_ASSERT (*slot == NULL); *slot = (riscv_pcrel_hi_reloc *) bfd_malloc (sizeof (riscv_pcrel_hi_reloc)); if (*slot == NULL) - return FALSE; + return false; **slot = entry; - return TRUE; + return true; } -static bfd_boolean +static bool riscv_record_pcrel_lo_reloc (riscv_pcrel_relocs *p, + bfd_vma addr, + const Elf_Internal_Rela *reloc, asection *input_section, struct bfd_link_info *info, reloc_howto_type *howto, - const Elf_Internal_Rela *reloc, - bfd_vma addr, - const char *name, bfd_byte *contents) { riscv_pcrel_lo_reloc *entry; entry = (riscv_pcrel_lo_reloc *) bfd_malloc (sizeof (riscv_pcrel_lo_reloc)); if (entry == NULL) - return FALSE; - *entry = (riscv_pcrel_lo_reloc) {input_section, info, howto, reloc, addr, - name, contents, p->lo_relocs}; + return false; + *entry = (riscv_pcrel_lo_reloc) {addr, reloc, input_section, info, + howto, contents, p->lo_relocs}; p->lo_relocs = entry; - return TRUE; + return true; } -static bfd_boolean +static bool riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p) { riscv_pcrel_lo_reloc *r; @@ -1878,26 +1917,44 @@ riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p) { bfd *input_bfd = r->input_section->owner; - riscv_pcrel_hi_reloc search = {r->addr, 0}; + riscv_pcrel_hi_reloc search = {r->address, 0, 0}; riscv_pcrel_hi_reloc *entry = htab_find (p->hi_relocs, &search); - if (entry == NULL - /* Check for overflow into bit 11 when adding reloc addend. */ - || (!(entry->value & 0x800) - && ((entry->value + r->reloc->r_addend) & 0x800))) + /* There may be a risk if the %pcrel_lo with addend refers to + an IFUNC symbol. The %pcrel_hi has been relocated to plt, + so the corresponding %pcrel_lo with addend looks wrong. */ + char *string = NULL; + if (entry == NULL) + string = _("%pcrel_lo missing matching %pcrel_hi"); + else if (entry->type == R_RISCV_GOT_HI20 + && r->reloc->r_addend != 0) + string = _("%pcrel_lo with addend isn't allowed for R_RISCV_GOT_HI20"); + else if (RISCV_CONST_HIGH_PART (entry->value) + != RISCV_CONST_HIGH_PART (entry->value + r->reloc->r_addend)) + { + /* Check the overflow when adding reloc addend. */ + if (asprintf (&string, + _("%%pcrel_lo overflow with an addend, the " + "value of %%pcrel_hi is 0x%" PRIx64 " without " + "any addend, but may be 0x%" PRIx64 " after " + "adding the %%pcrel_lo addend"), + (int64_t) RISCV_CONST_HIGH_PART (entry->value), + (int64_t) RISCV_CONST_HIGH_PART + (entry->value + r->reloc->r_addend)) == -1) + string = _("%pcrel_lo overflow with an addend"); + } + + if (string != NULL) { - char *string = (entry == NULL - ? "%pcrel_lo missing matching %pcrel_hi" - : "%pcrel_lo overflow with an addend"); (*r->info->callbacks->reloc_dangerous) (r->info, string, input_bfd, r->input_section, r->reloc->r_offset); - return TRUE; + return true; } perform_relocation (r->howto, r->reloc, entry->value, r->input_section, input_bfd, r->contents); } - return TRUE; + return true; } /* Relocate a RISC-V ELF section. @@ -1928,7 +1985,7 @@ riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p) section, which means that the addend must be adjusted accordingly. */ -static bfd_boolean +static int riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, bfd *input_bfd, @@ -1941,15 +1998,15 @@ riscv_elf_relocate_section (bfd *output_bfd, Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; riscv_pcrel_relocs pcrel_relocs; - bfd_boolean ret = FALSE; + bool ret = false; struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd); struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd); - bfd_boolean absolute; + bool absolute; if (!riscv_init_pcrel_relocs (&pcrel_relocs)) - return FALSE; + return false; relend = relocs + input_section->reloc_count; for (rel = relocs; rel < relend; rel++) @@ -1962,13 +2019,13 @@ riscv_elf_relocate_section (bfd *output_bfd, bfd_reloc_status_type r = bfd_reloc_ok; const char *name = NULL; bfd_vma off, ie_off; - bfd_boolean unresolved_reloc, is_ie = FALSE; + bool 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 (input_bfd, r_type); const char *msg = NULL; char *msg_buf = NULL; - bfd_boolean resolved_to_zero; + bool resolved_to_zero; if (howto == NULL || r_type == R_RISCV_GNU_VTINHERIT || r_type == R_RISCV_GNU_VTENTRY) @@ -1979,7 +2036,7 @@ riscv_elf_relocate_section (bfd *output_bfd, h = NULL; sym = NULL; sec = NULL; - unresolved_reloc = FALSE; + unresolved_reloc = false; if (r_symndx < symtab_hdr->sh_info) { sym = local_syms + r_symndx; @@ -1990,7 +2047,7 @@ riscv_elf_relocate_section (bfd *output_bfd, if (!bfd_link_relocatable (info) && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) { - h = riscv_elf_get_local_sym_hash (htab, input_bfd, rel, FALSE); + h = riscv_elf_get_local_sym_hash (htab, input_bfd, rel, false); if (h == NULL) abort (); @@ -2001,7 +2058,7 @@ riscv_elf_relocate_section (bfd *output_bfd, } else { - bfd_boolean warned, ignored; + bool warned, ignored; RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, r_symndx, symtab_hdr, sym_hashes, @@ -2084,7 +2141,7 @@ riscv_elf_relocate_section (bfd *output_bfd, "symbol `%s' has non-zero addend: %" PRId64), input_bfd, howto->name, name, (int64_t) rel->r_addend); bfd_set_error (bfd_error_bad_value); - return FALSE; + return false; } /* Generate dynamic relocation only when there is a non-GOT @@ -2209,12 +2266,9 @@ riscv_elf_relocate_section (bfd *output_bfd, relocation = base_got->output_section->vma + base_got->output_offset + off; - r_type = ELFNN_R_TYPE (rel->r_info); - 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, FALSE)) + if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, + relocation, r_type, + false)) r = bfd_reloc_overflow; goto do_relocation; @@ -2226,12 +2280,9 @@ riscv_elf_relocate_section (bfd *output_bfd, goto do_relocation; case R_RISCV_PCREL_HI20: - r_type = ELFNN_R_TYPE (rel->r_info); - 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, FALSE)) + if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, + relocation, r_type, + false)) r = bfd_reloc_overflow; goto do_relocation; @@ -2250,7 +2301,7 @@ riscv_elf_relocate_section (bfd *output_bfd, "symbol `%s' isn't supported"), input_bfd, howto->name, name); bfd_set_error (bfd_error_bad_value); - return FALSE; + return false; } } @@ -2297,7 +2348,7 @@ riscv_elf_relocate_section (bfd *output_bfd, case R_RISCV_GOT_HI20: if (h != NULL) { - bfd_boolean dyn, pic; + bool dyn, pic; off = h->got.offset; BFD_ASSERT (off != (bfd_vma) -1); @@ -2329,7 +2380,7 @@ riscv_elf_relocate_section (bfd *output_bfd, } } else - unresolved_reloc = FALSE; + unresolved_reloc = false; } else { @@ -2368,21 +2419,29 @@ riscv_elf_relocate_section (bfd *output_bfd, local_got_offsets[r_symndx] |= 1; } } - relocation = sec_addr (htab->elf.sgot) + off; - absolute = riscv_zero_pcrel_hi_reloc (rel, - info, - pc, - relocation, - contents, - howto, - input_bfd); - r_type = ELFNN_R_TYPE (rel->r_info); - 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; + + if (rel->r_addend != 0) + { + msg = _("The addend isn't allowed for R_RISCV_GOT_HI20"); + r = bfd_reloc_dangerous; + } + else + { + /* Address of got entry. */ + relocation = sec_addr (htab->elf.sgot) + off; + absolute = riscv_zero_pcrel_hi_reloc (rel, info, pc, + relocation, contents, + howto); + /* Update howto if relocation is changed. */ + howto = riscv_elf_rtype_to_howto (input_bfd, + ELFNN_R_TYPE (rel->r_info)); + if (howto == NULL) + r = bfd_reloc_notsupported; + else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, + relocation, r_type, + absolute)) + r = bfd_reloc_overflow; + } break; case R_RISCV_ADD8: @@ -2432,7 +2491,7 @@ riscv_elf_relocate_section (bfd *output_bfd, { /* Refer to the PLT entry. */ relocation = sec_addr (htab->elf.splt) + h->plt.offset; - unresolved_reloc = FALSE; + unresolved_reloc = false; } break; @@ -2464,7 +2523,7 @@ riscv_elf_relocate_section (bfd *output_bfd, case R_RISCV_GPREL_S: { bfd_vma gp = riscv_global_pointer_value (info); - bfd_boolean x0_base = VALID_ITYPE_IMM (relocation + rel->r_addend); + bool x0_base = VALID_ITYPE_IMM (relocation + rel->r_addend); if (x0_base || VALID_ITYPE_IMM (relocation + rel->r_addend - gp)) { /* We can use x0 or gp as the base register. */ @@ -2483,20 +2542,16 @@ riscv_elf_relocate_section (bfd *output_bfd, } case R_RISCV_PCREL_HI20: - absolute = riscv_zero_pcrel_hi_reloc (rel, - info, - pc, - relocation, - contents, - howto, - input_bfd); - r_type = ELFNN_R_TYPE (rel->r_info); - howto = riscv_elf_rtype_to_howto (input_bfd, r_type); + absolute = riscv_zero_pcrel_hi_reloc (rel, info, pc, relocation, + contents, howto); + /* Update howto if relocation is changed. */ + howto = riscv_elf_rtype_to_howto (input_bfd, + ELFNN_R_TYPE (rel->r_info)); if (howto == NULL) r = bfd_reloc_notsupported; else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, relocation + rel->r_addend, - absolute)) + r_type, absolute)) r = bfd_reloc_overflow; break; @@ -2516,8 +2571,8 @@ riscv_elf_relocate_section (bfd *output_bfd, break; } - if (riscv_record_pcrel_lo_reloc (&pcrel_relocs, input_section, info, - howto, rel, relocation, name, + if (riscv_record_pcrel_lo_reloc (&pcrel_relocs, relocation, rel, + input_section, info, howto, contents)) continue; r = bfd_reloc_overflow; @@ -2551,7 +2606,7 @@ riscv_elf_relocate_section (bfd *output_bfd, { Elf_Internal_Rela outrel; asection *sreloc; - bfd_boolean skip_static_relocation, skip_dynamic_relocation; + bool skip_static_relocation, skip_dynamic_relocation; /* When generating a shared object, these relocations are copied into the output file to be resolved at run @@ -2588,7 +2643,7 @@ riscv_elf_relocate_section (bfd *output_bfd, break; case R_RISCV_TLS_GOT_HI20: - is_ie = TRUE; + is_ie = true; /* Fall through. */ case R_RISCV_TLS_GD_HI20: @@ -2617,14 +2672,14 @@ riscv_elf_relocate_section (bfd *output_bfd, { Elf_Internal_Rela outrel; int indx = 0; - bfd_boolean need_relocs = FALSE; + bool need_relocs = false; if (htab->elf.srelgot == NULL) abort (); if (h != NULL) { - bfd_boolean dyn, pic; + bool dyn, pic; dyn = htab->elf.dynamic_sections_created; pic = bfd_link_pic (info); @@ -2639,7 +2694,7 @@ riscv_elf_relocate_section (bfd *output_bfd, && (h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak)) - need_relocs = TRUE; + need_relocs = true; if (tls_type & GOT_TLS_GD) { @@ -2710,9 +2765,10 @@ riscv_elf_relocate_section (bfd *output_bfd, BFD_ASSERT (off < (bfd_vma) -2); relocation = sec_addr (htab->elf.sgot) + off + (is_ie ? ie_off : 0); if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc, - relocation, FALSE)) + relocation, r_type, + false)) r = bfd_reloc_overflow; - unresolved_reloc = FALSE; + unresolved_reloc = false; break; default: @@ -2778,7 +2834,7 @@ riscv_elf_relocate_section (bfd *output_bfd, case bfd_reloc_undefined: info->callbacks->undefined_symbol (info, name, input_bfd, input_section, rel->r_offset, - TRUE); + true); break; case bfd_reloc_outofrange: @@ -2813,7 +2869,7 @@ riscv_elf_relocate_section (bfd *output_bfd, /* We already reported the error via a callback, so don't try to report it again by returning false. That leads to spurious errors. */ - ret = TRUE; + ret = true; goto out; } @@ -2826,7 +2882,7 @@ riscv_elf_relocate_section (bfd *output_bfd, /* Finish up dynamic symbol handling. We set the contents of various dynamic sections here. */ -static bfd_boolean +static bool riscv_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, struct elf_link_hash_entry *h, @@ -2868,7 +2924,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd, || plt == NULL || gotplt == NULL || relplt == NULL) - return FALSE; + return false; /* Calculate the address of the PLT header. */ header_address = sec_addr (plt); @@ -2896,7 +2952,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd, if (! riscv_make_plt_entry (output_bfd, got_address, header_address + h->plt.offset, plt_entry)) - return FALSE; + return false; for (i = 0; i < PLT_ENTRY_INSNS; i++) bfd_putl32 (plt_entry[i], loc + 4*i); @@ -2956,7 +3012,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd, asection *sgot; asection *srela; Elf_Internal_Rela rela; - bfd_boolean use_elf_append_rela = TRUE; + bool use_elf_append_rela = true; /* This symbol has an entry in the GOT. Set it up. */ @@ -2982,7 +3038,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd, /* Do not use riscv_elf_append_rela to add dynamic relocs. */ - use_elf_append_rela = FALSE; + use_elf_append_rela = false; } if (SYMBOL_REFERENCES_LOCAL (info, h)) @@ -3029,7 +3085,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd, + h->plt.offset), htab->elf.sgot->contents + (h->got.offset & ~(bfd_vma) 1)); - return TRUE; + return true; } } else if (bfd_link_pic (info) @@ -3100,13 +3156,13 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd, || (h == htab->elf.hgot || h == htab->elf.hplt)) sym->st_shndx = SHN_ABS; - return TRUE; + return true; } /* Finish up local dynamic symbol handling. We set the contents of various dynamic sections here. */ -static bfd_boolean +static int riscv_elf_finish_local_dynamic_symbol (void **slot, void *inf) { struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot; @@ -3117,7 +3173,7 @@ riscv_elf_finish_local_dynamic_symbol (void **slot, void *inf) /* Finish up the dynamic sections. */ -static bfd_boolean +static bool riscv_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, bfd *dynobj, asection *sdyn) { @@ -3154,10 +3210,10 @@ riscv_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); } - return TRUE; + return true; } -static bfd_boolean +static bool riscv_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { @@ -3174,7 +3230,7 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd, if (elf_hash_table (info)->dynamic_sections_created) { asection *splt; - bfd_boolean ret; + bool ret; splt = htab->elf.splt; BFD_ASSERT (splt != NULL && sdyn != NULL); @@ -3211,7 +3267,7 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd, { (*_bfd_error_handler) (_("discarded output section: `%pA'"), htab->elf.sgotplt); - return FALSE; + return false; } if (htab->elf.sgotplt->size > 0) @@ -3246,7 +3302,7 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd, riscv_elf_finish_local_dynamic_symbol, info); - return TRUE; + return true; } /* Return address for Ith PLT stub in section PLT, for relocation REL @@ -3309,53 +3365,38 @@ static riscv_subset_list_t merged_subsets; /* Predicator for standard extension. */ -static bfd_boolean +static bool riscv_std_ext_p (const char *name) { return (strlen (name) == 1) && (name[0] != 'x') && (name[0] != 's'); } -/* Check if the versions are compatible. */ +/* Update the output subset's version to match the input when the input + subset's version is newer. */ -static bfd_boolean -riscv_version_mismatch (bfd *ibfd, - struct riscv_subset_t *in, - struct riscv_subset_t *out) +static void +riscv_update_subset_version (struct riscv_subset_t *in, + struct riscv_subset_t *out) { if (in == NULL || out == NULL) - return TRUE; - - /* Since there are no version conflicts for now, we just report - warning when the versions are mis-matched. */ - if (in->major_version != out->major_version - || in->minor_version != out->minor_version) + return; + + /* Update the output ISA versions to the newest ones, but otherwise don't + provide any errors or warnings about mis-matched ISA versions as it's + generally too tricky to check for these at link time. */ + if ((in->major_version > out->major_version) + || (in->major_version == out->major_version + && in->minor_version > out->minor_version) + || (out->major_version == RISCV_UNKNOWN_VERSION)) { - _bfd_error_handler - (_("warning: %pB: mis-matched ISA version %d.%d for '%s' " - "extension, the output version is %d.%d"), - ibfd, - in->major_version, - in->minor_version, - in->name, - out->major_version, - out->minor_version); - - /* Update the output ISA versions to the newest ones. */ - if ((in->major_version > out->major_version) - || (in->major_version == out->major_version - && in->minor_version > out->minor_version)) - { - out->major_version = in->major_version; - out->minor_version = in->minor_version; - } + out->major_version = in->major_version; + out->minor_version = in->minor_version; } - - return TRUE; } /* Return true if subset is 'i' or 'e'. */ -static bfd_boolean +static bool riscv_i_or_e_p (bfd *ibfd, const char *arch, struct riscv_subset_t *subset) @@ -3367,9 +3408,9 @@ riscv_i_or_e_p (bfd *ibfd, (_("error: %pB: corrupted ISA string '%s'. " "First letter should be 'i' or 'e' but got '%s'"), ibfd, arch, subset->name); - return FALSE; + return false; } - return TRUE; + return true; } /* Merge standard extensions. @@ -3384,24 +3425,24 @@ riscv_i_or_e_p (bfd *ibfd, `pin`: Subset list for input object. `pout`: Subset list for output object. */ -static bfd_boolean +static bool riscv_merge_std_ext (bfd *ibfd, const char *in_arch, const char *out_arch, struct riscv_subset_t **pin, struct riscv_subset_t **pout) { - const char *standard_exts = riscv_supported_std_ext (); + const char *standard_exts = "mafdqlcbjtpvn"; const char *p; struct riscv_subset_t *in = *pin; struct riscv_subset_t *out = *pout; /* First letter should be 'i' or 'e'. */ if (!riscv_i_or_e_p (ibfd, in_arch, in)) - return FALSE; + return false; if (!riscv_i_or_e_p (ibfd, out_arch, out)) - return FALSE; + return false; if (strcasecmp (in->name, out->name) != 0) { @@ -3409,13 +3450,12 @@ riscv_merge_std_ext (bfd *ibfd, _bfd_error_handler (_("error: %pB: mis-matched ISA string to merge '%s' and '%s'"), ibfd, in->name, out->name); - return FALSE; + return false; } - else if (!riscv_version_mismatch (ibfd, in, out)) - return FALSE; - else - riscv_add_subset (&merged_subsets, - out->name, out->major_version, out->minor_version); + + riscv_update_subset_version(in, out); + riscv_add_subset (&merged_subsets, + out->name, out->major_version, out->minor_version); in = in->next; out = out->next; @@ -3425,7 +3465,7 @@ riscv_merge_std_ext (bfd *ibfd, { struct riscv_subset_t *ext_in, *ext_out, *ext_merged; char find_ext[2] = {*p, '\0'}; - bfd_boolean find_in, find_out; + bool find_in, find_out; find_in = riscv_lookup_subset (&in_subsets, find_ext, &ext_in); find_out = riscv_lookup_subset (&out_subsets, find_ext, &ext_out); @@ -3433,10 +3473,8 @@ riscv_merge_std_ext (bfd *ibfd, if (!find_in && !find_out) continue; - if (find_in - && find_out - && !riscv_version_mismatch (ibfd, ext_in, ext_out)) - return FALSE; + if (find_in && find_out) + riscv_update_subset_version(ext_in, ext_out); ext_merged = find_out ? ext_out : ext_in; riscv_add_subset (&merged_subsets, ext_merged->name, @@ -3450,16 +3488,15 @@ riscv_merge_std_ext (bfd *ibfd, *pin = in; *pout = out; - return TRUE; + return true; } /* Merge multi letter extensions. PIN is a pointer to the head of the input object subset list. Likewise for POUT and the output object. Return TRUE on success and FALSE when a conflict is found. */ -static bfd_boolean -riscv_merge_multi_letter_ext (bfd *ibfd, - riscv_subset_t **pin, +static bool +riscv_merge_multi_letter_ext (riscv_subset_t **pin, riscv_subset_t **pout) { riscv_subset_t *in = *pin; @@ -3489,8 +3526,7 @@ riscv_merge_multi_letter_ext (bfd *ibfd, else { /* Both present, check version and increment both. */ - if (!riscv_version_mismatch (ibfd, in, out)) - return FALSE; + riscv_update_subset_version (in, out); riscv_add_subset (&merged_subsets, out->name, out->major_version, out->minor_version); @@ -3512,7 +3548,7 @@ riscv_merge_multi_letter_ext (bfd *ibfd, } } - return TRUE; + return true; } /* Merge Tag_RISCV_arch attribute. */ @@ -3527,35 +3563,22 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch) merged_subsets.head = NULL; merged_subsets.tail = NULL; - riscv_parse_subset_t rpe_in; - riscv_parse_subset_t rpe_out; - - /* Only assembler needs to check the default version of ISA, so just set - the rpe_in.get_default_version and rpe_out.get_default_version to NULL. */ - rpe_in.subset_list = &in_subsets; - rpe_in.error_handler = _bfd_error_handler; - rpe_in.xlen = &xlen_in; - rpe_in.get_default_version = NULL; - - rpe_out.subset_list = &out_subsets; - rpe_out.error_handler = _bfd_error_handler; - rpe_out.xlen = &xlen_out; - rpe_out.get_default_version = NULL; + riscv_parse_subset_t riscv_rps_ld_in = + {&in_subsets, _bfd_error_handler, &xlen_in, NULL, false}; + riscv_parse_subset_t riscv_rps_ld_out = + {&out_subsets, _bfd_error_handler, &xlen_out, NULL, false}; if (in_arch == NULL && out_arch == NULL) return NULL; - if (in_arch == NULL && out_arch != NULL) return out_arch; - if (in_arch != NULL && out_arch == NULL) return in_arch; /* Parse subset from ISA string. */ - if (!riscv_parse_subset (&rpe_in, in_arch)) + if (!riscv_parse_subset (&riscv_rps_ld_in, in_arch)) return NULL; - - if (!riscv_parse_subset (&rpe_out, out_arch)) + if (!riscv_parse_subset (&riscv_rps_ld_out, out_arch)) return NULL; /* Checking XLEN. */ @@ -3576,7 +3599,7 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch) return NULL; /* Merge all non-single letter extensions with single call. */ - if (!riscv_merge_multi_letter_ext (ibfd, &in, &out)) + if (!riscv_merge_multi_letter_ext (&in, &out)) return NULL; if (xlen_in != xlen_out) @@ -3608,26 +3631,26 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch) /* Merge object attributes from IBFD into output_bfd of INFO. Raise an error if there are conflicting attributes. */ -static bfd_boolean +static bool riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info) { bfd *obfd = info->output_bfd; obj_attribute *in_attr; obj_attribute *out_attr; - bfd_boolean result = TRUE; - bfd_boolean priv_attrs_merged = FALSE; + bool result = true; + bool priv_attrs_merged = false; const char *sec_name = get_elf_backend_data (ibfd)->obj_attrs_section; unsigned int i; /* Skip linker created files. */ if (ibfd->flags & BFD_LINKER_CREATED) - return TRUE; + return true; /* Skip any input that doesn't have an attribute section. This enables to link object files without attribute section with any others. */ if (bfd_get_section_by_name (ibfd, sec_name) == NULL) - return TRUE; + return true; if (!elf_known_obj_attributes_proc (obfd)[0].i) { @@ -3640,7 +3663,7 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info) initialized. */ out_attr[0].i = 1; - return TRUE; + return true; } in_attr = elf_known_obj_attributes_proc (ibfd); @@ -3663,7 +3686,7 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info) out_attr[Tag_RISCV_arch].s); if (merged_arch == NULL) { - result = FALSE; + result = false; out_attr[Tag_RISCV_arch].s = ""; } else @@ -3733,7 +3756,7 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info) out_attr[Tag_c].i = in_attr[Tag_c].i; } } - priv_attrs_merged = TRUE; + priv_attrs_merged = true; } break; @@ -3752,7 +3775,7 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info) (_("error: %pB use %u-byte stack aligned but the output " "use %u-byte stack aligned"), ibfd, in_attr[i].i, out_attr[i].i); - result = FALSE; + result = false; } break; @@ -3767,7 +3790,7 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info) /* Merge Tag_compatibility attributes and any common GNU ones. */ if (!_bfd_elf_merge_object_attributes (ibfd, info)) - return FALSE; + return false; /* Check for any attributes not known on RISC-V. */ result &= _bfd_elf_merge_unknown_attribute_list (ibfd, obfd); @@ -3778,14 +3801,14 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info) /* Merge backend specific data from an object file to the output object file when linking. */ -static bfd_boolean +static bool _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) { bfd *obfd = info->output_bfd; flagword new_flags, old_flags; if (!is_riscv_elf (ibfd) || !is_riscv_elf (obfd)) - return TRUE; + return true; if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0) { @@ -3793,14 +3816,14 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) (_("%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; + return false; } if (!_bfd_elf_merge_object_attributes (ibfd, info)) - return FALSE; + return false; if (!riscv_merge_attributes (ibfd, info)) - return FALSE; + return false; /* Check to see if the input BFD actually contains any sections. If not, its flags may not have been initialized either, but it cannot actually @@ -3811,25 +3834,25 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) case, there is no need to check for code specific flags. */ if (!(ibfd->flags & DYNAMIC)) { - bfd_boolean null_input_bfd = TRUE; - bfd_boolean only_data_sections = TRUE; + bool null_input_bfd = true; + bool only_data_sections = true; asection *sec; for (sec = ibfd->sections; sec != NULL; sec = sec->next) { - null_input_bfd = FALSE; + null_input_bfd = false; if ((bfd_section_flags (sec) & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) { - only_data_sections = FALSE; + only_data_sections = false; break; } } if (null_input_bfd || only_data_sections) - return TRUE; + return true; } new_flags = elf_elfheader (ibfd)->e_flags; @@ -3837,9 +3860,9 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) if (!elf_flags_init (obfd)) { - elf_flags_init (obfd) = TRUE; + elf_flags_init (obfd) = true; elf_elfheader (obfd)->e_flags = new_flags; - return TRUE; + return true; } /* Disallow linking different float ABIs. */ @@ -3863,120 +3886,11 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) /* Allow linking RVC and non-RVC, and keep the RVC flag. */ elf_elfheader (obfd)->e_flags |= new_flags & EF_RISCV_RVC; - return TRUE; + return true; fail: bfd_set_error (bfd_error_bad_value); - return FALSE; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count, - struct bfd_link_info *link_info) -{ - unsigned int i, symcount; - bfd_vma toaddr = sec->size; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd); - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - unsigned int sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - struct bfd_elf_section_data *data = elf_section_data (sec); - bfd_byte *contents = data->this_hdr.contents; - - /* Actually delete the bytes. */ - sec->size -= count; - memmove (contents + addr, contents + addr + count, toaddr - addr - count); - - /* Adjust the location of all of the relocs. Note that we need not - adjust the addends, since all PC-relative references must be against - symbols, which we will adjust below. */ - for (i = 0; i < sec->reloc_count; i++) - if (data->relocs[i].r_offset > addr && data->relocs[i].r_offset < toaddr) - data->relocs[i].r_offset -= count; - - /* Adjust the local symbols defined in this section. */ - for (i = 0; i < symtab_hdr->sh_info; i++) - { - Elf_Internal_Sym *sym = (Elf_Internal_Sym *) symtab_hdr->contents + i; - if (sym->st_shndx == sec_shndx) - { - /* If the symbol is in the range of memory we just moved, we - have to adjust its value. */ - if (sym->st_value > addr && sym->st_value <= toaddr) - sym->st_value -= 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. - - 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; - } - } - - /* Now adjust the global symbols defined in this section. */ - symcount = ((symtab_hdr->sh_size / sizeof (ElfNN_External_Sym)) - - symtab_hdr->sh_info); - - for (i = 0; i < symcount; i++) - { - struct elf_link_hash_entry *sym_hash = sym_hashes[i]; - - /* The '--wrap SYMBOL' option is causing a pain when the object file, - containing the definition of __wrap_SYMBOL, includes a direct - 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. - - 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; - - /* Loop only over the symbols which have already been checked. */ - for (cur_sym_hashes = sym_hashes; cur_sym_hashes < &sym_hashes[i]; - cur_sym_hashes++) - { - /* If the current symbol is identical to 'sym_hash', that means - the symbol was already adjusted (or at least checked). */ - if (*cur_sym_hashes == sym_hash) - break; - } - /* Don't adjust the symbol again. */ - if (cur_sym_hashes < &sym_hashes[i]) - continue; - } - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec) - { - /* As above, adjust the value if needed. */ - if (sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value <= toaddr) - sym_hash->root.u.def.value -= count; - - /* As above, adjust the size if needed. */ - 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; - } - } - - return TRUE; + return false; } /* A second format for recording PC-relative hi relocations. This stores the @@ -3990,7 +3904,7 @@ struct riscv_pcgp_hi_reloc bfd_vma hi_addr; unsigned hi_sym; asection *sym_sec; - bfd_boolean undefined_weak; + bool undefined_weak; riscv_pcgp_hi_reloc *next; }; @@ -4009,12 +3923,12 @@ typedef struct /* Initialize the pcgp reloc info in P. */ -static bfd_boolean +static bool riscv_init_pcgp_relocs (riscv_pcgp_relocs *p) { p->hi = NULL; p->lo = NULL; - return TRUE; + return true; } /* Free the pcgp reloc info in P. */ @@ -4046,15 +3960,15 @@ riscv_free_pcgp_relocs (riscv_pcgp_relocs *p, The HI_ADDEND, HI_ADDR, HI_SYM, and SYM_SEC args contain info required to relax the corresponding lo part reloc. */ -static bfd_boolean +static bool riscv_record_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off, bfd_vma hi_addend, bfd_vma hi_addr, unsigned hi_sym, asection *sym_sec, - bfd_boolean undefined_weak) + bool undefined_weak) { riscv_pcgp_hi_reloc *new = bfd_malloc (sizeof (*new)); if (!new) - return FALSE; + return false; new->hi_sec_off = hi_sec_off; new->hi_addend = hi_addend; new->hi_addr = hi_addr; @@ -4063,7 +3977,7 @@ riscv_record_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off, new->undefined_weak = undefined_weak; new->next = p->hi; p->hi = new; - return TRUE; + return true; } /* Look up hi part pcgp reloc info in P, using HI_SEC_OFF as the lookup index. @@ -4083,55 +3997,204 @@ riscv_find_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off) /* Record pcgp lo part reloc info in P, using HI_SEC_OFF as the lookup info. This is used to record relocs that can't be relaxed. */ -static bfd_boolean +static bool riscv_record_pcgp_lo_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off) { riscv_pcgp_lo_reloc *new = bfd_malloc (sizeof (*new)); if (!new) - return FALSE; + return false; new->hi_sec_off = hi_sec_off; new->next = p->lo; p->lo = new; - return TRUE; + return true; } /* Look up lo part pcgp reloc info in P, using HI_SEC_OFF as the lookup index. This is used by a hi part reloc to find the corresponding lo part reloc. */ -static bfd_boolean +static bool riscv_find_pcgp_lo_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off) { riscv_pcgp_lo_reloc *c; for (c = p->lo; c != NULL; c = c->next) if (c->hi_sec_off == hi_sec_off) - return TRUE; - return FALSE; + return true; + return false; +} + +static void +riscv_update_pcgp_relocs (riscv_pcgp_relocs *p, asection *deleted_sec, + bfd_vma deleted_addr, size_t deleted_count) +{ + /* Bytes have already been deleted and toaddr should match the old section + size for our checks, so adjust it here. */ + bfd_vma toaddr = deleted_sec->size + deleted_count; + riscv_pcgp_lo_reloc *l; + riscv_pcgp_hi_reloc *h; + + /* Update section offsets of corresponding pcrel_hi relocs for the pcrel_lo + entries where they occur after the deleted bytes. */ + for (l = p->lo; l != NULL; l = l->next) + if (l->hi_sec_off > deleted_addr + && l->hi_sec_off < toaddr) + l->hi_sec_off -= deleted_count; + + /* Update both section offsets, and symbol values of pcrel_hi relocs where + these values occur after the deleted bytes. */ + for (h = p->hi; h != NULL; h = h->next) + { + if (h->hi_sec_off > deleted_addr + && h->hi_sec_off < toaddr) + h->hi_sec_off -= deleted_count; + if (h->sym_sec == deleted_sec + && h->hi_addr > deleted_addr + && h->hi_addr < toaddr) + h->hi_addr -= deleted_count; + } +} + +/* Delete some bytes from a section while relaxing. */ + +static bool +riscv_relax_delete_bytes (bfd *abfd, + asection *sec, + bfd_vma addr, + size_t count, + struct bfd_link_info *link_info, + riscv_pcgp_relocs *p) +{ + unsigned int i, symcount; + bfd_vma toaddr = sec->size; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd); + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + unsigned int sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + struct bfd_elf_section_data *data = elf_section_data (sec); + bfd_byte *contents = data->this_hdr.contents; + + /* Actually delete the bytes. */ + sec->size -= count; + memmove (contents + addr, contents + addr + count, toaddr - addr - count); + + /* Adjust the location of all of the relocs. Note that we need not + adjust the addends, since all PC-relative references must be against + symbols, which we will adjust below. */ + for (i = 0; i < sec->reloc_count; i++) + if (data->relocs[i].r_offset > addr && data->relocs[i].r_offset < toaddr) + data->relocs[i].r_offset -= count; + + /* Adjust the hi_sec_off, and the hi_addr of any entries in the pcgp relocs + table for which these values occur after the deleted bytes. */ + if (p) + riscv_update_pcgp_relocs (p, sec, addr, count); + + /* Adjust the local symbols defined in this section. */ + for (i = 0; i < symtab_hdr->sh_info; i++) + { + Elf_Internal_Sym *sym = (Elf_Internal_Sym *) symtab_hdr->contents + i; + if (sym->st_shndx == sec_shndx) + { + /* If the symbol is in the range of memory we just moved, we + have to adjust its value. */ + if (sym->st_value > addr && sym->st_value <= toaddr) + sym->st_value -= 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. + + 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; + } + } + + /* Now adjust the global symbols defined in this section. */ + symcount = ((symtab_hdr->sh_size / sizeof (ElfNN_External_Sym)) + - symtab_hdr->sh_info); + + for (i = 0; i < symcount; i++) + { + struct elf_link_hash_entry *sym_hash = sym_hashes[i]; + + /* The '--wrap SYMBOL' option is causing a pain when the object file, + containing the definition of __wrap_SYMBOL, includes a direct + 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. + + 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 != unversioned) + { + struct elf_link_hash_entry **cur_sym_hashes; + + /* Loop only over the symbols which have already been checked. */ + for (cur_sym_hashes = sym_hashes; cur_sym_hashes < &sym_hashes[i]; + cur_sym_hashes++) + { + /* If the current symbol is identical to 'sym_hash', that means + the symbol was already adjusted (or at least checked). */ + if (*cur_sym_hashes == sym_hash) + break; + } + /* Don't adjust the symbol again. */ + if (cur_sym_hashes < &sym_hashes[i]) + continue; + } + + if ((sym_hash->root.type == bfd_link_hash_defined + || sym_hash->root.type == bfd_link_hash_defweak) + && sym_hash->root.u.def.section == sec) + { + /* As above, adjust the value if needed. */ + if (sym_hash->root.u.def.value > addr + && sym_hash->root.u.def.value <= toaddr) + sym_hash->root.u.def.value -= count; + + /* As above, adjust the size if needed. */ + 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; + } + } + + return true; } -typedef bfd_boolean (*relax_func_t) (bfd *, asection *, asection *, - struct bfd_link_info *, - Elf_Internal_Rela *, - bfd_vma, bfd_vma, bfd_vma, bfd_boolean *, - riscv_pcgp_relocs *, - bfd_boolean undefined_weak); +typedef bool (*relax_func_t) (bfd *, asection *, asection *, + struct bfd_link_info *, + Elf_Internal_Rela *, + bfd_vma, bfd_vma, bfd_vma, bool *, + riscv_pcgp_relocs *, + bool undefined_weak); /* Relax AUIPC + JALR into JAL. */ -static bfd_boolean +static bool _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec, struct bfd_link_info *link_info, Elf_Internal_Rela *rel, bfd_vma symval, bfd_vma max_alignment, bfd_vma reserve_size ATTRIBUTE_UNUSED, - bfd_boolean *again, - riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED, - bfd_boolean undefined_weak ATTRIBUTE_UNUSED) + bool *again, + riscv_pcgp_relocs *pcgp_relocs, + bool undefined_weak ATTRIBUTE_UNUSED) { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; bfd_vma foff = symval - (sec_addr (sec) + rel->r_offset); - bfd_boolean near_zero = (symval + RISCV_IMM_REACH / 2) < RISCV_IMM_REACH; + bool near_zero = (symval + RISCV_IMM_REACH / 2) < RISCV_IMM_REACH; bfd_vma auipc, jalr; int rd, r_type, len = 4, rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC; @@ -4149,7 +4212,7 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec, /* See if this function call can be shortened. */ if (!VALID_JTYPE_IMM (foff) && !(!bfd_link_pic (link_info) && near_zero)) - return TRUE; + return true; /* Shorten the function call. */ BFD_ASSERT (rel->r_offset + 8 <= sec->size); @@ -4188,9 +4251,9 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec, riscv_put_insn (8 * len, auipc, contents + rel->r_offset); /* Delete unnecessary JALR. */ - *again = TRUE; + *again = true; return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + len, 8 - len, - link_info); + link_info, pcgp_relocs); } /* Traverse all output sections and return the max alignment. */ @@ -4212,7 +4275,7 @@ _bfd_riscv_get_max_alignment (asection *sec) /* Relax non-PIC global variable references to GP-relative references. */ -static bfd_boolean +static bool _bfd_riscv_relax_lui (bfd *abfd, asection *sec, asection *sym_sec, @@ -4221,9 +4284,9 @@ _bfd_riscv_relax_lui (bfd *abfd, bfd_vma symval, bfd_vma max_alignment, bfd_vma reserve_size, - bfd_boolean *again, - riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED, - bfd_boolean undefined_weak) + bool *again, + riscv_pcgp_relocs *pcgp_relocs, + bool undefined_weak) { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; bfd_vma gp = riscv_global_pointer_value (link_info); @@ -4236,8 +4299,8 @@ _bfd_riscv_relax_lui (bfd *abfd, /* If gp and the symbol are in the same output section, which is not the abs section, then consider only that output section's alignment. */ struct bfd_link_hash_entry *h = - bfd_link_hash_lookup (link_info->hash, RISCV_GP_SYMBOL, FALSE, FALSE, - TRUE); + bfd_link_hash_lookup (link_info->hash, RISCV_GP_SYMBOL, false, false, + true); if (h->u.def.section->output_section == sym_sec->output_section && sym_sec->output_section != bfd_abs_section_ptr) max_alignment = (bfd_vma) 1 << sym_sec->output_section->alignment_power; @@ -4265,7 +4328,7 @@ _bfd_riscv_relax_lui (bfd *abfd, } else rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I); - return TRUE; + return true; case R_RISCV_LO12_S: if (undefined_weak) @@ -4277,14 +4340,14 @@ _bfd_riscv_relax_lui (bfd *abfd, } else rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S); - return TRUE; + return true; case R_RISCV_HI20: /* We can delete the unnecessary LUI and reloc. */ rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); - *again = TRUE; + *again = true; return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4, - link_info); + link_info, pcgp_relocs); default: abort (); @@ -4307,7 +4370,7 @@ _bfd_riscv_relax_lui (bfd *abfd, bfd_vma lui = bfd_getl32 (contents + rel->r_offset); unsigned rd = ((unsigned)lui >> OP_SH_RD) & OP_MASK_RD; if (rd == 0 || rd == X_SP) - return TRUE; + return true; lui = (lui & (OP_MASK_RD << OP_SH_RD)) | MATCH_C_LUI; bfd_putl32 (lui, contents + rel->r_offset); @@ -4315,17 +4378,17 @@ _bfd_riscv_relax_lui (bfd *abfd, /* Replace the R_RISCV_HI20 reloc. */ rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), R_RISCV_RVC_LUI); - *again = TRUE; + *again = true; return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + 2, 2, - link_info); + link_info, pcgp_relocs); } - return TRUE; + return true; } /* Relax non-PIC TLS references to TP-relative references. */ -static bfd_boolean +static bool _bfd_riscv_relax_tls_le (bfd *abfd, asection *sec, asection *sym_sec ATTRIBUTE_UNUSED, @@ -4334,40 +4397,42 @@ _bfd_riscv_relax_tls_le (bfd *abfd, bfd_vma symval, bfd_vma max_alignment ATTRIBUTE_UNUSED, bfd_vma reserve_size ATTRIBUTE_UNUSED, - bfd_boolean *again, - riscv_pcgp_relocs *prcel_relocs ATTRIBUTE_UNUSED, - bfd_boolean undefined_weak ATTRIBUTE_UNUSED) + bool *again, + riscv_pcgp_relocs *pcgp_relocs, + bool undefined_weak ATTRIBUTE_UNUSED) { /* See if this symbol is in range of tp. */ if (RISCV_CONST_HIGH_PART (tpoff (link_info, symval)) != 0) - return TRUE; + return true; BFD_ASSERT (rel->r_offset + 4 <= sec->size); switch (ELFNN_R_TYPE (rel->r_info)) { case R_RISCV_TPREL_LO12_I: rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), R_RISCV_TPREL_I); - return TRUE; + return true; case R_RISCV_TPREL_LO12_S: rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), R_RISCV_TPREL_S); - return TRUE; + return true; case R_RISCV_TPREL_HI20: case R_RISCV_TPREL_ADD: /* We can delete the unnecessary instruction and reloc. */ rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); - *again = TRUE; - return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4, link_info); + *again = true; + return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4, link_info, + pcgp_relocs); default: abort (); } } -/* Implement R_RISCV_ALIGN by deleting excess alignment NOPs. */ +/* Implement R_RISCV_ALIGN by deleting excess alignment NOPs. + Once we've handled an R_RISCV_ALIGN, we can't relax anything else. */ -static bfd_boolean +static bool _bfd_riscv_relax_align (bfd *abfd, asection *sec, asection *sym_sec, struct bfd_link_info *link_info, @@ -4375,9 +4440,9 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec, bfd_vma symval, bfd_vma max_alignment ATTRIBUTE_UNUSED, bfd_vma reserve_size ATTRIBUTE_UNUSED, - bfd_boolean *again ATTRIBUTE_UNUSED, - riscv_pcgp_relocs *pcrel_relocs ATTRIBUTE_UNUSED, - bfd_boolean undefined_weak ATTRIBUTE_UNUSED) + bool *again ATTRIBUTE_UNUSED, + riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED, + bool undefined_weak ATTRIBUTE_UNUSED) { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; bfd_vma alignment = 1, pos; @@ -4389,7 +4454,7 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec, bfd_vma nop_bytes = aligned_addr - symval; /* Once we've handled an R_RISCV_ALIGN, we can't relax anything else. */ - sec->sec_flg0 = TRUE; + sec->sec_flg0 = true; /* Make sure there are enough NOPs to actually achieve the alignment. */ if (rel->r_addend < nop_bytes) @@ -4400,7 +4465,7 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec, 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; + return false; } /* Delete the reloc. */ @@ -4408,7 +4473,7 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec, /* If the number of NOPs is already correct, there's nothing to do. */ if (nop_bytes == rel->r_addend) - return TRUE; + return true; /* Write as many RISC-V NOPs as we need. */ for (pos = 0; pos < (nop_bytes & -4); pos += 4) @@ -4420,12 +4485,13 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec, /* Delete the excess bytes. */ return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + nop_bytes, - rel->r_addend - nop_bytes, link_info); + rel->r_addend - nop_bytes, link_info, + NULL); } /* Relax PC-relative references to GP-relative references. */ -static bfd_boolean +static bool _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, asection *sym_sec, @@ -4434,9 +4500,9 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, bfd_vma symval, bfd_vma max_alignment, bfd_vma reserve_size, - bfd_boolean *again ATTRIBUTE_UNUSED, + bool *again ATTRIBUTE_UNUSED, riscv_pcgp_relocs *pcgp_relocs, - bfd_boolean undefined_weak) + bool undefined_weak) { bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; bfd_vma gp = riscv_global_pointer_value (link_info); @@ -4462,7 +4528,7 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, if (hi == NULL) { riscv_record_pcgp_lo_reloc (pcgp_relocs, hi_sec_off); - return TRUE; + return true; } hi_reloc = *hi; @@ -4481,12 +4547,12 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, /* Mergeable symbols and code might later move out of range. */ if (! undefined_weak && sym_sec->flags & (SEC_MERGE | SEC_CODE)) - return TRUE; + return true; /* If the cooresponding lo relocation has already been seen then it's not safe to relax this relocation. */ if (riscv_find_pcgp_lo_reloc (pcgp_relocs, rel->r_offset)) - return TRUE; + return true; break; @@ -4499,8 +4565,8 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, /* If gp and the symbol are in the same output section, which is not the abs section, then consider only that output section's alignment. */ struct bfd_link_hash_entry *h = - bfd_link_hash_lookup (link_info->hash, RISCV_GP_SYMBOL, FALSE, FALSE, - TRUE); + bfd_link_hash_lookup (link_info->hash, RISCV_GP_SYMBOL, false, false, + true); if (h->u.def.section->output_section == sym_sec->output_section && sym_sec->output_section != bfd_abs_section_ptr) max_alignment = (bfd_vma) 1 << sym_sec->output_section->alignment_power; @@ -4534,7 +4600,7 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I); rel->r_addend += hi_reloc.hi_addend; } - return TRUE; + return true; case R_RISCV_PCREL_LO12_S: if (undefined_weak) @@ -4552,7 +4618,7 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_S); rel->r_addend += hi_reloc.hi_addend; } - return TRUE; + return true; case R_RISCV_PCREL_HI20: riscv_record_pcgp_hi_reloc (pcgp_relocs, @@ -4565,19 +4631,19 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, /* We can delete the unnecessary AUIPC and reloc. */ rel->r_info = ELFNN_R_INFO (0, R_RISCV_DELETE); rel->r_addend = 4; - return TRUE; + return true; default: abort (); } } - return TRUE; + return true; } /* Delete the bytes for R_RISCV_DELETE. */ -static bfd_boolean +static bool _bfd_riscv_relax_delete (bfd *abfd, asection *sec, asection *sym_sec ATTRIBUTE_UNUSED, @@ -4586,47 +4652,60 @@ _bfd_riscv_relax_delete (bfd *abfd, bfd_vma symval ATTRIBUTE_UNUSED, bfd_vma max_alignment ATTRIBUTE_UNUSED, bfd_vma reserve_size ATTRIBUTE_UNUSED, - bfd_boolean *again ATTRIBUTE_UNUSED, + bool *again ATTRIBUTE_UNUSED, riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED, - bfd_boolean undefined_weak ATTRIBUTE_UNUSED) + bool undefined_weak ATTRIBUTE_UNUSED) { if (!riscv_relax_delete_bytes (abfd, sec, rel->r_offset, rel->r_addend, - link_info)) - return FALSE; + link_info, NULL)) + return false; rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); - return TRUE; + return true; +} + +/* Called by after_allocation to set the information of data segment + before relaxing. */ + +void +bfd_elfNN_riscv_set_data_segment_info (struct bfd_link_info *info, + int *data_segment_phase) +{ + struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); + htab->data_segment_phase = data_segment_phase; } /* Relax a section. - Pass 0: Shortens code sequences for LUI/CALL/TPREL relocs. - Pass 1: Shortens code sequences for PCREL relocs. - Pass 2: Deletes the bytes that pass 1 made obselete. - Pass 3: Which cannot be disabled, handles code alignment directives. */ + Pass 0: Shortens code sequences for LUI/CALL/TPREL/PCREL relocs. + Pass 1: Deletes the bytes that PCREL relaxation in pass 0 made obsolete. + Pass 2: Which cannot be disabled, handles code alignment directives. */ -static bfd_boolean +static bool _bfd_riscv_relax_section (bfd *abfd, asection *sec, struct bfd_link_info *info, - bfd_boolean *again) + bool *again) { Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd); struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); struct bfd_elf_section_data *data = elf_section_data (sec); Elf_Internal_Rela *relocs; - bfd_boolean ret = FALSE; + bool ret = false; unsigned int i; bfd_vma max_alignment, reserve_size = 0; riscv_pcgp_relocs pcgp_relocs; - *again = FALSE; + *again = false; if (bfd_link_relocatable (info) || sec->sec_flg0 || (sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0 || (info->disable_target_specific_optimizations - && info->relax_pass < 2)) - return TRUE; + && info->relax_pass == 0) + /* The exp_seg_relro_adjust is enum phase_enum (0x4), + and defined in ld/ldexp.h. */ + || *(htab->data_segment_phase) == 4) + return true; riscv_init_pcgp_relocs (&pcgp_relocs); @@ -4658,7 +4737,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, int type = ELFNN_R_TYPE (rel->r_info); bfd_vma symval; char symtype; - bfd_boolean undefined_weak = FALSE; + bool undefined_weak = false; relax_func = NULL; if (info->relax_pass == 0) @@ -4675,24 +4754,14 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, || type == R_RISCV_TPREL_LO12_I || type == R_RISCV_TPREL_LO12_S) relax_func = _bfd_riscv_relax_tls_le; + else if (!bfd_link_pic (info) + && (type == R_RISCV_PCREL_HI20 + || type == R_RISCV_PCREL_LO12_I + || type == R_RISCV_PCREL_LO12_S)) + relax_func = _bfd_riscv_relax_pc; else continue; - } - else if (info->relax_pass == 1 - && !bfd_link_pic (info) - && (type == R_RISCV_PCREL_HI20 - || type == R_RISCV_PCREL_LO12_I - || type == R_RISCV_PCREL_LO12_S)) - relax_func = _bfd_riscv_relax_pc; - else if (info->relax_pass == 2 && type == R_RISCV_DELETE) - relax_func = _bfd_riscv_relax_delete; - else if (info->relax_pass == 3 && type == R_RISCV_ALIGN) - relax_func = _bfd_riscv_relax_align; - else - continue; - if (info->relax_pass < 2) - { /* Only relax this reloc if it is paired with R_RISCV_RELAX. */ if (i == sec->reloc_count - 1 || ELFNN_R_TYPE ((rel + 1)->r_info) != R_RISCV_RELAX @@ -4702,6 +4771,12 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, /* Skip over the R_RISCV_RELAX. */ i++; } + else if (info->relax_pass == 1 && type == R_RISCV_DELETE) + relax_func = _bfd_riscv_relax_delete; + else if (info->relax_pass == 2 && type == R_RISCV_ALIGN) + relax_func = _bfd_riscv_relax_align; + else + continue; data->relocs = relocs; @@ -4785,7 +4860,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, libraries can not happen currently. Once we support the auipc relaxations when creating shared libraries, then we will need the more rigorous checking for this optimization. */ - undefined_weak = TRUE; + undefined_weak = true; } /* This line has to match the check in riscv_elf_relocate_section @@ -4857,7 +4932,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, goto fail; } - ret = TRUE; + ret = true; fail: if (relocs != data->relocs) @@ -4877,6 +4952,8 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, # define PRPSINFO_OFFSET_PR_PID 16 # define PRPSINFO_OFFSET_PR_FNAME 32 # define PRPSINFO_OFFSET_PR_PSARGS 48 +# define PRPSINFO_PR_FNAME_LENGTH 16 +# define PRPSINFO_PR_PSARGS_LENGTH 80 #else # define PRSTATUS_SIZE 376 # define PRSTATUS_OFFSET_PR_CURSIG 12 @@ -4887,17 +4964,92 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, # define PRPSINFO_OFFSET_PR_PID 24 # define PRPSINFO_OFFSET_PR_FNAME 40 # define PRPSINFO_OFFSET_PR_PSARGS 56 +# define PRPSINFO_PR_FNAME_LENGTH 16 +# define PRPSINFO_PR_PSARGS_LENGTH 80 #endif +/* Write PRSTATUS and PRPSINFO note into core file. This will be called + before the generic code in elf.c. By checking the compiler defines we + only perform any action here if the generic code would otherwise not be + able to help us. The intention is that bare metal core dumps (where the + prstatus_t and/or prpsinfo_t might not be available) will use this code, + while non bare metal tools will use the generic elf code. */ + +static char * +riscv_write_core_note (bfd *abfd ATTRIBUTE_UNUSED, + char *buf ATTRIBUTE_UNUSED, + int *bufsiz ATTRIBUTE_UNUSED, + int note_type ATTRIBUTE_UNUSED, ...) +{ + switch (note_type) + { + default: + return NULL; + +#if !defined (HAVE_PRPSINFO_T) + case NT_PRPSINFO: + { + char data[PRPSINFO_SIZE] ATTRIBUTE_NONSTRING; + va_list ap; + + va_start (ap, note_type); + memset (data, 0, sizeof (data)); + strncpy (data + PRPSINFO_OFFSET_PR_FNAME, va_arg (ap, const char *), + PRPSINFO_PR_FNAME_LENGTH); +#if GCC_VERSION == 8000 || GCC_VERSION == 8001 + DIAGNOSTIC_PUSH; + /* GCC 8.0 and 8.1 warn about 80 equals destination size with + -Wstringop-truncation: + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643 + */ + DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION; +#endif + strncpy (data + PRPSINFO_OFFSET_PR_PSARGS, va_arg (ap, const char *), + PRPSINFO_PR_PSARGS_LENGTH); +#if GCC_VERSION == 8000 || GCC_VERSION == 8001 + DIAGNOSTIC_POP; +#endif + va_end (ap); + return elfcore_write_note (abfd, buf, bufsiz, + "CORE", note_type, data, sizeof (data)); + } +#endif /* !HAVE_PRPSINFO_T */ + +#if !defined (HAVE_PRSTATUS_T) + case NT_PRSTATUS: + { + char data[PRSTATUS_SIZE]; + va_list ap; + long pid; + int cursig; + const void *greg; + + va_start (ap, note_type); + memset (data, 0, sizeof(data)); + pid = va_arg (ap, long); + bfd_put_32 (abfd, pid, data + PRSTATUS_OFFSET_PR_PID); + cursig = va_arg (ap, int); + bfd_put_16 (abfd, cursig, data + PRSTATUS_OFFSET_PR_CURSIG); + greg = va_arg (ap, const void *); + memcpy (data + PRSTATUS_OFFSET_PR_REG, greg, + PRSTATUS_SIZE - PRSTATUS_OFFSET_PR_REG - ARCH_SIZE / 8); + va_end (ap); + return elfcore_write_note (abfd, buf, bufsiz, + "CORE", note_type, data, sizeof (data)); + } +#endif /* !HAVE_PRSTATUS_T */ + } +} + /* Support for core dump NOTE sections. */ -static bfd_boolean +static bool riscv_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) { switch (note->descsz) { default: - return FALSE; + return false; case PRSTATUS_SIZE: /* sizeof(struct elf_prstatus) on Linux/RISC-V. */ /* pr_cursig */ @@ -4915,13 +5067,13 @@ riscv_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) note->descpos + PRSTATUS_OFFSET_PR_REG); } -static bfd_boolean +static bool riscv_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) { switch (note->descsz) { default: - return FALSE; + return false; case PRPSINFO_SIZE: /* sizeof(struct elf_prpsinfo) on Linux/RISC-V. */ /* pr_pid */ @@ -4930,11 +5082,13 @@ riscv_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) /* pr_fname */ elf_tdata (abfd)->core->program = _bfd_elfcore_strndup - (abfd, note->descdata + PRPSINFO_OFFSET_PR_FNAME, 16); + (abfd, note->descdata + PRPSINFO_OFFSET_PR_FNAME, + PRPSINFO_PR_FNAME_LENGTH); /* pr_psargs */ elf_tdata (abfd)->core->command = _bfd_elfcore_strndup - (abfd, note->descdata + PRPSINFO_OFFSET_PR_PSARGS, 80); + (abfd, note->descdata + PRPSINFO_OFFSET_PR_PSARGS, + PRPSINFO_PR_PSARGS_LENGTH); break; } @@ -4950,12 +5104,12 @@ riscv_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) command[n - 1] = '\0'; } - return TRUE; + return true; } /* Set the right mach type. */ -static bfd_boolean +static bool riscv_elf_object_p (bfd *abfd) { /* There are only two mach types in RISCV currently. */ @@ -4965,7 +5119,7 @@ riscv_elf_object_p (bfd *abfd) else bfd_default_set_arch_mach (abfd, bfd_arch_riscv, bfd_mach_riscv64); - return TRUE; + return true; } /* Determine whether an object attribute tag takes an integer, a @@ -4977,6 +5131,113 @@ riscv_elf_obj_attrs_arg_type (int tag) return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL; } +/* Do not choose mapping symbols as a function name. */ + +static bfd_size_type +riscv_maybe_function_sym (const asymbol *sym, + asection *sec, + bfd_vma *code_off) +{ + if (sym->flags & BSF_LOCAL + && riscv_elf_is_mapping_symbols (sym->name)) + return 0; + + return _bfd_elf_maybe_function_sym (sym, sec, code_off); +} + +/* Treat the following cases as target special symbols, they are + usually omitted. */ + +static bool +riscv_elf_is_target_special_symbol (bfd *abfd, asymbol *sym) +{ + /* PR27584, local and empty symbols. Since they are usually + generated for pcrel relocations. */ + return (!strcmp (sym->name, "") + || _bfd_elf_is_local_label_name (abfd, sym->name) + /* PR27916, mapping symbols. */ + || riscv_elf_is_mapping_symbols (sym->name)); +} + +static int +riscv_elf_additional_program_headers (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + int ret = 0; + + /* See if we need a PT_RISCV_ATTRIBUTES segment. */ + if (bfd_get_section_by_name (abfd, RISCV_ATTRIBUTES_SECTION_NAME)) + ++ret; + + return ret; +} + +static bool +riscv_elf_modify_segment_map (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + asection *s; + struct elf_segment_map *m, **pm; + size_t amt; + + /* If there is a .riscv.attributes section, we need a PT_RISCV_ATTRIBUTES + segment. */ + s = bfd_get_section_by_name (abfd, RISCV_ATTRIBUTES_SECTION_NAME); + if (s != NULL) + { + for (m = elf_seg_map (abfd); m != NULL; m = m->next) + if (m->p_type == PT_RISCV_ATTRIBUTES) + break; + /* If there is already a PT_RISCV_ATTRIBUTES header, avoid adding + another. */ + if (m == NULL) + { + amt = sizeof (*m); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + return false; + + m->p_type = PT_RISCV_ATTRIBUTES; + m->count = 1; + m->sections[0] = s; + + /* We want to put it after the PHDR and INTERP segments. */ + pm = &elf_seg_map (abfd); + while (*pm != NULL + && ((*pm)->p_type == PT_PHDR + || (*pm)->p_type == PT_INTERP)) + pm = &(*pm)->next; + + m->next = *pm; + *pm = m; + } + } + + return true; +} + +/* Merge non-visibility st_other attributes. */ + +static void +riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, + unsigned int st_other, + bool definition ATTRIBUTE_UNUSED, + bool dynamic ATTRIBUTE_UNUSED) +{ + unsigned int isym_sto = st_other & ~ELF_ST_VISIBILITY (-1); + unsigned int h_sto = h->other & ~ELF_ST_VISIBILITY (-1); + + if (isym_sto == h_sto) + return; + + if (isym_sto & ~STO_RISCV_VARIANT_CC) + _bfd_error_handler (_("unknown attribute for symbol `%s': 0x%02x"), + h->root.root.string, isym_sto); + + if (isym_sto & STO_RISCV_VARIANT_CC) + h->other |= STO_RISCV_VARIANT_CC; +} + #define TARGET_LITTLE_SYM riscv_elfNN_vec #define TARGET_LITTLE_NAME "elfNN-littleriscv" #define TARGET_BIG_SYM riscv_elfNN_be_vec @@ -4989,6 +5250,7 @@ riscv_elf_obj_attrs_arg_type (int tag) #define bfd_elfNN_bfd_reloc_type_lookup riscv_reloc_type_lookup #define bfd_elfNN_bfd_merge_private_bfd_data \ _bfd_riscv_elf_merge_private_bfd_data +#define bfd_elfNN_bfd_is_target_special_symbol riscv_elf_is_target_special_symbol #define elf_backend_copy_indirect_symbol riscv_elf_copy_indirect_symbol #define elf_backend_create_dynamic_sections riscv_elf_create_dynamic_sections @@ -5003,10 +5265,16 @@ riscv_elf_obj_attrs_arg_type (int tag) #define elf_backend_grok_prstatus riscv_elf_grok_prstatus #define elf_backend_grok_psinfo riscv_elf_grok_psinfo #define elf_backend_object_p riscv_elf_object_p +#define elf_backend_write_core_note riscv_write_core_note +#define elf_backend_maybe_function_sym riscv_maybe_function_sym #define elf_info_to_howto_rel NULL #define elf_info_to_howto riscv_info_to_howto_rela #define bfd_elfNN_bfd_relax_section _bfd_riscv_relax_section #define bfd_elfNN_mkobject elfNN_riscv_mkobject +#define elf_backend_additional_program_headers \ + riscv_elf_additional_program_headers +#define elf_backend_modify_segment_map riscv_elf_modify_segment_map +#define elf_backend_merge_symbol_attribute riscv_elf_merge_symbol_attribute #define elf_backend_init_index_section _bfd_elf_init_1_index_section @@ -5028,6 +5296,6 @@ riscv_elf_obj_attrs_arg_type (int tag) #undef elf_backend_obj_attrs_section_type #define elf_backend_obj_attrs_section_type SHT_RISCV_ATTRIBUTES #undef elf_backend_obj_attrs_section -#define elf_backend_obj_attrs_section ".riscv.attributes" +#define elf_backend_obj_attrs_section RISCV_ATTRIBUTES_SECTION_NAME #include "elfNN-target.h"