@@ -5481,6 +5481,17 @@ enum bfd_reloc_code_real
BFD_RELOC_RX_ABS16UW,
BFD_RELOC_RX_ABS16UL,
BFD_RELOC_RX_RELAX,
+ BFD_RELOC_RX_COPY,
+ BFD_RELOC_RX_GLOB_DAT,
+ BFD_RELOC_RX_JMP_SLOT,
+ BFD_RELOC_RX_RELATIVE,
+ BFD_RELOC_RX_GOT,
+ BFD_RELOC_RX_GOTOFF,
+ BFD_RELOC_RX_PLT,
+ BFD_RELOC_RX_GOTFUNCDESC,
+ BFD_RELOC_RX_GOTOFFFUNCDESC,
+ BFD_RELOC_RX_FUNCDESC,
+ BFD_RELOC_RX_FUNCDESC_VALUE,
/* Direct 12 bit. */
BFD_RELOC_390_12,
@@ -580,6 +580,7 @@ enum elf_target_id
PPC64_ELF_DATA,
PRU_ELF_DATA,
RISCV_ELF_DATA,
+ RX_ELF_DATA,
S390_ELF_DATA,
SCORE_ELF_DATA,
SH_ELF_DATA,
@@ -35,7 +35,7 @@ const bfd_target rx_elf32_be_ns_vec;
const bfd_target rx_elf32_be_vec;
#ifdef DEBUG
-char * rx_get_reloc (long);
+const char * rx_get_reloc (long);
void rx_dump_symtab (bfd *, void *, void *);
#endif
@@ -51,14 +51,14 @@ static reloc_howto_type rx_elf_howto_table [] =
{
RXREL (NONE, 0, 0, 0, dont, false),
RXREL (DIR32, 4, 32, 0, signed, false),
- RXREL (DIR24S, 4, 24, 0, signed, false),
+ RXREL (DIR24S, 3, 24, 0, signed, false),
RXREL (DIR16, 2, 16, 0, dont, false),
RXREL (DIR16U, 2, 16, 0, unsigned, false),
RXREL (DIR16S, 2, 16, 0, signed, false),
RXREL (DIR8, 1, 8, 0, dont, false),
RXREL (DIR8U, 1, 8, 0, unsigned, false),
RXREL (DIR8S, 1, 8, 0, signed, false),
- RXREL (DIR24S_PCREL, 4, 24, 0, signed, true),
+ RXREL (DIR24S_PCREL, 3, 24, 0, signed, true),
RXREL (DIR16S_PCREL, 2, 16, 0, signed, true),
RXREL (DIR8S_PCREL, 1, 8, 0, signed, true),
RXREL (DIR16UL, 2, 16, 2, unsigned, false),
@@ -69,17 +69,18 @@ static reloc_howto_type rx_elf_howto_table [] =
RXREL (DIR16_REV, 2, 16, 0, dont, false),
RXREL (DIR3U_PCREL, 1, 3, 0, dont, true),
- EMPTY_HOWTO (0x13),
- EMPTY_HOWTO (0x14),
- EMPTY_HOWTO (0x15),
- EMPTY_HOWTO (0x16),
- EMPTY_HOWTO (0x17),
- EMPTY_HOWTO (0x18),
- EMPTY_HOWTO (0x19),
- EMPTY_HOWTO (0x1a),
- EMPTY_HOWTO (0x1b),
- EMPTY_HOWTO (0x1c),
- EMPTY_HOWTO (0x1d),
+ RXREL (GOT, 2, 16, 0, dont, false),
+ RXREL (PLT, 2, 32, 0, dont, true),
+ RXREL (COPY, 2, 32, 0, dont, false),
+ RXREL (GLOB_DAT, 2, 32, 0, dont, false),
+ RXREL (JMP_SLOT, 2, 32, 0, dont, false),
+ RXREL (RELATIVE, 2, 32, 0, dont, false),
+ RXREL (GOTOFF, 2, 32, 0, dont, false),
+ RXREL (GOTFUNCDESC, 2, 16, 0, dont, false),
+ RXREL (GOTOFFFUNCDESC, 2, 32, 0, dont, false),
+ RXREL (FUNCDESC, 2, 32, 0, dont, false),
+ RXREL (FUNCDESC_VALUE, 2, 64, 0, dont, false),
+
EMPTY_HOWTO (0x1e),
EMPTY_HOWTO (0x1f),
@@ -253,6 +254,16 @@ static const struct rx_reloc_map rx_reloc_map [] =
{ BFD_RELOC_24_PCREL, R_RX_DIR24S_PCREL },
{ BFD_RELOC_RX_8U, R_RX_DIR8U },
{ BFD_RELOC_RX_16U, R_RX_DIR16U },
+ { BFD_RELOC_RX_COPY, R_RX_COPY },
+ { BFD_RELOC_RX_GLOB_DAT, R_RX_GLOB_DAT },
+ { BFD_RELOC_RX_JMP_SLOT, R_RX_JMP_SLOT },
+ { BFD_RELOC_RX_RELATIVE, R_RX_RELATIVE },
+ { BFD_RELOC_RX_GOT, R_RX_GOT },
+ { BFD_RELOC_32_GOTOFF, R_RX_GOTOFF },
+ { BFD_RELOC_32_PLT_PCREL, R_RX_PLT },
+ { BFD_RELOC_RX_GOTFUNCDESC, R_RX_GOTFUNCDESC },
+ { BFD_RELOC_RX_GOTOFFFUNCDESC, R_RX_GOTOFFFUNCDESC },
+ { BFD_RELOC_RX_FUNCDESC, R_RX_FUNCDESC },
{ BFD_RELOC_RX_24U, R_RX_RH_24_UNS },
{ BFD_RELOC_RX_NEG8, R_RX_RH_8_NEG },
{ BFD_RELOC_RX_NEG16, R_RX_RH_16_NEG },
@@ -278,6 +289,104 @@ static const struct rx_reloc_map rx_reloc_map [] =
#define BIGE(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG)
+/* RX ELF linker hash table. */
+struct elf_rx_link_hash_table
+{
+ struct elf_link_hash_table root;
+ asection *sfuncdesc;
+ asection *srelfuncdesc;
+ asection *srofixup;
+
+ /* True if the target system uses FDPIC. */
+ bool fdpic_p;
+};
+
+/* Get the sh ELF linker hash table from a link_info structure. */
+
+#define rx_elf_hash_table(p) \
+ ((is_elf_hash_table ((p)->hash) \
+ && elf_hash_table_id (elf_hash_table (p)) == RX_ELF_DATA) \
+ ? (struct elf_rx_link_hash_table *) (p)->hash : NULL)
+#define MINUS_ONE ((bfd_vma) 0 - 1)
+
+union gotref {
+ bfd_signed_vma refcount;
+ bfd_vma offset;
+};
+
+/* RX ELF linker hash entry. */
+
+struct elf_rx_link_hash_entry
+{
+ struct elf_link_hash_entry root;
+
+ bfd_signed_vma gotplt_refcount;
+
+ /* A local function descriptor, for FDPIC. The refcount counts
+ R_RX_FUNCDESC, and R_RX_GOTOFFFUNCDESC relocations;
+ the PLT and GOT entry are accounted for separately.
+ After adjust_dynamic_symbol, the offset is
+ MINUS_ONE if there is no local descriptor (dynamic linker
+ managed and no PLT entry, or undefined weak non-dynamic).
+ During check_relocs we do not yet know whether the local
+ descriptor will be canonical. */
+ union gotref funcdesc;
+
+ /* How many of the above refcounted relocations were R_RX_FUNCDESC,
+ and thus require fixups or relocations. */
+ bfd_signed_vma abs_funcdesc_refcount;
+
+ enum got_type {
+ GOT_UNKNOWN = 0,
+ GOT_NORMAL = 1,
+ GOT_FUNCDESC = 2,
+ } got_type;
+};
+
+#define rx_elf_hash_entry(ent) ((struct elf_rx_link_hash_entry *)(ent))
+
+struct rx_elf_obj_tdata
+{
+ struct elf_obj_tdata root;
+
+ /* got_type for each local got entry. */
+ char *local_got_type;
+
+ /* Function descriptor refcount and offset for each local symbol. */
+ union gotref *local_funcdesc;
+};
+
+#define rx_elf_tdata(abfd) \
+ ((struct rx_elf_obj_tdata *) (abfd)->tdata.any)
+
+#define rx_elf_local_got_type(abfd) \
+ (rx_elf_tdata (abfd)->local_got_type)
+
+#define rx_elf_local_funcdesc(abfd) \
+ (rx_elf_tdata (abfd)->local_funcdesc)
+
+/* Decide whether a reference to a symbol can be resolved locally or
+ not. If the symbol is protected, we want the local address, but
+ its function descriptor must be assigned by the dynamic linker. */
+#define SYMBOL_FUNCDESC_LOCAL(INFO, H) \
+ (SYMBOL_REFERENCES_LOCAL (INFO, H) \
+ || ! elf_hash_table (INFO)->dynamic_sections_created)
+
+/* FDPIC stuff */
+static bool
+rx_elf_osec_readonly_p (bfd *output_bfd, asection *osec);
+
+static void
+rx_elf_add_rofixup (bfd *output_bfd, asection *srofixup, bfd_vma offset);
+
+static bool
+rx_elf_initialize_funcdesc (bfd *output_bfd,
+ struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ bfd_vma offset,
+ asection *section,
+ bfd_vma value);
+
static reloc_howto_type *
rx_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
bfd_reloc_code_real_type code)
@@ -291,6 +400,7 @@ rx_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
if (rx_reloc_map [i].bfd_reloc_val == code)
return rx_elf_howto_table + rx_reloc_map[i].rx_reloc_val;
+ bfd_set_error (bfd_error_bad_value);
return NULL;
}
@@ -503,6 +613,7 @@ rx_elf_relocate_section
Elf_Internal_Sym * local_syms,
asection ** local_sections)
{
+ struct elf_rx_link_hash_table *htab;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
Elf_Internal_Rela *rel;
@@ -512,15 +623,32 @@ rx_elf_relocate_section
const char *table_default_cache = NULL;
bfd_vma table_start_cache = 0;
bfd_vma table_end_cache = 0;
+ asection *sgot = NULL;
+ asection *sgotplt = NULL;
+ asection *splt = NULL;
+ asection *srelgot = NULL;
+ asection *sfuncdesc = NULL;
+ bfd_vma *local_got_offsets;
if (elf_elfheader (output_bfd)->e_flags & E_FLAG_RX_PID)
pid_mode = true;
else
pid_mode = false;
+ htab = rx_elf_hash_table (info);
+ if (htab != NULL)
+ {
+ sgot = htab->root.sgot;
+ sgotplt = htab->root.sgotplt;
+ srelgot = htab->root.srelgot;
+ splt = htab->root.splt;
+ sfuncdesc = htab->sfuncdesc;
+ }
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
relend = relocs + input_section->reloc_count;
+ local_got_offsets = elf_local_got_offsets (input_bfd);
+
for (rel = relocs; rel < relend; rel ++)
{
reloc_howto_type *howto;
@@ -533,11 +661,13 @@ rx_elf_relocate_section
const char * name = NULL;
bool unresolved_reloc = true;
int r_type;
+ bfd_vma off;
+ bool resolved_to_zero = false;
r_type = ELF32_R_TYPE (rel->r_info);
r_symndx = ELF32_R_SYM (rel->r_info);
- howto = rx_elf_howto_table + ELF32_R_TYPE (rel->r_info);
+ howto = rx_elf_howto_table + r_type;
h = NULL;
sym = NULL;
sec = NULL;
@@ -567,7 +697,13 @@ rx_elf_relocate_section
name = h->root.root.string;
}
+ if (sec != NULL && discarded_section (sec))
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, 1, relend, R_RX_NONE,
+ howto, 0, contents);
+ if (bfd_link_relocatable (info))
+ continue;
if (startswith (name, "$tableentry$default$"))
{
bfd_vma entry_vma;
@@ -856,6 +992,7 @@ rx_elf_relocate_section
relocation = - relocation;
/* Fall through. */
case R_RX_DIR24S_PCREL:
+ local_plt:
RANGE (-0x800000, 0x7fffff);
#if RX_OPCODE_BIG_ENDIAN
OP (2) = relocation;
@@ -866,6 +1003,9 @@ rx_elf_relocate_section
OP (1) = relocation >> 8;
OP (2) = relocation >> 16;
#endif
+ if (_bfd_elf_section_offset (output_bfd, info, input_section,
+ rel->r_offset) != (bfd_vma) -1)
+ unresolved_reloc = false;
break;
case R_RX_RH_24_OP:
@@ -963,6 +1103,22 @@ rx_elf_relocate_section
OP (2) = relocation >> 16;
OP (3) = relocation >> 24;
}
+
+ if (bfd_link_pic(info) && h == NULL &&
+ (input_section->flags & SEC_ALLOC))
+ {
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+
+ outrel.r_offset = (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+ outrel.r_addend = relocation;
+ outrel.r_info = ELF32_R_INFO (0, R_RX_GLOB_DAT);
+ loc = srelgot->contents;
+ loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ }
break;
case R_RX_DIR32_REV:
@@ -1453,12 +1609,455 @@ rx_elf_relocate_section
case R_RX_OPramtop:
RX_STACK_PUSH (get_ramstart (info, input_bfd, input_section, rel->r_offset));
break;
+ case R_RX_GOT:
+ /* Relocation is to the entry for this symbol in the global
+ offset table. */
+
+ BFD_ASSERT (htab);
+ BFD_ASSERT (sgot != NULL);
+
+ if (h != NULL)
+ {
+ bool dyn;
+
+ off = h->got.offset;
+ BFD_ASSERT (off != (bfd_vma) -1);
+
+ dyn = htab->root.dynamic_sections_created;
+ if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn,
+ bfd_link_pic (info),
+ h)
+ || (bfd_link_pic (info)
+ && SYMBOL_REFERENCES_LOCAL (info, h))
+ || ((ELF_ST_VISIBILITY (h->other)
+ || resolved_to_zero)
+ && h->root.type == bfd_link_hash_undefweak))
+ {
+ /* This is actually a static link, or it is a
+ -Bsymbolic link and the symbol is defined
+ locally, or the symbol was forced to be local
+ because of a version file. We must initialize
+ this entry in the global offset table. Since the
+ offset must always be a multiple of 4, we use the
+ least significant bit to record whether we have
+ initialized it already.
+
+ When doing a dynamic link, we create a .rela.got
+ relocation entry to initialize the value. This
+ is done in the finish_dynamic_symbol routine. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_32 (output_bfd, relocation,
+ sgot->contents + off);
+ h->got.offset |= 1;
+ }
+ }
+ relocation = off;
+ unresolved_reloc = false;
+ }
+ else
+ {
+ BFD_ASSERT (local_got_offsets != NULL
+ && local_got_offsets[r_symndx] != MINUS_ONE);
+
+ off = local_got_offsets[r_symndx];
+
+ /* The offset must always be a multiple of 4. We use
+ the least significant bit to record whether we have
+ already generated the necessary reloc. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+
+ if (bfd_link_pic (info))
+ {
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + off);
+ outrel.r_info = ELF32_R_INFO (0, R_RX_RELATIVE);
+ outrel.r_addend = relocation;
+ loc = srelgot->contents;
+ loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ }
+
+ local_got_offsets[r_symndx] |= 1;
+ }
+
+ relocation = off;
+ unresolved_reloc = false;
+ }
+
+#ifdef GOT_BIAS
+ relocation -= GOT_BIAS;
+#endif
+ RANGE(0, 0x3fffc);
+ ALIGN(3);
+ relocation >>= 2;
+ OP (0) = relocation;
+ OP (1) = relocation >> 8;
+ break;
+
+ case R_RX_GOTOFF:
+ BFD_ASSERT (htab);
+ BFD_ASSERT (sgotplt != NULL);
+ if (h && h->root.type == bfd_link_hash_undefweak)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA+%#" PRIx64 "): "
+ "%s relocation against external symbol \"%s\""),
+ input_bfd, input_section, (uint64_t) rel->r_offset,
+ howto->name, h->root.root.string);
+ return false;
+ }
+ else
+ {
+ relocation -= sgot->output_section->vma;
+ }
+#ifdef GOT_BIAS
+ relocation -= GOT_BIAS;
+#endif
+ OP (0) = relocation;
+ OP (1) = relocation >> 8;
+ OP (2) = relocation >> 16;
+ OP (3) = relocation >> 24;
+
+ break;
+
+ case R_RX_PLT:
+ /* Relocation is to the entry for this symbol in the
+ procedure linkage table. */
+
+ /* Resolve a PLT reloc against a local symbol directly,
+ without using the procedure linkage table. */
+ if (h == NULL || h->plt.refcount == -1)
+ goto local_plt;
+
+ if (splt && h->plt.offset != (bfd_vma) -1)
+ {
+ relocation = splt->output_section->vma + h->plt.offset;
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset) - 1;
+ OP (0) = relocation;
+ OP (1) = relocation >> 8;
+ OP (2) = relocation >> 16;
+ unresolved_reloc = false;
+ }
+
+ break;
+ /* Relocation is to the canonical function descriptor for this
+ symbol, possibly via the GOT. Initialize the GOT
+ entry and function descriptor if necessary. */
+ case R_RX_GOTFUNCDESC:
+ {
+ asection *reloc_section;
+ bfd_vma reloc_offset;
+
+ reloc_section = htab->root.sgot;
+
+ if (h != NULL)
+ reloc_offset = rx_elf_hash_entry (h)->funcdesc.offset;
+ else
+ {
+ union gotref *local_funcdesc;
+ local_funcdesc = rx_elf_local_funcdesc (input_bfd);
+ BFD_ASSERT (local_funcdesc != NULL);
+ reloc_offset = local_funcdesc[r_symndx].offset;
+ }
+ BFD_ASSERT (reloc_offset != MINUS_ONE);
+ reloc_offset += sgot->size;
+
+ if (reloc_offset & 1)
+ {
+ reloc_offset &= ~1;
+ relocation = h->got.offset & ~1;
+ goto funcdesc_done_got;
+ }
+
+ if (h && h->root.type == bfd_link_hash_undefweak
+ && (SYMBOL_CALLS_LOCAL (info, h)
+ || !htab->root.dynamic_sections_created))
+ /* Undefined weak symbol which will not be dynamically
+ resolved later; leave it at zero. */
+ goto funcdesc_leave_zero;
+ else if ( h && SYMBOL_CALLS_LOCAL (info, h)
+ && ! SYMBOL_FUNCDESC_LOCAL (info, h))
+ {
+ /* If the symbol needs a non-local function descriptor
+ but binds locally (i.e., its visibility is
+ protected), emit a dynamic relocation decayed to
+ section+offset. This is an optimization; the dynamic
+ linker would resolve our function descriptor request
+ to our copy of the function anyway. */
+ /*dynindx = elf_section_data (h->root.u.def.section
+ ->output_section)->dynindx;*/
+ relocation += h->root.u.def.section->output_offset
+ + h->root.u.def.value;
+ }
+ else
+ {
+ bfd_vma offset;
+
+ /* Otherwise, we know we have a private function
+ descriptor, so reference it directly. */
+
+ if (h)
+ {
+ bool dyn;
+
+ offset = rx_elf_hash_entry (h)->funcdesc.offset;
+ BFD_ASSERT (offset != MINUS_ONE);
+ if ((offset & 1) == 0)
+ {
+ bfd_vma value;
+ if (h->dynindx == -1)
+ {
+ value = relocation;
+ value -= h->root.u.def.section->output_section->vma;
+ }
+ else
+ {
+ value = h->root.u.def.value;
+ value += h->root.u.def.section->output_offset;
+ }
+ if (!rx_elf_initialize_funcdesc (output_bfd, info, h,
+ offset, NULL, value))
+ return false;
+ rx_elf_hash_entry (h)-> funcdesc.offset |= 1;
+ }
+ relocation = offset & ~1;
+ off = h->got.offset;
+ BFD_ASSERT (off != (bfd_vma) -1);
+ dyn = htab->root.dynamic_sections_created;
+ if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn,
+ bfd_link_pic (info),
+ h)
+ || (bfd_link_pic (info)
+ && SYMBOL_REFERENCES_LOCAL (info, h))
+ || ((ELF_ST_VISIBILITY (h->other)
+ || resolved_to_zero)
+ && h->root.type == bfd_link_hash_undefweak))
+ {
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_32 (output_bfd, relocation,
+ sgot->contents + off);
+ h->got.offset |= 1;
+ }
+ }
+ relocation = off;
+ }
+ else
+ {
+ union gotref *local_funcdesc;
+
+ local_funcdesc = rx_elf_local_funcdesc (input_bfd);
+ offset = local_funcdesc[r_symndx].offset;
+ BFD_ASSERT (offset != MINUS_ONE);
+ if ((offset & 1) == 0)
+ {
+ if (!rx_elf_initialize_funcdesc (output_bfd, info, NULL,
+ offset, sec,
+ sec->vma + sym->st_value))
+ return false;
+ local_funcdesc[r_symndx].offset |= 1;
+ }
+ BFD_ASSERT (local_got_offsets != NULL
+ && local_got_offsets[r_symndx] != MINUS_ONE);
+
+ off = local_got_offsets[r_symndx];
+ relocation = htab->sfuncdesc->output_offset + (off & ~1);
+ unresolved_reloc = false;
+ }
+ }
+
+ if (!bfd_link_pic(info) && SYMBOL_FUNCDESC_LOCAL (info, h))
+ {
+ bfd_vma offset;
+ BFD_ASSERT (htab);
+
+ if (rx_elf_osec_readonly_p (output_bfd,
+ input_section->output_section))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA+%#" PRIx64 "): "
+ "cannot emit fixup to `%s' in read-only section"),
+ input_bfd,
+ input_section,
+ (uint64_t) rel->r_offset,
+ name);
+ return false;
+ }
+
+ offset = _bfd_elf_section_offset (output_bfd, info,
+ reloc_section, reloc_offset);
+
+ if (offset != (bfd_vma)-1)
+ rx_elf_add_rofixup (output_bfd, htab->srofixup,
+ offset
+ + reloc_section->output_section->vma
+ + reloc_section->output_offset);
+ }
+ else if ((reloc_section->output_section->flags
+ & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+ {
+ if (rx_elf_osec_readonly_p (output_bfd,
+ reloc_section->output_section))
+ {
+ info->callbacks->warning
+ (info,
+ _("cannot emit dynamic relocations in read-only section"),
+ name, input_bfd, reloc_section, reloc_offset);
+ return false;
+ }
+ }
+ funcdesc_leave_zero:
+ bfd_put_32 (output_bfd, relocation,
+ reloc_section->contents + reloc_offset);
+ if (h != NULL)
+ h->got.offset |= 1;
+ else
+ local_got_offsets[r_symndx] |= 1;
+
+ funcdesc_done_got:
+ unresolved_reloc = false;
+#ifdef GOT_BIAS
+ relocation -= GOT_BIAS;
+#endif
+ RANGE(0, 0x3fffc);
+ ALIGN(3);
+ relocation >>= 2;
+ OP (0) = relocation;
+ OP (1) = relocation >> 8;
+ break;
+ }
+ case R_RX_FUNCDESC:
+ case R_RX_GOTOFFFUNCDESC:
+
+ relocation = 0;
+
+ if (h && (h->root.type == bfd_link_hash_undefweak
+ || !SYMBOL_FUNCDESC_LOCAL (info, h)))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA+%#" PRIx64 "): "
+ "%s relocation against external symbol \"%s\""),
+ input_bfd, input_section, (uint64_t) rel->r_offset,
+ howto->name, h->root.root.string);
+ return false;
+ }
+ else
+ {
+ bfd_vma offset;
+
+ /* Otherwise, we know we have a private function
+ descriptor, so reference it directly. */
+ if (h)
+ {
+ offset = rx_elf_hash_entry (h)->funcdesc.offset;
+ BFD_ASSERT (offset != MINUS_ONE);
+ if ((offset & 1) == 0)
+ {
+ bfd_vma value;
+ if (h->dynindx == -1)
+ {
+ value = relocation;
+ }
+ else
+ {
+ value = h->root.u.def.value;
+ value += h->root.u.def.section->output_offset;
+ }
+ if (!rx_elf_initialize_funcdesc (output_bfd, info, h,
+ offset, NULL, value))
+ return false;
+ rx_elf_hash_entry (h)->funcdesc.offset |= 1;
+ }
+ relocation = offset & ~1;
+ }
+ else
+ {
+ union gotref *local_funcdesc;
+
+ local_funcdesc = rx_elf_local_funcdesc (input_bfd);
+ offset = local_funcdesc[r_symndx].offset;
+ BFD_ASSERT (offset != MINUS_ONE);
+ if ((offset & 1) == 0)
+ {
+ if (!rx_elf_initialize_funcdesc (output_bfd, info, NULL,
+ offset, sec,
+ sec->output_offset
+ + sym->st_value))
+ return false;
+ local_funcdesc[r_symndx].offset |= 1;
+ }
+ }
+ relocation = htab->sfuncdesc->output_offset + (offset & ~1);
+ unresolved_reloc = false;
+ if (r_type == R_RX_FUNCDESC)
+ {
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+
+ outrel.r_offset = (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+ outrel.r_addend = sfuncdesc->output_section->vma + relocation;
+ outrel.r_info = ELF32_R_INFO (0, R_RX_GLOB_DAT);
+ loc = srelgot->contents;
+ loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ }
+ }
+
+#ifdef GOT_BIAS
+ relocation -= GOT_BIAS;
+#endif
+ OP (0) = relocation;
+ OP (1) = relocation >> 8;
+ OP (2) = relocation >> 16;
+ OP (3) = relocation >> 24;
+ break;
default:
r = bfd_reloc_notsupported;
break;
}
+ /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
+ because such sections are not SEC_ALLOC and thus ld.so will
+ not process them. */
+ if (unresolved_reloc && h != NULL
+ && !((input_section->flags & SEC_DEBUGGING) != 0
+ && h->def_dynamic)
+ && _bfd_elf_section_offset (output_bfd, info, input_section,
+ rel->r_offset) != (bfd_vma) -1)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA+%#" PRIx64 "): "
+ "unresolvable %s relocation against symbol `%s'"),
+ input_bfd,
+ input_section,
+ (uint64_t) rel->r_offset,
+ howto->name,
+ name);
+ return false;
+ }
+
if (r != bfd_reloc_ok)
{
const char * msg = NULL;
@@ -3414,7 +4013,7 @@ rx_dump_symtab (bfd * abfd, void * internal_syms, void * external_syms)
}
}
-char *
+const char *
rx_get_reloc (long reloc)
{
if (0 <= reloc && reloc < R_RX_max)
@@ -3565,7 +4164,6 @@ rx_set_section_contents (bfd * abfd,
bfd_size_type scount;
#ifdef DJDEBUG
- bfd_size_type i;
fprintf (stderr, "\ndj: set %ld %ld to %s %s e%d sc%d\n",
(long) offset, (long) count, section->name,
@@ -4048,6 +4646,1634 @@ rx_additional_link_map_text (bfd *obfd, struct bfd_link_info *info, FILE *mapfil
bfd_hash_traverse (&(info->hash->table), rx_table_map, &stuff);
}
+static enum elf_reloc_type_class
+rx_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ const asection *rel_sec ATTRIBUTE_UNUSED,
+ const Elf_Internal_Rela *rela)
+{
+ switch ((int) ELF32_R_TYPE (rela->r_info))
+ {
+ case R_RX_RELATIVE:
+ return reloc_class_relative;
+ case R_RX_JMP_SLOT:
+ return reloc_class_plt;
+ case R_RX_COPY:
+ return reloc_class_copy;
+ default:
+ return reloc_class_normal;
+ }
+}
+
+/* FDPIC binaries have a default 128K stack. */
+#define DEFAULT_STACK_SIZE 0x20000
+
+/* The name of the dynamic interpreter. This is put in the .interp
+ section. */
+#define ELF_DYNAMIC_INTERPRETER "/lib/ld-uClibc.so.1"
+
+#define FDPIC_PLT_ENTRY_SIZE 30
+#define FDPIC_PLT_FUNC 2
+#define FDPIC_PLT_LAZY 14
+#define FDPIC_PLT_REL 24
+
+/* First entry in an absolute procedure linkage table look like this. */
+static const bfd_byte fdpic_elf_rx_plt_entry[FDPIC_PLT_ENTRY_SIZE] =
+{
+ 0x70, 0xd5, /* 0: add #func@GOTOFFUNCDESC, r13, r5 */
+ 0, 0, 0, 0, /* 2: */
+ 0xec, 0x5e, /* 6: mov.l [r5], r14 */
+ 0xed, 0x5d, 0x01, /* 8: mov.l 4[r5], r13 */
+ 0x7f, 0x0e, /* b: jmp r14 */
+ 0x03, /* d: nop */
+ 0xec, 0xde, /* e: mov.l [r13], r14 */
+ 0xfd, 0x26, 0x0e, /* 10: mov.l r14, [-r0] */
+ 0xed, 0xde, 0x01, /* 13: mov.l 4[r13], r14 */
+ 0xfb, 0x52, /* 16: mov.l #rel.plt offset, r5 */
+ 0, 0, 0, 0, /* 18: */
+ 0x02, /* 1c: rts (jmp [r13]) */
+ 0x03, /* 1d: nop */
+};
+
+struct elf_rx_pcrel_relocs_copied
+{
+ /* Next section. */
+ struct elf_rx_pcrel_relocs_copied *next;
+ /* A section in dynobj. */
+ asection *section;
+ /* Number of relocs copied in this section. */
+ bfd_size_type count;
+};
+
+#define is_rx_elf(bfd) \
+ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+ && elf_tdata (bfd) != NULL \
+ && elf_object_id (bfd) == RX_ELF_DATA)
+
+/* Return true if OUTPUT_BFD is an FDPIC object. */
+static bool
+fdpic_object_p (bfd *abfd)
+{
+ extern const bfd_target rx_elf32_linux_le_vec;
+
+ return (abfd->xvec == &rx_elf32_linux_le_vec);
+}
+
+/* Override the generic function because we need to store rx_elf_obj_tdata
+ as the specific tdata. */
+
+inline static bool
+rx_elf_mkobject (bfd *abfd)
+{
+ return bfd_elf_allocate_object (abfd, sizeof (struct rx_elf_obj_tdata));
+}
+
+/* Install a 32-bit PLT field starting at ADDR, which occurs in OUTPUT_BFD.
+ VALUE is the field's value and CODE_P is true if VALUE refers to code,
+ not data. */
+
+inline static void
+install_plt_field (bfd *output_bfd, bool code_p ATTRIBUTE_UNUSED,
+ unsigned long value, bfd_byte *addr)
+{
+ bfd_put_32 (output_bfd, value, addr);
+}
+
+/* Create an entry in an RX ELF linker hash table. */
+
+static struct bfd_hash_entry *
+rx_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
+{
+ struct elf_rx_link_hash_entry *ret =
+ (struct elf_rx_link_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (ret == (struct elf_rx_link_hash_entry *) NULL)
+ ret = ((struct elf_rx_link_hash_entry *)
+ bfd_hash_allocate (table,
+ sizeof (struct elf_rx_link_hash_entry)));
+ if (ret == (struct elf_rx_link_hash_entry *) NULL)
+ return (struct bfd_hash_entry *) ret;
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct elf_rx_link_hash_entry *)
+ _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
+ table, string));
+ if (ret != (struct elf_rx_link_hash_entry *) NULL)
+ {
+ ret->gotplt_refcount = 0;
+ ret->funcdesc.refcount = 0;
+ ret->abs_funcdesc_refcount = 0;
+ ret->got_type = GOT_UNKNOWN;
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Create an RX ELF linker hash table. */
+
+static struct bfd_link_hash_table *
+rx_elf_link_hash_table_create (bfd *abfd)
+{
+ struct elf_rx_link_hash_table *ret;
+ size_t amt = sizeof (struct elf_rx_link_hash_table);
+
+ ret = (struct elf_rx_link_hash_table *) bfd_zmalloc (amt);
+ if (ret == (struct elf_rx_link_hash_table *) NULL)
+ return NULL;
+
+ if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
+ rx_elf_link_hash_newfunc,
+ sizeof (struct elf_rx_link_hash_entry)))
+ {
+ free (ret);
+ return NULL;
+ }
+
+ if (fdpic_object_p (abfd))
+ {
+ ret->root.dt_pltgot_required = true;
+ ret->fdpic_p = true;
+ }
+ return &ret->root.root;
+}
+
+static bool
+rx_elf_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info, asection *p)
+{
+ struct elf_rx_link_hash_table *htab = rx_elf_hash_table (info);
+
+ /* Non-FDPIC binaries do not need dynamic symbols for sections. */
+ if (!htab->fdpic_p)
+ return true;
+
+ /* We need dynamic symbols for every section, since segments can
+ relocate independently. */
+ switch (elf_section_data (p)->this_hdr.sh_type)
+ {
+ case SHT_PROGBITS:
+ case SHT_NOBITS:
+ /* If sh_type is yet undecided, assume it could be
+ SHT_PROGBITS/SHT_NOBITS. */
+ case SHT_NULL:
+ return false;
+
+ /* There shouldn't be section relative relocations
+ against any other section. */
+ default:
+ return true;
+ }
+}
+
+/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
+ shortcuts to them in our hash table. */
+
+static bool
+create_got_section (bfd *dynobj, struct bfd_link_info *info)
+{
+ struct elf_rx_link_hash_table *htab;
+
+ if (! _bfd_elf_create_got_section (dynobj, info))
+ return false;
+
+ htab = rx_elf_hash_table (info);
+ if (htab == NULL)
+ return false;
+
+ htab->sfuncdesc = bfd_make_section_anyway_with_flags (dynobj, ".got.funcdesc",
+ (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY));
+ if (htab->sfuncdesc == NULL
+ || !bfd_set_section_alignment (htab->sfuncdesc, 2))
+ return false;
+
+ htab->srelfuncdesc = bfd_make_section_anyway_with_flags (dynobj,
+ ".rela.got.funcdesc",
+ (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY));
+ if (htab->srelfuncdesc == NULL
+ || !bfd_set_section_alignment (htab->srelfuncdesc, 2))
+ return false;
+
+ /* Also create .rofixup. */
+ htab->srofixup = bfd_make_section_anyway_with_flags (dynobj, ".rofixup",
+ (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY));
+ if (htab->srofixup == NULL
+ || !bfd_set_section_alignment (htab->srofixup, 2))
+ return false;
+
+ return true;
+}
+
+/* Create dynamic sections when linking against a dynamic object. */
+
+static bool
+rx_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
+{
+ struct elf_rx_link_hash_table *htab;
+ flagword flags, pltflags;
+ asection *s;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ htab = rx_elf_hash_table (info);
+ if (htab == NULL)
+ return false;
+
+ if (htab->root.dynamic_sections_created)
+ return true;
+
+ /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
+ .rel[a].bss sections. */
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
+
+ pltflags = flags;
+ pltflags |= SEC_CODE;
+ if (bed->plt_not_loaded)
+ pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS);
+ if (bed->plt_readonly)
+ pltflags |= SEC_READONLY;
+
+ s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags);
+ htab->root.splt = s;
+ if (s == NULL
+ || !bfd_set_section_alignment (s, bed->plt_alignment))
+ return false;
+
+ if (bed->want_plt_sym)
+ {
+ /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
+ .plt section. */
+ struct elf_link_hash_entry *h;
+ struct bfd_link_hash_entry *bh = NULL;
+
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s,
+ (bfd_vma) 0, (const char *) NULL, false,
+ get_elf_backend_data (abfd)->collect, &bh)))
+ return false;
+
+ h = (struct elf_link_hash_entry *) bh;
+ h->def_regular = 1;
+ h->type = STT_OBJECT;
+ htab->root.hplt = h;
+
+ if (bfd_link_pic (info)
+ && ! bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ s = bfd_make_section_anyway_with_flags (abfd,
+ bed->default_use_rela_p
+ ? ".rela.plt" : ".rel.plt",
+ flags | SEC_READONLY);
+ htab->root.srelplt = s;
+ if (s == NULL
+ || !bfd_set_section_alignment (s, 2))
+ return false;
+
+ if (htab->root.sgot == NULL
+ && !create_got_section (abfd, info))
+ return false;
+
+ if (bed->want_dynbss)
+ {
+ /* The .dynbss section is a place to put symbols which are defined
+ by dynamic objects, are referenced by regular objects, and are
+ not functions. We must allocate space for them in the process
+ image and use a R_*_COPY reloc to tell the dynamic linker to
+ initialize them at run time. The linker script puts the .dynbss
+ section into the .bss section of the final image. */
+ s = bfd_make_section_anyway_with_flags (abfd, ".dynbss",
+ SEC_ALLOC | SEC_LINKER_CREATED);
+ htab->root.sdynbss = s;
+ if (s == NULL)
+ return false;
+
+ /* The .rel[a].bss section holds copy relocs. This section is not
+ normally needed. We need to create it here, though, so that the
+ linker will map it to an output section. We can't just create it
+ only if we need it, because we will not know whether we need it
+ until we have seen all the input files, and the first time the
+ main linker code calls BFD after examining all the input files
+ (size_dynamic_sections) the input sections have already been
+ mapped to the output sections. If the section turns out not to
+ be needed, we can discard it later. We will never need this
+ section when generating a shared object, since they do not use
+ copy relocs. */
+ if (! bfd_link_pic (info))
+ {
+ s = bfd_make_section_anyway_with_flags (abfd,
+ (bed->default_use_rela_p
+ ? ".rela.bss" : ".rel.bss"),
+ flags | SEC_READONLY);
+ htab->root.srelbss = s;
+ if (s == NULL
+ || !bfd_set_section_alignment (s, 2))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* 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
+ change the definition to something the rest of the link can
+ understand. */
+
+static bool
+rx_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ struct elf_rx_link_hash_table *htab;
+ asection *s;
+
+ htab = rx_elf_hash_table (info);
+ if (htab == NULL)
+ return false;
+
+ /* Make sure we know what is going on here. */
+ BFD_ASSERT (htab->root.dynobj != NULL
+ && (h->needs_plt
+ || h->is_weakalias
+ || (h->def_dynamic
+ && h->ref_regular
+ && !h->def_regular)));
+
+ /* If this is a function, put it in the procedure linkage table. We
+ will fill in the contents of the procedure linkage table later,
+ when we know the address of the .got section. */
+ if (h->type == STT_FUNC
+ || h->needs_plt)
+ {
+ if (h->plt.refcount <= 0
+ || SYMBOL_CALLS_LOCAL (info, h)
+ || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ && h->root.type == bfd_link_hash_undefweak))
+ {
+ /* This case can occur if we saw a PLT reloc in an input
+ file, but the symbol was never referred to by a dynamic
+ object. In such a case, we don't actually need to build
+ a procedure linkage table, and we can just do a REL32
+ reloc instead. */
+ h->plt.offset = (bfd_vma) -1;
+ h->needs_plt = 0;
+ }
+
+ return true;
+ }
+ else
+ h->plt.offset = (bfd_vma) -1;
+
+ /* If this is a weak symbol, and there is a real definition, the
+ processor independent code will have arranged for us to see the
+ real definition first, and we can just use the same value. */
+ if (h->is_weakalias)
+ {
+ struct elf_link_hash_entry *def = weakdef (h);
+ 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;
+ if (info->nocopyreloc)
+ h->non_got_ref = def->non_got_ref;
+ return true;
+ }
+
+ /* This is a reference to a symbol defined by a dynamic object which
+ is not a function. */
+
+ /* If we are creating a shared library, we must presume that the
+ only references to the symbol are via the global offset table.
+ 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;
+
+ /* 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;
+
+ /* If -z nocopyreloc was given, we won't generate them either. */
+ if (0 && info->nocopyreloc)
+ {
+ h->non_got_ref = 0;
+ return true;
+ }
+
+ /* 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 (0 && !_bfd_elf_readonly_dynrelocs (h))
+ {
+ h->non_got_ref = 0;
+ return true;
+ }
+
+ /* We must allocate the symbol in our .dynbss section, which will
+ become part of the .bss section of the executable. There will be
+ an entry for this symbol in the .dynsym section. The dynamic
+ object will contain position independent code, so all references
+ from the dynamic object to this symbol will go through the global
+ offset table. The dynamic linker will use the .dynsym entry to
+ determine the address it must put in the global offset table, so
+ both the dynamic object and the regular object will refer to the
+ same memory location for the variable. */
+
+ s = htab->root.sdynbss;
+ BFD_ASSERT (s != NULL);
+
+ /* We must generate a R_RX_COPY reloc to tell the dynamic linker to
+ copy the initial value out of the dynamic object and into the
+ runtime process image. We need to remember the offset into the
+ .rela.bss section we are going to use. */
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
+ {
+ asection *srel;
+
+ srel = htab->root.srelbss;
+ BFD_ASSERT (srel != NULL);
+ srel->size += sizeof (Elf32_External_Rela);
+ h->needs_copy = 1;
+ }
+
+ return _bfd_elf_adjust_dynamic_copy (info, h, s);
+}
+
+/* Allocate space in .plt, .got and associated reloc sections for
+ dynamic relocs. */
+
+static bool
+allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
+{
+ struct bfd_link_info *info;
+ struct elf_rx_link_hash_table *htab;
+ struct elf_rx_link_hash_entry *eh;
+ struct elf_dyn_relocs *p;
+
+ if (h->root.type == bfd_link_hash_indirect)
+ return true;
+
+ info = (struct bfd_link_info *) inf;
+ htab = rx_elf_hash_table (info);
+ if (htab == NULL)
+ return false;
+
+ eh = (struct elf_rx_link_hash_entry *) h;
+ if ((h->got.refcount > 0
+ || h->forced_local)
+ && eh->gotplt_refcount > 0)
+ {
+ /* The symbol has been forced local, or we have some direct got refs,
+ so treat all the gotplt refs as got refs. */
+ h->got.refcount += eh->gotplt_refcount;
+ if (h->plt.refcount >= eh->gotplt_refcount)
+ h->plt.refcount -= eh->gotplt_refcount;
+ }
+
+ if (htab->root.dynamic_sections_created
+ && h->plt.refcount > 0
+ && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ {
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ if (bfd_link_pic (info)
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
+ {
+ asection *s = htab->root.splt;
+
+ h->plt.offset = s->size;
+
+ /* If this symbol is not defined in a regular file, and we are
+ not generating a shared library, then set the symbol to this
+ location in the .plt. This is required to make function
+ pointers compare as equal between the normal executable and
+ the shared library. Skip this for FDPIC, since the
+ function's address will be the address of the canonical
+ function descriptor. */
+ if (!htab->fdpic_p && !bfd_link_pic (info) && !h->def_regular)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = h->plt.offset;
+ }
+
+ /* Make room for this entry. */
+ s->size += sizeof(fdpic_elf_rx_plt_entry);
+
+ /* We also need to make an entry in the .got.plt section, which
+ will be placed in the .got section by the linker script. */
+ if (!htab->fdpic_p)
+ htab->root.sgotplt->size += 4;
+ else
+ htab->root.sgotplt->size += 8;
+
+ /* We also need to make an entry in the .rel.plt section. */
+ htab->root.srelplt->size += sizeof (Elf32_External_Rela);
+
+ }
+ else
+ {
+ h->plt.offset = (bfd_vma) -1;
+ h->needs_plt = 0;
+ }
+ }
+ else
+ {
+ h->plt.offset = (bfd_vma) -1;
+ h->needs_plt = 0;
+ }
+
+ if ((h->got.refcount > 0) || (h->non_got_ref && h->plt.refcount > 0))
+ {
+ asection *sgot;
+ bool dyn;
+ enum got_type got_type = rx_elf_hash_entry (h)->got_type;
+
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ sgot = htab->root.sgot;
+ if (sgot->size == 0)
+ sgot->size += 12;
+
+ h->got.offset = sgot->size;
+ sgot->size += 4;
+ dyn = htab->root.dynamic_sections_created;
+ if (!dyn)
+ {
+ /* No dynamic relocations required. */
+ if (htab->fdpic_p && !bfd_link_pic (info)
+ && h->root.type != bfd_link_hash_undefweak
+ && (got_type == GOT_NORMAL || got_type == GOT_FUNCDESC))
+ htab->srofixup->size += 4;
+ }
+ else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
+ && (bfd_link_pic (info))) {
+ htab->root.srelgot->size += sizeof (Elf32_External_Rela);
+ }
+ else if (htab->fdpic_p
+ && !bfd_link_pic (info)
+ && got_type == GOT_NORMAL
+ && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ htab->srofixup->size += 4;
+ }
+ else
+ h->got.offset = MINUS_ONE;
+
+ /* Allocate space for any dynamic relocations to function
+ descriptors, canonical or otherwise. We need to relocate the
+ reference unless it resolves to zero, which only happens for
+ undefined weak symbols (either non-default visibility, or when
+ static linking). Any GOT slot is accounted for elsewhere. */
+ if (eh->abs_funcdesc_refcount > 0
+ && (h->root.type != bfd_link_hash_undefweak
+ || (htab->root.dynamic_sections_created
+ && ! SYMBOL_CALLS_LOCAL (info, h))))
+ {
+ if (!bfd_link_pic (info) && SYMBOL_FUNCDESC_LOCAL (info, h))
+ htab->srofixup->size += eh->abs_funcdesc_refcount * 4;
+ else
+ htab->root.srelgot->size
+ += eh->abs_funcdesc_refcount * sizeof (Elf32_External_Rela);
+ }
+
+ /* We must allocate a function descriptor if there are references to
+ a canonical descriptor (R_RX_GOTFUNCDESC or R_RX_FUNCDESC) and
+ the dynamic linker isn't going to allocate it. None of this
+ applies if we already created one in .got.plt, but if the
+ canonical function descriptor can be in this object, there
+ won't be a PLT entry at all. */
+ if ((eh->funcdesc.refcount > 0
+ || (h->got.offset != MINUS_ONE && eh->got_type == GOT_FUNCDESC))
+ && h->root.type != bfd_link_hash_undefweak)
+ {
+ /* Make room for this function descriptor. */
+ eh->funcdesc.offset = htab->sfuncdesc->size;
+ htab->sfuncdesc->size += 8;
+
+ /* We will need a relocation or two fixups to initialize the
+ function descriptor, so allocate those too. */
+ if (!bfd_link_pic(info) && SYMBOL_CALLS_LOCAL (info, h))
+ htab->srofixup->size += 8;
+ else
+ htab->srelfuncdesc->size += sizeof (Elf32_External_Rela);
+ }
+
+ if (h->dyn_relocs == NULL)
+ return true;
+
+ /* In the shared -Bsymbolic case, discard space allocated for
+ dynamic pc-relative relocs against symbols which turn out to be
+ defined in regular objects. For the normal shared case, discard
+ space for pc-relative relocs that have become local due to symbol
+ visibility changes. */
+
+ if (bfd_link_pic (info))
+ {
+ if (SYMBOL_CALLS_LOCAL (info, h))
+ {
+ struct elf_dyn_relocs **pp;
+
+ for (pp = &h->dyn_relocs; (p = *pp) != NULL; )
+ {
+ p->count -= p->pc_count;
+ p->pc_count = 0;
+ if (p->count == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
+ }
+
+ /* Also discard relocs on undefined weak syms with non-default
+ visibility. */
+ 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))
+ h->dyn_relocs = NULL;
+
+ /* Make sure undefined weak symbols are output as a dynamic
+ symbol in PIEs. */
+ else if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+ }
+ }
+ else
+ {
+ /* For the non-shared case, discard space for relocs against
+ symbols which turn out to need copy relocs or are not
+ dynamic. */
+
+ if (!h->non_got_ref
+ && ((h->def_dynamic
+ && !h->def_regular)
+ || (htab->root.dynamic_sections_created
+ && (h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_undefined))))
+ {
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ /* If that succeeded, we know we'll be keeping all the
+ relocs. */
+ if (h->dynindx != -1)
+ goto keep;
+ }
+
+ h->dyn_relocs = NULL;
+
+ keep: ;
+ }
+
+ /* Finally, allocate space. */
+ for (p = h->dyn_relocs; p != NULL; p = p->next)
+ {
+ asection *sreloc = elf_section_data (p->sec)->sreloc;
+ sreloc->size += p->count * sizeof (Elf32_External_Rela);
+ /* If we need relocations, we do not need fixups. */
+ if (htab->fdpic_p && !bfd_link_pic(info))
+ htab->srofixup->size -= 4 * (p->count - p->pc_count);
+ }
+ return true;
+}
+
+/* This function is called after all the input files have been read,
+ and the input sections have been assigned to output sections.
+ It's a convenient place to determine the PLT style. */
+
+static bool
+rx_elf_early_size_sections (bfd *output_bfd, struct bfd_link_info *info)
+{
+ if (rx_elf_hash_table (info)->fdpic_p && !bfd_link_relocatable (info)
+ && !bfd_elf_stack_segment_size (output_bfd, info,
+ "__stacksize", DEFAULT_STACK_SIZE))
+ return false;
+ return true;
+}
+
+/* Reserve space for COUNT dynamic relocations in relocation selection
+ SRELOC. */
+
+static bool
+rx_elf_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info)
+{
+ struct elf_rx_link_hash_table *htab;
+ bfd *dynobj;
+ asection *s;
+ bool relocs;
+ bfd *ibfd;
+
+ htab = rx_elf_hash_table (info);
+ if (htab == NULL)
+ return false;
+
+ dynobj = htab->root.dynobj;
+ if (dynobj == NULL)
+ return true;
+
+
+ if (htab->root.dynamic_sections_created)
+ {
+ /* Set the contents of the .interp section to the interpreter. */
+ if (bfd_link_executable (info) && !info->nointerp)
+ {
+ s = bfd_get_linker_section (dynobj, ".interp");
+ BFD_ASSERT (s != NULL);
+ s->size = sizeof ELF_DYNAMIC_INTERPRETER;
+ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+ s->alloced = 1;
+ }
+ }
+
+ /* Set up .got offsets for local syms, and space for local dynamic
+ relocs. */
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+ {
+ bfd_signed_vma *local_got;
+ bfd_signed_vma *end_local_got;
+ bfd_size_type locsymcount;
+ Elf_Internal_Shdr *symtab_hdr;
+ asection *srel;
+ union gotref *local_funcdesc, *end_local_funcdesc;
+ char *local_got_type;
+
+ if (! is_rx_elf (ibfd))
+ continue;
+
+ symtab_hdr = & elf_symtab_hdr (ibfd);
+ locsymcount = symtab_hdr->sh_info;
+ for (s = ibfd->sections; s != NULL; s = s->next)
+ {
+ struct elf_dyn_relocs *p;
+
+ for (p = ((struct elf_dyn_relocs *)
+ elf_section_data (s)->local_dynrel);
+ p != NULL;
+ p = p->next)
+ {
+ if (! bfd_is_abs_section (p->sec)
+ && bfd_is_abs_section (p->sec->output_section))
+ {
+ /* Input section has been discarded, either because
+ it is a copy of a linkonce section or due to
+ linker script /DISCARD/, so we'll be discarding
+ the relocs too. */
+ }
+ else if (p->count != 0)
+ {
+ srel = elf_section_data (p->sec)->sreloc;
+ srel->size += p->count * sizeof (Elf32_External_Rela);
+ if ((p->sec->output_section->flags & SEC_READONLY) != 0)
+ {
+ info->flags |= DF_TEXTREL;
+ info->callbacks->minfo (_("%pB: dynamic relocation in read-only section `%pA'\n"),
+ p->sec->owner, p->sec);
+
+ /* If we need relocations, we do not need fixups. */
+ if (htab->fdpic_p && !bfd_link_pic(info))
+ htab->srofixup->size -= 4 * (p->count - p->pc_count);
+ }
+ }
+ }
+ if (s->flags & SEC_ALLOC && s->reloc_count > 0)
+ {
+ Elf_Internal_Rela *rel = elf_section_data (s)->relocs;
+ unsigned long r_symndx;
+ unsigned int r;
+
+ srel = htab->root.srelgot;
+ for (r = 0; r < s->reloc_count; r++, rel++)
+ {
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if ((bfd_link_pic(info) &&
+ ELF32_R_TYPE(rel->r_info) == R_RX_DIR32 &&
+ r_symndx < locsymcount) ||
+ ELF32_R_TYPE(rel->r_info) == R_RX_FUNCDESC)
+ srel->size += sizeof (Elf32_External_Rela);
+ }
+ }
+ }
+
+ s = htab->root.sgot;
+ srel = htab->root.srelgot;
+ local_got = elf_local_got_refcounts (ibfd);
+ if (local_got)
+ {
+ int r_indx;
+ end_local_got = local_got + locsymcount;
+ local_got_type = rx_elf_local_got_type (ibfd);
+ local_funcdesc = rx_elf_local_funcdesc (ibfd);
+ for (r_indx = 0; local_got < end_local_got; ++local_got, ++local_got_type, r_indx++)
+ {
+ if (*local_got > 0)
+ {
+ if (s->size == 0)
+ s->size += 12;
+ *local_got = s->size;
+ s->size += 4;
+
+ switch (*local_got_type)
+ {
+ case GOT_FUNCDESC:
+ if (local_funcdesc == NULL)
+ {
+ bfd_size_type size;
+
+ size = locsymcount * sizeof (union gotref);
+ local_funcdesc = (union gotref *) bfd_zalloc (ibfd,
+ size);
+ if (local_funcdesc == NULL)
+ return false;
+ rx_elf_local_funcdesc (ibfd) = local_funcdesc;
+ local_funcdesc += (local_got
+ - elf_local_got_refcounts (ibfd));
+ }
+ local_funcdesc->refcount++;
+ break;
+ case GOT_NORMAL:
+ if (bfd_link_pic(info))
+ srel->size += sizeof (Elf32_External_Rela);
+ else
+ htab->srofixup->size += 4;
+ break;
+ }
+ }
+ if (local_funcdesc)
+ local_funcdesc++;
+ }
+ }
+ local_funcdesc = rx_elf_local_funcdesc (ibfd);
+ if (local_funcdesc)
+ {
+ int r_indx = 0;
+ end_local_funcdesc = local_funcdesc + locsymcount;
+
+ for (; local_funcdesc < end_local_funcdesc; ++local_funcdesc)
+ {
+ if (local_funcdesc->refcount > 0)
+ {
+ local_funcdesc->offset = htab->sfuncdesc->size;
+ htab->sfuncdesc->size += 8;
+ if (!bfd_link_pic (info))
+ htab->srofixup->size += 8;
+ else
+ htab->srelfuncdesc->size += sizeof (Elf32_External_Rela);
+ }
+ else
+ local_funcdesc->offset = MINUS_ONE;
+ r_indx++;
+ }
+ }
+ }
+ /* Only the reserved entries should be present. For FDPIC, they go at
+ the end of .got.plt. */
+ if (htab->fdpic_p)
+ {
+ BFD_ASSERT (htab->root.sgotplt && htab->root.sgotplt->size == 12);
+ htab->root.sgotplt->size = 0;
+ }
+
+ /* Allocate global sym .plt and .got entries, and space for global
+ sym dynamic relocs. */
+ elf_link_hash_traverse (&htab->root, allocate_dynrelocs, info);
+
+ if (htab->fdpic_p)
+ {
+ htab->root.hgot->root.u.def.value = htab->root.sgotplt->size;
+ htab->root.sgotplt->size += 12;
+ }
+
+ /* At the very end of the .rofixup section is a pointer to the GOT. */
+ if (htab->fdpic_p && htab->srofixup != NULL)
+ htab->srofixup->size += 4;
+
+ /* We now have determined the sizes of the various dynamic sections.
+ Allocate memory for them. */
+ relocs = false;
+ for (s = dynobj->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_LINKER_CREATED) == 0)
+ continue;
+
+ if (s == htab->root.splt
+ || s == htab->root.sgot
+ || s == htab->root.srelgot
+ || s == htab->root.srelplt
+ || s == htab->root.sgotplt
+ || s == htab->sfuncdesc
+ || s == htab->srofixup
+ || s == htab->root.sdynbss)
+ {
+ /* Strip this section if we don't need it; see the
+ comment below. */
+ }
+ else if (startswith (bfd_section_name (s), ".rela"))
+ {
+ if (s->size != 0 && s != htab->root.srelplt )
+ relocs = true;
+
+ /* We use the reloc_count field as a counter if we need
+ to copy relocs into the output file. */
+ s->reloc_count = 0;
+ }
+ else
+ {
+ /* It's not one of our sections, so don't allocate space. */
+ continue;
+ }
+
+ if (s->size == 0)
+ {
+ /* If we don't need this section, strip it from the
+ output file. This is mostly to handle .rela.bss and
+ .rela.plt. We must create both sections in
+ create_dynamic_sections, because they must be created
+ before the linker maps input sections to output
+ sections. The linker does that before
+ adjust_dynamic_symbol is called, and it is that
+ function which decides whether anything needs to go
+ into these sections. */
+
+ s->flags |= SEC_EXCLUDE;
+ continue;
+ }
+
+ if ((s->flags & SEC_HAS_CONTENTS) == 0)
+ continue;
+
+ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
+ if (s->contents == NULL)
+ return false;
+ s->alloced = 1;
+ }
+
+ return _bfd_elf_add_dynamic_tags (output_bfd, info, relocs);
+}
+
+/* Add a dynamic relocation to the SRELOC section. */
+
+inline static bfd_vma
+rx_elf_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset,
+ int reloc_type, long dynindx, bfd_vma addend)
+{
+ Elf_Internal_Rela outrel;
+ bfd_vma reloc_offset;
+
+ outrel.r_offset = offset;
+ outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
+ outrel.r_addend = addend;
+
+ reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rela);
+
+ BFD_ASSERT (reloc_offset < sreloc->size);
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ sreloc->contents + reloc_offset);
+ sreloc->reloc_count++;
+
+ return reloc_offset;
+}
+
+/* Add an FDPIC read-only fixup. */
+inline static void
+rx_elf_add_rofixup (bfd *output_bfd, asection *srofixup, bfd_vma offset)
+{
+ bfd_vma fixup_offset;
+
+ fixup_offset = srofixup->reloc_count++ * 4;
+ BFD_ASSERT (fixup_offset < srofixup->size);
+ bfd_put_32 (output_bfd, offset, srofixup->contents + fixup_offset);
+}
+
+/* Find the segment number in which OSEC, and output section, is
+ located. */
+
+static unsigned
+rx_elf_osec_to_segment (bfd *output_bfd, asection *osec)
+{
+ Elf_Internal_Phdr *p = NULL;
+
+ if (output_bfd->xvec->flavour == bfd_target_elf_flavour
+ && output_bfd->direction != read_direction)
+ p = _bfd_elf_find_segment_containing_section (output_bfd, osec);
+
+ return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1;
+}
+
+static bool
+rx_elf_osec_readonly_p (bfd *output_bfd, asection *osec)
+{
+ unsigned seg = rx_elf_osec_to_segment (output_bfd, osec);
+
+ return (seg != (unsigned) -1
+ && ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W));
+}
+
+/* Generate the initial contents of a local function descriptor, along
+ with any relocations or fixups required. */
+static bool
+rx_elf_initialize_funcdesc (bfd *output_bfd,
+ struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ bfd_vma offset,
+ asection *section,
+ bfd_vma value)
+{
+ struct elf_rx_link_hash_table *htab;
+ int dynindx;
+ bfd_vma addr, seg;
+
+ htab = rx_elf_hash_table (info);
+
+ if (h != NULL && SYMBOL_CALLS_LOCAL (info, h))
+ section = h->root.u.def.section;
+
+ if (h == NULL || SYMBOL_CALLS_LOCAL (info, h))
+ {
+ dynindx = elf_section_data (section->output_section)->dynindx;
+ addr = value + section->output_offset;
+ seg = rx_elf_osec_to_segment (output_bfd, section->output_section);
+ }
+ else
+ {
+ dynindx = h->dynindx;
+ addr = seg = 0;
+ }
+
+ if (!bfd_link_pic (info) && SYMBOL_CALLS_LOCAL (info, h))
+ {
+ if (h == NULL || h->root.type != bfd_link_hash_undefweak)
+ {
+ rx_elf_add_rofixup (output_bfd, htab->srofixup,
+ offset
+ + htab->sfuncdesc->output_section->vma
+ + htab->sfuncdesc->output_offset);
+ rx_elf_add_rofixup (output_bfd, htab->srofixup,
+ offset + 4
+ + htab->sfuncdesc->output_section->vma
+ + htab->sfuncdesc->output_offset);
+ }
+
+ /* There are no dynamic relocations so fill in the final
+ address and gp value (barring fixups). */
+ addr += section->output_section->vma;
+ seg = htab->root.hgot->root.u.def.value
+ + htab->root.hgot->root.u.def.section->output_section->vma
+ + htab->root.hgot->root.u.def.section->output_offset;
+ }
+ else
+ {
+ rx_elf_add_dyn_reloc (output_bfd, htab->srelfuncdesc,
+ offset
+ + htab->sfuncdesc->output_section->vma
+ + htab->sfuncdesc->output_offset,
+ R_RX_FUNCDESC_VALUE, dynindx, value);
+ }
+ bfd_put_32 (output_bfd, addr, htab->sfuncdesc->contents + offset);
+ bfd_put_32 (output_bfd, seg, htab->sfuncdesc->contents + offset + 4);
+
+ return true;
+}
+
+/* Finish up dynamic symbol handling. We set the contents of various
+ dynamic sections here. */
+
+static bool
+rx_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
+{
+ struct elf_rx_link_hash_table *htab;
+
+ htab = rx_elf_hash_table (info);
+ if (htab == NULL)
+ return false;
+
+ if (h->plt.offset != MINUS_ONE)
+ {
+ asection *splt;
+ asection *sgotplt;
+ asection *srelplt;
+
+ bfd_vma plt_index;
+ bfd_vma got_offset;
+ bfd_vma gotplt_base;
+ Elf_Internal_Rela rel;
+ bfd_byte *loc;
+
+ /* This symbol has an entry in the procedure linkage table. Set
+ it up. */
+
+ BFD_ASSERT (h->dynindx != -1);
+
+ splt = htab->root.splt;
+ sgotplt = htab->root.sgotplt;
+ srelplt = htab->root.srelplt;
+ gotplt_base = htab->root.sgot->size + htab->sfuncdesc->size;
+ BFD_ASSERT (splt != NULL && sgotplt != NULL && srelplt != NULL);
+
+ /* Get the index in the procedure linkage table which
+ corresponds to this symbol. This is the index of this symbol
+ in all the symbols for which we are making plt entries. The
+ first entry in the procedure linkage table is reserved. */
+ plt_index = h->plt.offset / sizeof(fdpic_elf_rx_plt_entry);
+
+ /* Get the offset into the .got table of the entry that
+ corresponds to this function. */
+ if (htab->fdpic_p)
+ got_offset = plt_index * 8 + gotplt_base;
+ else
+ /* Each .got entry is 4 bytes. The first three are
+ reserved. */
+ got_offset = (plt_index + 3) * 4;
+#ifdef GOT_BIAS
+ if (bfd_link_pic (info))
+ got_offset -= GOT_BIAS;
+#endif
+ /* Fill in the entry in the procedure linkage table. */
+ memcpy (splt->contents + h->plt.offset,
+ fdpic_elf_rx_plt_entry, sizeof(fdpic_elf_rx_plt_entry));
+ if (bfd_link_pic (info) || htab->fdpic_p)
+ {
+ install_plt_field (output_bfd, false, got_offset,
+ (splt->contents
+ + h->plt.offset
+ + FDPIC_PLT_FUNC));
+ if (!(info->flags & DF_BIND_NOW))
+ install_plt_field (output_bfd, false,
+ srelplt->reloc_count * sizeof (Elf32_External_Rela),
+ (splt->contents
+ + h->plt.offset
+ + FDPIC_PLT_REL));
+ }
+
+ /* Make got_offset relative to the start of .got.plt. */
+#ifdef GOT_BIAS
+ if (bfd_link_pic (info))
+ got_offset += GOT_BIAS;
+#endif
+ if (htab->fdpic_p)
+ got_offset = plt_index * 8;
+
+ /* Fill in the entry in the global offset table. */
+ bfd_put_32 (output_bfd,
+ splt->output_section->vma + h->plt.offset + FDPIC_PLT_LAZY,
+ sgotplt->contents + got_offset);
+
+ if (htab->fdpic_p)
+ bfd_put_32 (output_bfd,
+ rx_elf_osec_to_segment (output_bfd, splt->output_section),
+ sgotplt->contents + got_offset + 4);
+
+ /* Fill in the entry in the .rela.plt section. */
+ rel.r_offset = (sgotplt->output_section->vma +
+ sgotplt->output_offset + got_offset);
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_RX_FUNCDESC_VALUE);
+ rel.r_addend = 0;
+#ifdef GOT_BIAS
+ rel.r_addend = GOT_BIAS;
+#endif
+ loc = srelplt->contents + plt_index * sizeof (Elf32_External_Rela);
+ srelplt->reloc_count++;
+ bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
+
+ if (!h->def_regular)
+ {
+ /* Mark the symbol as undefined, rather than as defined in
+ the .plt section. Leave the value alone. */
+ sym->st_shndx = SHN_UNDEF;
+ }
+ }
+
+ if (h->got.offset != MINUS_ONE) {
+ asection *sgot;
+ asection *srelgot;
+ asection *sfuncdesc;
+ Elf_Internal_Rela rel;
+ bfd_byte *loc;
+
+ /* This symbol has an entry in the global offset table. Set it
+ up. */
+
+ sgot = htab->root.sgot;
+ srelgot = htab->root.srelgot;
+ sfuncdesc = htab->sfuncdesc;
+ BFD_ASSERT (sgot != NULL && srelgot != NULL);
+
+ rel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + (h->got.offset &~ (bfd_vma) 1));
+ if (h->root.u.def.section->output_section)
+ {
+ if (rx_elf_hash_entry (h)->got_type != GOT_FUNCDESC)
+ {
+ rel.r_info = ELF32_R_INFO (0, R_RX_RELATIVE);
+ rel.r_addend = h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset;
+ }
+ else
+ {
+ rel.r_info = ELF32_R_INFO (0, R_RX_RELATIVE);
+ rel.r_addend = (rx_elf_hash_entry (h)->funcdesc.offset & ~1)
+ + sfuncdesc->output_section->vma
+ + sfuncdesc->output_offset;
+ }
+ }
+ else
+ {
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_RX_GLOB_DAT);
+ rel.r_addend = 0;
+ }
+ loc = srelgot->contents;
+ loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
+ }
+
+ if (h->needs_copy)
+ {
+ asection *s;
+ Elf_Internal_Rela rel;
+ bfd_byte *loc;
+
+ /* This symbol needs a copy reloc. Set it up. */
+
+ BFD_ASSERT (h->dynindx != -1
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak));
+
+ s = bfd_get_linker_section (htab->root.dynobj, ".rela.bss");
+ BFD_ASSERT (s != NULL);
+
+ rel.r_offset = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_RX_COPY);
+ rel.r_addend = 0;
+ loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
+ }
+
+ if (h == htab->root.hdynamic
+ || h == htab->root.hgot)
+ sym->st_shndx = SHN_ABS;
+
+ return true;
+}
+
+/* Finish up the dynamic sections. */
+
+static bool
+rx_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info,
+ bfd_byte *buf ATTRIBUTE_UNUSED)
+{
+ struct elf_rx_link_hash_table *htab;
+ asection *sgotplt;
+ asection *sdyn;
+
+ htab = rx_elf_hash_table (info);
+ if (htab == NULL)
+ return false;
+
+ sgotplt = htab->root.sgotplt;
+ sdyn = bfd_get_linker_section (htab->root.dynobj, ".dynamic");
+
+ if (htab->root.dynamic_sections_created)
+ {
+ Elf32_External_Dyn *dyncon, *dynconend;
+
+ BFD_ASSERT (sgotplt != NULL && sdyn != NULL);
+
+ dyncon = (Elf32_External_Dyn *) sdyn->contents;
+ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
+ for (; dyncon < dynconend; dyncon++)
+ {
+ Elf_Internal_Dyn dyn;
+ asection *s;
+
+ bfd_elf32_swap_dyn_in (htab->root.dynobj, dyncon, &dyn);
+
+ switch (dyn.d_tag)
+ {
+
+ case DT_PLTGOT:
+ s = htab->root.sgot;
+ BFD_ASSERT (s != NULL);
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ break;
+
+ case DT_JMPREL:
+ s = htab->root.srelplt->output_section;
+ BFD_ASSERT (s != NULL);
+ dyn.d_un.d_ptr = s->vma;
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ break;
+
+ case DT_PLTRELSZ:
+ s = htab->root.srelplt->output_section;
+ BFD_ASSERT (s != NULL);
+ dyn.d_un.d_val = s->size;
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ break;
+ }
+ }
+ }
+
+ /* At the very end of the .rofixup section is a pointer to the GOT. */
+ if (htab->fdpic_p && htab->srofixup != NULL)
+ {
+ struct elf_link_hash_entry *hgot = htab->root.hgot;
+ bfd_vma got_value = hgot->root.u.def.value +
+ hgot->root.u.def.section->output_section->vma;
+ rx_elf_add_rofixup (output_bfd, htab->srofixup, got_value);
+
+ /* Make sure we allocated and generated the same number of fixups. */
+ BFD_ASSERT (htab->srofixup->reloc_count * 4 == htab->srofixup->size);
+ }
+
+ if (htab->srelfuncdesc)
+ BFD_ASSERT (htab->srelfuncdesc->reloc_count * sizeof (Elf32_External_Rela)
+ == htab->srelfuncdesc->size);
+
+ if (htab->root.srelgot)
+ BFD_ASSERT (htab->root.srelgot->reloc_count * sizeof (Elf32_External_Rela)
+ == htab->root.srelgot->size);
+ return true;
+}
+
+/* Copy the extra info we tack onto an elf_link_hash_entry. */
+
+static void
+rx_elf_copy_indirect_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *dir,
+ struct elf_link_hash_entry *ind)
+{
+ struct elf_rx_link_hash_entry *edir, *eind;
+
+ edir = (struct elf_rx_link_hash_entry *) dir;
+ eind = (struct elf_rx_link_hash_entry *) ind;
+
+ edir->gotplt_refcount = eind->gotplt_refcount;
+ eind->gotplt_refcount = 0;
+ edir->funcdesc.refcount += eind->funcdesc.refcount;
+ eind->funcdesc.refcount = 0;
+ edir->abs_funcdesc_refcount += eind->abs_funcdesc_refcount;
+ eind->abs_funcdesc_refcount = 0;
+
+ if (ind->root.type == bfd_link_hash_indirect
+ && dir->got.refcount <= 0)
+ {
+ edir->got_type = eind->got_type;
+ eind->got_type = GOT_UNKNOWN;
+ }
+
+ if (ind->root.type != bfd_link_hash_indirect
+ && dir->dynamic_adjusted)
+ {
+ /* If called to transfer flags for a weakdef during processing
+ of elf_adjust_dynamic_symbol, don't copy non_got_ref.
+ We clear it ourselves for ELIMINATE_COPY_RELOCS. */
+ if (dir->versioned != versioned_hidden)
+ dir->ref_dynamic |= ind->ref_dynamic;
+ dir->ref_regular |= ind->ref_regular;
+ dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
+ dir->needs_plt |= ind->needs_plt;
+ }
+ else
+ _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+}
+
+static bfd_signed_vma *allocate_local_got_refcounts(bfd *abfd)
+{
+ bfd_signed_vma *local_got_refcounts;
+ Elf_Internal_Shdr *symtab_hdr;
+
+ symtab_hdr = &elf_symtab_hdr (abfd);
+
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+ if (local_got_refcounts == NULL)
+ {
+ bfd_size_type size;
+
+ size = symtab_hdr->sh_info;
+ size *= sizeof (bfd_signed_vma);
+ size += symtab_hdr->sh_info;
+ local_got_refcounts = ((bfd_signed_vma *)
+ bfd_zalloc (abfd, size));
+ if (local_got_refcounts == NULL)
+ return NULL;
+
+ elf_local_got_refcounts (abfd) = local_got_refcounts;
+ rx_elf_local_got_type (abfd)
+ = (char *) (local_got_refcounts + symtab_hdr->sh_info);
+ }
+ return local_got_refcounts;
+}
+
+/* Look through the relocs for a section during the first phase.
+ Since we don't do .gots or .plts, we just need to consider the
+ virtual table relocs for gc. */
+
+static bool
+rx_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
+ const Elf_Internal_Rela *relocs)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ struct elf_rx_link_hash_table *htab;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ unsigned int r_type;
+ enum got_type got_type, old_got_type;
+
+ if (bfd_link_relocatable (info))
+ return true;
+
+ BFD_ASSERT (is_rx_elf (abfd));
+
+ symtab_hdr = &elf_symtab_hdr (abfd);
+ sym_hashes = elf_sym_hashes (abfd);
+
+ htab = rx_elf_hash_table (info);
+ if (htab == NULL)
+ return false;
+
+ rel_end = relocs + sec->reloc_count;
+ for (rel = relocs; rel < rel_end; rel++)
+ {
+ struct elf_link_hash_entry *h;
+ unsigned long r_symndx;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ r_type = ELF32_R_TYPE (rel->r_info);
+
+ if (r_symndx < symtab_hdr->sh_info)
+ h = NULL;
+ else
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+
+ /* Some relocs require a global offset table. */
+ if (htab->root.sgot == NULL)
+ {
+ switch (r_type)
+ {
+ case R_RX_DIR32:
+ /* This may require an rofixup. */
+ if (!htab->fdpic_p)
+ break;
+ /* Fall through. */
+ case R_RX_GOT:
+ case R_RX_GOTOFF:
+ case R_RX_FUNCDESC:
+ case R_RX_GOTFUNCDESC:
+ case R_RX_GOTOFFFUNCDESC:
+ if (htab->root.dynobj == NULL)
+ htab->root.dynobj = abfd;
+ if (!create_got_section (htab->root.dynobj, info))
+ return false;
+ break;
+
+ default:
+ break;
+ }
+ }
+ switch (r_type)
+ {
+ case R_RX_GOT:
+ got_type = GOT_NORMAL;
+ if (h != NULL)
+ {
+ h->got.refcount++;
+ old_got_type = rx_elf_hash_entry (h)->got_type;
+ }
+ else
+ {
+ bfd_signed_vma *local_got_refcounts;
+
+ local_got_refcounts = allocate_local_got_refcounts (abfd);
+ if (local_got_refcounts == NULL)
+ return false;
+
+ local_got_refcounts[r_symndx] += 1;
+ old_got_type = rx_elf_local_got_type (abfd) [r_symndx];
+ }
+
+ if (old_got_type != got_type)
+ {
+ if (h != NULL)
+ rx_elf_hash_entry (h)->got_type = got_type;
+ else
+ rx_elf_local_got_type (abfd) [r_symndx] = got_type;
+ }
+ break;
+
+ case R_RX_PLT:
+ /* This symbol requires a procedure linkage table entry. We
+ actually build the entry in adjust_dynamic_symbol,
+ because this might be a case of linking PIC code which is
+ never referenced by a dynamic object, in which case we
+ don't need to generate a procedure linkage table entry
+ after all. */
+
+ /* If this is a local symbol, we resolve it directly without
+ creating a procedure linkage table entry. */
+ if (h == NULL)
+ continue;
+
+ if (h->forced_local)
+ break;
+
+ h->needs_plt = 1;
+ h->plt.refcount++;
+ break;
+
+ case R_RX_FUNCDESC:
+ case R_RX_GOTFUNCDESC:
+ case R_RX_GOTOFFFUNCDESC:
+ if (h != NULL) {
+ if (! bfd_link_pic (info))
+ {
+ h->non_got_ref = 1;
+ h->plt.refcount += 1;
+ }
+ else
+ {
+ h->got.refcount += 1;
+ }
+ }
+ if (htab->fdpic_p && !bfd_link_pic (info)
+ && (sec->flags & SEC_ALLOC) != 0)
+ htab->srofixup->size += 4;
+ if (h != NULL)
+ rx_elf_hash_entry (h)->got_type = GOT_FUNCDESC;
+ else {
+ bfd_signed_vma *local_got_refcounts;
+
+ local_got_refcounts = allocate_local_got_refcounts (abfd);
+ if (local_got_refcounts == NULL)
+ return false;
+
+ local_got_refcounts[r_symndx] += 1;
+ rx_elf_local_got_type (abfd) [r_symndx] = GOT_FUNCDESC;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
#define ELF_ARCH bfd_arch_rx
#define ELF_MACHINE_CODE EM_RX
@@ -4111,5 +6337,60 @@ rx_additional_link_map_text (bfd *obfd, struct bfd_link_info *info, FILE *mapfil
#undef elf_symbol_leading_char
#undef elf32_bed
#define elf32_bed elf32_rx_le_linux_bed
+#undef ELF_TARGET_ID
+#define ELF_TARGET_ID RX_ELF_DATA
+
+#undef bfd_elf32_mkobject
+#define bfd_elf32_mkobject rx_elf_mkobject
+
+#undef elf_backend_omit_section_dynsym
+#define elf_backend_omit_section_dynsym rx_elf_omit_section_dynsym
+#undef elf_backend_create_dynamic_sections
+#define elf_backend_create_dynamic_sections \
+ rx_elf_create_dynamic_sections
+#undef bfd_elf32_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_create \
+ rx_elf_link_hash_table_create
+#undef elf_backend_adjust_dynamic_symbol
+#define elf_backend_adjust_dynamic_symbol \
+ rx_elf_adjust_dynamic_symbol
+#undef elf_backend_early_size_sections
+#define elf_backend_early_size_sections rx_elf_early_size_sections
+#undef elf_backend_late_size_sections
+#define elf_backend_late_size_sections rx_elf_late_size_sections
+#undef elf_backend_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_symbol \
+ rx_elf_finish_dynamic_symbol
+#undef elf_backend_finish_dynamic_sections
+#define elf_backend_finish_dynamic_sections \
+ rx_elf_finish_dynamic_sections
+#undef elf_backend_check_relocs
+#define elf_backend_check_relocs rx_elf_check_relocs
+
+#undef elf_backend_modify_program_headers
+#define elf_backend_modify_program_headers \
+ rx_elf_modify_program_headers
+#undef elf_backend_copy_indirect_symbol
+#define elf_backend_copy_indirect_symbol \
+ rx_elf_copy_indirect_symbol
+#undef elf_backend_reloc_type_class
+#define elf_backend_reloc_type_class rx_elf_reloc_type_class
+
+#undef elf_backend_want_got_plt
+#define elf_backend_want_got_plt 1
+#undef elf_backend_plt_readonly
+#define elf_backend_plt_readonly 1
+#undef elf_backend_want_plt_sym
+#define elf_backend_want_plt_sym 0
+#undef elf_backend_got_header_size
+#define elf_backend_got_header_size 12
+#undef elf_backend_plt_header_size
+#define elf_backend_plt_header_size PLT_ENTRY_SIZE
+#undef elf_backend_can_refcount
+#define elf_backend_can_refcount 1
+#undef elf_backend_special_sections
+#define elf_backend_special_sections NULL
+#undef elf_backend_dtrel_excludes_plt
+#define elf_backend_dtrel_excludes_plt 1
#include "elf32-target.h"
@@ -2476,6 +2476,17 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_RX_ABS16UW",
"BFD_RELOC_RX_ABS16UL",
"BFD_RELOC_RX_RELAX",
+ "BFD_RELOC_RX_COPY",
+ "BFD_RELOC_RX_GLOB_DAT",
+ "BFD_RELOC_RX_JMP_SLOT",
+ "BFD_RELOC_RX_RELATIVE",
+ "BFD_RELOC_RX_GOT",
+ "BFD_RELOC_RX_GOTOFF",
+ "BFD_RELOC_RX_PLT",
+ "BFD_RELOC_RX_GOTFUNCDESC",
+ "BFD_RELOC_RX_GOTOFFFUNCDESC",
+ "BFD_RELOC_RX_FUNCDESC",
+ "BFD_RELOC_RX_FUNCDESC_VALUE",
"BFD_RELOC_390_12",
"BFD_RELOC_390_GOT12",
"BFD_RELOC_390_GOTPC",
@@ -5015,6 +5015,28 @@ ENUMX
BFD_RELOC_RX_ABS16UL
ENUMX
BFD_RELOC_RX_RELAX
+ENUMX
+ BFD_RELOC_RX_COPY
+ENUMX
+ BFD_RELOC_RX_GLOB_DAT
+ENUMX
+ BFD_RELOC_RX_JMP_SLOT
+ENUMX
+ BFD_RELOC_RX_RELATIVE
+ENUMX
+ BFD_RELOC_RX_GOT
+ENUMX
+ BFD_RELOC_RX_GOTOFF
+ENUMX
+ BFD_RELOC_RX_PLT
+ENUMX
+ BFD_RELOC_RX_GOTFUNCDESC
+ENUMX
+ BFD_RELOC_RX_GOTOFFFUNCDESC
+ENUMX
+ BFD_RELOC_RX_FUNCDESC
+ENUMX
+ BFD_RELOC_RX_FUNCDESC_VALUE
ENUMDOC
Renesas RX Relocations.