* elf64-ppc.c (bfd_elf64_mkobject): Define.

(struct ppc64_elf_obj_tdata): New.
	(ppc64_elf_tdata, ppc64_tlsld_got): Define.
	(ppc64_elf_mkobject): New function.
	(struct got_entry): Add "owner".  Move "tls_type".
	(struct ppc_link_hash_table): Delete "relgot", "tlsld_got".
	(ppc64_elf_init_stub_bfd): New function.
	(create_got_section): Create header .got in dynobj.  Create .got
	and .rela.got in each bfd.  Stash pointers in ppc64_elf_obj_tdata.
	(ppc64_elf_create_dynamic_sections): Don't call create_got_section.
	Look for dynobj .got, and test it.
	(ppc64_elf_copy_indirect_symbol): Adjust for changed got.
	(update_local_sym_info): Likewise.
	(ppc64_elf_check_relocs): Likewise.
	(ppc64_elf_gc_sweep_hook): Likewise.
	(ppc64_elf_tls_optimize): Likewise.
	(allocate_dynrelocs): Likewise.
	(ppc64_elf_size_dynamic_sections): Likewise.
	(ppc64_elf_relocate_section): Likewise.
	(ppc64_elf_next_toc_section): Update comment.
	(toc_adjusting_stub_needed): Remove unneeded cast.
	(ppc64_elf_build_stubs): Check for stub sections in stub bfd by
	testing section flags.
	(ppc64_elf_build_stubs): Likewise.
	(ppc64_elf_size_stubs): Likewise.  Remove stub_bfd param.
	(ppc64_elf_finish_dynamic_sections): Write out got sections.
	(func_desc_adjust): Copy over dynamic info for undef weaks.
	* elf64-ppc.h (ppc64_elf_init_stub_bfd): Declare.
	(ppc64_elf_size_stubs): Update prototype.
	* elflink.h (elf_link_sort_relocs): Use link_orders to find reldyn
	input sections rather than scanning dynobj.
This commit is contained in:
Alan Modra 2003-07-10 00:37:27 +00:00
parent 149ebfb1de
commit e717da7ead
4 changed files with 298 additions and 130 deletions

View file

@ -1,3 +1,37 @@
2003-07-10 Alan Modra <amodra@bigpond.net.au>
* elf64-ppc.c (bfd_elf64_mkobject): Define.
(struct ppc64_elf_obj_tdata): New.
(ppc64_elf_tdata, ppc64_tlsld_got): Define.
(ppc64_elf_mkobject): New function.
(struct got_entry): Add "owner". Move "tls_type".
(struct ppc_link_hash_table): Delete "relgot", "tlsld_got".
(ppc64_elf_init_stub_bfd): New function.
(create_got_section): Create header .got in dynobj. Create .got
and .rela.got in each bfd. Stash pointers in ppc64_elf_obj_tdata.
(ppc64_elf_create_dynamic_sections): Don't call create_got_section.
Look for dynobj .got, and test it.
(ppc64_elf_copy_indirect_symbol): Adjust for changed got.
(update_local_sym_info): Likewise.
(ppc64_elf_check_relocs): Likewise.
(ppc64_elf_gc_sweep_hook): Likewise.
(ppc64_elf_tls_optimize): Likewise.
(allocate_dynrelocs): Likewise.
(ppc64_elf_size_dynamic_sections): Likewise.
(ppc64_elf_relocate_section): Likewise.
(ppc64_elf_next_toc_section): Update comment.
(toc_adjusting_stub_needed): Remove unneeded cast.
(ppc64_elf_build_stubs): Check for stub sections in stub bfd by
testing section flags.
(ppc64_elf_build_stubs): Likewise.
(ppc64_elf_size_stubs): Likewise. Remove stub_bfd param.
(ppc64_elf_finish_dynamic_sections): Write out got sections.
(func_desc_adjust): Copy over dynamic info for undef weaks.
* elf64-ppc.h (ppc64_elf_init_stub_bfd): Declare.
(ppc64_elf_size_stubs): Update prototype.
* elflink.h (elf_link_sort_relocs): Use link_orders to find reldyn
input sections rather than scanning dynobj.
2003-07-09 Richard Sandiford <rsandifo@redhat.com>
* elfxx-mips.c (mips_elf_link_hash_entry): Remove min_dyn_reloc_index.

