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;
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)
{
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)
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
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 =
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()
}
// 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.
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,
// 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>
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.
{
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>(
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>
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();
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);
}
}
&& 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);
}
}
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);
}
}
}
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
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
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.
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)
// 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.