diff options
author | Alan Modra <amodra@gmail.com> | 2017-09-20 09:17:56 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2017-09-20 09:56:19 +0930 |
commit | 64b5d6d785eb4c337b7c071ab9607186541a8b14 (patch) | |
tree | c6dd995b5b91dde8a284551d384e637526c68ea3 /gold/powerpc.cc | |
parent | dba74cb2b725ee8857dee865fb7f49c86aad1aed (diff) | |
download | gdb-64b5d6d785eb4c337b7c071ab9607186541a8b14.zip gdb-64b5d6d785eb4c337b7c071ab9607186541a8b14.tar.gz gdb-64b5d6d785eb4c337b7c071ab9607186541a8b14.tar.bz2 |
[GOLD] PowerPC function address in non-PIC
ppc32, like many targets, defines the address of a function as the PLT
call stub code for functions referenced but not defined in a non-PIC
executable. ppc32 gold, unlike other targets, inherits the ppc64
multiple stub capability for dealing with very large binaries where
one set of stubs can't be reached from all code locations. This means
there can be multiple choices of address for a function, which might
cause function pointer comparison failures. So for ppc32, make
non-branch references always use the first stub group.
(PowerPC64 ELFv1 is always PIC so doesn't need to define the address
of an external function as the PLT stub. PowerPC64 ELFv2 needs a
special set of global entry stubs to serve as the address of external
functions, so it too is not affected by this bug.)
* powerpc.cc (Target_powerpc::Branch_info::make_stub): Put
stubs for ppc32 non-branch relocs in first stub table.
(Target_powerpc::Relocate::relocate): Resolve similarly.
Diffstat (limited to 'gold/powerpc.cc')
-rw-r--r-- | gold/powerpc.cc | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/gold/powerpc.cc b/gold/powerpc.cc index ff116e3..ba302f2 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -3151,11 +3151,17 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub( target->glink_section()->add_global_entry(gsym); else { - if (stub_table == NULL) + if (stub_table == NULL + && !(size == 32 + && gsym != NULL + && !parameters->options().output_is_position_independent() + && !is_branch_reloc(this->r_type_))) stub_table = this->object_->stub_table(this->shndx_); if (stub_table == NULL) { - // This is a ref from a data section to an ifunc symbol. + // This is a ref from a data section to an ifunc symbol, + // or a non-branch reloc for which we always want to use + // one set of stubs for resolving function addresses. stub_table = ifunc_stub_table; } gold_assert(stub_table != NULL); @@ -8334,11 +8340,20 @@ Target_powerpc<size, big_endian>::Relocate::relocate( } else { - Stub_table<size, big_endian>* stub_table - = object->stub_table(relinfo->data_shndx); + Stub_table<size, big_endian>* stub_table = NULL; + if (target->stub_tables().size() == 1) + stub_table = target->stub_tables()[0]; + if (stub_table == NULL + && !(size == 32 + && gsym != NULL + && !parameters->options().output_is_position_independent() + && !is_branch_reloc(r_type))) + stub_table = object->stub_table(relinfo->data_shndx); if (stub_table == NULL) { - // This is a ref from a data section to an ifunc symbol. + // This is a ref from a data section to an ifunc symbol, + // or a non-branch reloc for which we always want to use + // one set of stubs for resolving function addresses. if (target->stub_tables().size() != 0) stub_table = target->stub_tables()[0]; } |