mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-25 11:04:18 +08:00
bfd/
* elf64-ppc.c (struct ppc_stub_hash_entry): Delete "addend". (ppc64_elf_size_stubs): Don't set "addend". (ppc64_elf_relocate_section): Don't allow calls via toc-adjusting stubs without a following nop even in an executable, except for self-calls and both libc_start_main and .libc_start_main. gold/ * powerpc.cc (Target_powerpc::Relocate::relocate): Update self-call comment.
This commit is contained in:
parent
c66bb0eea0
commit
ba8ca3e739
@ -1,3 +1,12 @@
|
||||
2013-07-03 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* elf64-ppc.c (struct ppc_stub_hash_entry): Delete "addend".
|
||||
(ppc64_elf_size_stubs): Don't set "addend".
|
||||
(ppc64_elf_relocate_section): Don't allow calls via
|
||||
toc-adjusting stubs without a following nop even in an
|
||||
executable, except for self-calls and both libc_start_main
|
||||
and .libc_start_main.
|
||||
|
||||
2013-07-03 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* elf64-ppc.c (ppc64_elf_func_desc_adjust): Hide ".TOC.".
|
||||
|
115
bfd/elf64-ppc.c
115
bfd/elf64-ppc.c
@ -3618,9 +3618,6 @@ struct ppc_stub_hash_entry {
|
||||
struct ppc_link_hash_entry *h;
|
||||
struct plt_entry *plt_ent;
|
||||
|
||||
/* And the reloc addend that this was derived from. */
|
||||
bfd_vma addend;
|
||||
|
||||
/* Where this stub is being called from, or, in the case of combined
|
||||
stub sections, the first input section in the group. */
|
||||
asection *id_sec;
|
||||
@ -11752,7 +11749,6 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
|
||||
}
|
||||
stub_entry->h = hash;
|
||||
stub_entry->plt_ent = plt_ent;
|
||||
stub_entry->addend = irela->r_addend;
|
||||
|
||||
if (stub_entry->h != NULL)
|
||||
htab->stub_globals += 1;
|
||||
@ -13015,60 +13011,89 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
||||
{
|
||||
bfd_boolean can_plt_call = FALSE;
|
||||
|
||||
/* All of these stubs will modify r2, so there must be a
|
||||
branch and link followed by a nop. The nop is
|
||||
replaced by an insn to restore r2. */
|
||||
if (rel->r_offset + 8 <= input_section->size)
|
||||
{
|
||||
unsigned long nop;
|
||||
nop = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
|
||||
if (nop == NOP
|
||||
|| nop == CROR_151515 || nop == CROR_313131)
|
||||
unsigned long br;
|
||||
|
||||
br = bfd_get_32 (input_bfd,
|
||||
contents + rel->r_offset);
|
||||
if ((br & 1) != 0)
|
||||
{
|
||||
if (h != NULL
|
||||
&& (h == htab->tls_get_addr_fd
|
||||
|| h == htab->tls_get_addr)
|
||||
&& !htab->no_tls_get_addr_opt)
|
||||
unsigned long nop;
|
||||
|
||||
nop = bfd_get_32 (input_bfd,
|
||||
contents + rel->r_offset + 4);
|
||||
if (nop == NOP
|
||||
|| nop == CROR_151515 || nop == CROR_313131)
|
||||
{
|
||||
/* Special stub used, leave nop alone. */
|
||||
if (h != NULL
|
||||
&& (h == htab->tls_get_addr_fd
|
||||
|| h == htab->tls_get_addr)
|
||||
&& !htab->no_tls_get_addr_opt)
|
||||
{
|
||||
/* Special stub used, leave nop alone. */
|
||||
}
|
||||
else
|
||||
bfd_put_32 (input_bfd, LD_R2_40R1,
|
||||
contents + rel->r_offset + 4);
|
||||
can_plt_call = TRUE;
|
||||
}
|
||||
else
|
||||
bfd_put_32 (input_bfd, LD_R2_40R1,
|
||||
contents + rel->r_offset + 4);
|
||||
}
|
||||
}
|
||||
|
||||
if (!can_plt_call && h != NULL)
|
||||
{
|
||||
const char *name = h->elf.root.root.string;
|
||||
|
||||
if (*name == '.')
|
||||
++name;
|
||||
|
||||
if (strncmp (name, "__libc_start_main", 17) == 0
|
||||
&& (name[17] == 0 || name[17] == '@'))
|
||||
{
|
||||
/* Allow crt1 branch to go via a toc adjusting
|
||||
stub. Other calls that never return could do
|
||||
the same, if we could detect such. */
|
||||
can_plt_call = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!can_plt_call)
|
||||
{
|
||||
if (stub_entry->stub_type == ppc_stub_plt_call
|
||||
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
|
||||
{
|
||||
/* If this is a plain branch rather than a branch
|
||||
and link, don't require a nop. However, don't
|
||||
allow tail calls in a shared library as they
|
||||
will result in r2 being corrupted. */
|
||||
unsigned long br;
|
||||
br = bfd_get_32 (input_bfd, contents + rel->r_offset);
|
||||
if (info->executable && (br & 1) == 0)
|
||||
can_plt_call = TRUE;
|
||||
else
|
||||
stub_entry = NULL;
|
||||
}
|
||||
else if (h != NULL
|
||||
&& strcmp (h->elf.root.root.string,
|
||||
".__libc_start_main") == 0)
|
||||
{
|
||||
/* Allow crt1 branch to go via a toc adjusting stub. */
|
||||
can_plt_call = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->callbacks->einfo
|
||||
(_("%P: %H: call to `%T' lacks nop, can't restore toc; "
|
||||
"recompile with -fPIC"),
|
||||
input_bfd, input_section, rel->r_offset, sym_name);
|
||||
/* g++ as of 20130507 emits self-calls without a
|
||||
following nop. This is arguably wrong since we
|
||||
have conflicting information. On the one hand a
|
||||
global symbol and on the other a local call
|
||||
sequence, but don't error for this special case.
|
||||
It isn't possible to cheaply verify we have
|
||||
exactly such a call. Allow all calls to the same
|
||||
section. */
|
||||
asection *code_sec = sec;
|
||||
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
ret = FALSE;
|
||||
if (get_opd_info (sec) != NULL)
|
||||
{
|
||||
bfd_vma off = (relocation + addend
|
||||
- sec->output_section->vma
|
||||
- sec->output_offset);
|
||||
|
||||
opd_entry_value (sec, off, &code_sec, NULL, FALSE);
|
||||
}
|
||||
if (code_sec == input_section)
|
||||
can_plt_call = TRUE;
|
||||
}
|
||||
|
||||
if (!can_plt_call)
|
||||
{
|
||||
info->callbacks->einfo
|
||||
(_("%P: %H: call to `%T' lacks nop, can't restore toc; "
|
||||
"recompile with -fPIC"),
|
||||
input_bfd, input_section, rel->r_offset, sym_name);
|
||||
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
if (can_plt_call
|
||||
|
@ -1,3 +1,8 @@
|
||||
2013-07-03 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* powerpc.cc (Target_powerpc::Relocate::relocate): Update self-call
|
||||
comment.
|
||||
|
||||
2013-07-01 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
* dwarf_reader.cc (Dwarf_ranges_table::read_ranges_table): Save
|
||||
|
@ -6346,10 +6346,13 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
|
||||
}
|
||||
if (!can_plt_call)
|
||||
{
|
||||
// This is not an error in one special case: A self
|
||||
// call. It isn't possible to cheaply verify we have
|
||||
// such a call so just check for a call to the same
|
||||
// section.
|
||||
// g++ as of 20130507 emits self-calls without a
|
||||
// following nop. This is arguably wrong since we have
|
||||
// conflicting information. On the one hand a global
|
||||
// symbol and on the other a local call sequence, but
|
||||
// don't error for this special case.
|
||||
// It isn't possible to cheaply verify we have exactly
|
||||
// such a call. Allow all calls to the same section.
|
||||
bool ok = false;
|
||||
Address code = value;
|
||||
if (gsym->source() == Symbol::FROM_OBJECT
|
||||
|
Loading…
Reference in New Issue
Block a user