This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[GOLD] powerpc opd reloc warnings
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org
- Date: Wed, 12 Sep 2012 18:55:24 +0930
- Subject: [GOLD] powerpc opd reloc warnings
This silences "relocation refers to discarded section" warnings for
powerpc64 .opd section entries. I note which entries are discarded
during Scan::local (and Scan::global, but .opd entries ought to be
using local syms), then use that info later during section
relocation. The same info will be used to remove symbols defined on
discarded entries and in resizing .opd when I figure out how to do all
that.. OK?
* target-reloc.h (scan_relocs): Call scan.local for relocs
against symbols in discarded sections. Pass is_discarded
param.
* arm.cc, * i386.cc, * sparc.cc, * x86_64.cc (Target_*::Scan::local):
Add is_discarded param.
* powerpc (Target_powerpc::Scan::local): Likewise. Use
is_discarded to flag opd entry as discarded. Don't emit dyn
relocs on such entries.
(Target_powerpc::Scan::global): Similarly detect and handle
such opd entries.
(Powerpc_relobj): Replace opd_ent_shndx_ and opd_ent_off_ with
opd_ent_. Update all uses.
(Powerpc_relobj::get_opd_discard, set_opd_discard): New functions.
(Target_powerpc::relocate_section): Zero out discarded opd
entry relocs.
Index: gold/target-reloc.h
===================================================================
RCS file: /cvs/src/src/gold/target-reloc.h,v
retrieving revision 1.53
diff -u -p -r1.53 target-reloc.h
--- gold/target-reloc.h 5 Sep 2012 00:34:20 -0000 1.53
+++ gold/target-reloc.h 12 Sep 2012 05:24:54 -0000
@@ -81,30 +81,25 @@ scan_relocs(
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
- if (is_ordinary
- && shndx != elfcpp::SHN_UNDEF
- && !object->is_section_included(shndx)
- && !symtab->is_section_folded(object, shndx))
- {
- // RELOC is a relocation against a local symbol in a
- // section we are discarding. We can ignore this
- // relocation. It will eventually become a reloc
- // against the value zero.
- //
- // FIXME: We should issue a warning if this is an
- // allocated section; is this the best place to do it?
- //
- // FIXME: The old GNU linker would in some cases look
- // for the linkonce section which caused this section to
- // be discarded, and, if the other section was the same
- // size, change the reloc to refer to the other section.
- // That seems risky and weird to me, and I don't know of
- // any case where it is actually required.
-
- continue;
- }
+ // If RELOC is a relocation against a local symbol in a
+ // section we are discarding then we can ignore it. It will
+ // eventually become a reloc against the value zero.
+ //
+ // FIXME: We should issue a warning if this is an
+ // allocated section; is this the best place to do it?
+ //
+ // FIXME: The old GNU linker would in some cases look
+ // for the linkonce section which caused this section to
+ // be discarded, and, if the other section was the same
+ // size, change the reloc to refer to the other section.
+ // That seems risky and weird to me, and I don't know of
+ // any case where it is actually required.
+ bool is_discarded = (is_ordinary
+ && shndx != elfcpp::SHN_UNDEF
+ && !object->is_section_included(shndx)
+ && !symtab->is_section_folded(object, shndx));
scan.local(symtab, layout, target, object, data_shndx,
- output_section, reloc, r_type, lsym);
+ output_section, reloc, r_type, lsym, is_discarded);
}
else
{
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.154
diff -u -p -r1.154 arm.cc
--- gold/arm.cc 10 Sep 2012 23:05:54 -0000 1.154
+++ gold/arm.cc 12 Sep 2012 02:45:44 -0000
@@ -2551,7 +2551,8 @@ class Target_arm : public Sized_target<3
unsigned int data_shndx,
Output_section* output_section,
const elfcpp::Rel<32, big_endian>& reloc, unsigned int r_type,
- const elfcpp::Sym<32, big_endian>& lsym);
+ const elfcpp::Sym<32, big_endian>& lsym,
+ bool is_discarded);
inline void
global(Symbol_table* symtab, Layout* layout, Target_arm* target,
@@ -7857,8 +7858,12 @@ Target_arm<big_endian>::Scan::local(Symb
Output_section* output_section,
const elfcpp::Rel<32, big_endian>& reloc,
unsigned int r_type,
- const elfcpp::Sym<32, big_endian>& lsym)
+ const elfcpp::Sym<32, big_endian>& lsym,
+ bool is_discarded)
{
+ if (is_discarded)
+ return;
+
r_type = get_real_reloc_type(r_type);
switch (r_type)
{
Index: gold/i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.147
diff -u -p -r1.147 i386.cc
--- gold/i386.cc 10 Sep 2012 23:05:54 -0000 1.147
+++ gold/i386.cc 12 Sep 2012 02:45:44 -0000
@@ -538,7 +538,8 @@ class Target_i386 : public Sized_target<
unsigned int data_shndx,
Output_section* output_section,
const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
- const elfcpp::Sym<32, false>& lsym);
+ const elfcpp::Sym<32, false>& lsym,
+ bool is_discarded);
inline void
global(Symbol_table* symtab, Layout* layout, Target_i386* target,
@@ -1702,15 +1703,19 @@ Target_i386::Scan::reloc_needs_plt_for_i
inline void
Target_i386::Scan::local(Symbol_table* symtab,
- Layout* layout,
- Target_i386* target,
- Sized_relobj_file<32, false>* object,
- unsigned int data_shndx,
- Output_section* output_section,
- const elfcpp::Rel<32, false>& reloc,
- unsigned int r_type,
- const elfcpp::Sym<32, false>& lsym)
+ Layout* layout,
+ Target_i386* target,
+ Sized_relobj_file<32, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rel<32, false>& reloc,
+ unsigned int r_type,
+ const elfcpp::Sym<32, false>& lsym,
+ bool is_discarded)
{
+ if (is_discarded)
+ return;
+
// A local STT_GNU_IFUNC symbol may require a PLT entry.
if (lsym.get_st_type() == elfcpp::STT_GNU_IFUNC
&& this->reloc_needs_plt_for_ifunc(object, r_type))
Index: gold/sparc.cc
===================================================================
RCS file: /cvs/src/src/gold/sparc.cc,v
retrieving revision 1.60
diff -u -p -r1.60 sparc.cc
--- gold/sparc.cc 10 Sep 2012 23:05:54 -0000 1.60
+++ gold/sparc.cc 12 Sep 2012 02:45:45 -0000
@@ -237,7 +237,8 @@ class Target_sparc : public Sized_target
unsigned int data_shndx,
Output_section* output_section,
const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
- const elfcpp::Sym<size, big_endian>& lsym);
+ const elfcpp::Sym<size, big_endian>& lsym,
+ bool is_discarded);
inline void
global(Symbol_table* symtab, Layout* layout, Target_sparc* target,
@@ -2240,8 +2241,12 @@ Target_sparc<size, big_endian>::Scan::lo
Output_section* output_section,
const elfcpp::Rela<size, big_endian>& reloc,
unsigned int r_type,
- const elfcpp::Sym<size, big_endian>& lsym)
+ const elfcpp::Sym<size, big_endian>& lsym,
+ bool is_discarded)
{
+ if (is_discarded)
+ return;
+
bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
unsigned int orig_r_type = r_type;
r_type &= 0xff;
Index: gold/x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.156
diff -u -p -r1.156 x86_64.cc
--- gold/x86_64.cc 10 Sep 2012 23:05:54 -0000 1.156
+++ gold/x86_64.cc 12 Sep 2012 02:45:45 -0000
@@ -676,7 +676,8 @@ class Target_x86_64 : public Sized_targe
unsigned int data_shndx,
Output_section* output_section,
const elfcpp::Rela<size, false>& reloc, unsigned int r_type,
- const elfcpp::Sym<size, false>& lsym);
+ const elfcpp::Sym<size, false>& lsym,
+ bool is_discarded);
inline void
global(Symbol_table* symtab, Layout* layout, Target_x86_64* target,
@@ -2270,8 +2271,12 @@ Target_x86_64<size>::Scan::local(Symbol_
Output_section* output_section,
const elfcpp::Rela<size, false>& reloc,
unsigned int r_type,
- const elfcpp::Sym<size, false>& lsym)
+ const elfcpp::Sym<size, false>& lsym,
+ bool is_discarded)
{
+ if (is_discarded)
+ return;
+
// A local STT_GNU_IFUNC symbol may require a PLT entry.
bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type))
Index: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.57
diff -u -p -r1.57 powerpc.cc
--- gold/powerpc.cc 10 Sep 2012 23:05:54 -0000 1.57
+++ gold/powerpc.cc 12 Sep 2012 05:22:58 -0000
@@ -65,8 +65,7 @@ public:
Powerpc_relobj(const std::string& name, Input_file* input_file, off_t offset,
const typename elfcpp::Ehdr<size, big_endian>& ehdr)
: Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr),
- special_(0), opd_ent_shndx_(), opd_ent_off_(), access_from_map_(),
- opd_valid_(false)
+ special_(0), opd_valid_(false), opd_ent_(), access_from_map_()
{ }
~Powerpc_relobj()
@@ -97,8 +96,7 @@ public:
init_opd(size_t opd_size)
{
size_t count = this->opd_ent_ndx(opd_size);
- this->opd_ent_shndx_.resize(count);
- this->opd_ent_off_.reserve(count);
+ this->opd_ent_.resize(count);
}
// Return section and offset of function entry for .opd + R_OFF.
@@ -106,11 +104,11 @@ public:
get_opd_ent(Address r_off, Address* value = NULL) const
{
size_t ndx = this->opd_ent_ndx(r_off);
- gold_assert(ndx < this->opd_ent_shndx_.size());
- gold_assert(this->opd_ent_shndx_[ndx] != 0);
+ gold_assert(ndx < this->opd_ent_.size());
+ gold_assert(this->opd_ent_[ndx].shndx != 0);
if (value != NULL)
- *value = this->opd_ent_off_[ndx];
- return this->opd_ent_shndx_[ndx];
+ *value = this->opd_ent_[ndx].off;
+ return this->opd_ent_[ndx].shndx;
}
// Set section and offset of function entry for .opd + R_OFF.
@@ -118,9 +116,27 @@ public:
set_opd_ent(Address r_off, unsigned int shndx, Address value)
{
size_t ndx = this->opd_ent_ndx(r_off);
- gold_assert(ndx < this->opd_ent_shndx_.size());
- this->opd_ent_shndx_[ndx] = shndx;
- this->opd_ent_off_[ndx] = value;
+ gold_assert(ndx < this->opd_ent_.size());
+ this->opd_ent_[ndx].shndx = shndx;
+ this->opd_ent_[ndx].off = value;
+ }
+
+ // Return discard flag for .opd + R_OFF.
+ bool
+ get_opd_discard(Address r_off) const
+ {
+ size_t ndx = this->opd_ent_ndx(r_off);
+ gold_assert(ndx < this->opd_ent_.size());
+ return this->opd_ent_[ndx].discard;
+ }
+
+ // Set discard flag for .opd + R_OFF.
+ void
+ set_opd_discard(Address r_off)
+ {
+ size_t ndx = this->opd_ent_ndx(r_off);
+ gold_assert(ndx < this->opd_ent_.size());
+ this->opd_ent_[ndx].discard = true;
}
Access_from*
@@ -165,38 +181,47 @@ public:
{ return 0x8000; }
private:
- // Return index into opd_ent_shndx or opd_ent_off array for .opd entry
- // at OFF. .opd entries are 24 bytes long, but they can be spaced
- // 16 bytes apart when the language doesn't use the last 8-byte
- // word, the environment pointer. Thus dividing the entry section
- // offset by 16 will give an index into opd_ent_shndx_ and
- // opd_ent_off_ that works for either layout of .opd. (It leaves
- // some elements of the vectors unused when .opd entries are spaced
- // 24 bytes apart, but we don't know the spacing until relocations
- // are processed, and in any case it is possible for an object to
- // have some entries spaced 16 bytes apart and others 24 bytes apart.)
+ struct Opd_ent
+ {
+ unsigned int shndx;
+ bool discard;
+ Offset off;
+ };
+
+ // Return index into opd_ent_ array for .opd entry at OFF.
+ // .opd entries are 24 bytes long, but they can be spaced 16 bytes
+ // apart when the language doesn't use the last 8-byte word, the
+ // environment pointer. Thus dividing the entry section offset by
+ // 16 will give an index into opd_ent_ that works for either layout
+ // of .opd. (It leaves some elements of the vector unused when .opd
+ // entries are spaced 24 bytes apart, but we don't know the spacing
+ // until relocations are processed, and in any case it is possible
+ // for an object to have some entries spaced 16 bytes apart and
+ // others 24 bytes apart.)
size_t
opd_ent_ndx(size_t off) const
{ return off >> 4;}
// For 32-bit the .got2 section shdnx, for 64-bit the .opd section shndx.
unsigned int special_;
+
+ // Set at the start of gc_process_relocs, when we know opd_ent_
+ // vector is valid. The flag could be made atomic and set in
+ // do_read_relocs with memory_order_release and then tested with
+ // memory_order_acquire, potentially resulting in fewer entries in
+ // access_from_map_.
+ bool opd_valid_;
+
// The first 8-byte word of an OPD entry gives the address of the
// entry point of the function. Relocatable object files have a
- // relocation on this word. The following two vectors record the
+ // relocation on this word. The following vector records the
// section and offset specified by these relocations.
- std::vector<unsigned int> opd_ent_shndx_;
- std::vector<Offset> opd_ent_off_;
+ std::vector<Opd_ent> opd_ent_;
+
// References made to this object's .opd section when running
- // gc_process_relocs for another object, before the opd_ent vectors
- // are valid for this object.
+ // gc_process_relocs for another object, before the opd_ent_ vector
+ // is valid for this object.
Access_from access_from_map_;
- // Set at the start of gc_process_relocs, when we know opd_ent
- // vectors are valid. The flag could be made atomic and set in
- // do_read_relocs with memory_order_release and then tested with
- // memory_order_acquire, potentially resulting in fewer entries in
- // access_from_map_.
- bool opd_valid_;
};
template<int size, bool big_endian>
@@ -413,6 +438,8 @@ class Target_powerpc : public Sized_targ
class Scan
{
public:
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
Scan()
: issued_non_pic_error_(false)
{ }
@@ -426,7 +453,8 @@ class Target_powerpc : public Sized_targ
unsigned int data_shndx,
Output_section* output_section,
const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
- const elfcpp::Sym<size, big_endian>& lsym);
+ const elfcpp::Sym<size, big_endian>& lsym,
+ bool is_discarded);
inline void
global(Symbol_table* symtab, Layout* layout, Target_powerpc* target,
@@ -2361,11 +2389,21 @@ Target_powerpc<size, big_endian>::Scan::
Output_section* output_section,
const elfcpp::Rela<size, big_endian>& reloc,
unsigned int r_type,
- const elfcpp::Sym<size, big_endian>& /* lsym */)
+ const elfcpp::Sym<size, big_endian>& /* lsym */,
+ bool is_discarded)
{
Powerpc_relobj<size, big_endian>* ppc_object
= static_cast<Powerpc_relobj<size, big_endian>*>(object);
+ if (is_discarded)
+ {
+ if (size == 64
+ && data_shndx == ppc_object->opd_shndx()
+ && r_type == elfcpp::R_PPC64_ADDR64)
+ ppc_object->set_opd_discard(reloc.get_r_offset());
+ return;
+ }
+
switch (r_type)
{
case elfcpp::R_POWERPC_NONE:
@@ -2382,13 +2420,19 @@ Target_powerpc<size, big_endian>::Scan::
= target->got_section(symtab, layout);
if (parameters->options().output_is_position_independent())
{
+ Address off = reloc.get_r_offset();
+ if (size == 64
+ && data_shndx == ppc_object->opd_shndx()
+ && ppc_object->get_opd_discard(off - 8))
+ break;
+
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ Powerpc_relobj<size, big_endian>* symobj = ppc_object;
rela_dyn->add_output_section_relative(got->output_section(),
elfcpp::R_POWERPC_RELATIVE,
output_section,
- object, data_shndx,
- reloc.get_r_offset(),
- ppc_object->toc_base_offset());
+ object, data_shndx, off,
+ symobj->toc_base_offset());
}
}
break;
@@ -2658,6 +2702,12 @@ Target_powerpc<size, big_endian>::Scan::
= target->got_section(symtab, layout);
if (parameters->options().output_is_position_independent())
{
+ Address off = reloc.get_r_offset();
+ if (size == 64
+ && data_shndx == ppc_object->opd_shndx()
+ && ppc_object->get_opd_discard(off - 8))
+ break;
+
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
Powerpc_relobj<size, big_endian>* symobj = ppc_object;
if (data_shndx != ppc_object->opd_shndx())
@@ -2666,14 +2716,22 @@ Target_powerpc<size, big_endian>::Scan::
rela_dyn->add_output_section_relative(got->output_section(),
elfcpp::R_POWERPC_RELATIVE,
output_section,
- object, data_shndx,
- reloc.get_r_offset(),
+ object, data_shndx, off,
symobj->toc_base_offset());
}
}
break;
case elfcpp::R_PPC64_ADDR64:
+ if (size == 64
+ && data_shndx == ppc_object->opd_shndx()
+ && (gsym->is_defined_in_discarded_section()
+ || gsym->object() != object))
+ {
+ ppc_object->set_opd_discard(reloc.get_r_offset());
+ break;
+ }
+ // Fall thru
case elfcpp::R_PPC64_UADDR64:
case elfcpp::R_POWERPC_ADDR32:
case elfcpp::R_POWERPC_UADDR32:
@@ -4038,6 +4096,43 @@ Target_powerpc<size, big_endian>::reloca
gold_assert(sh_type == elfcpp::SHT_RELA);
+ unsigned char *opd_rel = NULL;
+ Powerpc_relobj<size, big_endian>* const object
+ = static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
+ if (size == 64
+ && relinfo->data_shndx == object->opd_shndx())
+ {
+ // Rewrite opd relocs, omitting those for discarded sections
+ // to silence gold::relocate_section errors.
+ const int reloc_size
+ = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+ opd_rel = new unsigned char[reloc_count * reloc_size];
+ const unsigned char* rrel = prelocs;
+ unsigned char* wrel = opd_rel;
+
+ for (size_t i = 0;
+ i < reloc_count;
+ ++i, rrel += reloc_size, wrel += reloc_size)
+ {
+ typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+ reloc(rrel);
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info
+ = reloc.get_r_info();
+ unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+ Address r_off = reloc.get_r_offset();
+ if (r_type == elfcpp::R_PPC64_TOC)
+ r_off -= 8;
+ bool is_discarded = object->get_opd_discard(r_off);
+
+ // Reloc number is reported in some errors, so keep all relocs.
+ if (is_discarded)
+ memset(wrel, 0, reloc_size);
+ else
+ memcpy(wrel, rrel, reloc_size);
+ }
+ prelocs = opd_rel;
+ }
+
gold::relocate_section<size, big_endian, Powerpc, elfcpp::SHT_RELA,
Powerpc_relocate>(
relinfo,
@@ -4050,6 +4145,9 @@ Target_powerpc<size, big_endian>::reloca
address,
view_size,
reloc_symbol_changes);
+
+ if (opd_rel != NULL)
+ delete[] opd_rel;
}
class Powerpc_scan_relocatable_reloc
--
Alan Modra
Australia Development Lab, IBM