* gold.cc (queue_middle_tasks): Move detect_odr_violations..
* layout.cc (Layout_task_runner::run): ..to here. * symtab.h (struct Symbol_location): Extract from.. (class Symbol_table): ..here. * symtab.cc (Symbol_table::linenos_from_loc): Invoke function_location. * target.h (class Target): Add function_location and do_function_location functions. (class Sized_target): Add do_function_location. * object.h (class Sized_relobj_file): Move find_shdr.. (class Object): ..to here. * object.cc: Likewise. Update to suit. Instantiate. (Sized_relobj_file::find_eh_frame): Update find_shdr call. * powerpc.cc (class Powerpc_dynobj): New. (Target_powerpc::do_function_location): New function. (Powerpc_relobj::do_find_special_sections): Update find_shdr call. (Powerpc_dynobj::do_read_symbols): New function. (Target_powerpc::do_make_elf_object): Make a Powerpc_dynobj.
This commit is contained in:
parent
3bcc542289
commit
dc3714f31f
@ -1,3 +1,23 @@
|
||||
2013-03-11 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* gold.cc (queue_middle_tasks): Move detect_odr_violations..
|
||||
* layout.cc (Layout_task_runner::run): ..to here.
|
||||
* symtab.h (struct Symbol_location): Extract from..
|
||||
(class Symbol_table): ..here.
|
||||
* symtab.cc (Symbol_table::linenos_from_loc): Invoke function_location.
|
||||
* target.h (class Target): Add function_location and
|
||||
do_function_location functions.
|
||||
(class Sized_target): Add do_function_location.
|
||||
* object.h (class Sized_relobj_file): Move find_shdr..
|
||||
(class Object): ..to here.
|
||||
* object.cc: Likewise. Update to suit. Instantiate.
|
||||
(Sized_relobj_file::find_eh_frame): Update find_shdr call.
|
||||
* powerpc.cc (class Powerpc_dynobj): New.
|
||||
(Target_powerpc::do_function_location): New function.
|
||||
(Powerpc_relobj::do_find_special_sections): Update find_shdr call.
|
||||
(Powerpc_dynobj::do_read_symbols): New function.
|
||||
(Target_powerpc::do_make_elf_object): Make a Powerpc_dynobj.
|
||||
|
||||
2013-03-08 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* options.cc (General_options::string_to_object_format): Accept
|
||||
|
||||
@ -653,10 +653,6 @@ queue_middle_tasks(const General_options& options,
|
||||
// dynamic objects that it depends upon.
|
||||
input_objects->check_dynamic_dependencies();
|
||||
|
||||
// See if any of the input definitions violate the One Definition Rule.
|
||||
// TODO: if this is too slow, do this as a task, rather than inline.
|
||||
symtab->detect_odr_violations(task, options.output_file_name());
|
||||
|
||||
// Do the --no-undefined-version check.
|
||||
if (!parameters->options().undefined_version())
|
||||
{
|
||||
|
||||
@ -317,6 +317,10 @@ Layout::Relaxation_debug_check::verify_sections(
|
||||
void
|
||||
Layout_task_runner::run(Workqueue* workqueue, const Task* task)
|
||||
{
|
||||
// See if any of the input definitions violate the One Definition Rule.
|
||||
// TODO: if this is too slow, do this as a task, rather than inline.
|
||||
this->symtab_->detect_odr_violations(task, this->options_.output_file_name());
|
||||
|
||||
Layout* layout = this->layout_;
|
||||
off_t file_size = layout->finalize(this->input_objects_,
|
||||
this->symtab_,
|
||||
|
||||
@ -517,15 +517,16 @@ Sized_relobj_file<size, big_endian>::check_eh_frame_flags(
|
||||
|
||||
template<int size, bool big_endian>
|
||||
const unsigned char*
|
||||
Sized_relobj_file<size, big_endian>::find_shdr(
|
||||
Object::find_shdr(
|
||||
const unsigned char* pshdrs,
|
||||
const char* name,
|
||||
const char* names,
|
||||
section_size_type names_size,
|
||||
const unsigned char* hdr) const
|
||||
{
|
||||
const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
|
||||
const unsigned int shnum = this->shnum();
|
||||
const unsigned char* hdr_end = pshdrs + This::shdr_size * shnum;
|
||||
const unsigned char* hdr_end = pshdrs + shdr_size * shnum;
|
||||
size_t sh_name = 0;
|
||||
|
||||
while (1)
|
||||
@ -533,7 +534,7 @@ Sized_relobj_file<size, big_endian>::find_shdr(
|
||||
if (hdr)
|
||||
{
|
||||
// We found HDR last time we were called, continue looking.
|
||||
typename This::Shdr shdr(hdr);
|
||||
typename elfcpp::Shdr<size, big_endian> shdr(hdr);
|
||||
sh_name = shdr.get_sh_name();
|
||||
}
|
||||
else
|
||||
@ -557,13 +558,13 @@ Sized_relobj_file<size, big_endian>::find_shdr(
|
||||
return hdr;
|
||||
}
|
||||
|
||||
hdr += This::shdr_size;
|
||||
hdr += shdr_size;
|
||||
while (hdr < hdr_end)
|
||||
{
|
||||
typename This::Shdr shdr(hdr);
|
||||
typename elfcpp::Shdr<size, big_endian> shdr(hdr);
|
||||
if (shdr.get_sh_name() == sh_name)
|
||||
return hdr;
|
||||
hdr += This::shdr_size;
|
||||
hdr += shdr_size;
|
||||
}
|
||||
hdr = NULL;
|
||||
if (sh_name == 0)
|
||||
@ -585,7 +586,8 @@ Sized_relobj_file<size, big_endian>::find_eh_frame(
|
||||
|
||||
while (1)
|
||||
{
|
||||
s = this->find_shdr(pshdrs, ".eh_frame", names, names_size, s);
|
||||
s = this->template find_shdr<size, big_endian>(pshdrs, ".eh_frame",
|
||||
names, names_size, s);
|
||||
if (s == NULL)
|
||||
return false;
|
||||
|
||||
@ -3163,6 +3165,10 @@ template
|
||||
void
|
||||
Object::read_section_data<32, false>(elfcpp::Elf_file<32, false, Object>*,
|
||||
Read_symbols_data*);
|
||||
template
|
||||
const unsigned char*
|
||||
Object::find_shdr<32,false>(const unsigned char*, const char*, const char*,
|
||||
section_size_type, const unsigned char*) const;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
@ -3170,6 +3176,10 @@ template
|
||||
void
|
||||
Object::read_section_data<32, true>(elfcpp::Elf_file<32, true, Object>*,
|
||||
Read_symbols_data*);
|
||||
template
|
||||
const unsigned char*
|
||||
Object::find_shdr<32,true>(const unsigned char*, const char*, const char*,
|
||||
section_size_type, const unsigned char*) const;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
@ -3177,6 +3187,10 @@ template
|
||||
void
|
||||
Object::read_section_data<64, false>(elfcpp::Elf_file<64, false, Object>*,
|
||||
Read_symbols_data*);
|
||||
template
|
||||
const unsigned char*
|
||||
Object::find_shdr<64,false>(const unsigned char*, const char*, const char*,
|
||||
section_size_type, const unsigned char*) const;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
@ -3184,6 +3198,10 @@ template
|
||||
void
|
||||
Object::read_section_data<64, true>(elfcpp::Elf_file<64, true, Object>*,
|
||||
Read_symbols_data*);
|
||||
template
|
||||
const unsigned char*
|
||||
Object::find_shdr<64,true>(const unsigned char*, const char*, const char*,
|
||||
section_size_type, const unsigned char*) const;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
|
||||
@ -881,6 +881,16 @@ class Object
|
||||
read_section_data(elfcpp::Elf_file<size, big_endian, Object>*,
|
||||
Read_symbols_data*);
|
||||
|
||||
// Find the section header with the given NAME. If HDR is non-NULL
|
||||
// then it is a section header returned from a previous call to this
|
||||
// function and the next section header with the same name will be
|
||||
// returned.
|
||||
template<int size, bool big_endian>
|
||||
const unsigned char*
|
||||
find_shdr(const unsigned char* pshdrs, const char* name,
|
||||
const char* names, section_size_type names_size,
|
||||
const unsigned char* hdr) const;
|
||||
|
||||
// Let the child class initialize the xindex object directly.
|
||||
void
|
||||
set_xindex(Xindex* xindex)
|
||||
@ -2161,15 +2171,6 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
|
||||
Address
|
||||
map_to_kept_section(unsigned int shndx, bool* found) const;
|
||||
|
||||
// Find the section header with the given NAME. If HDR is non-NULL
|
||||
// then it is a section header returned from a previous call to this
|
||||
// function and the next section header with the same name will be
|
||||
// returned.
|
||||
const unsigned char*
|
||||
find_shdr(const unsigned char* pshdrs, const char* name,
|
||||
const char* names, section_size_type names_size,
|
||||
const unsigned char* hdr) const;
|
||||
|
||||
// Compute final local symbol value. R_SYM is the local symbol index.
|
||||
// LV_IN points to a local symbol value containing the input value.
|
||||
// LV_OUT points to a local symbol value storing the final output value,
|
||||
|
||||
251
gold/powerpc.cc
251
gold/powerpc.cc
@ -23,6 +23,7 @@
|
||||
|
||||
#include "gold.h"
|
||||
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include "elfcpp.h"
|
||||
#include "dwarf.h"
|
||||
@ -319,6 +320,109 @@ private:
|
||||
std::vector<Stub_table<size, big_endian>*> stub_table_;
|
||||
};
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Powerpc_dynobj : public Sized_dynobj<size, big_endian>
|
||||
{
|
||||
public:
|
||||
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
|
||||
|
||||
Powerpc_dynobj(const std::string& name, Input_file* input_file, off_t offset,
|
||||
const typename elfcpp::Ehdr<size, big_endian>& ehdr)
|
||||
: Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr),
|
||||
opd_shndx_(0), opd_ent_()
|
||||
{ }
|
||||
|
||||
~Powerpc_dynobj()
|
||||
{ }
|
||||
|
||||
// Call Sized_dynobj::do_read_symbols to read the symbols then
|
||||
// read .opd from a dynamic object, filling in opd_ent_ vector,
|
||||
void
|
||||
do_read_symbols(Read_symbols_data*);
|
||||
|
||||
// The .opd section shndx.
|
||||
unsigned int
|
||||
opd_shndx() const
|
||||
{
|
||||
return this->opd_shndx_;
|
||||
}
|
||||
|
||||
// The .opd section address.
|
||||
Address
|
||||
opd_address() const
|
||||
{
|
||||
return this->opd_address_;
|
||||
}
|
||||
|
||||
// Init OPD entry arrays.
|
||||
void
|
||||
init_opd(size_t opd_size)
|
||||
{
|
||||
size_t count = this->opd_ent_ndx(opd_size);
|
||||
this->opd_ent_.resize(count);
|
||||
}
|
||||
|
||||
// Return section and offset of function entry for .opd + R_OFF.
|
||||
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_.size());
|
||||
gold_assert(this->opd_ent_[ndx].shndx != 0);
|
||||
if (value != NULL)
|
||||
*value = this->opd_ent_[ndx].off;
|
||||
return this->opd_ent_[ndx].shndx;
|
||||
}
|
||||
|
||||
// Set section and offset of function entry for .opd + R_OFF.
|
||||
void
|
||||
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_.size());
|
||||
this->opd_ent_[ndx].shndx = shndx;
|
||||
this->opd_ent_[ndx].off = value;
|
||||
}
|
||||
|
||||
private:
|
||||
// Used to specify extent of executable sections.
|
||||
struct Sec_info
|
||||
{
|
||||
Sec_info(Address start_, Address len_, unsigned int shndx_)
|
||||
: start(start_), len(len_), shndx(shndx_)
|
||||
{ }
|
||||
|
||||
bool
|
||||
operator<(const Sec_info& that) const
|
||||
{ return this->start < that.start; }
|
||||
|
||||
Address start;
|
||||
Address len;
|
||||
unsigned int shndx;
|
||||
};
|
||||
|
||||
struct Opd_ent
|
||||
{
|
||||
unsigned int shndx;
|
||||
Address off;
|
||||
};
|
||||
|
||||
// Return index into opd_ent_ array for .opd entry at OFF.
|
||||
size_t
|
||||
opd_ent_ndx(size_t off) const
|
||||
{ return off >> 4;}
|
||||
|
||||
// For 64-bit the .opd section shndx and address.
|
||||
unsigned int opd_shndx_;
|
||||
Address opd_address_;
|
||||
|
||||
// The first 8-byte word of an OPD entry gives the address of the
|
||||
// entry point of the function. Records the section and offset
|
||||
// corresponding to the address. Note that in dynamic objects,
|
||||
// offset is *not* relative to the section.
|
||||
std::vector<Opd_ent> opd_ent_;
|
||||
};
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Target_powerpc : public Sized_target<size, big_endian>
|
||||
{
|
||||
@ -448,6 +552,9 @@ class Target_powerpc : public Sized_target<size, big_endian>
|
||||
int64_t
|
||||
do_tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const;
|
||||
|
||||
void
|
||||
do_function_location(Symbol_location*) const;
|
||||
|
||||
// Relocate a section.
|
||||
void
|
||||
relocate_section(const Relocate_info<size, big_endian>*,
|
||||
@ -1518,8 +1625,9 @@ Powerpc_relobj<size, big_endian>::do_find_special_sections(
|
||||
section_size_type names_size = sd->section_names_size;
|
||||
const unsigned char* s;
|
||||
|
||||
s = this->find_shdr(pshdrs, size == 32 ? ".got2" : ".opd",
|
||||
names, names_size, NULL);
|
||||
s = this->template find_shdr<size, big_endian>(pshdrs,
|
||||
size == 32 ? ".got2" : ".opd",
|
||||
names, names_size, NULL);
|
||||
if (s != NULL)
|
||||
{
|
||||
unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
|
||||
@ -1634,6 +1742,105 @@ Powerpc_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
|
||||
}
|
||||
}
|
||||
|
||||
// Call Sized_dynobj::do_read_symbols to read the symbols then
|
||||
// read .opd from a dynamic object, filling in opd_ent_ vector,
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Powerpc_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
|
||||
{
|
||||
Sized_dynobj<size, big_endian>::do_read_symbols(sd);
|
||||
if (size == 64)
|
||||
{
|
||||
const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
|
||||
const unsigned char* const pshdrs = sd->section_headers->data();
|
||||
const unsigned char* namesu = sd->section_names->data();
|
||||
const char* names = reinterpret_cast<const char*>(namesu);
|
||||
const unsigned char* s = NULL;
|
||||
const unsigned char* opd;
|
||||
section_size_type opd_size;
|
||||
|
||||
// Find and read .opd section.
|
||||
while (1)
|
||||
{
|
||||
s = this->template find_shdr<size, big_endian>(pshdrs, ".opd", names,
|
||||
sd->section_names_size,
|
||||
s);
|
||||
if (s == NULL)
|
||||
return;
|
||||
|
||||
typename elfcpp::Shdr<size, big_endian> shdr(s);
|
||||
if (shdr.get_sh_type() == elfcpp::SHT_PROGBITS
|
||||
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0)
|
||||
{
|
||||
this->opd_shndx_ = (s - pshdrs) / shdr_size;
|
||||
this->opd_address_ = shdr.get_sh_addr();
|
||||
opd_size = convert_to_section_size_type(shdr.get_sh_size());
|
||||
opd = this->get_view(shdr.get_sh_offset(), opd_size,
|
||||
true, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Build set of executable sections.
|
||||
// Using a set is probably overkill. There is likely to be only
|
||||
// a few executable sections, typically .init, .text and .fini,
|
||||
// and they are generally grouped together.
|
||||
typedef std::set<Sec_info> Exec_sections;
|
||||
Exec_sections exec_sections;
|
||||
s = pshdrs;
|
||||
for (unsigned int i = 1; i < this->shnum(); ++i, s += shdr_size)
|
||||
{
|
||||
typename elfcpp::Shdr<size, big_endian> shdr(s);
|
||||
if (shdr.get_sh_type() == elfcpp::SHT_PROGBITS
|
||||
&& ((shdr.get_sh_flags()
|
||||
& (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR))
|
||||
== (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR))
|
||||
&& shdr.get_sh_size() != 0)
|
||||
{
|
||||
exec_sections.insert(Sec_info(shdr.get_sh_addr(),
|
||||
shdr.get_sh_size(), i));
|
||||
}
|
||||
}
|
||||
if (exec_sections.empty())
|
||||
return;
|
||||
|
||||
// Look over the OPD entries. This is complicated by the fact
|
||||
// that some binaries will use two-word entries while others
|
||||
// will use the standard three-word entries. In most cases
|
||||
// the third word (the environment pointer for languages like
|
||||
// Pascal) is unused and will be zero. If the third word is
|
||||
// used it should not be pointing into executable sections,
|
||||
// I think.
|
||||
this->init_opd(opd_size);
|
||||
for (const unsigned char* p = opd; p < opd + opd_size; p += 8)
|
||||
{
|
||||
typedef typename elfcpp::Swap<64, big_endian>::Valtype Valtype;
|
||||
const Valtype* valp = reinterpret_cast<const Valtype*>(p);
|
||||
Valtype val = elfcpp::Swap<64, big_endian>::readval(valp);
|
||||
if (val == 0)
|
||||
// Chances are that this is the third word of an OPD entry.
|
||||
continue;
|
||||
typename Exec_sections::const_iterator e
|
||||
= exec_sections.upper_bound(Sec_info(val, 0, 0));
|
||||
if (e != exec_sections.begin())
|
||||
{
|
||||
--e;
|
||||
if (e->start <= val && val < e->start + e->len)
|
||||
{
|
||||
// We have an address in an executable section.
|
||||
// VAL ought to be the function entry, set it up.
|
||||
this->set_opd_ent(p - opd, e->shndx, val);
|
||||
// Skip second word of OPD entry, the TOC pointer.
|
||||
p += 8;
|
||||
}
|
||||
}
|
||||
// If we didn't match any executable sections, we likely
|
||||
// have a non-zero third word in the OPD entry.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up some symbols.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
@ -1706,8 +1913,8 @@ Target_powerpc<size, big_endian>::do_make_elf_object(
|
||||
}
|
||||
else if (et == elfcpp::ET_DYN)
|
||||
{
|
||||
Sized_dynobj<size, big_endian>* obj =
|
||||
new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
|
||||
Powerpc_dynobj<size, big_endian>* obj =
|
||||
new Powerpc_dynobj<size, big_endian>(name, input_file, offset, ehdr);
|
||||
obj->setup();
|
||||
return obj;
|
||||
}
|
||||
@ -5581,6 +5788,42 @@ Target_powerpc<size, big_endian>::do_gc_mark_symbol(
|
||||
}
|
||||
}
|
||||
|
||||
// For a symbol location in .opd, set LOC to the location of the
|
||||
// function entry.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Target_powerpc<size, big_endian>::do_function_location(
|
||||
Symbol_location* loc) const
|
||||
{
|
||||
if (size == 64)
|
||||
{
|
||||
if (loc->object->is_dynamic())
|
||||
{
|
||||
Powerpc_dynobj<size, big_endian>* ppc_object
|
||||
= static_cast<Powerpc_dynobj<size, big_endian>*>(loc->object);
|
||||
if (loc->shndx == ppc_object->opd_shndx())
|
||||
{
|
||||
Address dest_off;
|
||||
Address off = loc->offset - ppc_object->opd_address();
|
||||
loc->shndx = ppc_object->get_opd_ent(off, &dest_off);
|
||||
loc->offset = dest_off;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const Powerpc_relobj<size, big_endian>* ppc_object
|
||||
= static_cast<const Powerpc_relobj<size, big_endian>*>(loc->object);
|
||||
if (loc->shndx == ppc_object->opd_shndx())
|
||||
{
|
||||
Address dest_off;
|
||||
loc->shndx = ppc_object->get_opd_ent(loc->offset, &dest_off);
|
||||
loc->offset = dest_off;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scan relocations for a section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
|
||||
@ -3175,9 +3175,11 @@ Symbol_table::linenos_from_loc(const Task* task,
|
||||
Task_lock_obj<Object> tl(task, loc.object);
|
||||
|
||||
std::vector<std::string> result;
|
||||
Symbol_location code_loc = loc;
|
||||
parameters->target().function_location(&code_loc);
|
||||
// 16 is the size of the object-cache that one_addr2line should use.
|
||||
std::string canonical_result = Dwarf_line_info::one_addr2line(
|
||||
loc.object, loc.shndx, loc.offset, 16, &result);
|
||||
code_loc.object, code_loc.shndx, code_loc.offset, 16, &result);
|
||||
if (!canonical_result.empty())
|
||||
result.push_back(canonical_result);
|
||||
return result;
|
||||
|
||||
@ -1180,6 +1180,25 @@ struct Define_symbol_in_segment
|
||||
bool only_if_ref;
|
||||
};
|
||||
|
||||
// Specify an object/section/offset location. Used by ODR code.
|
||||
|
||||
struct Symbol_location
|
||||
{
|
||||
// Object where the symbol is defined.
|
||||
Object* object;
|
||||
// Section-in-object where the symbol is defined.
|
||||
unsigned int shndx;
|
||||
// For relocatable objects, offset-in-section where the symbol is defined.
|
||||
// For dynamic objects, address where the symbol is defined.
|
||||
off_t offset;
|
||||
bool operator==(const Symbol_location& that) const
|
||||
{
|
||||
return (this->object == that.object
|
||||
&& this->shndx == that.shndx
|
||||
&& this->offset == that.offset);
|
||||
}
|
||||
};
|
||||
|
||||
// This class manages warnings. Warnings are a GNU extension. When
|
||||
// we see a section named .gnu.warning.SYM in an object file, and if
|
||||
// we wind using the definition of SYM from that object file, then we
|
||||
@ -1599,19 +1618,6 @@ class Symbol_table
|
||||
// the locations the symbols is (weakly) defined (and certain other
|
||||
// conditions are met). This map will be used later to detect
|
||||
// possible One Definition Rule (ODR) violations.
|
||||
struct Symbol_location
|
||||
{
|
||||
Object* object; // Object where the symbol is defined.
|
||||
unsigned int shndx; // Section-in-object where the symbol is defined.
|
||||
off_t offset; // Offset-in-section where the symbol is defined.
|
||||
bool operator==(const Symbol_location& that) const
|
||||
{
|
||||
return (this->object == that.object
|
||||
&& this->shndx == that.shndx
|
||||
&& this->offset == that.offset);
|
||||
}
|
||||
};
|
||||
|
||||
struct Symbol_location_hash
|
||||
{
|
||||
size_t operator()(const Symbol_location& loc) const
|
||||
|
||||
@ -61,6 +61,7 @@ class Output_data_got_base;
|
||||
class Output_section;
|
||||
class Input_objects;
|
||||
class Task;
|
||||
struct Symbol_location;
|
||||
|
||||
// The abstract class for target specific handling.
|
||||
|
||||
@ -286,6 +287,12 @@ class Target
|
||||
tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const
|
||||
{ return do_tls_offset_for_global(gsym, got_indx); }
|
||||
|
||||
// For targets that use function descriptors, if LOC is the location
|
||||
// of a function, modify it to point at the function entry location.
|
||||
void
|
||||
function_location(Symbol_location* loc) const
|
||||
{ return do_function_location(loc); }
|
||||
|
||||
// Return whether this target can use relocation types to determine
|
||||
// if a function's address is taken.
|
||||
bool
|
||||
@ -575,6 +582,9 @@ class Target
|
||||
do_tls_offset_for_global(Symbol*, unsigned int) const
|
||||
{ gold_unreachable(); }
|
||||
|
||||
virtual void
|
||||
do_function_location(Symbol_location*) const = 0;
|
||||
|
||||
// Virtual function which may be overriden by the child class.
|
||||
virtual bool
|
||||
do_can_check_for_function_pointers() const
|
||||
@ -1009,6 +1019,10 @@ class Sized_target : public Target
|
||||
Object*, unsigned int,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr) const
|
||||
{ }
|
||||
|
||||
virtual void
|
||||
do_function_location(Symbol_location*) const
|
||||
{ }
|
||||
};
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user