This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[GOLD] adjust local symbol values
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org
- Date: Mon, 24 Sep 2012 08:30:57 +0930
- Subject: [GOLD] adjust local symbol values
This adds a means of adjusting and/or dropping local symbols defined
in relaxed sections. compute_final_local_value might be a better
place to do any adjustment, but that would require two virtual
functions, one to discard unnecessary or invalid local symbols and
another to adjust values.
The powerpc changes here don't make any adjustments to symbols; That
will come in a later patch that shrinks .opd.
OK to apply?
* object.h (Sized_relobj_file::adjust_local_symbol,
do_adjust_local_symbol): New functions.
* object.cc (Sized_relobj_file::do_count_local_symbols): Use the above.
* powerpc.cc (Powerpc_relobj::do_adjust_local_symbol): New function.
(Powerpc_relobj::scan_opd_relocs): Warn on unexpected opd relocs
and irregular opd entry spacing.
(Powerpc_relobj::do_read_relocs): Add opd size checks.
(Global_symbol_visitor_opd): New functor.
(Target_powerpc::do_finalize_sections): Omit global symbols defined
on deleted opd entries.
Index: gold/object.h
===================================================================
RCS file: /cvs/src/src/gold/object.h,v
retrieving revision 1.120
diff -u -p -r1.120 object.h
--- gold/object.h 12 Sep 2012 18:29:18 -0000 1.120
+++ gold/object.h 20 Sep 2012 06:54:09 -0000
@@ -2112,6 +2112,12 @@ class Sized_relobj_file : public Sized_r
void
set_local_plt_offset(unsigned int symndx, unsigned int plt_offset);
+ // Adjust this local symbol value. Return false if the symbol
+ // should be discarded from the output file.
+ bool
+ adjust_local_symbol(Symbol_value<size>* lv) const
+ { return this->do_adjust_local_symbol(lv); }
+
// Return the name of the symbol that spans the given offset in the
// specified section in this object. This is used only for error
// messages and is not particularly efficient.
@@ -2381,6 +2387,12 @@ class Sized_relobj_file : public Sized_r
const unsigned char* pshdrs, Output_file* of,
Views* pviews);
+ // Adjust this local symbol value. Return false if the symbol
+ // should be discarded from the output file.
+ virtual bool
+ do_adjust_local_symbol(Symbol_value<size>*) const
+ { return true; }
+
// Allow a child to set output local symbol count.
void
set_output_local_symbol_count(unsigned int value)
Index: gold/object.cc
===================================================================
RCS file: /cvs/src/src/gold/object.cc,v
retrieving revision 1.159
diff -u -p -r1.159 object.cc
--- gold/object.cc 7 Sep 2012 20:14:06 -0000 1.159
+++ gold/object.cc 20 Sep 2012 06:54:09 -0000
@@ -2110,7 +2110,8 @@ Sized_relobj_file<size, big_endian>::do_
continue;
}
- if (sym.get_st_type() == elfcpp::STT_SECTION)
+ if (sym.get_st_type() == elfcpp::STT_SECTION
+ || !this->adjust_local_symbol(&lv))
{
lv.set_no_output_symtab_entry();
gold_assert(!lv.needs_output_dynsym_entry());
Index: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.58
diff -u -p -r1.58 powerpc.cc
--- gold/powerpc.cc 12 Sep 2012 22:43:54 -0000 1.58
+++ gold/powerpc.cc 20 Sep 2012 06:54:09 -0000
@@ -174,6 +174,22 @@ public:
bool
do_find_special_sections(Read_symbols_data* sd);
+ // Adjust this local symbol value. Return false if the symbol
+ // should be discarded from the output file.
+ bool
+ do_adjust_local_symbol(Symbol_value<size>* lv) const
+ {
+ if (size == 64 && this->opd_shndx() != 0)
+ {
+ bool is_ordinary;
+ if (lv->input_shndx(&is_ordinary) != this->opd_shndx())
+ return true;
+ if (this->get_opd_discard(lv->input_value()))
+ return false;
+ }
+ return true;
+ }
+
// Return offset in output GOT section that this object will use
// as a TOC pointer. Won't be just a constant with multi-toc support.
Address
@@ -1183,6 +1199,9 @@ Powerpc_relobj<size, big_endian>::scan_o
const int reloc_size
= Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+ Address expected_off = 0;
+ bool regular = true;
+ unsigned int opd_ent_size = 0;
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
{
@@ -1209,8 +1228,37 @@ Powerpc_relobj<size, big_endian>::scan_o
&is_ordinary);
this->set_opd_ent(reloc.get_r_offset(), shndx,
value + reloc.get_r_addend());
+ if (i == 2)
+ {
+ expected_off = reloc.get_r_offset();
+ opd_ent_size = expected_off;
+ }
+ else if (expected_off != reloc.get_r_offset())
+ regular = false;
+ expected_off += opd_ent_size;
+ }
+ else if (r_type == elfcpp::R_PPC64_TOC)
+ {
+ if (expected_off - opd_ent_size + 8 != reloc.get_r_offset())
+ regular = false;
+ }
+ else
+ {
+ gold_warning(_("%s: unexpected reloc type %u in .opd section"),
+ this->name().c_str(), r_type);
+ regular = false;
}
}
+ if (reloc_count <= 2)
+ opd_ent_size = this->section_size(this->opd_shndx());
+ if (opd_ent_size != 24 && opd_ent_size != 16)
+ regular = false;
+ if (!regular)
+ {
+ gold_warning(_("%s: .opd is not a regular array of opd entries"),
+ this->name().c_str());
+ opd_ent_size = 0;
+ }
}
}
@@ -1227,9 +1275,14 @@ Powerpc_relobj<size, big_endian>::do_rea
{
if (p->data_shndx == this->opd_shndx())
{
- this->init_opd(this->section_size(this->opd_shndx()));
- this->scan_opd_relocs(p->reloc_count, p->contents->data(),
- rd->local_symbols->data());
+ uint64_t opd_size = this->section_size(this->opd_shndx());
+ gold_assert(opd_size == static_cast<size_t>(opd_size));
+ if (opd_size != 0)
+ {
+ this->init_opd(opd_size);
+ this->scan_opd_relocs(p->reloc_count, p->contents->data(),
+ rd->local_symbols->data());
+ }
break;
}
}
@@ -3204,6 +3257,38 @@ Target_powerpc<size, big_endian>::scan_r
plocal_symbols);
}
+// Functor class for processing the global symbol table.
+// Removes symbols defined on discarded opd entries.
+
+template<bool big_endian>
+class Global_symbol_visitor_opd
+{
+ public:
+ Global_symbol_visitor_opd()
+ { }
+
+ void
+ operator()(Sized_symbol<64>* sym)
+ {
+ if (sym->has_symtab_index()
+ || sym->source() != Symbol::FROM_OBJECT
+ || !sym->in_real_elf())
+ return;
+
+ Powerpc_relobj<64, big_endian>* symobj
+ = static_cast<Powerpc_relobj<64, big_endian>*>(sym->object());
+ if (symobj->is_dynamic()
+ || symobj->opd_shndx() == 0)
+ return;
+
+ bool is_ordinary;
+ unsigned int shndx = sym->shndx(&is_ordinary);
+ if (shndx == symobj->opd_shndx()
+ && symobj->get_opd_discard(sym->value()))
+ sym->set_symtab_index(-1U);
+ }
+};
+
// Finalize the sections.
template<int size, bool big_endian>
@@ -3211,8 +3296,14 @@ void
Target_powerpc<size, big_endian>::do_finalize_sections(
Layout* layout,
const Input_objects*,
- Symbol_table*)
+ Symbol_table* symtab)
{
+ if (size == 64)
+ {
+ typedef Global_symbol_visitor_opd<big_endian> Symbol_visitor;
+ symtab->for_all_symbols<64, Symbol_visitor>(Symbol_visitor());
+ }
+
// Fill in some more dynamic tags.
const Reloc_section* rel_plt = (this->plt_ == NULL
? NULL
--
Alan Modra
Australia Development Lab, IBM