diff options
-rw-r--r-- | gold/ChangeLog | 13 | ||||
-rw-r--r-- | gold/object.cc | 3 | ||||
-rw-r--r-- | gold/object.h | 12 | ||||
-rw-r--r-- | gold/powerpc.cc | 99 |
4 files changed, 122 insertions, 5 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 6429004..b7226b1 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,16 @@ +2012-09-25 Alan Modra <amodra@gmail.com> + + * 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. + 2012-09-15 Jiong Wang <jiwang@tilera.com> * tilegx.cc: New file. diff --git a/gold/object.cc b/gold/object.cc index 6ee10f5..3492f46 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -2110,7 +2110,8 @@ Sized_relobj_file<size, big_endian>::do_count_local_symbols(Stringpool* pool, 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()); diff --git a/gold/object.h b/gold/object.h index a507204..522b63f 100644 --- a/gold/object.h +++ b/gold/object.h @@ -2112,6 +2112,12 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian> 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_relobj<size, big_endian> 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) diff --git a/gold/powerpc.cc b/gold/powerpc.cc index 62e850f..2392abe 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -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_opd_relocs( 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_opd_relocs( &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_read_relocs(Read_relocs_data* rd) { 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_relocs( 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 |