X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felfnn-riscv.c;h=00553f774644d98ac30a2c358014c9a1c0b98137;hb=2e573c0a3f9de232587f75de0af765abb8e193b9;hp=4ffe6a36e68f6c6c8e2301627dceedfef908f2db;hpb=9d1da81b261a20050ef2ad01a5b4c8cf78404222;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 4ffe6a36e6..00553f7746 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-2019 Free Software Foundation, Inc. + Copyright (C) 2011-2020 Free Software Foundation, Inc. Contributed by Andrew Waterman (andrew@sifive.com). Based on TILE-Gx and MIPS targets. @@ -61,9 +61,6 @@ struct riscv_elf_link_hash_entry { struct elf_link_hash_entry elf; - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - #define GOT_UNKNOWN 0 #define GOT_NORMAL 1 #define GOT_TLS_GD 2 @@ -98,6 +95,14 @@ struct _bfd_riscv_elf_obj_tdata && elf_tdata (bfd) != NULL \ && elf_object_id (bfd) == RISCV_ELF_DATA) +static bfd_boolean +elfNN_riscv_mkobject (bfd *abfd) +{ + return bfd_elf_allocate_object (abfd, + sizeof (struct _bfd_riscv_elf_obj_tdata), + RISCV_ELF_DATA); +} + #include "elf/common.h" #include "elf/internal.h" @@ -256,7 +261,6 @@ link_hash_newfunc (struct bfd_hash_entry *entry, struct riscv_elf_link_hash_entry *eh; eh = (struct riscv_elf_link_hash_entry *) entry; - eh->dyn_relocs = NULL; eh->tls_type = GOT_UNKNOWN; } @@ -269,7 +273,7 @@ static struct bfd_link_hash_table * riscv_elf_link_hash_table_create (bfd *abfd) { struct riscv_elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct riscv_elf_link_hash_table); + size_t amt = sizeof (struct riscv_elf_link_hash_table); ret = (struct riscv_elf_link_hash_table *) bfd_zmalloc (amt); if (ret == NULL) @@ -411,37 +415,6 @@ riscv_elf_copy_indirect_symbol (struct bfd_link_info *info, edir = (struct riscv_elf_link_hash_entry *) dir; eind = (struct riscv_elf_link_hash_entry *) ind; - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_dyn_relocs *p; - - /* Add reloc counts against the indirect sym to the direct sym - list. Merge any entries against the same section. */ - for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) - { - struct elf_dyn_relocs *q; - - for (q = edir->dyn_relocs; q != NULL; q = q->next) - if (q->sec == p->sec) - { - q->pc_count += p->pc_count; - q->count += p->count; - *pp = p->next; - break; - } - if (q == NULL) - pp = &p->next; - } - *pp = edir->dyn_relocs; - } - - edir->dyn_relocs = eind->dyn_relocs; - eind->dyn_relocs = NULL; - } - if (ind->root.type == bfd_link_hash_indirect && dir->got.refcount <= 0) { @@ -697,7 +670,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* If this is a global symbol, we count the number of relocations we need for this symbol. */ if (h != NULL) - head = &((struct riscv_elf_link_hash_entry *) h)->dyn_relocs; + head = &h->dyn_relocs; else { /* Track dynamic relocs needed for local syms too. @@ -724,7 +697,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, p = *head; if (p == NULL || p->sec != sec) { - bfd_size_type amt = sizeof *p; + size_t amt = sizeof *p; p = ((struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj, amt)); if (p == NULL) @@ -778,23 +751,6 @@ riscv_elf_gc_mark_hook (asection *sec, return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); } -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = riscv_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -883,7 +839,7 @@ riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info, /* If we don't find any dynamic relocs in read-only sections, then we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (!readonly_dynrelocs (h)) + if (!_bfd_elf_readonly_dynrelocs (h)) { h->non_got_ref = 0; return TRUE; @@ -936,7 +892,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { struct bfd_link_info *info; struct riscv_elf_link_hash_table *htab; - struct riscv_elf_link_hash_entry *eh; struct elf_dyn_relocs *p; if (h->root.type == bfd_link_hash_indirect) @@ -1045,8 +1000,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) else h->got.offset = (bfd_vma) -1; - eh = (struct riscv_elf_link_hash_entry *) h; - if (eh->dyn_relocs == NULL) + if (h->dyn_relocs == NULL) return TRUE; /* In the shared -Bsymbolic case, discard space allocated for @@ -1061,7 +1015,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { struct elf_dyn_relocs **pp; - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + for (pp = &h->dyn_relocs; (p = *pp) != NULL; ) { p->count -= p->pc_count; p->pc_count = 0; @@ -1074,12 +1028,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* Also discard relocs on undefined weak syms with non-default visibility. */ - if (eh->dyn_relocs != NULL + if (h->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak) { if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - eh->dyn_relocs = NULL; + h->dyn_relocs = NULL; /* Make sure undefined weak symbols are output as a dynamic symbol in PIEs. */ @@ -1119,13 +1073,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) goto keep; } - eh->dyn_relocs = NULL; + h->dyn_relocs = NULL; keep: ; } /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) + for (p = h->dyn_relocs; p != NULL; p = p->next) { asection *sreloc = elf_section_data (p->sec)->sreloc; sreloc->size += p->count * sizeof (ElfNN_External_Rela); @@ -1134,33 +1088,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) return TRUE; } -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%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. */ - return FALSE; - } - return TRUE; -} - static bfd_boolean riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { @@ -1367,7 +1294,8 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) /* If any dynamic relocs apply to a read-only section, then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info); + elf_link_hash_traverse (&htab->elf, + _bfd_elf_maybe_set_textrel, info); if (info->flags & DF_TEXTREL) { @@ -1787,6 +1715,7 @@ riscv_elf_relocate_section (bfd *output_bfd, 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; if (howto == NULL @@ -1986,10 +1915,11 @@ riscv_elf_relocate_section (bfd *output_bfd, break; case R_RISCV_CALL: + case R_RISCV_CALL_PLT: /* 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) + && (!bfd_link_pic (info) || h->plt.offset == MINUS_ONE)) { /* We can use x0 as the base register. */ bfd_vma insn = bfd_get_32 (input_bfd, @@ -2002,9 +1932,9 @@ riscv_elf_relocate_section (bfd *output_bfd, } /* Fall through. */ - case R_RISCV_CALL_PLT: case R_RISCV_JAL: case R_RISCV_RVC_JUMP: + /* This line has to match the check in _bfd_riscv_relax_section. */ if (bfd_link_pic (info) && h != NULL && h->plt.offset != MINUS_ONE) { /* Refer to the PLT entry. */ @@ -2088,6 +2018,7 @@ riscv_elf_relocate_section (bfd *output_bfd, || (h != NULL && h->type == STT_SECTION)) && rel->r_addend) { + msg = _("%pcrel_lo section symbol with an addend"); r = bfd_reloc_dangerous; break; } @@ -2302,24 +2233,42 @@ riscv_elf_relocate_section (bfd *output_bfd, && _bfd_elf_section_offset (output_bfd, info, input_section, rel->r_offset) != (bfd_vma) -1) { - (*_bfd_error_handler) - (_("%pB(%pA+%#" PRIx64 "): " - "unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - (uint64_t) rel->r_offset, - howto->name, - h->root.root.string); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - goto out; + switch (r_type) + { + case R_RISCV_CALL: + case R_RISCV_JAL: + case R_RISCV_RVC_JUMP: + if (asprintf (&msg_buf, + _("%%X%%P: relocation %s against `%s' can " + "not be used when making a shared object; " + "recompile with -fPIC\n"), + howto->name, + h->root.root.string) == -1) + msg_buf = NULL; + break; + + default: + if (asprintf (&msg_buf, + _("%%X%%P: unresolvable %s relocation against " + "symbol `%s'\n"), + howto->name, + h->root.root.string) == -1) + msg_buf = NULL; + break; + } + + msg = msg_buf; + r = bfd_reloc_notsupported; } if (r == bfd_reloc_ok) r = perform_relocation (howto, rel, relocation, input_section, input_bfd, contents); + /* We should have already detected the error and set message before. + If the error message isn't set since the linker runs out of memory + or we don't set it before, then we should set the default message + with the "internal error" string here. */ switch (r) { case bfd_reloc_ok: @@ -2338,17 +2287,21 @@ riscv_elf_relocate_section (bfd *output_bfd, break; case bfd_reloc_outofrange: - msg = _("%X%P: internal error: out of range error\n"); + if (msg == NULL) + msg = _("%X%P: internal error: out of range error\n"); break; case bfd_reloc_notsupported: - msg = _("%X%P: internal error: unsupported relocation error\n"); + if (msg == NULL) + msg = _("%X%P: internal error: unsupported relocation error\n"); break; case bfd_reloc_dangerous: + /* The error message should already be set. */ + if (msg == NULL) + msg = _("dangerous relocation error"); info->callbacks->reloc_dangerous - (info, "%pcrel_lo section symbol with an addend", input_bfd, - input_section, rel->r_offset); + (info, msg, input_bfd, input_section, rel->r_offset); break; default: @@ -2356,9 +2309,13 @@ riscv_elf_relocate_section (bfd *output_bfd, break; } - if (msg) + /* Do not report error message for the dangerous relocation again. */ + if (msg && r != bfd_reloc_dangerous) info->callbacks->einfo (msg); + /* Free the unused `msg_buf`. */ + free (msg_buf); + /* 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; @@ -2366,7 +2323,7 @@ riscv_elf_relocate_section (bfd *output_bfd, } ret = riscv_resolve_pcrel_lo_relocs (&pcrel_relocs); -out: + out: riscv_free_pcrel_relocs (&pcrel_relocs); return ret; } @@ -2706,30 +2663,6 @@ riscv_std_ext_p (const char *name) return (strlen (name) == 1) && (name[0] != 'x') && (name[0] != 's'); } -/* Predicator for non-standard extension. */ - -static bfd_boolean -riscv_non_std_ext_p (const char *name) -{ - return (strlen (name) >= 2) && (name[0] == 'x'); -} - -/* Predicator for standard supervisor extension. */ - -static bfd_boolean -riscv_std_sv_ext_p (const char *name) -{ - return (strlen (name) >= 2) && (name[0] == 's') && (name[1] != 'x'); -} - -/* Predicator for non-standard supervisor extension. */ - -static bfd_boolean -riscv_non_std_sv_ext_p (const char *name) -{ - return (strlen (name) >= 3) && (name[0] == 's') && (name[1] == 'x'); -} - /* Error handler when version mis-match. */ static void @@ -2796,7 +2729,7 @@ riscv_merge_std_ext (bfd *ibfd, if (!riscv_i_or_e_p (ibfd, out_arch, out)) return FALSE; - if (in->name[0] != out->name[0]) + if (strcasecmp (in->name, out->name) != 0) { /* TODO: We might allow merge 'i' with 'e'. */ _bfd_error_handler @@ -2855,53 +2788,102 @@ riscv_merge_std_ext (bfd *ibfd, return TRUE; } -/* Merge non-standard and supervisor extensions. - Return Value: - Return FALSE if failed to merge. +/* If C is a prefix class, then return the EXT string without the prefix. + Otherwise return the entire EXT string. */ - Arguments: - `bfd`: bfd handler. - `in_arch`: Raw arch string for input object. - `out_arch`: Raw arch string for output object. - `pin`: subset list for input object, and it'll skip all merged subset after - merge. - `pout`: Like `pin`, but for output object. */ +static const char * +riscv_skip_prefix (const char *ext, riscv_isa_ext_class_t c) +{ + switch (c) + { + case RV_ISA_CLASS_X: return &ext[1]; + case RV_ISA_CLASS_S: return &ext[1]; + case RV_ISA_CLASS_Z: return &ext[1]; + default: return ext; + } +} + +/* Compare prefixed extension names canonically. */ + +static int +riscv_prefix_cmp (const char *a, const char *b) +{ + riscv_isa_ext_class_t ca = riscv_get_prefix_class (a); + riscv_isa_ext_class_t cb = riscv_get_prefix_class (b); + + /* Extension name without prefix */ + const char *anp = riscv_skip_prefix (a, ca); + const char *bnp = riscv_skip_prefix (b, cb); + + if (ca == cb) + return strcasecmp (anp, bnp); + + return (int)ca - (int)cb; +} + +/* 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_non_std_and_sv_ext (bfd *ibfd, - riscv_subset_t **pin, - riscv_subset_t **pout, - bfd_boolean (*predicate_func) (const char *)) +riscv_merge_multi_letter_ext (bfd *ibfd, + riscv_subset_t **pin, + riscv_subset_t **pout) { riscv_subset_t *in = *pin; riscv_subset_t *out = *pout; + riscv_subset_t *tail; - for (in = *pin; in != NULL && predicate_func (in->name); in = in->next) - riscv_add_subset (&merged_subsets, in->name, in->major_version, - in->minor_version); + int cmp; - for (out = *pout; out != NULL && predicate_func (out->name); out = out->next) + while (in && out) { - riscv_subset_t *find_ext = - riscv_lookup_subset (&merged_subsets, out->name); - if (find_ext != NULL) + cmp = riscv_prefix_cmp (in->name, out->name); + + if (cmp < 0) + { + /* `in' comes before `out', append `in' and increment. */ + riscv_add_subset (&merged_subsets, in->name, in->major_version, + in->minor_version); + in = in->next; + } + else if (cmp > 0) { - /* Check version is same or not. */ - /* TODO: Allow different merge policy. */ - if ((find_ext->major_version != out->major_version) - || (find_ext->minor_version != out->minor_version)) + /* `out' comes before `in', append `out' and increment. */ + riscv_add_subset (&merged_subsets, out->name, out->major_version, + out->minor_version); + out = out->next; + } + else + { + /* Both present, check version and increment both. */ + if ((in->major_version != out->major_version) + || (in->minor_version != out->minor_version)) { - riscv_version_mismatch (ibfd, find_ext, out); + riscv_version_mismatch (ibfd, in, out); return FALSE; } + + riscv_add_subset (&merged_subsets, out->name, out->major_version, + out->minor_version); + out = out->next; + in = in->next; } - else - riscv_add_subset (&merged_subsets, out->name, - out->major_version, out->minor_version); } - *pin = in; - *pout = out; + if (in || out) { + /* If we're here, either `in' or `out' is running longer than + the other. So, we need to append the corresponding tail. */ + tail = in ? in : out; + + while (tail) + { + riscv_add_subset (&merged_subsets, tail->name, tail->major_version, + tail->minor_version); + tail = tail->next; + } + } + return TRUE; } @@ -2920,13 +2902,17 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch) 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; if (in_arch == NULL && out_arch == NULL) return NULL; @@ -2960,14 +2946,9 @@ riscv_merge_arch_attr_info (bfd *ibfd, char *in_arch, char *out_arch) /* Merge standard extension. */ if (!riscv_merge_std_ext (ibfd, in_arch, out_arch, &in, &out)) return NULL; - /* Merge non-standard extension. */ - if (!riscv_merge_non_std_and_sv_ext (ibfd, &in, &out, riscv_non_std_ext_p)) - return NULL; - /* Merge standard supervisor extension. */ - if (!riscv_merge_non_std_and_sv_ext (ibfd, &in, &out, riscv_std_sv_ext_p)) - return NULL; - /* Merge non-standard supervisor extension. */ - if (!riscv_merge_non_std_and_sv_ext (ibfd, &in, &out, riscv_non_std_sv_ext_p)) + + /* Merge all non-single letter extensions with single call. */ + if (!riscv_merge_multi_letter_ext (ibfd, &in, &out)) return NULL; if (xlen_in != xlen_out) @@ -3006,6 +2987,7 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info) obj_attribute *in_attr; obj_attribute *out_attr; bfd_boolean result = TRUE; + bfd_boolean priv_attrs_merged = FALSE; const char *sec_name = get_elf_backend_data (ibfd)->obj_attrs_section; unsigned int i; @@ -3060,20 +3042,78 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info) out_attr[Tag_RISCV_arch].s = merged_arch; } break; + case Tag_RISCV_priv_spec: case Tag_RISCV_priv_spec_minor: case Tag_RISCV_priv_spec_revision: - if (out_attr[i].i != in_attr[i].i) + /* If we have handled the priv attributes, then skip it. */ + if (!priv_attrs_merged) { - _bfd_error_handler - (_("error: %pB: conflicting priv spec version " - "(major/minor/revision)."), ibfd); - result = FALSE; + unsigned int Tag_a = Tag_RISCV_priv_spec; + unsigned int Tag_b = Tag_RISCV_priv_spec_minor; + unsigned int Tag_c = Tag_RISCV_priv_spec_revision; + enum riscv_priv_spec_class in_priv_spec; + enum riscv_priv_spec_class out_priv_spec; + + /* Get the priv spec class from elf attribute numbers. */ + riscv_get_priv_spec_class_from_numbers (in_attr[Tag_a].i, + in_attr[Tag_b].i, + in_attr[Tag_c].i, + &in_priv_spec); + riscv_get_priv_spec_class_from_numbers (out_attr[Tag_a].i, + out_attr[Tag_b].i, + out_attr[Tag_c].i, + &out_priv_spec); + + /* Allow to link the object without the priv specs. */ + if (out_priv_spec == PRIV_SPEC_CLASS_NONE) + { + out_attr[Tag_a].i = in_attr[Tag_a].i; + out_attr[Tag_b].i = in_attr[Tag_b].i; + out_attr[Tag_c].i = in_attr[Tag_c].i; + } + else if (in_priv_spec != PRIV_SPEC_CLASS_NONE + && in_priv_spec != out_priv_spec) + { + _bfd_error_handler + (_("warning: %pB use privilege spec version %u.%u.%u but " + "the output use version %u.%u.%u."), + ibfd, + in_attr[Tag_a].i, + in_attr[Tag_b].i, + in_attr[Tag_c].i, + out_attr[Tag_a].i, + out_attr[Tag_b].i, + out_attr[Tag_c].i); + + /* The priv spec v1.9.1 can be linked with other spec + versions since the conflicts. We plan to drop the + v1.9.1 in a year or two, so this confict should be + removed in the future. */ + if (in_priv_spec == PRIV_SPEC_CLASS_1P9P1 + || out_priv_spec == PRIV_SPEC_CLASS_1P9P1) + { + _bfd_error_handler + (_("warning: privilege spec version 1.9.1 can not be " + "linked with other spec versions.")); + } + + /* Update the output priv attributes to the newest. */ + if (in_priv_spec > out_priv_spec) + { + out_attr[Tag_a].i = in_attr[Tag_a].i; + out_attr[Tag_b].i = in_attr[Tag_b].i; + out_attr[Tag_c].i = in_attr[Tag_c].i; + } + } + priv_attrs_merged = TRUE; } break; + case Tag_RISCV_unaligned_access: out_attr[i].i |= in_attr[i].i; break; + case Tag_RISCV_stack_align: if (out_attr[i].i == 0) out_attr[i].i = in_attr[i].i; @@ -3088,6 +3128,7 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info) result = FALSE; } break; + default: result &= _bfd_elf_merge_unknown_attribute_low (ibfd, obfd, i); } @@ -3195,7 +3236,7 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) return TRUE; -fail: + fail: bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -3465,9 +3506,16 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec, int rd, r_type, len = 4, rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC; /* If the call crosses section boundaries, an alignment directive could - cause the PC-relative offset to later increase. */ - if (VALID_UJTYPE_IMM (foff) && sym_sec->output_section != sec->output_section) - foff += (foff < 0 ? -max_alignment : max_alignment); + cause the PC-relative offset to later increase, so we need to add in the + max alignment of any section inclusive from the call to the target. + Otherwise, we only need to use the alignment of the current section. */ + if (VALID_UJTYPE_IMM (foff)) + { + if (sym_sec->output_section == sec->output_section + && sym_sec->output_section != bfd_abs_section_ptr) + max_alignment = (bfd_vma) 1 << sym_sec->output_section->alignment_power; + foff += (foff < 0 ? -max_alignment : max_alignment); + } /* See if this function call can be shortened. */ if (!VALID_UJTYPE_IMM (foff) && !(!bfd_link_pic (link_info) && near_zero)) @@ -4092,7 +4140,9 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, undefined_weak = TRUE; } - if (h->plt.offset != MINUS_ONE) + /* This line has to match the check in riscv_elf_relocate_section + in the R_RISCV_CALL[_PLT] case. */ + if (bfd_link_pic (info) && h->plt.offset != MINUS_ONE) { sym_sec = htab->elf.splt; symval = h->plt.offset; @@ -4102,15 +4152,16 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, symval = 0; sym_sec = bfd_und_section_ptr; } - else if (h->root.u.def.section->output_section == NULL - || (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak)) - continue; - else + else if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->root.u.def.section != NULL + && h->root.u.def.section->output_section != NULL) { symval = h->root.u.def.value; sym_sec = h->root.u.def.section; } + else + continue; if (h->type != STT_FUNC) reserve_size = @@ -4160,7 +4211,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, ret = TRUE; -fail: + fail: if (relocs != data->relocs) free (relocs); riscv_free_pcgp_relocs(&pcgp_relocs, abfd, sec); @@ -4303,6 +4354,7 @@ riscv_elf_obj_attrs_arg_type (int tag) #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_init_index_section _bfd_elf_init_1_index_section