diff options
author | Alan Modra <amodra@gmail.com> | 2012-09-09 03:43:51 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2012-09-09 03:43:51 +0000 |
commit | e81fea4d172699b2e986bc541f812cac0995da6b (patch) | |
tree | f53406e2ad174c23989c3052f9f6367ff7967099 /gold | |
parent | b7099d964f9a5736272cadb6d19083d643005aa1 (diff) | |
download | fsf-binutils-gdb-e81fea4d172699b2e986bc541f812cac0995da6b.zip fsf-binutils-gdb-e81fea4d172699b2e986bc541f812cac0995da6b.tar.gz fsf-binutils-gdb-e81fea4d172699b2e986bc541f812cac0995da6b.tar.bz2 |
* target.h (Target::gc_mark_symbol, do_gc_mark_symbol): New functions.
(Sized_target::gc_add_reference, do_gc_add_reference): New functions.
* gc.h (gc_process_relocs): Call target gc_add_reference.
* gold.cc (queue_middle_tasks): Use gc_mark_symbol on start sym.
* symtab.cc (Symbol_table::gc_mark_undef_symbols): Use gc_mark_symbol.
(Symbol_table::gc_mark_symbol): Call target gc_mark_symbol. Remove
unnecessary cast.
* powerpc.cc (Powerpc_relobj::get_opd_ent): Rearrange parameters
to cater for when we don't need code offset. Update use.
(Powerpc_relobj::access_from_map_, opd_valid_): New vars.
(Powerpc_relobj::access_from_map, add_reference, opd_valid,
set_opd_valid): New functions.
(Target_powerpc::do_gc_add_reference): New function.
(Target_powerpc::gc_process_relocs): Call gc()->add_reference on
stashed refs.
(Target_powerpc::do_gc_mark_symbol): New function.
Diffstat (limited to 'gold')
-rw-r--r-- | gold/ChangeLog | 19 | ||||
-rw-r--r-- | gold/gc.h | 13 | ||||
-rw-r--r-- | gold/gold.cc | 10 | ||||
-rw-r--r-- | gold/powerpc.cc | 153 | ||||
-rw-r--r-- | gold/symtab.cc | 31 | ||||
-rw-r--r-- | gold/target.h | 32 |
6 files changed, 215 insertions, 43 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index ce00f17..7c16d7b 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,22 @@ +2012-09-09 Alan Modra <amodra@gmail.com> + + * target.h (Target::gc_mark_symbol, do_gc_mark_symbol): New functions. + (Sized_target::gc_add_reference, do_gc_add_reference): New functions. + * gc.h (gc_process_relocs): Call target gc_add_reference. + * gold.cc (queue_middle_tasks): Use gc_mark_symbol on start sym. + * symtab.cc (Symbol_table::gc_mark_undef_symbols): Use gc_mark_symbol. + (Symbol_table::gc_mark_symbol): Call target gc_mark_symbol. Remove + unnecessary cast. + * powerpc.cc (Powerpc_relobj::get_opd_ent): Rearrange parameters + to cater for when we don't need code offset. Update use. + (Powerpc_relobj::access_from_map_, opd_valid_): New vars. + (Powerpc_relobj::access_from_map, add_reference, opd_valid, + set_opd_valid): New functions. + (Target_powerpc::do_gc_add_reference): New function. + (Target_powerpc::gc_process_relocs): Call gc()->add_reference on + stashed refs. + (Target_powerpc::do_gc_mark_symbol): New function. + 2012-09-06 Cary Coutant <ccoutant@google.com> * dwarf_reader.cc (Dwarf_die::read_attributes): Add @@ -187,8 +187,6 @@ gc_process_relocs( size_t local_count, const unsigned char* plocal_syms) { - Object* dst_obj; - unsigned int dst_indx; Scan scan; typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype; @@ -235,6 +233,9 @@ gc_process_relocs( unsigned int r_type = elfcpp::elf_r_type<size>(r_info); typename elfcpp::Elf_types<size>::Elf_Swxword addend = Reloc_types<sh_type, size, big_endian>::get_reloc_addend_noerror(&reloc); + Object* dst_obj; + unsigned int dst_indx; + typename elfcpp::Elf_types<size>::Elf_Addr dst_off; if (r_sym < local_count) { @@ -246,6 +247,8 @@ gc_process_relocs( shndx = src_obj->adjust_sym_shndx(r_sym, shndx, &is_ordinary); dst_obj = src_obj; dst_indx = shndx; + dst_off = lsym.get_st_value(); + if (is_icf_tracked) { if (is_ordinary) @@ -288,11 +291,13 @@ gc_process_relocs( dst_obj = NULL; dst_indx = 0; + dst_off = 0; bool is_ordinary = false; if (gsym->source() == Symbol::FROM_OBJECT) { dst_obj = gsym->object(); dst_indx = gsym->shndx(&is_ordinary); + dst_off = static_cast<const Sized_symbol<size>*>(gsym)->value(); } // When doing safe folding, check to see if this relocation is that @@ -348,6 +353,10 @@ gc_process_relocs( if (parameters->options().gc_sections()) { symtab->gc()->add_reference(src_obj, src_indx, dst_obj, dst_indx); + dst_off += addend; + parameters->sized_target<size, big_endian>() + ->gc_add_reference(symtab, src_obj, src_indx, + dst_obj, dst_indx, dst_off); if (cident_section_name != NULL) { Garbage_collection::Cident_section_map::iterator ele = diff --git a/gold/gold.cc b/gold/gold.cc index 1b4badc..0f9a228 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -504,15 +504,7 @@ queue_middle_tasks(const General_options& options, // Find the start symbol if any. Symbol* start_sym = symtab->lookup(parameters->entry()); if (start_sym != NULL) - { - bool is_ordinary; - unsigned int shndx = start_sym->shndx(&is_ordinary); - if (is_ordinary) - { - symtab->gc()->worklist().push( - Section_id(start_sym->object(), shndx)); - } - } + symtab->gc_mark_symbol(start_sym); // Symbols named with -u should not be considered garbage. symtab->gc_mark_undef_symbols(layout); gold_assert(symtab->gc() != NULL); diff --git a/gold/powerpc.cc b/gold/powerpc.cc index 9ac81a1..f9a14ce 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -59,11 +59,14 @@ class Powerpc_relobj : public Sized_relobj_file<size, big_endian> public: typedef typename elfcpp::Elf_types<size>::Elf_Addr Address; typedef typename elfcpp::Elf_types<size>::Elf_Off Offset; + typedef Unordered_set<Section_id, Section_id_hash> Section_refs; + typedef Unordered_map<Address, Section_refs> Access_from; 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_() + special_(0), opd_ent_shndx_(), opd_ent_off_(), access_from_map_(), + opd_valid_(false) { } ~Powerpc_relobj() @@ -99,14 +102,15 @@ public: } // Return section and offset of function entry for .opd + R_OFF. - void - get_opd_ent(Address r_off, unsigned int* shndx, Address* value) const + unsigned int + 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); - *shndx = this->opd_ent_shndx_[ndx]; - *value = this->opd_ent_off_[ndx]; + if (value != NULL) + *value = this->opd_ent_off_[ndx]; + return this->opd_ent_shndx_[ndx]; } // Set section and offset of function entry for .opd + R_OFF. @@ -119,6 +123,29 @@ public: this->opd_ent_off_[ndx] = value; } + Access_from* + access_from_map() + { return &this->access_from_map_; } + + // Add a reference from SRC_OBJ, SRC_INDX to this object's .opd + // section at DST_OFF. + void + add_reference(Object* src_obj, + unsigned int src_indx, + typename elfcpp::Elf_types<size>::Elf_Addr dst_off) + { + Section_id src_id(src_obj, src_indx); + this->access_from_map_[dst_off].insert(src_id); + } + + bool + opd_valid() const + { return this->opd_valid_; } + + void + set_opd_valid() + { this->opd_valid_ = true; } + // Examine .rela.opd to build info about function entry points. void scan_opd_relocs(size_t reloc_count, @@ -160,6 +187,16 @@ private: // section and offset specified by these relocations. std::vector<unsigned int> opd_ent_shndx_; std::vector<Offset> opd_ent_off_; + // 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. + 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> @@ -340,6 +377,24 @@ class Target_powerpc : public Sized_target<size, big_endian> unsigned int plt_entry_size() const; + // Add any special sections for this symbol to the gc work list. + // For powerpc64, this adds the code section of a function + // descriptor. + void + do_gc_mark_symbol(Symbol_table* symtab, Symbol* sym) const; + + // Handle target specific gc actions when adding a gc reference from + // SRC_OBJ, SRC_SHNDX to a location specified by DST_OBJ, DST_SHNDX + // and DST_OFF. For powerpc64, this adds a referenc to the code + // section of a function descriptor. + void + do_gc_add_reference(Symbol_table* symtab, + Object* src_obj, + unsigned int src_shndx, + Object* dst_obj, + unsigned int dst_shndx, + Address dst_off) const; + private: // The class which scans relocations. @@ -2913,6 +2968,33 @@ Target_powerpc<size, big_endian>::gc_process_relocs( { typedef Target_powerpc<size, big_endian> Powerpc; typedef typename Target_powerpc<size, big_endian>::Scan Scan; + Powerpc_relobj<size, big_endian>* ppc_object + = static_cast<Powerpc_relobj<size, big_endian>*>(object); + if (size == 64) + ppc_object->set_opd_valid(); + if (size == 64 && data_shndx == ppc_object->opd_shndx()) + { + typename Powerpc_relobj<size, big_endian>::Access_from::iterator p; + for (p = ppc_object->access_from_map()->begin(); + p != ppc_object->access_from_map()->end(); + ++p) + { + Address dst_off = p->first; + unsigned int dst_indx = ppc_object->get_opd_ent(dst_off); + typename Powerpc_relobj<size, big_endian>::Section_refs::iterator s; + for (s = p->second.begin(); s != p->second.end(); ++s) + { + Object* src_obj = s->first; + unsigned int src_indx = s->second; + symtab->gc()->add_reference(src_obj, src_indx, + ppc_object, dst_indx); + } + p->second.clear(); + } + ppc_object->access_from_map()->clear(); + // Don't look at .opd relocs as .opd will reference everything. + return; + } gold::gc_process_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan, typename Target_powerpc::Relocatable_size_for_reloc>( @@ -2929,6 +3011,65 @@ Target_powerpc<size, big_endian>::gc_process_relocs( plocal_symbols); } +// Handle target specific gc actions when adding a gc reference from +// SRC_OBJ, SRC_SHNDX to a location specified by DST_OBJ, DST_SHNDX +// and DST_OFF. For powerpc64, this adds a referenc to the code +// section of a function descriptor. + +template<int size, bool big_endian> +void +Target_powerpc<size, big_endian>::do_gc_add_reference( + Symbol_table* symtab, + Object* src_obj, + unsigned int src_shndx, + Object* dst_obj, + unsigned int dst_shndx, + Address dst_off) const +{ + Powerpc_relobj<size, big_endian>* ppc_object + = static_cast<Powerpc_relobj<size, big_endian>*>(dst_obj); + if (size == 64 && dst_shndx == ppc_object->opd_shndx()) + { + if (ppc_object->opd_valid()) + { + dst_shndx = ppc_object->get_opd_ent(dst_off); + symtab->gc()->add_reference(src_obj, src_shndx, dst_obj, dst_shndx); + } + else + { + // If we haven't run scan_opd_relocs, we must delay + // processing this function descriptor reference. + ppc_object->add_reference(src_obj, src_shndx, dst_off); + } + } +} + +// Add any special sections for this symbol to the gc work list. +// For powerpc64, this adds the code section of a function +// descriptor. + +template<int size, bool big_endian> +void +Target_powerpc<size, big_endian>::do_gc_mark_symbol( + Symbol_table* symtab, + Symbol* sym) const +{ + if (size == 64) + { + Powerpc_relobj<size, big_endian>* ppc_object + = static_cast<Powerpc_relobj<size, big_endian>*>(sym->object()); + bool is_ordinary; + unsigned int shndx = sym->shndx(&is_ordinary); + if (is_ordinary && shndx == ppc_object->opd_shndx()) + { + Sized_symbol<size>* gsym = symtab->get_sized_symbol<size>(sym); + Address dst_off = gsym->value(); + unsigned int dst_indx = ppc_object->get_opd_ent(dst_off); + symtab->gc()->worklist().push(Section_id(ppc_object, dst_indx)); + } + } +} + // Scan relocations for a section. template<int size, bool big_endian> @@ -3064,7 +3205,7 @@ Target_powerpc<size, big_endian>::symval_for_branch( if (value >= opd_addr && value < opd_addr + symobj->section_size(shndx)) { Address sec_off; - symobj->get_opd_ent(value - opd_addr, dest_shndx, &sec_off); + *dest_shndx = symobj->get_opd_ent(value - opd_addr, &sec_off); Address sec_addr = symobj->get_output_section_offset(*dest_shndx); gold_assert(sec_addr != invalid_address); sec_addr += symobj->output_section(*dest_shndx)->address(); diff --git a/gold/symtab.cc b/gold/symtab.cc index e97f642..8fadd1d 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -577,14 +577,7 @@ Symbol_table::gc_mark_undef_symbols(Layout* layout) if (sym->source() == Symbol::FROM_OBJECT && !sym->object()->is_dynamic()) { - Relobj* obj = static_cast<Relobj*>(sym->object()); - bool is_ordinary; - unsigned int shndx = sym->shndx(&is_ordinary); - if (is_ordinary) - { - gold_assert(this->gc_ != NULL); - this->gc_->worklist().push(Section_id(obj, shndx)); - } + this->gc_mark_symbol(sym); } } @@ -601,14 +594,7 @@ Symbol_table::gc_mark_undef_symbols(Layout* layout) && sym->source() == Symbol::FROM_OBJECT && !sym->object()->is_dynamic()) { - Relobj* obj = static_cast<Relobj*>(sym->object()); - bool is_ordinary; - unsigned int shndx = sym->shndx(&is_ordinary); - if (is_ordinary) - { - gold_assert(this->gc_ != NULL); - this->gc_->worklist().push(Section_id(obj, shndx)); - } + this->gc_mark_symbol(sym); } } @@ -622,14 +608,7 @@ Symbol_table::gc_mark_undef_symbols(Layout* layout) if (sym->source() == Symbol::FROM_OBJECT && !sym->object()->is_dynamic()) { - Relobj* obj = static_cast<Relobj*>(sym->object()); - bool is_ordinary; - unsigned int shndx = sym->shndx(&is_ordinary); - if (is_ordinary) - { - gold_assert(this->gc_ != NULL); - this->gc_->worklist().push(Section_id(obj, shndx)); - } + this->gc_mark_symbol(sym); } } } @@ -638,14 +617,14 @@ void Symbol_table::gc_mark_symbol(Symbol* sym) { // Add the object and section to the work list. - Relobj* obj = static_cast<Relobj*>(sym->object()); bool is_ordinary; unsigned int shndx = sym->shndx(&is_ordinary); if (is_ordinary && shndx != elfcpp::SHN_UNDEF) { gold_assert(this->gc_!= NULL); - this->gc_->worklist().push(Section_id(obj, shndx)); + this->gc_->worklist().push(Section_id(sym->object(), shndx)); } + parameters->target().gc_mark_symbol(this, sym); } // When doing garbage collection, keep symbols that have been seen in diff --git a/gold/target.h b/gold/target.h index 25ac96b..effde15 100644 --- a/gold/target.h +++ b/gold/target.h @@ -421,6 +421,11 @@ class Target size_t* plen) const { return this->do_output_section_name(relobj, name, plen); } + // Add any special sections for this symbol to the gc work list. + void + gc_mark_symbol(Symbol_table* symtab, Symbol* sym) const + { this->do_gc_mark_symbol(symtab, sym); } + protected: // This struct holds the constant information for a child class. We // use a struct to avoid the overhead of virtual function calls for @@ -669,6 +674,11 @@ class Target do_output_section_name(const Relobj*, const char*, size_t*) const { return NULL; } + // This may be overridden by the child class. + virtual void + do_gc_mark_symbol(Symbol_table*, Symbol*) const + { } + private: // The implementations of the four do_make_elf_object virtual functions are // almost identical except for their sizes and endianness. We use a template. @@ -935,6 +945,21 @@ class Sized_target : public Target section_size_type /* view_size */) { gold_unreachable(); } + // Handle target specific gc actions when adding a gc reference from + // SRC_OBJ, SRC_SHNDX to a location specified by DST_OBJ, DST_SHNDX + // and DST_OFF. + void + gc_add_reference(Symbol_table* symtab, + Object* src_obj, + unsigned int src_shndx, + Object* dst_obj, + unsigned int dst_shndx, + typename elfcpp::Elf_types<size>::Elf_Addr dst_off) const + { + this->do_gc_add_reference(symtab, src_obj, src_shndx, + dst_obj, dst_shndx, dst_off); + } + protected: Sized_target(const Target::Target_info* pti) : Target(pti) @@ -946,6 +971,13 @@ class Sized_target : public Target // Set the EI_OSABI field if requested. virtual void do_adjust_elf_header(unsigned char*, int) const; + + // Handle target specific gc actions when adding a gc reference. + virtual void + do_gc_add_reference(Symbol_table*, Object*, unsigned int, + Object*, unsigned int, + typename elfcpp::Elf_types<size>::Elf_Addr) const + { } }; } // End namespace gold. |