View file

@ -69,6 +69,7 @@ static bfd_reloc_status_type ppc64_elf_unhandled_reloc
#define elf_backend_can_refcount 1
#define elf_backend_rela_normal 1
#define bfd_elf64_mkobject ppc64_elf_mkobject
#define bfd_elf64_bfd_reloc_type_lookup ppc64_elf_reloc_type_lookup
#define bfd_elf64_bfd_merge_private_bfd_data ppc64_elf_merge_private_bfd_data
#define bfd_elf64_new_section_hook ppc64_elf_new_section_hook
@ -2316,6 +2317,40 @@ ppc64_elf_unhandled_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
return bfd_reloc_dangerous;
}
struct ppc64_elf_obj_tdata
{
struct elf_obj_tdata elf;
/* Shortcuts to dynamic linker sections. */
asection *got;
asection *relgot;
/* TLS local dynamic got entry handling. Suppose for multiple GOT
sections means we potentially need one of these for each input bfd. */
union {
bfd_signed_vma refcount;
bfd_vma offset;
} tlsld_got;
};
#define ppc64_elf_tdata(bfd) \
((struct ppc64_elf_obj_tdata *) (bfd)->tdata.any)
#define ppc64_tlsld_got(bfd) \
(&ppc64_elf_tdata (bfd)->tlsld_got)
/* Override the generic function because we store some extras. */
static bfd_boolean
ppc64_elf_mkobject (bfd *abfd)
{
bfd_size_type amt = sizeof (struct ppc64_elf_obj_tdata);
abfd->tdata.any = bfd_zalloc (abfd, amt);
if (abfd->tdata.any == NULL)
return FALSE;
return TRUE;
}
/* Fix bad default arch selected for a 64 bit input bfd when the
default is 32 bit. */
@ -2497,16 +2532,24 @@ struct got_entry
/* The symbol addend that we'll be placing in the GOT. */
bfd_vma addend;
/* Unlike other ELF targets, we use separate GOT entries for the same
symbol referenced from different input files. This is to support
automatic multiple TOC/GOT sections, where the TOC base can vary
from one input file to another.
Point to the BFD owning this GOT entry. */
bfd *owner;
/* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD,
TLS_TPREL or TLS_DTPREL for tls entries. */
char tls_type;
/* Reference count until size_dynamic_sections, GOT offset thereafter. */
union
{
bfd_signed_vma refcount;
bfd_vma offset;
} got;
/* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD,
TLS_TPREL or TLS_DTPREL for tls entries. */
char tls_type;
};
/* The same for PLT. */
@ -2719,7 +2762,6 @@ struct ppc_link_hash_table
/* Short-cuts to get to dynamic linker sections. */
asection *got;
asection *relgot;
asection *plt;
asection *relplt;
asection *dynbss;
@ -2735,12 +2777,6 @@ struct ppc_link_hash_table
/* Shortcut to .__tls_get_addr. */
struct elf_link_hash_entry *tls_get_addr;
/* TLS local dynamic got entry handling. */
union {
bfd_signed_vma refcount;
bfd_vma offset;
} tlsld_got;
/* Statistics. */
unsigned long stub_count[ppc_stub_plt_call];
@ -2928,6 +2964,23 @@ ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
_bfd_generic_link_hash_table_free (hash);
}
/* Satisfy the ELF linker by filling in some fields in our fake bfd. */
void
ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
elf_elfheader (abfd)->e_ident[EI_CLASS] = ELFCLASS64;
/* Always hook our dynamic sections into the first bfd, which is the
linker created stub bfd. This ensures that the GOT header is at
the start of the output TOC section. */
htab = ppc_hash_table (info);
htab->stub_bfd = abfd;
htab->elf.dynobj = abfd;
}
/* Build a name for an entry in the stub hash table. */
static char *
@ -3122,30 +3175,43 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
return TRUE;
}
/* Create .got and .rela.got sections in DYNOBJ, and set up
shortcuts to them in our hash table. */
/* Create .got and .rela.got sections in ABFD, and .got in dynobj if
not already done. */
static bfd_boolean
create_got_section (bfd *dynobj, struct bfd_link_info *info)
create_got_section (bfd *abfd, struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
asection *got, *relgot;
flagword flags;
struct ppc_link_hash_table *htab = ppc_hash_table (info);
if (! _bfd_elf_create_got_section (dynobj, info))
return FALSE;
htab = ppc_hash_table (info);
htab->got = bfd_get_section_by_name (dynobj, ".got");
if (!htab->got)
abort ();
{
if (! _bfd_elf_create_got_section (htab->elf.dynobj, info))
return FALSE;
htab->relgot = bfd_make_section (dynobj, ".rela.got");
if (!htab->relgot
|| ! bfd_set_section_flags (dynobj, htab->relgot,
(SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
| SEC_IN_MEMORY | SEC_LINKER_CREATED
| SEC_READONLY))
|| ! bfd_set_section_alignment (dynobj, htab->relgot, 3))
htab->got = bfd_get_section_by_name (htab->elf.dynobj, ".got");
if (!htab->got)
abort ();
}
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED);
got = bfd_make_section (abfd, ".got");
if (!got
|| !bfd_set_section_flags (abfd, got, flags)
|| !bfd_set_section_alignment (abfd, got, 3))
return FALSE;
relgot = bfd_make_section (abfd, ".rela.got");
if (!relgot
|| ! bfd_set_section_flags (abfd, relgot, flags | SEC_READONLY)
|| ! bfd_set_section_alignment (abfd, relgot, 3))
return FALSE;
ppc64_elf_tdata (abfd)->got = got;
ppc64_elf_tdata (abfd)->relgot = relgot;
return TRUE;
}
@ -3156,20 +3222,19 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
htab = ppc_hash_table (info);
if (!htab->got && !create_got_section (dynobj, info))
return FALSE;
if (!_bfd_elf_create_dynamic_sections (dynobj, info))
return FALSE;
htab = ppc_hash_table (info);
if (!htab->got)
htab->got = bfd_get_section_by_name (dynobj, ".got");
htab->plt = bfd_get_section_by_name (dynobj, ".plt");
htab->relplt = bfd_get_section_by_name (dynobj, ".rela.plt");
htab->dynbss = bfd_get_section_by_name (dynobj, ".dynbss");
if (!info->shared)
htab->relbss = bfd_get_section_by_name (dynobj, ".rela.bss");
if (!htab->plt || !htab->relplt || !htab->dynbss
if (!htab->got || !htab->plt || !htab->relplt || !htab->dynbss
|| (!info->shared && !htab->relbss))
abort ();
@ -3260,6 +3325,7 @@ ppc64_elf_copy_indirect_symbol (struct elf_backend_data *bed ATTRIBUTE_UNUSED,
for (dent = edir->elf.got.glist; dent != NULL; dent = dent->next)
if (dent->addend == ent->addend
&& dent->owner == ent->owner
&& dent->tls_type == ent->tls_type)
{
dent->got.refcount += ent->got.refcount;
@ -3360,7 +3426,9 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
struct got_entry *ent;
for (ent = local_got_ents[r_symndx]; ent != NULL; ent = ent->next)
if (ent->addend == r_addend && ent->tls_type == tls_type)
if (ent->addend == r_addend
&& ent->owner == abfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
{
@ -3370,6 +3438,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
return FALSE;
ent->next = local_got_ents[r_symndx];
ent->addend = r_addend;
ent->owner = abfd;
ent->tls_type = tls_type;
ent->got.refcount = 0;
local_got_ents[r_symndx] = ent;
@ -3460,8 +3529,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
ppc64_elf_section_data (sec)->opd.func_sec = opd_sym_map;
}
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
if (htab->sfpr == NULL
&& !create_linkage_sections (htab->elf.dynobj, info))
return FALSE;
@ -3487,7 +3554,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
htab->tlsld_got.refcount += 1;
ppc64_tlsld_got (abfd)->refcount += 1;
tls_type = TLS_TLS | TLS_LD;
goto dogottls;
@ -3524,8 +3591,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT16_LO_DS:
/* This symbol requires a global offset table entry. */
sec->has_gp_reloc = 1;
if (htab->got == NULL
&& !create_got_section (htab->elf.dynobj, info))
if (ppc64_elf_tdata (abfd)->got == NULL
&& !create_got_section (abfd, info))
return FALSE;
if (h != NULL)
@ -3536,6 +3603,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
eh = (struct ppc_link_hash_entry *) h;
for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
&& ent->owner == abfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
@ -3546,6 +3614,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
return FALSE;
ent->next = eh->elf.got.glist;
ent->addend = rel->r_addend;
ent->owner = abfd;
ent->tls_type = tls_type;
ent->got.refcount = 0;
eh->elf.got.glist = ent;
@ -4054,7 +4123,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
htab->tlsld_got.refcount -= 1;
ppc64_tlsld_got (abfd)->refcount -= 1;
tls_type = TLS_TLS | TLS_LD;
goto dogot;
@ -4096,6 +4165,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
for (; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
&& ent->owner == abfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
@ -4213,7 +4283,9 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
&& (fdh->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
&& (info->shared
|| (fdh->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
|| (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0))
|| (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
|| (fdh->root.type == bfd_link_hash_undefweak
&& ELF_ST_VISIBILITY (fdh->other) == STV_DEFAULT)))
{
if (fdh->dynindx == -1)
if (! bfd_elf64_link_record_dynamic_symbol (info, fdh))
@ -5138,7 +5210,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
/* These relocs should never be against a symbol
defined in a shared lib. Leave them alone if
that turns out to be the case. */
htab->tlsld_got.refcount -= 1;
ppc64_tlsld_got (ibfd)->refcount -= 1;
if (!is_local)
continue;
@ -5276,6 +5348,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
for (; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
&& ent->owner == ibfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
@ -5431,7 +5504,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
for (ent = h->got.glist; ent != NULL; ent = ent->next)
if (ent->got.refcount > 0
&& (ent->tls_type & TLS_TPREL) != 0
&& ent->addend == gent->addend)
&& ent->addend == gent->addend
&& ent->owner == gent->owner)
{
gent->got.refcount = 0;
break;
@ -5460,11 +5534,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if ((gent->tls_type & TLS_LD) != 0
&& !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC))
{
gent->got.offset = htab->tlsld_got.offset;
gent->got.offset = ppc64_tlsld_got (gent->owner)->offset;
continue;
}
s = htab->got;
s = ppc64_elf_tdata (gent->owner)->got;
gent->got.offset = s->_raw_size;
s->_raw_size
+= (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)) ? 16 : 8;
@ -5473,7 +5547,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
htab->relgot->_raw_size
ppc64_elf_tdata (gent->owner)->relgot->_raw_size
+= (gent->tls_type & eh->tls_mask & TLS_GD
? 2 * sizeof (Elf64_External_Rela)
: sizeof (Elf64_External_Rela));
@ -5618,16 +5692,6 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
}
}
if (htab->tlsld_got.refcount > 0)
{
htab->tlsld_got.offset = htab->got->_raw_size;
htab->got->_raw_size += 16;
if (info->shared)
htab->relgot->_raw_size += sizeof (Elf64_External_Rela);
}
else
htab->tlsld_got.offset = (bfd_vma) -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)
@ -5642,6 +5706,20 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
continue;
if (ppc64_tlsld_got (ibfd)->refcount > 0)
{
s = ppc64_elf_tdata (ibfd)->got;
ppc64_tlsld_got (ibfd)->offset = s->_raw_size;
s->_raw_size += 16;
if (info->shared)
{
srel = ppc64_elf_tdata (ibfd)->relgot;
srel->_raw_size += sizeof (Elf64_External_Rela);
}
}
else
ppc64_tlsld_got (ibfd)->offset = (bfd_vma) -1;
for (s = ibfd->sections; s != NULL; s = s->next)
{
struct ppc_dyn_relocs *p;
@ -5677,8 +5755,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
locsymcount = symtab_hdr->sh_info;
end_lgot_ents = lgot_ents + locsymcount;
lgot_masks = (char *) end_lgot_ents;
s = htab->got;
srel = htab->relgot;
s = ppc64_elf_tdata (ibfd)->got;
srel = ppc64_elf_tdata (ibfd)->relgot;
for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
{
struct got_entry *ent;
@ -5688,14 +5766,14 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
{
if ((ent->tls_type & *lgot_masks & TLS_LD) != 0)
{
if (htab->tlsld_got.offset == (bfd_vma) -1)
if (ppc64_tlsld_got (ibfd)->offset == (bfd_vma) -1)
{
htab->tlsld_got.offset = s->_raw_size;
ppc64_tlsld_got (ibfd)->offset = s->_raw_size;
s->_raw_size += 16;
if (info->shared)
srel->_raw_size += sizeof (Elf64_External_Rela);
}
ent->got.offset = htab->tlsld_got.offset;
ent->got.offset = ppc64_tlsld_got (ibfd)->offset;
}
else
{
@ -5738,16 +5816,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
if (s == htab->brlt || s == htab->relbrlt)
/* These haven't been allocated yet; don't strip. */
continue;
else if (s == htab->got)
{
/* Automatic multiple tocs aren't possible if we are using the
GOT. The GOT is accessed via r2, so we can't adjust r2.
FIXME: There's no reason why we couldn't lay out multiple
GOTs too. */
if (s->_raw_size > elf_backend_got_header_size)
htab->no_multi_toc = 1;
}
else if (s == htab->plt
else if (s == htab->got
|| s == htab->plt
|| s == htab->glink)
{
/* Strip this section if we don't need it; see the
@ -5805,6 +5875,38 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
return FALSE;
}
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
s = ppc64_elf_tdata (ibfd)->got;
if (s != NULL && s != htab->got)
{
s->_cooked_size = 0;
if (s->_raw_size == 0)
_bfd_strip_section_from_output (info, s);
else
{
s->contents = bfd_zalloc (ibfd, s->_raw_size);
if (s->contents == NULL)
return FALSE;
}
}
s = ppc64_elf_tdata (ibfd)->relgot;
if (s != NULL)
{
s->_cooked_size = 0;
if (s->_raw_size == 0)
_bfd_strip_section_from_output (info, s);
else
{
s->contents = bfd_zalloc (ibfd, s->_raw_size);
if (s->contents == NULL)
return FALSE;
relocs = TRUE;
s->reloc_count = 0;
}
}
}
if (htab->elf.dynamic_sections_created)
{
/* Add some entries to the .dynamic section. We fill in the
@ -6323,10 +6425,10 @@ ppc64_elf_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info)
return 1;
}
/* The linker repeatedly calls this function for each toc input
section. Group input bfds such that the toc within a group
is less than 64k in size. Will break with cute linker scripts
that play games with dot in the output toc section. */
/* The linker repeatedly calls this function for each TOC input section
and linker generated GOT section. Group input bfds such that the toc
within a group is less than 64k in size. Will break with cute linker
scripts that play games with dot in the output toc section. */
void
ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
@ -6389,7 +6491,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
if (contents == NULL)
return -1;
if (! bfd_get_section_contents (isec->owner, isec, contents,
(file_ptr) 0, isec->_raw_size))
0, isec->_raw_size))
{
free (contents);
return -1;
@ -6555,7 +6657,6 @@ group_sections (struct ppc_link_hash_table *htab,
bfd_boolean
ppc64_elf_size_stubs (bfd *output_bfd,
bfd *stub_bfd,
struct bfd_link_info *info,
bfd_signed_vma group_size,
asection *(*add_stub_section) (const char *, asection *),
@ -6566,7 +6667,6 @@ ppc64_elf_size_stubs (bfd *output_bfd,
struct ppc_link_hash_table *htab = ppc_hash_table (info);
/* Stash our params away. */
htab->stub_bfd = stub_bfd;
htab->add_stub_section = add_stub_section;
htab->layout_sections_again = layout_sections_again;
stubs_always_before_branch = group_size < 0;
@ -6820,10 +6920,11 @@ ppc64_elf_size_stubs (bfd *output_bfd,
for (stub_sec = htab->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
{
stub_sec->_raw_size = 0;
stub_sec->_cooked_size = 0;
}
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
stub_sec->_raw_size = 0;
stub_sec->_cooked_size = 0;
}
htab->brlt->_raw_size = 0;
htab->brlt->_cooked_size = 0;
@ -6909,24 +7010,26 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
struct ppc_link_hash_table *htab = ppc_hash_table (info);
asection *stub_sec;
bfd_byte *p;
int stub_sec_count = 0;
htab->emit_stub_syms = emit_stub_syms;
for (stub_sec = htab->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
{
bfd_size_type size;
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
bfd_size_type size;
/* Allocate memory to hold the linker stubs. */
size = stub_sec->_raw_size;
if (size != 0)
{
stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
if (stub_sec->contents == NULL)
return FALSE;
}
stub_sec->_cooked_size = 0;
}
/* Allocate memory to hold the linker stubs. */
size = stub_sec->_raw_size;
if (size != 0)
{
stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
if (stub_sec->contents == NULL)
return FALSE;
}
stub_sec->_cooked_size = 0;
}
if (htab->plt != NULL)
{
@ -7018,10 +7121,12 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
for (stub_sec = htab->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
{
if (stub_sec->_raw_size != stub_sec->_cooked_size)
break;
}
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
stub_sec_count += 1;
if (stub_sec->_raw_size != stub_sec->_cooked_size)
break;
}
if (stub_sec != NULL
|| htab->glink->_raw_size != htab->glink->_cooked_size)
@ -7045,7 +7150,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
" long branch %lu\n"
" long toc adj %lu\n"
" plt call %lu"),
htab->stub_bfd->section_count,
stub_sec_count,
htab->stub_count[ppc_stub_long_branch - 1],
htab->stub_count[ppc_stub_long_branch_r2off - 1],
htab->stub_count[ppc_stub_plt_branch - 1],
@ -7736,17 +7841,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
{
/* Relocation is to the entry for this symbol in the global
offset table. */
asection *got;
bfd_vma *offp;
bfd_vma off;
unsigned long indx = 0;
if (htab->got == NULL)
abort ();
if (tls_type == (TLS_TLS | TLS_LD)
&& (h == NULL
|| !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)))
offp = &htab->tlsld_got.offset;
offp = &ppc64_tlsld_got (input_bfd)->offset;
else
{
struct got_entry *ent;
@ -7778,6 +7881,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
for (; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
&& ent->owner == input_bfd
&& ent->tls_type == tls_type)
break;
if (ent == NULL)
@ -7785,6 +7889,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
offp = &ent->got.offset;
}
got = ppc64_elf_tdata (input_bfd)->got;
if (got == NULL)
abort ();
/* The offset must always be a multiple of 8. We use the
least significant bit to record whether we have already
processed this entry. */
@ -7796,14 +7904,16 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Generate relocs for the dynamic linker, except in
the case of TLSLD where we'll use one entry per
module. */
asection *relgot = ppc64_elf_tdata (input_bfd)->relgot;
*offp = off | 1;
if ((info->shared || indx != 0)
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
{
outrel.r_offset = (htab->got->output_section->vma
+ htab->got->output_offset
outrel.r_offset = (got->output_section->vma
+ got->output_offset
+ off);
outrel.r_addend = rel->r_addend;
if (tls_type & (TLS_LD | TLS_GD))
@ -7812,8 +7922,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPMOD64);
if (tls_type == (TLS_TLS | TLS_GD))
{
loc = htab->relgot->contents;
loc += (htab->relgot->reloc_count++
loc = relgot->contents;
loc += (relgot->reloc_count++
* sizeof (Elf64_External_Rela));
bfd_elf64_swap_reloca_out (output_bfd,
&outrel, loc);
@ -7833,7 +7943,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Write the .got section contents for the sake
of prelink. */
loc = htab->got->contents + off;
loc = got->contents + off;
bfd_put_64 (output_bfd, outrel.r_addend + relocation,
loc);
}
@ -7846,8 +7956,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (tls_type & (TLS_GD | TLS_DTPREL | TLS_TPREL))
outrel.r_addend -= htab->tls_sec->vma;
}
loc = htab->relgot->contents;
loc += (htab->relgot->reloc_count++
loc = relgot->contents;
loc += (relgot->reloc_count++
* sizeof (Elf64_External_Rela));
bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
}
@ -7868,23 +7978,23 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (tls_type == (TLS_TLS | TLS_GD))
{
bfd_put_64 (output_bfd, relocation,
htab->got->contents + off + 8);
got->contents + off + 8);
relocation = 1;
}
}
bfd_put_64 (output_bfd, relocation,
htab->got->contents + off);
got->contents + off);
}
}
if (off >= (bfd_vma) -2)
abort ();
relocation = htab->got->output_offset + off;
relocation = got->output_offset + off;
/* TOC base (r2) is TOC start plus 0x8000. */
addend = - TOC_BASE_OFF;
addend = -TOC_BASE_OFF;
}
break;
@ -8626,6 +8736,29 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
= PLT_ENTRY_SIZE;
}
/* We need to handle writing out multiple GOT sections ourselves,
since we didn't add them to DYNOBJ. */
while ((dynobj = dynobj->link_next) != NULL)
{
asection *s;
s = ppc64_elf_tdata (dynobj)->got;
if (s != NULL
&& s->_raw_size != 0
&& s->output_section != bfd_abs_section_ptr
&& !bfd_set_section_contents (output_bfd, s->output_section,
s->contents, s->output_offset,
s->_raw_size))
return FALSE;
s = ppc64_elf_tdata (dynobj)->relgot;
if (s != NULL
&& s->_raw_size != 0
&& s->output_section != bfd_abs_section_ptr
&& !bfd_set_section_contents (output_bfd, s->output_section,
s->contents, s->output_offset,
s->_raw_size))
return FALSE;
}
return TRUE;
}

View file

@ -17,6 +17,8 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
void ppc64_elf_init_stub_bfd
(bfd *, struct bfd_link_info *);
bfd_boolean ppc64_elf_mark_entry_syms
(struct bfd_link_info *);
bfd_boolean ppc64_elf_edit_opd
@ -36,7 +38,7 @@ void ppc64_elf_reinit_toc
bfd_boolean ppc64_elf_next_input_section
(struct bfd_link_info *, asection *);
bfd_boolean ppc64_elf_size_stubs
(bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma,
(bfd *, struct bfd_link_info *, bfd_signed_vma,
asection *(*) (const char *, asection *), void (*) (void));
bfd_boolean ppc64_elf_build_stubs
(bfd_boolean, struct bfd_link_info *, char **);

View file

@ -3029,8 +3029,7 @@ elf_link_sort_relocs (abfd, info, psec)
struct bfd_link_info *info;
asection **psec;
{
bfd *dynobj = elf_hash_table (info)->dynobj;
asection *reldyn, *o;
asection *reldyn;
bfd_size_type count, size;
size_t i, ret, sort_elt, ext_size;
bfd_byte *sort, *s_non_relative, *p;
@ -3039,6 +3038,7 @@ elf_link_sort_relocs (abfd, info, psec)
int i2e = bed->s->int_rels_per_ext_rel;
void (*swap_in) PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *));
void (*swap_out) PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *));
struct bfd_link_order *lo;
reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
if (reldyn == NULL || reldyn->_raw_size == 0)
@ -3059,11 +3059,12 @@ elf_link_sort_relocs (abfd, info, psec)
count = reldyn->_raw_size / ext_size;
size = 0;
for (o = dynobj->sections; o != NULL; o = o->next)
if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
== (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
&& o->output_section == reldyn)
size += o->_raw_size;
for (lo = reldyn->link_order_head; lo != NULL; lo = lo->next)
if (lo->type == bfd_indirect_link_order)
{
asection *o = lo->u.indirect.section;
size += o->_raw_size;
}
if (size != reldyn->_raw_size)
return 0;
@ -3079,12 +3080,11 @@ elf_link_sort_relocs (abfd, info, psec)
return 0;
}
for (o = dynobj->sections; o != NULL; o = o->next)
if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
== (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
&& o->output_section == reldyn)
for (lo = reldyn->link_order_head; lo != NULL; lo = lo->next)
if (lo->type == bfd_indirect_link_order)
{
bfd_byte *erel, *erelend;
asection *o = lo->u.indirect.section;
erel = o->contents;
erelend = o->contents + o->_raw_size;
@ -3121,12 +3121,11 @@ elf_link_sort_relocs (abfd, info, psec)
qsort (s_non_relative, (size_t) count - ret, sort_elt, elf_link_sort_cmp2);
for (o = dynobj->sections; o != NULL; o = o->next)
if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
== (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
&& o->output_section == reldyn)
for (lo = reldyn->link_order_head; lo != NULL; lo = lo->next)
if (lo->type == bfd_indirect_link_order)
{
bfd_byte *erel, *erelend;
asection *o = lo->u.indirect.section;
erel = o->contents;
erelend = o->contents + o->_raw_size;