/* The type of PLT we have chosen to use. */
enum ppc_elf_plt_type plt_type;
- /* True if the target system is VxWorks. */
- unsigned int is_vxworks:1;
-
/* Whether there exist local gnu indirect function resolvers,
referenced by dynamic relocations. */
unsigned int local_ifunc_resolver:1;
int plt_slot_size;
/* The size of the first PLT entry. */
int plt_initial_entry_size;
-
- /* Small local sym cache. */
- struct sym_cache sym_cache;
};
/* Rename some of the generic section flags to better document how they
/* Get the PPC ELF linker hash table from a link_info structure. */
#define ppc_elf_hash_table(p) \
- (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
- == PPC32_ELF_DATA ? ((struct ppc_elf_link_hash_table *) ((p)->hash)) : NULL)
+ ((is_elf_hash_table ((p)->hash) \
+ && elf_hash_table_id (elf_hash_table (p)) == PPC32_ELF_DATA) \
+ ? (struct ppc_elf_link_hash_table *) (p)->hash : NULL)
/* Create an entry in a PPC ELF linker hash table. */
return FALSE;
htab = ppc_elf_hash_table (info);
- if (!htab->is_vxworks)
+ if (htab->elf.target_os != is_vxworks)
{
/* The powerpc .got has a blrl instruction in it. Mark it
executable. */
return FALSE;
}
- if (htab->is_vxworks
+ if (htab->elf.target_os == is_vxworks
&& !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
return FALSE;
htab = ppc_elf_hash_table (info);
if (htab->sbss == NULL)
{
- flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED;
+ flagword flags = SEC_IS_COMMON | SEC_SMALL_DATA | SEC_LINKER_CREATED;
if (!htab->elf.dynobj)
htab->elf.dynobj = abfd;
if (bfd_link_relocatable (info))
return TRUE;
- /* Don't do anything special with non-loaded, non-alloced sections.
- In particular, any relocs in such sections should not affect GOT
- and PLT reference counting (ie. we don't allow them to create GOT
- or PLT entries), there's no possibility or desire to optimize TLS
- relocs, and there's not much point in propagating relocs to shared
- libs that the dynamic linker won't relocate. */
- if ((sec->flags & SEC_ALLOC) == 0)
- return TRUE;
-
#ifdef DEBUG
_bfd_error_handler ("ppc_elf_check_relocs called for section %pA in %pB",
sec, abfd);
tls_type = 0;
r_type = ELF32_R_TYPE (rel->r_info);
ifunc = NULL;
- if (h == NULL && !htab->is_vxworks)
+ if (h == NULL && htab->elf.target_os != is_vxworks)
{
- Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
}
}
- if (!htab->is_vxworks
+ if (htab->elf.target_os != is_vxworks
&& is_branch_reloc (r_type)
&& h != NULL
&& h == tga)
return FALSE;
break;
+ case R_PPC_TPREL16_HI:
+ case R_PPC_TPREL16_HA:
+ sec->has_tls_reloc = 1;
+ /* Fall through. */
/* We shouldn't really be seeing TPREL32. */
case R_PPC_TPREL32:
case R_PPC_TPREL16:
case R_PPC_TPREL16_LO:
- case R_PPC_TPREL16_HI:
- case R_PPC_TPREL16_HA:
if (bfd_link_dll (info))
info->flags |= DF_STATIC_TLS;
goto dodyn;
asection *s;
Elf_Internal_Sym *isym;
- isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
void *vpp;
Elf_Internal_Sym *isym;
- isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
abfd, r_symndx);
if (isym == NULL)
return FALSE;
if (htab == NULL)
return FALSE;
+ htab->do_tls_opt = 1;
+
/* Make two passes through the relocs. First time check that tls
relocs involved in setting up a tls_get_addr call are indeed
followed by such a call. If they are not, don't do any tls
tls_clear = 0;
break;
+ case R_PPC_TPREL16_HA:
+ if (pass == 0)
+ {
+ unsigned char buf[4];
+ unsigned int insn;
+ bfd_vma off = rel->r_offset & ~3;
+ if (!bfd_get_section_contents (ibfd, sec, buf,
+ off, 4))
+ {
+ if (elf_section_data (sec)->relocs != relstart)
+ free (relstart);
+ return FALSE;
+ }
+ insn = bfd_get_32 (ibfd, buf);
+ /* addis rt,2,imm */
+ if ((insn & ((0x3fu << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)))
+ {
+ /* xgettext:c-format */
+ info->callbacks->minfo
+ (_("%H: warning: %s unexpected insn %#x.\n"),
+ ibfd, sec, off, "R_PPC_TPREL16_HA", insn);
+ htab->do_tls_opt = 0;
+ }
+ }
+ continue;
+
+ case R_PPC_TPREL16_HI:
+ htab->do_tls_opt = 0;
+ continue;
+
default:
continue;
}
free (relstart);
}
}
- htab->do_tls_opt = 1;
return TRUE;
}
\f
|| (h->non_got_ref
&& !h->ref_regular_nonweak
&& !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
- && !htab->is_vxworks
+ && htab->elf.target_os != is_vxworks
&& !ppc_elf_hash_entry (h)->has_sda_refs
&& !_bfd_elf_readonly_dynrelocs (h))
{
executable. */
if (ELIMINATE_COPY_RELOCS
&& !ppc_elf_hash_entry (h)->has_sda_refs
- && !htab->is_vxworks
+ && htab->elf.target_os != is_vxworks
&& !h->def_regular
&& !alias_readonly_dynrelocs (h))
return TRUE;
}
}
- if (htab->is_vxworks)
+ if (htab->elf.target_os == is_vxworks)
{
struct elf_dyn_relocs **pp;
linker script /DISCARD/, so we'll be discarding
the relocs too. */
}
- else if (htab->is_vxworks
+ else if (htab->elf.target_os == is_vxworks
&& strcmp (p->sec->output_section->name,
".tls_vars") == 0)
{
else
*local_got = (bfd_vma) -1;
- if (htab->is_vxworks)
+ if (htab->elf.target_os == is_vxworks)
continue;
/* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */
#define add_dynamic_entry(TAG, VAL) \
_bfd_elf_add_dynamic_entry (info, TAG, VAL)
- if (bfd_link_executable (info))
- {
- if (!add_dynamic_entry (DT_DEBUG, 0))
- return FALSE;
- }
-
- if (htab->elf.splt != NULL && htab->elf.splt->size != 0)
- {
- if (!add_dynamic_entry (DT_PLTGOT, 0)
- || !add_dynamic_entry (DT_PLTRELSZ, 0)
- || !add_dynamic_entry (DT_PLTREL, DT_RELA)
- || !add_dynamic_entry (DT_JMPREL, 0))
- return FALSE;
- }
+ if (!_bfd_elf_maybe_vxworks_add_dynamic_tags (output_bfd, info,
+ relocs))
+ return FALSE;
if (htab->plt_type == PLT_NEW
&& htab->glink != NULL
&& !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS))
return FALSE;
}
-
- if (relocs)
- {
- if (!add_dynamic_entry (DT_RELA, 0)
- || !add_dynamic_entry (DT_RELASZ, 0)
- || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
- return FALSE;
- }
-
- /* If any dynamic relocs apply to a read-only section, then we
- need a DT_TEXTREL entry. */
- if ((info->flags & DF_TEXTREL) == 0)
- elf_link_hash_traverse (elf_hash_table (info),
- _bfd_elf_maybe_set_textrel,
- info);
-
- if ((info->flags & DF_TEXTREL) != 0)
- {
- if (!add_dynamic_entry (DT_TEXTREL, 0))
- return FALSE;
- }
- if (htab->is_vxworks
- && !elf_vxworks_add_dynamic_entries (output_bfd, info))
- return FALSE;
}
#undef add_dynamic_entry
sym_hashes = elf_sym_hashes (input_bfd);
/* We have to handle relocations in vxworks .tls_vars sections
specially, because the dynamic loader is 'weird'. */
- is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info)
+ is_vxworks_tls = (htab->elf.target_os == is_vxworks && bfd_link_pic (info)
&& !strcmp (input_section->output_section->name,
".tls_vars"));
if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
}
ifunc = NULL;
- if (!htab->is_vxworks)
+ if (htab->elf.target_os != is_vxworks)
{
struct plt_entry *ent;
if (r_type < R_PPC_max)
howto = ppc_elf_howto_table[r_type];
- switch (r_type)
- {
- default:
- break;
-
- case R_PPC_TPREL16_HA:
- if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
- {
- bfd_byte *p = contents + (rel->r_offset & ~3);
- unsigned int insn = bfd_get_32 (input_bfd, p);
- if ((insn & ((0x3fu << 26) | 0x1f << 16))
- != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
- /* xgettext:c-format */
- info->callbacks->minfo
- (_("%H: warning: %s unexpected insn %#x.\n"),
- input_bfd, input_section, rel->r_offset, howto->name, insn);
- else
- bfd_put_32 (input_bfd, NOP, p);
- }
- break;
-
- case R_PPC_TPREL16_LO:
- if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
- {
- bfd_byte *p = contents + (rel->r_offset & ~3);
- unsigned int insn = bfd_get_32 (input_bfd, p);
- insn &= ~(0x1f << 16);
- insn |= 2 << 16;
- bfd_put_32 (input_bfd, insn, p);
- }
- break;
- }
-
tls_type = 0;
switch (r_type)
{
goto copy_reloc;
}
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case R_PPC_TPREL16_HA:
+ if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ bfd_put_32 (input_bfd, NOP, p);
+ }
+ break;
+
+ case R_PPC_TPREL16_LO:
+ if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ unsigned int insn = bfd_get_32 (input_bfd, p);
+ insn &= ~(0x1f << 16);
+ insn |= 2 << 16;
+ bfd_put_32 (input_bfd, insn, p);
+ }
+ break;
+ }
+
switch (r_type)
{
default:
switch (dyn.d_tag)
{
case DT_PLTGOT:
- if (htab->is_vxworks)
+ if (htab->elf.target_os == is_vxworks)
s = htab->elf.sgotplt;
else
s = htab->elf.splt;
continue;
default:
- if (htab->is_vxworks
+ if (htab->elf.target_os == is_vxworks
&& elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
break;
continue;
}
/* Fill in the first entry in the VxWorks procedure linkage table. */
- if (htab->is_vxworks
+ if (htab->elf.target_os == is_vxworks
&& htab->elf.splt != NULL
&& htab->elf.splt->size != 0
&& htab->elf.splt->output_section != bfd_abs_section_ptr)
#undef ELF_OSABI
+#undef ELF_TARGET_OS
+#define ELF_TARGET_OS is_vxworks
+
/* VxWorks uses the elf default section flags for .plt. */
static const struct bfd_elf_special_section *
ppc_elf_vxworks_get_sec_type_attr (bfd *abfd, asection *sec)
{
struct ppc_elf_link_hash_table *htab
= (struct ppc_elf_link_hash_table *)ret;
- htab->is_vxworks = 1;
htab->plt_type = PLT_VXWORKS;
htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE;
htab->plt_slot_size = VXWORKS_PLT_ENTRY_SIZE;