/* 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.
#include "opcode/riscv.h"
#include "objalloc.h"
-#ifdef HAVE_LIMITS_H
#include <limits.h>
-#endif
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
#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
{
struct elf_link_hash_entry elf;
-#define GOT_UNKNOWN 0
-#define GOT_NORMAL 1
-#define GOT_TLS_GD 2
-#define GOT_TLS_IE 4
-#define GOT_TLS_LE 8
+#define GOT_UNKNOWN 0
+#define GOT_NORMAL 1
+#define GOT_TLS_GD 2
+#define GOT_TLS_IE 4
+#define GOT_TLS_LE 8
char tls_type;
};
#define riscv_elf_hash_entry(ent) \
- ((struct riscv_elf_link_hash_entry *)(ent))
+ ((struct riscv_elf_link_hash_entry *) (ent))
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,
/* 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. */
&& 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)
/* 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
/* 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)
{
{
_bfd_error_handler (_("%pB: warning: RVE PLT generation not supported"),
output_bfd);
- return FALSE;
+ return false;
}
/* auipc t2, %hi(.got.plt)
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)
{
{
_bfd_error_handler (_("%pB: warning: RVE PLT generation not supported"),
output_bfd);
- return FALSE;
+ return false;
}
/* auipc t3, %hi(.got.plt entry)
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. */
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;
/* Create the .got section. */
-static bfd_boolean
+static bool
riscv_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
{
flagword flags;
/* This function may be called more than once. */
if (htab->sgot != NULL)
- return TRUE;
+ return true;
flags = bed->dynamic_sec_flags;
| 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. */
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. */
"_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)
{
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))
{
|| (!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. */
_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)
{
(*_bfd_error_handler)
(_("%pB: `%s' accessed both as normal and thread local symbol"),
abfd, h ? h->root.root.string : "<local>");
- 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)
{
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. */
{
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);
abfd, r ? r->name : _("<unknown>"),
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)
{
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;
{
(*_bfd_error_handler) (_("%pB: bad symbol index: %d"),
abfd, r_symndx);
- return FALSE;
+ return false;
}
if (r_symndx < symtab_hdr->sh_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,
executables. */
if (h->type == STT_GNU_IFUNC
&& !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
- return FALSE;
+ return false;
break;
default:
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:
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:
{
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
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)
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;
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:
}
}
- return TRUE;
+ return true;
}
static asection *
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)
{
h->needs_plt = 0;
}
- return TRUE;
+ return true;
}
else
h->plt.offset = (bfd_vma) -1;
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
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
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
/* 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;
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);
&& 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)
{
&& !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))
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
{
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.
&& !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ return false;
}
s = htab->elf.sgot;
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
&& !h->forced_local)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ return false;
}
}
}
&& !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
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;
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
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;
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_. */
/* 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)
{
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;
}
- return _bfd_elf_add_dynamic_tags (output_bfd, info, TRUE);
+ /* 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 true;
}
#define TP_OFFSET 0
{
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;
break;
case R_RISCV_JAL:
- if (!VALID_UJTYPE_IMM (value))
+ if (!VALID_JTYPE_IMM (value))
return bfd_reloc_overflow;
- value = ENCODE_UJTYPE_IMM (value);
+ value = ENCODE_JTYPE_IMM (value);
break;
case R_RISCV_BRANCH:
- if (!VALID_SBTYPE_IMM (value))
+ if (!VALID_BTYPE_IMM (value))
return bfd_reloc_overflow;
- value = ENCODE_SBTYPE_IMM (value);
+ value = ENCODE_BTYPE_IMM (value);
break;
case R_RISCV_RVC_BRANCH:
- if (!VALID_RVC_B_IMM (value))
+ if (!VALID_CBTYPE_IMM (value))
return bfd_reloc_overflow;
- value = ENCODE_RVC_B_IMM (value);
+ value = ENCODE_CBTYPE_IMM (value);
break;
case R_RISCV_RVC_JUMP:
- if (!VALID_RVC_J_IMM (value))
+ if (!VALID_CJTYPE_IMM (value))
return bfd_reloc_overflow;
- value = ENCODE_RVC_J_IMM (value);
+ value = ENCODE_CJTYPE_IMM (value);
break;
case R_RISCV_RVC_LUI:
contents + rel->r_offset);
insn = (insn & ~MATCH_C_LUI) | MATCH_C_LI;
riscv_put_insn (howto->bitsize, insn, contents + rel->r_offset);
- value = ENCODE_RVC_IMM (0);
+ value = ENCODE_CITYPE_IMM (0);
}
- else if (!VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value)))
+ else if (!VALID_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (value)))
return bfd_reloc_overflow;
else
- value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value));
+ value = ENCODE_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (value));
break;
case R_RISCV_32:
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
{
- 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;
- struct riscv_pcrel_lo_reloc * next;
+ /* 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;
+ 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;
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;
p->hi_relocs = htab_create (1024, riscv_pcrel_reloc_hash,
riscv_pcrel_reloc_eq, free);
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
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);
+ rel->r_info = ELFNN_R_INFO (addr, R_RISCV_HI20);
- bfd_vma insn = riscv_get_insn(howto->bitsize, contents + rel->r_offset);
+ 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;
+ riscv_put_insn (howto->bitsize, insn, contents + rel->r_offset);
+ 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;
{
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.
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,
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++)
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)
h = NULL;
sym = NULL;
sec = NULL;
- unresolved_reloc = FALSE;
+ unresolved_reloc = false;
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
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 ();
}
else
{
- bfd_boolean warned, ignored;
+ bool warned, ignored;
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes,
"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
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;
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;
default:
- bad_ifunc_reloc:
+ bad_ifunc_reloc:
if (h->root.root.string)
name = h->root.root.string;
else
"symbol `%s' isn't supported"), input_bfd,
howto->name, name);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
}
- skip_ifunc:
+ skip_ifunc:
if (h != NULL)
name = h->root.root.string;
else
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);
}
}
else
- unresolved_reloc = FALSE;
+ unresolved_reloc = false;
}
else
{
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:
{
/* Refer to the PLT entry. */
relocation = sec_addr (htab->elf.splt) + h->plt.offset;
- unresolved_reloc = FALSE;
+ unresolved_reloc = false;
}
break;
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. */
}
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;
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;
|| (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
&& !resolved_to_zero)
|| h->root.type != bfd_link_hash_undefweak)
- && (! howto->pc_relative
+ && (!howto->pc_relative
|| !SYMBOL_CALLS_LOCAL (info, h)))
|| (!bfd_link_pic (info)
&& h != NULL
{
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
break;
case R_RISCV_TLS_GOT_HI20:
- is_ie = TRUE;
+ is_ie = true;
/* Fall through. */
case R_RISCV_TLS_GD_HI20:
{
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);
&& (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)
{
BFD_ASSERT (! unresolved_reloc);
bfd_put_NN (output_bfd,
dtpoff (info, relocation),
- (htab->elf.sgot->contents + off +
- RISCV_ELF_WORD_BYTES));
+ (htab->elf.sgot->contents
+ + off + RISCV_ELF_WORD_BYTES));
}
else
{
bfd_put_NN (output_bfd, 0,
- (htab->elf.sgot->contents + off +
- RISCV_ELF_WORD_BYTES));
+ (htab->elf.sgot->contents
+ + off + RISCV_ELF_WORD_BYTES));
outrel.r_info = ELFNN_R_INFO (indx, R_RISCV_TLS_DTPRELNN);
outrel.r_offset += RISCV_ELF_WORD_BYTES;
riscv_elf_append_rela (output_bfd, htab->elf.srelgot, &outrel);
htab->elf.sgot->contents + off);
bfd_put_NN (output_bfd,
dtpoff (info, relocation),
- (htab->elf.sgot->contents + off +
- RISCV_ELF_WORD_BYTES));
+ (htab->elf.sgot->contents
+ + off + RISCV_ELF_WORD_BYTES));
}
}
bfd_put_NN (output_bfd, 0,
htab->elf.sgot->contents + off + ie_off);
outrel.r_offset = sec_addr (htab->elf.sgot)
- + off + ie_off;
+ + off + ie_off;
outrel.r_addend = 0;
if (indx == 0)
outrel.r_addend = tpoff (info, relocation);
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:
case bfd_reloc_undefined:
info->callbacks->undefined_symbol
(info, name, input_bfd, input_section, rel->r_offset,
- TRUE);
+ true);
break;
case bfd_reloc_outofrange:
/* 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;
}
/* 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,
|| plt == NULL
|| gotplt == NULL
|| relplt == NULL)
- return FALSE;
+ return false;
/* Calculate the address of the PLT header. */
header_address = sec_addr (plt);
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);
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. */
/* 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))
else
{
/* Generate R_RISCV_NN. */
- BFD_ASSERT((h->got.offset & 1) == 0);
+ BFD_ASSERT ((h->got.offset & 1) == 0);
BFD_ASSERT (h->dynindx != -1);
rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_NN);
rela.r_addend = 0;
else if (bfd_link_pic (info))
{
/* Generate R_RISCV_NN. */
- BFD_ASSERT((h->got.offset & 1) == 0);
+ BFD_ASSERT ((h->got.offset & 1) == 0);
BFD_ASSERT (h->dynindx != -1);
rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_NN);
rela.r_addend = 0;
+ h->plt.offset),
htab->elf.sgot->contents
+ (h->got.offset & ~(bfd_vma) 1));
- return TRUE;
+ return true;
}
}
else if (bfd_link_pic (info)
or a pie link, or the symbol was forced to be local because
of a version file. The entry in the global offset table will
already have been initialized in the relocate_section function. */
- BFD_ASSERT((h->got.offset & 1) != 0);
+ BFD_ASSERT ((h->got.offset & 1) != 0);
asection *sec = h->root.u.def.section;
rela.r_info = ELFNN_R_INFO (0, R_RISCV_RELATIVE);
rela.r_addend = (h->root.u.def.value
}
else
{
- BFD_ASSERT((h->got.offset & 1) == 0);
+ BFD_ASSERT ((h->got.offset & 1) == 0);
BFD_ASSERT (h->dynindx != -1);
rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_NN);
rela.r_addend = 0;
|| (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;
/* 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)
{
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)
{
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);
{
(*_bfd_error_handler)
(_("discarded output section: `%pA'"), htab->elf.sgotplt);
- return FALSE;
+ return false;
}
if (htab->elf.sgotplt->size > 0)
riscv_elf_finish_local_dynamic_symbol,
info);
- return TRUE;
+ return true;
}
/* Return address for Ith PLT stub in section PLT, for relocation REL
/* 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)
(_("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.
`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)
{
_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;
{
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);
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,
*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;
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);
}
}
- 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;
- }
- }
+ 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;
+ return true;
}
/* Merge Tag_RISCV_arch attribute. */
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. */
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)
/* 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)
{
initialized. */
out_attr[0].i = 1;
- return TRUE;
+ return true;
}
in_attr = elf_known_obj_attributes_proc (ibfd);
out_attr[Tag_RISCV_arch].s);
if (merged_arch == NULL)
{
- result = FALSE;
+ result = false;
out_attr[Tag_RISCV_arch].s = "";
}
else
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;
+ enum riscv_spec_class in_priv_spec = PRIV_SPEC_CLASS_NONE;
+ enum riscv_spec_class out_priv_spec = PRIV_SPEC_CLASS_NONE;
/* Get the privileged spec class from elf attributes. */
riscv_get_priv_spec_class_from_numbers (in_attr[Tag_a].i,
out_attr[Tag_c].i = in_attr[Tag_c].i;
}
}
- priv_attrs_merged = TRUE;
+ priv_attrs_merged = true;
}
break;
(_("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;
/* 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);
/* 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)
{
(_("%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;
-
- new_flags = elf_elfheader (ibfd)->e_flags;
- old_flags = elf_elfheader (obfd)->e_flags;
-
- if (! elf_flags_init (obfd))
- {
- elf_flags_init (obfd) = TRUE;
- elf_elfheader (obfd)->e_flags = new_flags;
- return TRUE;
- }
+ 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
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;
+
if ((bfd_section_flags (sec)
& (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
== (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
- only_data_sections = FALSE;
-
- null_input_bfd = FALSE;
- break;
+ {
+ only_data_sections = false;
+ break;
+ }
}
if (null_input_bfd || only_data_sections)
- return TRUE;
+ return true;
+ }
+
+ new_flags = elf_elfheader (ibfd)->e_flags;
+ old_flags = elf_elfheader (obfd)->e_flags;
+
+ if (!elf_flags_init (obfd))
+ {
+ elf_flags_init (obfd) = true;
+ elf_elfheader (obfd)->e_flags = new_flags;
+ return true;
}
/* Disallow linking different float ABIs. */
/* 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
bfd_vma hi_addr;
unsigned hi_sym;
asection *sym_sec;
- bfd_boolean undefined_weak;
+ bool undefined_weak;
riscv_pcgp_hi_reloc *next;
};
/* 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. */
riscv_pcgp_hi_reloc *c;
riscv_pcgp_lo_reloc *l;
- for (c = p->hi; c != NULL;)
+ for (c = p->hi; c != NULL; )
{
riscv_pcgp_hi_reloc *next = c->next;
free (c);
c = next;
}
- for (l = p->lo; l != NULL;)
+ for (l = p->lo; l != NULL; )
{
riscv_pcgp_lo_reloc *next = l->next;
free (l);
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));
+ 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;
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.
This is used by a lo part reloc to find the corresponding hi part reloc. */
static riscv_pcgp_hi_reloc *
-riscv_find_pcgp_hi_reloc(riscv_pcgp_relocs *p, bfd_vma hi_sec_off)
+riscv_find_pcgp_hi_reloc (riscv_pcgp_relocs *p, bfd_vma hi_sec_off)
{
riscv_pcgp_hi_reloc *c;
/* 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));
+ 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;
}
-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);
+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 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;
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 (VALID_JTYPE_IMM (foff))
{
if (sym_sec->output_section == sec->output_section
&& sym_sec->output_section != bfd_abs_section_ptr)
}
/* See if this function call can be shortened. */
- if (!VALID_UJTYPE_IMM (foff) && !(!bfd_link_pic (link_info) && near_zero))
- return TRUE;
+ if (!VALID_JTYPE_IMM (foff) && !(!bfd_link_pic (link_info) && near_zero))
+ return true;
/* Shorten the function call. */
BFD_ASSERT (rel->r_offset + 8 <= sec->size);
auipc = bfd_getl32 (contents + rel->r_offset);
jalr = bfd_getl32 (contents + rel->r_offset + 4);
rd = (jalr >> OP_SH_RD) & OP_MASK_RD;
- rvc = rvc && VALID_RVC_J_IMM (foff);
+ rvc = rvc && VALID_CJTYPE_IMM (foff);
/* C.J exists on RV32 and RV64, but C.JAL is RV32-only. */
rvc = rvc && (rd == 0 || (rd == X_RA && ARCH_SIZE == 32));
auipc = rd == 0 ? MATCH_C_J : MATCH_C_JAL;
len = 2;
}
- else if (VALID_UJTYPE_IMM (foff))
+ else if (VALID_JTYPE_IMM (foff))
{
/* Relax to JAL rd, addr. */
r_type = R_RISCV_JAL;
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. */
/* 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,
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);
/* 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;
}
else
rel->r_info = ELFNN_R_INFO (sym, R_RISCV_GPREL_I);
- return TRUE;
+ return true;
case R_RISCV_LO12_S:
if (undefined_weak)
}
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 ();
if (use_rvc
&& ELFNN_R_TYPE (rel->r_info) == R_RISCV_HI20
- && VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (symval))
- && VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (symval)
+ && VALID_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (symval))
+ && VALID_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (symval)
+ (link_info->relro ? 2 * ELF_MAXPAGESIZE
: ELF_MAXPAGESIZE)))
{
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);
/* 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,
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,
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;
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)
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. */
/* 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)
/* 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
-_bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
- 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,
- bfd_boolean *again ATTRIBUTE_UNUSED,
- riscv_pcgp_relocs *pcgp_relocs,
- bfd_boolean undefined_weak)
+static bool
+_bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED,
+ 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,
+ bool *again ATTRIBUTE_UNUSED,
+ 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);
if (hi == NULL)
{
riscv_record_pcgp_lo_reloc (pcgp_relocs, hi_sec_off);
- return TRUE;
+ return true;
}
hi_reloc = *hi;
/* 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;
/* 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;
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)
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,
/* 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,
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, NULL))
+ return false;
+ rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
+ 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)
{
- if (!riscv_relax_delete_bytes(abfd, sec, rel->r_offset, rel->r_addend,
- link_info))
- return FALSE;
- rel->r_info = ELFNN_R_INFO(0, R_RISCV_NONE);
- return TRUE;
+ 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);
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)
|| 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
/* 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;
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
goto fail;
}
- ret = TRUE;
+ ret = true;
fail:
if (relocs != data->relocs)
free (relocs);
- riscv_free_pcgp_relocs(&pcgp_relocs, abfd, sec);
+ riscv_free_pcgp_relocs (&pcgp_relocs, abfd, sec);
return ret;
}
# 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
# 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 */
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 */
/* 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;
}
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. */
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
return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL;
}
-#define TARGET_LITTLE_SYM riscv_elfNN_vec
-#define TARGET_LITTLE_NAME "elfNN-littleriscv"
-#define TARGET_BIG_SYM riscv_elfNN_be_vec
-#define TARGET_BIG_NAME "elfNN-bigriscv"
+/* 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;
+ }
+ }
-#define elf_backend_reloc_type_class riscv_reloc_type_class
+ return true;
+}
-#define bfd_elfNN_bfd_reloc_name_lookup riscv_reloc_name_lookup
-#define bfd_elfNN_bfd_link_hash_table_create riscv_elf_link_hash_table_create
-#define bfd_elfNN_bfd_reloc_type_lookup riscv_reloc_type_lookup
+/* 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
+#define TARGET_BIG_NAME "elfNN-bigriscv"
+
+#define elf_backend_reloc_type_class riscv_reloc_type_class
+
+#define bfd_elfNN_bfd_reloc_name_lookup riscv_reloc_name_lookup
+#define bfd_elfNN_bfd_link_hash_table_create riscv_elf_link_hash_table_create
+#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 elf_backend_copy_indirect_symbol riscv_elf_copy_indirect_symbol
-#define elf_backend_create_dynamic_sections riscv_elf_create_dynamic_sections
-#define elf_backend_check_relocs riscv_elf_check_relocs
-#define elf_backend_adjust_dynamic_symbol riscv_elf_adjust_dynamic_symbol
-#define elf_backend_size_dynamic_sections riscv_elf_size_dynamic_sections
-#define elf_backend_relocate_section riscv_elf_relocate_section
-#define elf_backend_finish_dynamic_symbol riscv_elf_finish_dynamic_symbol
-#define elf_backend_finish_dynamic_sections riscv_elf_finish_dynamic_sections
-#define elf_backend_gc_mark_hook riscv_elf_gc_mark_hook
-#define elf_backend_plt_sym_val riscv_elf_plt_sym_val
-#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_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
-
-#define elf_backend_can_gc_sections 1
-#define elf_backend_can_refcount 1
-#define elf_backend_want_got_plt 1
-#define elf_backend_plt_readonly 1
-#define elf_backend_plt_alignment 4
-#define elf_backend_want_plt_sym 1
-#define elf_backend_got_header_size (ARCH_SIZE / 8)
-#define elf_backend_want_dynrelro 1
-#define elf_backend_rela_normal 1
-#define elf_backend_default_execstack 0
+#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
+#define elf_backend_check_relocs riscv_elf_check_relocs
+#define elf_backend_adjust_dynamic_symbol riscv_elf_adjust_dynamic_symbol
+#define elf_backend_size_dynamic_sections riscv_elf_size_dynamic_sections
+#define elf_backend_relocate_section riscv_elf_relocate_section
+#define elf_backend_finish_dynamic_symbol riscv_elf_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_sections riscv_elf_finish_dynamic_sections
+#define elf_backend_gc_mark_hook riscv_elf_gc_mark_hook
+#define elf_backend_plt_sym_val riscv_elf_plt_sym_val
+#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
+
+#define elf_backend_can_gc_sections 1
+#define elf_backend_can_refcount 1
+#define elf_backend_want_got_plt 1
+#define elf_backend_plt_readonly 1
+#define elf_backend_plt_alignment 4
+#define elf_backend_want_plt_sym 1
+#define elf_backend_got_header_size (ARCH_SIZE / 8)
+#define elf_backend_want_dynrelro 1
+#define elf_backend_rela_normal 1
+#define elf_backend_default_execstack 0
#undef elf_backend_obj_attrs_vendor
-#define elf_backend_obj_attrs_vendor "riscv"
+#define elf_backend_obj_attrs_vendor "riscv"
#undef elf_backend_obj_attrs_arg_type
-#define elf_backend_obj_attrs_arg_type riscv_elf_obj_attrs_arg_type
+#define elf_backend_obj_attrs_arg_type riscv_elf_obj_attrs_arg_type
#undef elf_backend_obj_attrs_section_type
-#define elf_backend_obj_attrs_section_type SHT_RISCV_ATTRIBUTES
+#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"