/* Renesas RL78 specific support for 32-bit ELF.
- Copyright (C) 2011
- Free Software Foundation, Inc.
+ Copyright (C) 2011-2015 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
static reloc_howto_type rl78_elf_howto_table [] =
{
- RL78REL (NONE, 0, 0, 0, dont, FALSE),
+ RL78REL (NONE, 3, 0, 0, dont, FALSE),
RL78REL (DIR32, 2, 32, 0, signed, FALSE),
RL78REL (DIR24S, 2, 24, 0, signed, FALSE),
RL78REL (DIR16, 1, 16, 0, dont, FALSE),
if (code == BFD_RELOC_RL78_32_OP)
return rl78_elf_howto_table + R_RL78_DIR32;
- for (i = ARRAY_SIZE (rl78_reloc_map); --i;)
+ for (i = ARRAY_SIZE (rl78_reloc_map); i--;)
if (rl78_reloc_map [i].bfd_reloc_val == code)
return rl78_elf_howto_table + rl78_reloc_map[i].rl78_reloc_val;
unsigned int r_type;
r_type = ELF32_R_TYPE (dst->r_info);
- BFD_ASSERT (r_type < (unsigned int) R_RL78_max);
+ if (r_type >= (unsigned int) R_RL78_max)
+ {
+ _bfd_error_handler (_("%B: invalid RL78 reloc number: %d"), abfd, r_type);
+ r_type = 0;
+ }
cache_ptr->howto = rl78_elf_howto_table + r_type;
}
\f
dynobj = elf_hash_table (info)->dynobj;
splt = NULL;
if (dynobj != NULL)
- splt = bfd_get_section_by_name (dynobj, ".plt");
+ splt = bfd_get_linker_section (dynobj, ".plt");
for (rel = relocs; rel < relend; rel ++)
{
}
else
{
- bfd_boolean warned;
+ bfd_boolean warned ATTRIBUTE_UNUSED;
+ bfd_boolean ignored ATTRIBUTE_UNUSED;
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes, h,
sec, relocation, unresolved_reloc,
- warned);
+ warned, ignored);
name = h->root.root.string;
}
- if (sec != NULL && elf_discarded_section (sec))
+ if (sec != NULL && discarded_section (sec))
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
- rel, relend, howto, contents);
+ rel, 1, relend, howto, 0, contents);
if (info->relocatable)
{
else
plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
- /* printf("%s: rel %x plt %d\n", h ? h->root.root.string : "(none)",
- relocation, *plt_offset);*/
if (! valid_16bit_address (relocation))
{
/* If this is the first time we've processed this symbol,
break;
case R_RL78_RH_SFR:
- printf("SFR 0x%" BFD_VMA_FMT "x\n", relocation);
RANGE (0xfff00, 0xfffff);
OP (0) = relocation & 0xff;
break;
case R_RL78_RH_SADDR:
- printf("SADDR 0x%" BFD_VMA_FMT "x\n", relocation);
RANGE (0xffe20, 0xfff1f);
OP (0) = relocation & 0xff;
- printf(" - in\n");
break;
/* Complex reloc handling: */
+ sec->output_section->vma
+ sec->output_offset
+ rel->r_addend);
+ else if (h->root.type == bfd_link_hash_undefweak)
+ RL78_STACK_PUSH (0);
else
_bfd_error_handler (_("Warning: RL78_SYM reloc with an unknown symbol"));
}
{
int32_t tmp1, tmp2;
- RL78_STACK_POP (tmp2);
- RL78_STACK_POP (tmp1);
- tmp2 -= tmp1;
- RL78_STACK_PUSH (tmp2);
+ /* For the expression "A - B", the assembler pushes A,
+ then B, then OPSUB. So the first op we pop is B, not
+ A. */
+ RL78_STACK_POP (tmp2); /* B */
+ RL78_STACK_POP (tmp1); /* A */
+ tmp1 -= tmp2; /* A - B */
+ RL78_STACK_PUSH (tmp1);
}
break;
no_warn_mismatch = user_no_warn_mismatch;
}
+static const char *
+rl78_cpu_name (flagword flags)
+{
+ switch (flags & E_FLAG_RL78_CPU_MASK)
+ {
+ default: return "";
+ case E_FLAG_RL78_G10: return "G10";
+ case E_FLAG_RL78_G13: return "G13";
+ case E_FLAG_RL78_G14: return "G14";
+ }
+}
+
/* Merge backend specific data from an object file to the output
object file when linking. */
rl78_elf_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
{
flagword new_flags;
+ flagword old_flags;
bfd_boolean error = 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;
}
+ else if (old_flags != new_flags)
+ {
+ flagword changed_flags = old_flags ^ new_flags;
+
+ if (changed_flags & E_FLAG_RL78_CPU_MASK)
+ {
+ flagword out_cpu = old_flags & E_FLAG_RL78_CPU_MASK;
+ flagword in_cpu = new_flags & E_FLAG_RL78_CPU_MASK;
+
+ if (in_cpu == E_FLAG_RL78_ANY_CPU || in_cpu == out_cpu)
+ /* It does not matter what new_cpu may have. */;
+ else if (out_cpu == E_FLAG_RL78_ANY_CPU)
+ {
+ if (in_cpu == E_FLAG_RL78_G10)
+ {
+ /* G10 files can only be linked with other G10 files.
+ If the output is set to "any" this means that it is
+ a G14 file that does not use hardware multiply/divide,
+ but that is still incompatible with the G10 ABI. */
+ error = TRUE;
+
+ (*_bfd_error_handler)
+ (_("RL78 ABI conflict: G10 file %s cannot be linked with %s file %s"),
+ bfd_get_filename (ibfd),
+ rl78_cpu_name (out_cpu), bfd_get_filename (obfd));
+ }
+ else
+ {
+ old_flags &= ~ E_FLAG_RL78_CPU_MASK;
+ old_flags |= in_cpu;
+ elf_elfheader (obfd)->e_flags = old_flags;
+ }
+ }
+ else
+ {
+ error = TRUE;
+
+ (*_bfd_error_handler)
+ (_("RL78 ABI conflict: cannot link %s file %s with %s file %s"),
+ rl78_cpu_name (in_cpu), bfd_get_filename (ibfd),
+ rl78_cpu_name (out_cpu), bfd_get_filename (obfd));
+ }
+ }
+
+ if (changed_flags & E_FLAG_RL78_64BIT_DOUBLES)
+ {
+ (*_bfd_error_handler)
+ (_("RL78 merge conflict: cannot link 32-bit and 64-bit objects together"));
+
+ if (old_flags & E_FLAG_RL78_64BIT_DOUBLES)
+ (*_bfd_error_handler) (_("- %s is 64-bit, %s is not"),
+ bfd_get_filename (obfd), bfd_get_filename (ibfd));
+ else
+ (*_bfd_error_handler) (_("- %s is 64-bit, %s is not"),
+ bfd_get_filename (ibfd), bfd_get_filename (obfd));
+ error = TRUE;
+ }
+ }
return !error;
}
flags = elf_elfheader (abfd)->e_flags;
fprintf (file, _("private flags = 0x%lx:"), (long) flags);
+ if (flags & E_FLAG_RL78_CPU_MASK)
+ fprintf (file, " [%s]", rl78_cpu_name (flags));
+
+ if (flags & E_FLAG_RL78_64BIT_DOUBLES)
+ fprintf (file, _(" [64-bit doubles]"));
+
fputc ('\n', file);
return TRUE;
}
/* Return the MACH for an e_flags value. */
static int
-elf32_rl78_machine (bfd * abfd)
+elf32_rl78_machine (bfd * abfd ATTRIBUTE_UNUSED)
{
- if ((elf_elfheader (abfd)->e_flags & EF_RL78_CPU_MASK) == EF_RL78_CPU_RL78)
- return bfd_mach_rl78;
-
- return 0;
+ return bfd_mach_rl78;
}
static bfd_boolean
elf32_rl78_machine (abfd));
return TRUE;
}
- \f
-#ifdef DEBUG
-void
-rl78_dump_symtab (bfd * abfd, void * internal_syms, void * external_syms)
-{
- size_t locsymcount;
- Elf_Internal_Sym * isymbuf;
- Elf_Internal_Sym * isymend;
- Elf_Internal_Sym * isym;
- Elf_Internal_Shdr * symtab_hdr;
- bfd_boolean free_internal = FALSE, free_external = FALSE;
- char * st_info_str;
- char * st_info_stb_str;
- char * st_other_str;
- char * st_shndx_str;
-
- if (! internal_syms)
- {
- internal_syms = bfd_malloc (1000);
- free_internal = 1;
- }
- if (! external_syms)
- {
- external_syms = bfd_malloc (1000);
- free_external = 1;
- }
-
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- locsymcount = symtab_hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym;
- if (free_internal)
- isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
- symtab_hdr->sh_info, 0,
- internal_syms, external_syms, NULL);
- else
- isymbuf = internal_syms;
- isymend = isymbuf + locsymcount;
-
- for (isym = isymbuf ; isym < isymend ; isym++)
- {
- switch (ELF_ST_TYPE (isym->st_info))
- {
- case STT_FUNC: st_info_str = "STT_FUNC";
- case STT_SECTION: st_info_str = "STT_SECTION";
- case STT_FILE: st_info_str = "STT_FILE";
- case STT_OBJECT: st_info_str = "STT_OBJECT";
- case STT_TLS: st_info_str = "STT_TLS";
- default: st_info_str = "";
- }
- switch (ELF_ST_BIND (isym->st_info))
- {
- case STB_LOCAL: st_info_stb_str = "STB_LOCAL";
- case STB_GLOBAL: st_info_stb_str = "STB_GLOBAL";
- default: st_info_stb_str = "";
- }
- switch (ELF_ST_VISIBILITY (isym->st_other))
- {
- case STV_DEFAULT: st_other_str = "STV_DEFAULT";
- case STV_INTERNAL: st_other_str = "STV_INTERNAL";
- case STV_PROTECTED: st_other_str = "STV_PROTECTED";
- default: st_other_str = "";
- }
- switch (isym->st_shndx)
- {
- case SHN_ABS: st_shndx_str = "SHN_ABS";
- case SHN_COMMON: st_shndx_str = "SHN_COMMON";
- case SHN_UNDEF: st_shndx_str = "SHN_UNDEF";
- default: st_shndx_str = "";
- }
-
- printf ("isym = %p st_value = %lx st_size = %lx st_name = (%lu) %s "
- "st_info = (%d) %s %s st_other = (%d) %s st_shndx = (%d) %s\n",
- isym,
- (unsigned long) isym->st_value,
- (unsigned long) isym->st_size,
- isym->st_name,
- bfd_elf_string_from_elf_section (abfd, symtab_hdr->sh_link,
- isym->st_name),
- isym->st_info, st_info_str, st_info_stb_str,
- isym->st_other, st_other_str,
- isym->st_shndx, st_shndx_str);
- }
- if (free_internal)
- free (internal_syms);
- if (free_external)
- free (external_syms);
-}
-
-char *
-rl78_get_reloc (long reloc)
-{
- if (0 <= reloc && reloc < R_RL78_max)
- return rl78_elf_howto_table[reloc].name;
- return "";
-}
-#endif /* DEBUG */
-
\f
/* support PLT for 16-bit references to 24-bit functions. */
/* We support 16-bit pointers to code above 64k by generating a thunk
below 64k containing a JMP instruction to the final address. */
-
+
static bfd_boolean
rl78_elf_check_relocs
(bfd * abfd,
if (info->relocatable)
return TRUE;
-
+
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
local_plt_offsets = elf_local_got_offsets (abfd);
struct elf_link_hash_entry *h;
unsigned long r_symndx;
bfd_vma *offset;
-
+
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
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;
+
+ /* PR15323, ref flags aren't set for references in the same
+ object. */
+ h->root.non_ir_ref = 1;
}
-
+
switch (ELF32_R_TYPE (rel->r_info))
{
/* This relocation describes a 16-bit pointer to a function.
elf_hash_table (info)->dynobj = dynobj = abfd;
if (splt == NULL)
{
- splt = bfd_get_section_by_name (dynobj, ".plt");
+ splt = bfd_get_linker_section (dynobj, ".plt");
if (splt == NULL)
{
flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
| SEC_IN_MEMORY | SEC_LINKER_CREATED
| SEC_READONLY | SEC_CODE);
- splt = bfd_make_section_with_flags (dynobj, ".plt", flags);
+ splt = bfd_make_section_anyway_with_flags (dynobj, ".plt",
+ flags);
if (splt == NULL
|| ! bfd_set_section_alignment (dynobj, splt, 1))
return FALSE;
break;
}
}
-
+
return TRUE;
}
bfd *dynobj;
asection *splt;
+ if (!elf_hash_table (info)->dynamic_sections_created)
+ return TRUE;
+
/* As an extra sanity check, verify that all plt entries have been
filled in. However, relaxing might have changed the relocs so
that some plt entries don't get filled in, so we have to skip
called before relaxation. */
if (info->relax_trip > 0)
+ return TRUE;
+
+ if ((dynobj = elf_hash_table (info)->dynobj) != NULL
+ && (splt = bfd_get_linker_section (dynobj, ".plt")) != NULL)
{
- if ((dynobj = elf_hash_table (info)->dynobj) != NULL
- && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
+ bfd_byte *contents = splt->contents;
+ unsigned int i, size = splt->size;
+
+ for (i = 0; i < size; i += 4)
{
- bfd_byte *contents = splt->contents;
- unsigned int i, size = splt->size;
- for (i = 0; i < size; i += 4)
- {
- unsigned int x = bfd_get_32 (dynobj, contents + i);
- BFD_ASSERT (x != 0);
- }
+ unsigned int x = bfd_get_32 (dynobj, contents + i);
+ BFD_ASSERT (x != 0);
}
}
if (dynobj == NULL)
return TRUE;
- splt = bfd_get_section_by_name (dynobj, ".plt");
+ splt = bfd_get_linker_section (dynobj, ".plt");
BFD_ASSERT (splt != NULL);
splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->size);
};
static bfd_boolean
-rl78_relax_plt_check (struct elf_link_hash_entry *h,
- PTR xdata)
+rl78_relax_plt_check (struct elf_link_hash_entry *h, void * xdata)
{
struct relax_plt_data *data = (struct relax_plt_data *) xdata;
previously had a plt entry, give it a new entry offset. */
static bfd_boolean
-rl78_relax_plt_realloc (struct elf_link_hash_entry *h,
- PTR xdata)
+rl78_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata)
{
bfd_vma *entry = (bfd_vma *) xdata;
/* Likewise for local symbols, though that's somewhat less convenient
as we have to walk the list of input bfds and swap in symbol data. */
- for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
+ for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
{
bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
Elf_Internal_Shdr *symtab_hdr;
elf_link_hash_traverse (elf_hash_table (info),
rl78_relax_plt_realloc, &entry);
- for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
+ for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next)
{
bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
static bfd_boolean
elf32_rl78_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, int count,
- Elf_Internal_Rela *alignment_rel, int force_snip)
+ Elf_Internal_Rela *alignment_rel, int force_snip)
{
Elf_Internal_Shdr * symtab_hdr;
unsigned int sec_shndx;
toaddr = alignment_rel->r_offset;
irel = elf_section_data (sec)->relocs;
+ if (irel == NULL)
+ {
+ _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL, TRUE);
+ irel = elf_section_data (sec)->relocs;
+ }
+
irelend = irel + sec->reloc_count;
/* Actually delete the bytes. */
memset (contents + toaddr - count, 0x03, count);
/* Adjust all the relocs. */
- for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
+ for (; irel && irel < irelend; irel++)
{
/* Get the new reloc address. */
if (irel->r_offset > addr
if (ssec)
{
if ((ssec->flags & SEC_MERGE)
- && ssec->sec_info_type == ELF_INFO_TYPE_MERGE)
+ && ssec->sec_info_type == SEC_INFO_TYPE_MERGE)
symval = _bfd_merged_section_offset (abfd, & ssec,
elf_section_data (ssec)->sec_info,
symval);
{ 0x71, 0x58, 0x53, 0x5b }, /* CLR1 !addr16.0 */
{ 0x71, 0x68, 0x63, 0x6b }, /* CLR1 !addr16.0 */
{ 0x71, 0x78, 0x73, 0x7b }, /* CLR1 !addr16.0 */
-
+
{ -1, -1, -1, -1 }
};
if (shndx_buf == NULL)
goto error_return;
if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
+ || bfd_bread (shndx_buf, amt, abfd) != amt)
goto error_return;
shndx_hdr->contents = (bfd_byte *) shndx_buf;
}
/* Get a copy of the native relocations. */
internal_relocs = (_bfd_elf_link_read_relocs
- (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+ (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
nbytes /= alignment;
nbytes *= alignment;
- elf32_rl78_relax_delete_bytes (abfd, sec, erel->r_offset-nbytes, nbytes, next_alignment,
- erel->r_offset == sec->size);
+ elf32_rl78_relax_delete_bytes (abfd, sec, erel->r_offset - nbytes, nbytes,
+ next_alignment, erel->r_offset == sec->size);
*again = TRUE;
continue;
pc = sec->output_section->vma + sec->output_offset
+ srel->r_offset;
-#define GET_RELOC \
- symval = OFFSET_FOR_RELOC (srel, &srel, &scale); \
- pcrel = symval - pc + srel->r_addend; \
+#define GET_RELOC \
+ BFD_ASSERT (nrelocs > 0); \
+ symval = OFFSET_FOR_RELOC (srel, &srel, &scale); \
+ pcrel = symval - pc + srel->r_addend; \
nrelocs --;
#define SNIPNR(offset, nbytes) \
elf32_rl78_relax_delete_bytes (abfd, sec, (insn - contents) + offset, nbytes, next_alignment, 0);
-#define SNIP(offset, nbytes, newtype) \
- SNIPNR (offset, nbytes); \
+
+#define SNIP(offset, nbytes, newtype) \
+ SNIPNR (offset, nbytes); \
srel->r_info = ELF32_R_INFO (ELF32_R_SYM (srel->r_info), newtype)
/* The order of these bit tests must match the order that the
61 F3 EF ad SKNH ; BR $rel8
*/
- if (irel->r_addend & RL78_RELAXA_BRA)
+ if ((irel->r_addend & RL78_RELAXA_MASK) == RL78_RELAXA_BRA)
{
- GET_RELOC;
+ /* SKIP opcodes that skip non-branches will have a relax tag
+ but no corresponding symbol to relax against; we just
+ skip those. */
+ if (irel->r_addend & RL78_RELAXA_RNUM)
+ {
+ GET_RELOC;
+ }
switch (insn[0])
{
/* For SKIP/BR, we change the BR opcode and delete the
SKIP. That way, we don't have to find and change the
relocation for the BR. */
+ /* Note that, for the case where we're skipping some
+ other insn, we have no "other" reloc but that's safe
+ here anyway. */
switch (insn[1])
{
case 0xc8: /* SKC */
}
break;
}
-
}
- if (irel->r_addend & RL78_RELAXA_ADDR16)
+ if ((irel->r_addend & RL78_RELAXA_MASK) == RL78_RELAXA_ADDR16
+ && nrelocs > 0)
{
/*----------------------------------------------------------------------*/
/* Some insns have both a 16-bit address operand and an 8-bit
GET_RELOC;
- printf ("relax_addr16 detected, "
- "symval 0x%" BFD_VMA_FMT "x %02x %02x\n",
- symval, insn[0], insn[1]);
-
if (0xffe20 <= symval && symval <= 0xfffff)
{
{
insn[poff] = relax_addr16[idx].insn_for_sfr;
SNIP (poff+2, 1, R_RL78_RH_SFR);
- printf(" - replaced by SFR\n");
}
else if (is_saddr && relax_addr16[idx].insn_for_saddr != -1)
{
insn[poff] = relax_addr16[idx].insn_for_saddr;
SNIP (poff+2, 1, R_RL78_RH_SADDR);
- printf(" - replaced by SADDR\n");
}
-
}
}
}
-
/*----------------------------------------------------------------------*/
-
}
return TRUE;
#define ELF_MACHINE_CODE EM_RL78
#define ELF_MAXPAGESIZE 0x1000
-#define TARGET_LITTLE_SYM bfd_elf32_rl78_vec
+#define TARGET_LITTLE_SYM rl78_elf32_vec
#define TARGET_LITTLE_NAME "elf32-rl78"
#define elf_info_to_howto_rel NULL