edir = (struct riscv_elf_link_hash_entry *) dir;
eind = (struct riscv_elf_link_hash_entry *) ind;
- if (ind->dyn_relocs != NULL)
- {
- if (dir->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 = &ind->dyn_relocs; (p = *pp) != NULL; )
- {
- struct elf_dyn_relocs *q;
-
- for (q = dir->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 = dir->dyn_relocs;
- }
-
- dir->dyn_relocs = ind->dyn_relocs;
- ind->dyn_relocs = NULL;
- }
-
if (ind->root.type == bfd_link_hash_indirect
&& dir->got.refcount <= 0)
{
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 = _bfd_elf_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)
{
/* 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)
{
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;
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;
result = FALSE;
}
break;
+
default:
result &= _bfd_elf_merge_unknown_attribute_low (ibfd, obfd, i);
}