aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf64-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2010-06-25 03:46:04 +0000
committerAlan Modra <amodra@gmail.com>2010-06-25 03:46:04 +0000
commit854b41e7c1e636b0ef937a86b452969022bc6073 (patch)
tree3ca44789acfd42381b4f538f8fe86d5bcb8d287e /bfd/elf64-ppc.c
parent8a75a161b2c2b23f87f986e186c18dc5e267753f (diff)
downloadgdb-854b41e7c1e636b0ef937a86b452969022bc6073.zip
gdb-854b41e7c1e636b0ef937a86b452969022bc6073.tar.gz
gdb-854b41e7c1e636b0ef937a86b452969022bc6073.tar.bz2
* elf64-ppc.c (is_static_defined): New function.
(get_tls_mask, ppc_type_of_stub): Use it here. (ppc64_elf_edit_opd): Ensure we only attempt to edit ppc64 input. (ppc64_elf_tls_setup): Typo fix. (adjust_toc_syms): Correctly handle symbols defined past the end of the toc. Move syms on removed entries to next entry rather than to start of toc. (ppc64_elf_edit_toc): Likewise. Ensure we only attempt to edit ppc64 input. Allocate one extra word in skip array. Honour info->keep_memory when reading relocs if we can. Adjust toc relocs after adjusting symbols.
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r--bfd/elf64-ppc.c160
1 files changed, 100 insertions, 60 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 769b0a4..fbc7600 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -5566,6 +5566,17 @@ opd_entry_value (asection *opd_sec,
return val;
}
+/* Return true if symbol is defined in a regular object file. */
+
+static bfd_boolean
+is_static_defined (struct elf_link_hash_entry *h)
+{
+ return ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->root.u.def.section != NULL
+ && h->root.u.def.section->output_section != NULL);
+}
+
/* If FDH is a function descriptor symbol, return the associated code
entry symbol if it is defined. Return NULL otherwise. */
@@ -6704,10 +6715,7 @@ get_tls_mask (unsigned char **tls_maskp,
*toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8];
if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
return 0;
- if ((h == NULL
- || ((h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && !h->def_dynamic))
+ if ((h == NULL || is_static_defined (h))
&& (next_r == -1 || next_r == -2))
return 1 - next_r;
return 1;
@@ -6924,6 +6932,9 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
bfd_boolean need_edit, add_aux_fields;
bfd_size_type cnt_16b = 0;
+ if (!is_ppc64_elf (ibfd))
+ continue;
+
sec = bfd_get_section_by_name (ibfd, ".opd");
if (sec == NULL || sec->size == 0)
continue;
@@ -7375,7 +7386,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info,
_bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
opt_fd->dynstr_index);
if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd))
- return FALSE;
+ return NULL;
}
htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) opt_fd;
tga = &htab->tls_get_addr->elf;
@@ -7840,6 +7851,7 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
{
struct ppc_link_hash_entry *eh;
struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf;
+ unsigned long i;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
@@ -7857,16 +7869,22 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
if (eh->elf.root.u.def.section == toc_inf->toc)
{
- unsigned long skip = toc_inf->skip[eh->elf.root.u.def.value >> 3];
- if (skip != (unsigned long) -1)
- eh->elf.root.u.def.value -= skip;
+ if (eh->elf.root.u.def.value > toc_inf->toc->rawsize)
+ i = toc_inf->toc->rawsize >> 3;
else
+ i = eh->elf.root.u.def.value >> 3;
+
+ if (toc_inf->skip[i] == (unsigned long) -1)
{
(*_bfd_error_handler)
- (_("%s defined in removed toc entry"), eh->elf.root.root.string);
- eh->elf.root.u.def.section = &bfd_abs_section;
- eh->elf.root.u.def.value = 0;
+ (_("%s defined on removed toc entry"), eh->elf.root.root.string);
+ do
+ ++i;
+ while (toc_inf->skip[i] == (unsigned long) -1);
+ eh->elf.root.u.def.value = (bfd_vma) i << 3;
}
+
+ eh->elf.root.u.def.value -= toc_inf->skip[i];
eh->adjust_done = 1;
}
else if (strcmp (eh->elf.root.u.def.section->name, ".toc") == 0)
@@ -7898,6 +7916,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
unsigned char *used;
unsigned char *keep, last, some_unused;
+ if (!is_ppc64_elf (ibfd))
+ continue;
+
toc = bfd_get_section_by_name (ibfd, ".toc");
if (toc == NULL
|| toc->size == 0
@@ -7975,7 +7996,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
if (skip == NULL)
{
- skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 7) / 8);
+ skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 15) / 8);
if (skip == NULL)
goto error_ret;
}
@@ -8025,7 +8046,8 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
|| (sec->flags & SEC_DEBUGGING) != 0)
continue;
- relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, TRUE);
+ relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+ info->keep_memory);
if (relstart == NULL)
goto error_ret;
@@ -8091,6 +8113,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
used[val >> 3] = 1;
}
while (repeat);
+
+ if (elf_section_data (sec)->relocs != relstart)
+ free (relstart);
}
/* Merge the used and skip arrays. Assume that TOC
@@ -8143,40 +8168,10 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
memcpy (src - off, src, 8);
}
}
+ *drop = off;
toc->rawsize = toc->size;
toc->size = src - contents - off;
- if (toc->reloc_count != 0)
- {
- Elf_Internal_Rela *wrel;
- bfd_size_type sz;
-
- /* Read toc relocs. */
- relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
- TRUE);
- if (relstart == NULL)
- goto error_ret;
-
- /* Remove unused toc relocs, and adjust those we keep. */
- wrel = relstart;
- for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
- if (skip[rel->r_offset >> 3] != (unsigned long) -1)
- {
- wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
- wrel->r_info = rel->r_info;
- wrel->r_addend = rel->r_addend;
- ++wrel;
- }
- else if (!dec_dynrel_count (rel->r_info, toc, info,
- &local_syms, NULL, NULL))
- goto error_ret;
-
- toc->reloc_count = wrel - relstart;
- sz = elf_section_data (toc)->rel_hdr.sh_entsize;
- elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz;
- BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL);
- }
-
/* Adjust addends for relocs against the toc section sym. */
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
{
@@ -8185,7 +8180,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
continue;
relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
- TRUE);
+ info->keep_memory);
if (relstart == NULL)
goto error_ret;
@@ -8196,6 +8191,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
asection *sym_sec;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
+ bfd_vma val;
r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
@@ -8221,8 +8217,17 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
if (sym_sec != toc || h != NULL || sym->st_value != 0)
continue;
- rel->r_addend -= skip[rel->r_addend >> 3];
+ val = rel->r_addend;
+
+ if (val > toc->rawsize)
+ val = toc->rawsize;
+
+ rel->r_addend -= skip[val >> 3];
+ elf_section_data (sec)->relocs = relstart;
}
+
+ if (elf_section_data (sec)->relocs != relstart)
+ free (relstart);
}
/* We shouldn't have local or global symbols defined in the TOC,
@@ -8237,22 +8242,30 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
if (sym->st_value != 0
&& bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
{
- if (skip[sym->st_value >> 3] != (unsigned long) -1)
- sym->st_value -= skip[sym->st_value >> 3];
+ unsigned long i;
+
+ if (sym->st_value > toc->rawsize)
+ i = toc->rawsize >> 3;
else
+ i = sym->st_value >> 3;
+
+ if (skip[sym->st_value >> 3] == (unsigned long) -1)
{
(*_bfd_error_handler)
- (_("%s defined in removed toc entry"),
- bfd_elf_sym_name (ibfd, symtab_hdr, sym,
- NULL));
- sym->st_value = 0;
- sym->st_shndx = SHN_ABS;
+ (_("%s defined on removed toc entry"),
+ bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
+ do
+ ++i;
+ while (skip[i] == (unsigned long) -1);
+ sym->st_value = (bfd_vma) i << 3;
}
+
+ sym->st_value -= skip[i];
symtab_hdr->contents = (unsigned char *) local_syms;
}
}
- /* Finally, adjust any global syms defined in the toc. */
+ /* Adjust any global syms defined in this toc input section. */
if (toc_inf.global_toc_syms)
{
toc_inf.toc = toc;
@@ -8261,6 +8274,37 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
&toc_inf);
}
+
+ if (toc->reloc_count != 0)
+ {
+ Elf_Internal_Rela *wrel;
+ bfd_size_type sz;
+
+ /* Read toc relocs. */
+ relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
+ TRUE);
+ if (relstart == NULL)
+ goto error_ret;
+
+ /* Remove unused toc relocs, and adjust those we keep. */
+ wrel = relstart;
+ for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
+ if (skip[rel->r_offset >> 3] != (unsigned long) -1)
+ {
+ wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
+ wrel->r_info = rel->r_info;
+ wrel->r_addend = rel->r_addend;
+ ++wrel;
+ }
+ else if (!dec_dynrel_count (rel->r_info, toc, info,
+ &local_syms, NULL, NULL))
+ goto error_ret;
+
+ toc->reloc_count = wrel - relstart;
+ sz = elf_section_data (toc)->rel_hdr.sh_entsize;
+ elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz;
+ BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL);
+ }
}
if (local_syms != NULL
@@ -9007,12 +9051,8 @@ ppc_type_of_stub (asection *input_sec,
either a defined function descriptor or a defined entry symbol
in a regular object file, then it is pointless trying to make
any other type of stub. */
- if (!((fdh->elf.root.type == bfd_link_hash_defined
- || fdh->elf.root.type == bfd_link_hash_defweak)
- && fdh->elf.root.u.def.section->output_section != NULL)
- && !((h->elf.root.type == bfd_link_hash_defined
- || h->elf.root.type == bfd_link_hash_defweak)
- && h->elf.root.u.def.section->output_section != NULL))
+ if (!is_static_defined (&fdh->elf)
+ && !is_static_defined (&h->elf))
return ppc_stub_none;
}
else if (elf_local_got_ents (input_sec->owner) != NULL)