/* Motorola 68k series support for 32-bit ELF
Copyright 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
};
static void
-rtype_to_howto (abfd, cache_ptr, dst)
- bfd *abfd ATTRIBUTE_UNUSED;
- arelent *cache_ptr;
- Elf_Internal_Rela *dst;
+rtype_to_howto (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst)
{
- BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_68K_max);
- cache_ptr->howto = &howto_table[ELF32_R_TYPE(dst->r_info)];
+ unsigned int indx = ELF32_R_TYPE (dst->r_info);
+
+ if (indx >= (unsigned int) R_68K_max)
+ {
+ (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+ abfd, (int) indx);
+ indx = R_68K_NONE;
+ }
+ cache_ptr->howto = &howto_table[indx];
}
#define elf_info_to_howto rtype_to_howto
#define bfd_elf32_bfd_reloc_type_lookup reloc_type_lookup
#define bfd_elf32_bfd_reloc_name_lookup reloc_name_lookup
#define ELF_ARCH bfd_arch_m68k
+#define ELF_TARGET_ID M68K_ELF_DATA
\f
/* Functions for the m68k ELF linker. */
/* Get the m68k ELF linker hash table from a link_info structure. */
#define elf_m68k_hash_table(p) \
- ((struct elf_m68k_link_hash_table *) (p)->hash)
+ (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+ == M68K_ELF_DATA ? ((struct elf_m68k_link_hash_table *) ((p)->hash)) : NULL)
/* Shortcut to multi-GOT data. */
#define elf_m68k_multi_got(INFO) (&elf_m68k_hash_table (INFO)->multi_got_)
/* Create an entry in an m68k ELF linker hash table. */
static struct bfd_hash_entry *
-elf_m68k_link_hash_newfunc (entry, table, string)
- struct bfd_hash_entry *entry;
- struct bfd_hash_table *table;
- const char *string;
+elf_m68k_link_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
{
struct bfd_hash_entry *ret = entry;
/* Create an m68k ELF linker hash table. */
static struct bfd_link_hash_table *
-elf_m68k_link_hash_table_create (abfd)
- bfd *abfd;
+elf_m68k_link_hash_table_create (bfd *abfd)
{
struct elf_m68k_link_hash_table *ret;
bfd_size_type amt = sizeof (struct elf_m68k_link_hash_table);
if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
elf_m68k_link_hash_newfunc,
- sizeof (struct elf_m68k_link_hash_entry)))
+ sizeof (struct elf_m68k_link_hash_entry),
+ M68K_ELF_DATA))
{
free (ret);
return NULL;
return TRUE;
}
+/* Somewhat reverse of elf32_m68k_object_p, this sets the e_flag
+ field based on the machine number. */
+
+static void
+elf_m68k_final_write_processing (bfd *abfd,
+ bfd_boolean linker ATTRIBUTE_UNUSED)
+{
+ int mach = bfd_get_mach (abfd);
+ unsigned long e_flags = elf_elfheader (abfd)->e_flags;
+
+ if (!e_flags)
+ {
+ unsigned int arch_mask;
+
+ arch_mask = bfd_m68k_mach_to_features (mach);
+
+ if (arch_mask & m68000)
+ e_flags = EF_M68K_M68000;
+ else if (arch_mask & cpu32)
+ e_flags = EF_M68K_CPU32;
+ else if (arch_mask & fido_a)
+ e_flags = EF_M68K_FIDO;
+ else
+ {
+ switch (arch_mask
+ & (mcfisa_a | mcfisa_aa | mcfisa_b | mcfisa_c | mcfhwdiv | mcfusp))
+ {
+ case mcfisa_a:
+ e_flags |= EF_M68K_CF_ISA_A_NODIV;
+ break;
+ case mcfisa_a | mcfhwdiv:
+ e_flags |= EF_M68K_CF_ISA_A;
+ break;
+ case mcfisa_a | mcfisa_aa | mcfhwdiv | mcfusp:
+ e_flags |= EF_M68K_CF_ISA_A_PLUS;
+ break;
+ case mcfisa_a | mcfisa_b | mcfhwdiv:
+ e_flags |= EF_M68K_CF_ISA_B_NOUSP;
+ break;
+ case mcfisa_a | mcfisa_b | mcfhwdiv | mcfusp:
+ e_flags |= EF_M68K_CF_ISA_B;
+ break;
+ case mcfisa_a | mcfisa_c | mcfhwdiv | mcfusp:
+ e_flags |= EF_M68K_CF_ISA_C;
+ break;
+ case mcfisa_a | mcfisa_c | mcfusp:
+ e_flags |= EF_M68K_CF_ISA_C_NODIV;
+ break;
+ }
+ if (arch_mask & mcfmac)
+ e_flags |= EF_M68K_CF_MAC;
+ else if (arch_mask & mcfemac)
+ e_flags |= EF_M68K_CF_EMAC;
+ if (arch_mask & cfloat)
+ e_flags |= EF_M68K_CF_FLOAT | EF_M68K_CFV4E;
+ }
+ elf_elfheader (abfd)->e_flags = e_flags;
+ }
+}
+
/* Keep m68k-specific flags in the ELF header. */
+
static bfd_boolean
elf32_m68k_set_private_flags (abfd, flags)
bfd *abfd;
case EF_M68K_CF_EMAC:
mac = "emac";
break;
+ case EF_M68K_CF_EMAC_B:
+ mac = "emac_b";
+ break;
}
if (mac)
fprintf (file, " [%s]", mac);
static enum elf_m68k_reloc_type
elf_m68k_update_got_entry_type (struct elf_m68k_got *got,
enum elf_m68k_reloc_type was,
- enum elf_m68k_reloc_type new)
+ enum elf_m68k_reloc_type new_reloc)
{
enum elf_m68k_got_offset_size was_size;
enum elf_m68k_got_offset_size new_size;
/* Update all got->n_slots counters, including n_slots[R_32]. */
was_size = R_LAST;
- was = new;
+ was = new_reloc;
}
else
{
/* !!! We, probably, should emit an error rather then fail on assert
in such a case. */
BFD_ASSERT (elf_m68k_reloc_got_type (was)
- == elf_m68k_reloc_got_type (new));
+ == elf_m68k_reloc_got_type (new_reloc));
was_size = elf_m68k_reloc_got_offset_size (was);
}
- new_size = elf_m68k_reloc_got_offset_size (new);
- n_slots = elf_m68k_reloc_got_n_slots (new);
+ new_size = elf_m68k_reloc_got_offset_size (new_reloc);
+ n_slots = elf_m68k_reloc_got_n_slots (new_reloc);
while (was_size > new_size)
{
got->n_slots[was_size] += n_slots;
}
- if (new > was)
+ if (new_reloc > was)
/* Relocations are ordered from bigger got offset size to lesser,
so choose the relocation type with lesser offset size. */
- was = new;
+ was = new_reloc;
return was;
}
struct elf_link_hash_entry **sym_hashes;
const Elf_Internal_Rela *rel, *relend;
bfd *dynobj;
- asection *sgot;
- asection *srelgot;
struct elf_m68k_got *got;
if (info->relocatable)
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
-
- sgot = bfd_get_section_by_name (dynobj, ".got");
- srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
got = NULL;
relend = relocs + sec->reloc_count;
bfd_elf32_swap_reloca_out (output_bfd, rela, loc);
}
-/* Return the base VMA address which should be subtracted from real addresses
- when resolving @dtpoff relocation.
- This is PT_TLS segment p_vaddr. */
+/* Find the base offsets for thread-local storage in this object,
+ for GD/LD and IE/LE respectively. */
+
+#define DTP_OFFSET 0x8000
+#define TP_OFFSET 0x7000
static bfd_vma
dtpoff_base (struct bfd_link_info *info)
/* If tls_sec is NULL, we should have signalled an error already. */
if (elf_hash_table (info)->tls_sec == NULL)
return 0;
- return elf_hash_table (info)->tls_sec->vma;
+ return elf_hash_table (info)->tls_sec->vma + DTP_OFFSET;
}
-/* Return the relocation value for @tpoff relocation
- if STT_TLS virtual address is ADDRESS. */
-
static bfd_vma
-tpoff (struct bfd_link_info *info, bfd_vma address)
+tpoff_base (struct bfd_link_info *info)
{
- struct elf_link_hash_table *htab = elf_hash_table (info);
- bfd_vma base;
-
/* If tls_sec is NULL, we should have signalled an error already. */
- if (htab->tls_sec == NULL)
+ if (elf_hash_table (info)->tls_sec == NULL)
return 0;
- base = align_power ((bfd_vma) 8, htab->tls_sec->alignment_power);
- return address - htab->tls_sec->vma + base;
+ return elf_hash_table (info)->tls_sec->vma + TP_OFFSET;
+}
+
+/* Output necessary relocation to handle a symbol during static link.
+ This function is called from elf_m68k_relocate_section. */
+
+static void
+elf_m68k_init_got_entry_static (struct bfd_link_info *info,
+ bfd *output_bfd,
+ enum elf_m68k_reloc_type r_type,
+ asection *sgot,
+ bfd_vma got_entry_offset,
+ bfd_vma relocation)
+{
+ switch (elf_m68k_reloc_got_type (r_type))
+ {
+ case R_68K_GOT32O:
+ bfd_put_32 (output_bfd, relocation, sgot->contents + got_entry_offset);
+ break;
+
+ case R_68K_TLS_GD32:
+ /* We know the offset within the module,
+ put it into the second GOT slot. */
+ bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
+ sgot->contents + got_entry_offset + 4);
+ /* FALLTHRU */
+
+ case R_68K_TLS_LDM32:
+ /* Mark it as belonging to module 1, the executable. */
+ bfd_put_32 (output_bfd, 1, sgot->contents + got_entry_offset);
+ break;
+
+ case R_68K_TLS_IE32:
+ bfd_put_32 (output_bfd, relocation - tpoff_base (info),
+ sgot->contents + got_entry_offset);
+ break;
+
+ default:
+ BFD_ASSERT (FALSE);
+ }
+}
+
+/* Output necessary relocation to handle a local symbol
+ during dynamic link.
+ This function is called either from elf_m68k_relocate_section
+ or from elf_m68k_finish_dynamic_symbol. */
+
+static void
+elf_m68k_init_got_entry_local_shared (struct bfd_link_info *info,
+ bfd *output_bfd,
+ enum elf_m68k_reloc_type r_type,
+ asection *sgot,
+ bfd_vma got_entry_offset,
+ bfd_vma relocation,
+ asection *srela)
+{
+ Elf_Internal_Rela outrel;
+
+ switch (elf_m68k_reloc_got_type (r_type))
+ {
+ case R_68K_GOT32O:
+ /* Emit RELATIVE relocation to initialize GOT slot
+ at run-time. */
+ outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+ outrel.r_addend = relocation;
+ break;
+
+ case R_68K_TLS_GD32:
+ /* We know the offset within the module,
+ put it into the second GOT slot. */
+ bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
+ sgot->contents + got_entry_offset + 4);
+ /* FALLTHRU */
+
+ case R_68K_TLS_LDM32:
+ /* We don't know the module number,
+ create a relocation for it. */
+ outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32);
+ outrel.r_addend = 0;
+ break;
+
+ case R_68K_TLS_IE32:
+ /* Emit TPREL relocation to initialize GOT slot
+ at run-time. */
+ outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_TPREL32);
+ outrel.r_addend = relocation - elf_hash_table (info)->tls_sec->vma;
+ break;
+
+ default:
+ BFD_ASSERT (FALSE);
+ }
+
+ /* Offset of the GOT entry. */
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + got_entry_offset);
+
+ /* Install one of the above relocations. */
+ elf_m68k_install_rela (output_bfd, srela, &outrel);
+
+ bfd_put_32 (output_bfd, outrel.r_addend, sgot->contents + got_entry_offset);
}
/* Relocate an M68K ELF section. */
asection *sgot;
asection *splt;
asection *sreloc;
+ asection *srela;
struct elf_m68k_got *got;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
sgot = NULL;
splt = NULL;
sreloc = NULL;
+ srela = NULL;
got = NULL;
}
if (sec != NULL && elf_discarded_section (sec))
- {
- /* For relocs against symbols from removed linkonce sections,
- or sections discarded by a linker script, we just want the
- section contents zeroed. Avoid any special processing. */
- _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
- rel->r_info = 0;
- rel->r_addend = 0;
- continue;
- }
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, relend, howto, contents);
if (info->relocatable)
continue;
/* 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
+ 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
relocation entry to initialize the value. This
is done in the finish_dynamic_symbol routine. */
- if (elf_m68k_reloc_got_type (r_type) == R_68K_GOT32O)
- bfd_put_32 (output_bfd, relocation,
- sgot->contents + off);
- else if (elf_m68k_reloc_got_type (r_type)
- == R_68K_TLS_GD32)
- /* Mark it as belonging to module 1,
- the executable. */
- {
- bfd_put_32 (output_bfd, 1,
- sgot->contents + off);
- bfd_put_32 (output_bfd, (relocation
- - dtpoff_base (info)),
- sgot->contents + off + 4);
- }
- else if (elf_m68k_reloc_got_type (r_type)
- == R_68K_TLS_IE32)
- bfd_put_32 (output_bfd, tpoff (info, relocation),
- sgot->contents + off);
- else
- BFD_ASSERT (FALSE);
+ elf_m68k_init_got_entry_static (info,
+ output_bfd,
+ r_type,
+ sgot,
+ off,
+ relocation);
*off_ptr |= 1;
}
unresolved_reloc = FALSE;
}
else if (info->shared) /* && h == NULL */
+ /* Process local symbol during dynamic link. */
{
- asection *srela;
- Elf_Internal_Rela outrel;
-
- srela = bfd_get_section_by_name (dynobj, ".rela.got");
- BFD_ASSERT (srela != NULL);
-
- if (elf_m68k_reloc_got_type (r_type) == R_68K_GOT32O)
- {
- /* Emit RELATIVE relocation to initialize GOT slot
- at run-time. */
- outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
- outrel.r_addend = relocation;
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + off);
-
- elf_m68k_install_rela (output_bfd, srela, &outrel);
- }
- else if (elf_m68k_reloc_got_type (r_type)
- == R_68K_TLS_LDM32)
- {
- /* If we don't know the module number, create
- a relocation for it. */
- outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32);
- outrel.r_addend = 0;
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + off);
-
- elf_m68k_install_rela (output_bfd, srela, &outrel);
- }
- else if (elf_m68k_reloc_got_type (r_type)
- == R_68K_TLS_GD32)
+ if (srela == NULL)
{
- /* If we don't know the module number, create
- a relocation for it. */
- outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32);
- outrel.r_addend = 0;
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + off);
-
- elf_m68k_install_rela (output_bfd, srela, &outrel);
-
- bfd_put_32 (output_bfd, (relocation
- - dtpoff_base (info)),
- sgot->contents + off + 4);
+ srela = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (srela != NULL);
}
- else if (elf_m68k_reloc_got_type (r_type)
- == R_68K_TLS_IE32)
- {
- outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_TPREL32);
- outrel.r_addend = relocation - dtpoff_base (info);
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + off);
- elf_m68k_install_rela (output_bfd, srela, &outrel);
- }
- else
- BFD_ASSERT (FALSE);
-
- bfd_put_32 (output_bfd, outrel.r_addend,
- sgot->contents + off);
+ elf_m68k_init_got_entry_local_shared (info,
+ output_bfd,
+ r_type,
+ sgot,
+ off,
+ relocation,
+ srela);
*off_ptr |= 1;
}
else /* h == NULL && !info->shared */
{
- if (elf_m68k_reloc_got_type (r_type) == R_68K_GOT32O)
- bfd_put_32 (output_bfd, relocation,
- sgot->contents + off);
- else if (elf_m68k_reloc_got_type (r_type)
- == R_68K_TLS_LDM32)
- /* If this is a static link, put the number of the
- only module in the GOT slot. */
- bfd_put_32 (output_bfd, 1, sgot->contents + off);
- else if (elf_m68k_reloc_got_type (r_type)
- == R_68K_TLS_GD32)
- {
- /* If we are not emitting relocations for a
- general dynamic reference, then we must be in a
- static link or an executable link with the
- symbol binding locally. Mark it as belonging
- to module 1, the executable. */
- bfd_put_32 (output_bfd, 1, sgot->contents + off);
- bfd_put_32 (output_bfd, (relocation
- - dtpoff_base (info)),
- sgot->contents + off + 4);
- }
- else if (elf_m68k_reloc_got_type (r_type)
- == R_68K_TLS_IE32)
- bfd_put_32 (output_bfd, tpoff (info, relocation),
- sgot->contents + off);
- else
- BFD_ASSERT (FALSE);
+ elf_m68k_init_got_entry_static (info,
+ output_bfd,
+ r_type,
+ sgot,
+ off,
+ relocation);
*off_ptr |= 1;
}
}
/* This relocation does not use the addend. */
- BFD_ASSERT (rel->r_addend == 0);
rel->r_addend = 0;
}
else
return FALSE;
}
else
- relocation = tpoff (info, relocation);
+ relocation -= tpoff_base (info);
break;
case R_68K_PC16:
case R_68K_PC32:
if (info->shared
- && r_symndx != 0
+ && r_symndx != STN_UNDEF
&& (input_section->flags & SEC_ALLOC) != 0
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
return FALSE;
}
- if (r_symndx != 0
+ if (r_symndx != STN_UNDEF
&& r_type != R_68K_NONE
&& (h == NULL
|| h->root.type == bfd_link_hash_defined
while (got_entry != NULL)
{
- Elf_Internal_Rela rela;
+ enum elf_m68k_reloc_type r_type;
bfd_vma got_entry_offset;
+ r_type = got_entry->key_.type;
got_entry_offset = got_entry->u.s2.offset &~ (bfd_vma) 1;
- rela.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + got_entry_offset);
-
/* If this is a -Bsymbolic link, and the symbol is defined
locally, we just want to emit a RELATIVE reloc. Likewise if
the symbol was forced to be local because of a version file.
if (info->shared
&& SYMBOL_REFERENCES_LOCAL (info, h))
{
- rela.r_addend = bfd_get_signed_32 (output_bfd,
- (sgot->contents
- + got_entry_offset));
+ bfd_vma relocation;
- switch (elf_m68k_reloc_got_type (got_entry->key_.type))
+ relocation = bfd_get_signed_32 (output_bfd,
+ (sgot->contents
+ + got_entry_offset));
+
+ /* Undo TP bias. */
+ switch (elf_m68k_reloc_got_type (r_type))
{
case R_68K_GOT32O:
- rela.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+ case R_68K_TLS_LDM32:
break;
case R_68K_TLS_GD32:
- rela.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32);
+ /* The value for this relocation is actually put in
+ the second GOT slot. */
+ relocation = bfd_get_signed_32 (output_bfd,
+ (sgot->contents
+ + got_entry_offset + 4));
+ relocation += dtpoff_base (info);
break;
case R_68K_TLS_IE32:
- rela.r_info = ELF32_R_INFO (0, R_68K_TLS_TPREL32);
+ relocation += tpoff_base (info);
break;
default:
BFD_ASSERT (FALSE);
- break;
}
- elf_m68k_install_rela (output_bfd, srela, &rela);
+ elf_m68k_init_got_entry_local_shared (info,
+ output_bfd,
+ r_type,
+ sgot,
+ got_entry_offset,
+ relocation,
+ srela);
}
else
{
+ Elf_Internal_Rela rela;
+
/* Put zeros to GOT slots that will be initialized
at run-time. */
{
}
rela.r_addend = 0;
+ rela.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + got_entry_offset);
- switch (elf_m68k_reloc_got_type (got_entry->key_.type))
+ switch (elf_m68k_reloc_got_type (r_type))
{
case R_68K_GOT32O:
rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_GLOB_DAT);
bfd_elf_m68k_set_target_options (struct bfd_link_info *info, int got_handling)
{
struct elf_m68k_link_hash_table *htab;
-
- htab = elf_m68k_hash_table (info);
+ bfd_boolean use_neg_got_offsets_p;
+ bfd_boolean allow_multigot_p;
+ bfd_boolean local_gp_p;
switch (got_handling)
{
case 0:
/* --got=single. */
- htab->local_gp_p = FALSE;
- htab->use_neg_got_offsets_p = FALSE;
- htab->allow_multigot_p = FALSE;
+ local_gp_p = FALSE;
+ use_neg_got_offsets_p = FALSE;
+ allow_multigot_p = FALSE;
break;
case 1:
/* --got=negative. */
- htab->local_gp_p = TRUE;
- htab->use_neg_got_offsets_p = TRUE;
- htab->allow_multigot_p = FALSE;
+ local_gp_p = TRUE;
+ use_neg_got_offsets_p = TRUE;
+ allow_multigot_p = FALSE;
break;
case 2:
/* --got=multigot. */
- htab->local_gp_p = TRUE;
- htab->use_neg_got_offsets_p = TRUE;
- htab->allow_multigot_p = TRUE;
+ local_gp_p = TRUE;
+ use_neg_got_offsets_p = TRUE;
+ allow_multigot_p = TRUE;
break;
default:
BFD_ASSERT (FALSE);
+ return;
+ }
+
+ htab = elf_m68k_hash_table (info);
+ if (htab != NULL)
+ {
+ htab->local_gp_p = local_gp_p;
+ htab->use_neg_got_offsets_p = use_neg_got_offsets_p;
+ htab->allow_multigot_p = allow_multigot_p;
}
}
elf_m68k_adjust_dynamic_symbol
#define elf_backend_size_dynamic_sections \
elf_m68k_size_dynamic_sections
+#define elf_backend_final_write_processing elf_m68k_final_write_processing
#define elf_backend_init_index_section _bfd_elf_init_1_index_section
#define elf_backend_relocate_section elf_m68k_relocate_section
#define elf_backend_finish_dynamic_symbol \