* 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.
This commit is contained in:
Alan Modra 2010-06-25 03:46:04 +00:00
parent 8a75a161b2
commit 854b41e7c1
2 changed files with 159 additions and 105 deletions

View File

@ -1,3 +1,17 @@
2010-06-25 Alan Modra <amodra@gmail.com>
* 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.
2010-06-23 Nathan Sidwell <nathan@codesourcery.com>
* archive64.c (bfd_elf64_archive_write_armap): Fix buffer overrun
@ -559,7 +573,7 @@
* pe-x86_64.c (TARGET_UNDERSCORE): Set value dependent
to USE_MINGW64_LEADING_UNDERSCORES.
* pei-x86_64.c (TARGET_UNDERSCORE): Likewise.
* pei-x86_64.c (TARGET_UNDERSCORE): Likewise.
* config.bfd: Change underscoring default for x64 mingw
to false.
* coffcode.h (coff_write_relocs): Add check that dereferenced

View File

@ -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,9 +8168,113 @@ 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;
/* Adjust addends for relocs against the toc section sym. */
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
{
if (sec->reloc_count == 0
|| elf_discarded_section (sec))
continue;
relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
info->keep_memory);
if (relstart == NULL)
goto error_ret;
for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
{
enum elf_ppc64_reloc_type r_type;
unsigned long r_symndx;
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)
{
default:
continue;
case R_PPC64_TOC16:
case R_PPC64_TOC16_LO:
case R_PPC64_TOC16_HI:
case R_PPC64_TOC16_HA:
case R_PPC64_TOC16_DS:
case R_PPC64_TOC16_LO_DS:
case R_PPC64_ADDR64:
break;
}
r_symndx = ELF64_R_SYM (rel->r_info);
if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
r_symndx, ibfd))
goto error_ret;
if (sym_sec != toc || h != NULL || sym->st_value != 0)
continue;
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,
but handle them anyway. */
if (local_syms != NULL)
{
Elf_Internal_Sym *sym;
for (sym = local_syms;
sym < local_syms + symtab_hdr->sh_info;
++sym)
if (sym->st_value != 0
&& bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
{
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 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;
}
}
/* Adjust any global syms defined in this toc input section. */
if (toc_inf.global_toc_syms)
{
toc_inf.toc = toc;
toc_inf.skip = skip;
toc_inf.global_toc_syms = FALSE;
elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
&toc_inf);
}
if (toc->reloc_count != 0)
{
Elf_Internal_Rela *wrel;
@ -8176,91 +8305,6 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
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)
{
if (sec->reloc_count == 0
|| elf_discarded_section (sec))
continue;
relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
TRUE);
if (relstart == NULL)
goto error_ret;
for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
{
enum elf_ppc64_reloc_type r_type;
unsigned long r_symndx;
asection *sym_sec;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
{
default:
continue;
case R_PPC64_TOC16:
case R_PPC64_TOC16_LO:
case R_PPC64_TOC16_HI:
case R_PPC64_TOC16_HA:
case R_PPC64_TOC16_DS:
case R_PPC64_TOC16_LO_DS:
case R_PPC64_ADDR64:
break;
}
r_symndx = ELF64_R_SYM (rel->r_info);
if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
r_symndx, ibfd))
goto error_ret;
if (sym_sec != toc || h != NULL || sym->st_value != 0)
continue;
rel->r_addend -= skip[rel->r_addend >> 3];
}
}
/* We shouldn't have local or global symbols defined in the TOC,
but handle them anyway. */
if (local_syms != NULL)
{
Elf_Internal_Sym *sym;
for (sym = local_syms;
sym < local_syms + symtab_hdr->sh_info;
++sym)
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];
else
{
(*_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;
}
symtab_hdr->contents = (unsigned char *) local_syms;
}
}
/* Finally, adjust any global syms defined in the toc. */
if (toc_inf.global_toc_syms)
{
toc_inf.toc = toc;
toc_inf.skip = skip;
toc_inf.global_toc_syms = FALSE;
elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
&toc_inf);
}
}
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)