Browse Source
point of symbol resolution and can now issue a multiple definition error. Also added target selection infrastructure.gdb_6_6-branch
20 changed files with 1673 additions and 109 deletions
@ -0,0 +1,47 @@ |
|||
// i386.cc -- i386 target support for gold.
|
|||
|
|||
#include "gold.h" |
|||
#include "elfcpp.h" |
|||
#include "target.h" |
|||
#include "target-select.h" |
|||
|
|||
namespace |
|||
{ |
|||
|
|||
using namespace gold; |
|||
|
|||
// The i386 target class.
|
|||
|
|||
class Target_i386 : public Sized_target<32, false> |
|||
{ |
|||
public: |
|||
Target_i386() |
|||
: Sized_target<32, false>(false, false) |
|||
{ } |
|||
}; |
|||
|
|||
// The selector for i386 object files.
|
|||
|
|||
class Target_selector_i386 : public Target_selector |
|||
{ |
|||
public: |
|||
Target_selector_i386() |
|||
: Target_selector(elfcpp::EM_386, 32, false) |
|||
{ } |
|||
|
|||
Target* |
|||
recognize(int machine, int osabi, int abiversion) const; |
|||
}; |
|||
|
|||
// Recognize an i386 object file when we already know that the machine
|
|||
// number is EM_386.
|
|||
|
|||
Target* |
|||
Target_selector_i386::recognize(int, int, int) const |
|||
{ |
|||
return new Target_i386(); |
|||
} |
|||
|
|||
Target_selector_i386 target_selector_i386; |
|||
|
|||
} // End anonymous namespace.
|
|||
@ -0,0 +1,349 @@ |
|||
// resolve.cc -- symbol resolution for gold
|
|||
|
|||
#include "gold.h" |
|||
|
|||
#include "elfcpp.h" |
|||
#include "target.h" |
|||
#include "object.h" |
|||
#include "symtab.h" |
|||
|
|||
namespace gold |
|||
{ |
|||
|
|||
// Resolve a symbol. This is called the second and subsequent times
|
|||
// we see a symbol. TO is the pre-existing symbol. SYM is the new
|
|||
// symbol, seen in OBJECT.
|
|||
|
|||
template<int size, bool big_endian> |
|||
void |
|||
Symbol_table::resolve(Symbol* to, |
|||
const elfcpp::Sym<size, big_endian>& sym, |
|||
Object* object) |
|||
{ |
|||
if (object->target()->has_resolve()) |
|||
{ |
|||
object->sized_target<size, big_endian>()->resolve(to, sym, object); |
|||
return; |
|||
} |
|||
|
|||
// Build a little code for each symbol.
|
|||
// Bit 0: 0 for global, 1 for weak.
|
|||
// Bit 1: 0 for regular object, 1 for shared object
|
|||
// Bits 2-3: 0 for normal, 1 for undefined, 2 for common
|
|||
// This gives us values from 0 to 11:
|
|||
|
|||
enum |
|||
{ |
|||
DEF = 0, |
|||
WEAK_DEF = 1, |
|||
DYN_DEF = 2, |
|||
DYN_WEAK_DEF = 3, |
|||
UNDEF = 4, |
|||
WEAK_UNDEF = 5, |
|||
DYN_UNDEF = 6, |
|||
DYN_WEAK_UNDEF = 7, |
|||
COMMON = 8, |
|||
WEAK_COMMON = 9, |
|||
DYN_COMMON = 10, |
|||
DYN_WEAK_COMMON = 11 |
|||
}; |
|||
|
|||
int tobits; |
|||
switch (to->binding()) |
|||
{ |
|||
case elfcpp::STB_GLOBAL: |
|||
tobits = 0; |
|||
break; |
|||
|
|||
case elfcpp::STB_WEAK: |
|||
tobits = 1; |
|||
break; |
|||
|
|||
case elfcpp::STB_LOCAL: |
|||
// We should only see externally visible symbols in the symbol
|
|||
// table.
|
|||
abort(); |
|||
|
|||
default: |
|||
// Any target which wants to handle STB_LOOS, etc., needs to
|
|||
// define a resolve method.
|
|||
abort(); |
|||
} |
|||
|
|||
if (to->object() != NULL && to->object()->is_dynamic()) |
|||
tobits |= (1 << 1); |
|||
|
|||
switch (to->shnum()) |
|||
{ |
|||
case elfcpp::SHN_UNDEF: |
|||
tobits |= (1 << 2); |
|||
break; |
|||
|
|||
case elfcpp::SHN_COMMON: |
|||
tobits |= (2 << 2); |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
int frombits; |
|||
switch (sym.get_st_bind()) |
|||
{ |
|||
case elfcpp::STB_GLOBAL: |
|||
frombits = 0; |
|||
break; |
|||
|
|||
case elfcpp::STB_WEAK: |
|||
frombits = 1; |
|||
break; |
|||
|
|||
case elfcpp::STB_LOCAL: |
|||
fprintf(stderr, |
|||
_("%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"), |
|||
program_name, object->name().c_str(), to->name()); |
|||
gold_exit(false); |
|||
|
|||
default: |
|||
fprintf(stderr, |
|||
_("%s: %s: unsupported symbol binding %d for symbol %s\n"), |
|||
program_name, object->name().c_str(), |
|||
static_cast<int>(sym.get_st_bind()), to->name()); |
|||
gold_exit(false); |
|||
} |
|||
|
|||
if (object->is_dynamic()) |
|||
frombits |= (1 << 1); |
|||
|
|||
switch (sym.get_st_shndx()) |
|||
{ |
|||
case elfcpp::SHN_UNDEF: |
|||
frombits |= (1 << 2); |
|||
break; |
|||
|
|||
case elfcpp::SHN_COMMON: |
|||
frombits |= (2 << 2); |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
// We use a giant switch table for symbol resolution. This code is
|
|||
// unwieldy, but: 1) it is efficient; 2) we definitely handle all
|
|||
// cases; 3) it is easy to change the handling of a particular case.
|
|||
// The alternative would be a series of conditionals, but it is easy
|
|||
// to get the ordering wrong. This could also be done as a table,
|
|||
// but that is no easier to understand than this large switch
|
|||
// statement.
|
|||
|
|||
switch (tobits * 16 + frombits) |
|||
{ |
|||
case DEF * 16 + DEF: |
|||
// Two definitions of the same symbol.
|
|||
fprintf(stderr, "%s: %s: multiple definition of %s\n", |
|||
program_name, object->name().c_str(), to->name()); |
|||
// FIXME: Report locations. Record that we have seen an error.
|
|||
return; |
|||
|
|||
case WEAK_DEF * 16 + DEF: |
|||
// In the original SVR4 linker, a weak definition followed by a
|
|||
// regular definition was treated as a multiple definition
|
|||
// error. In the Solaris linker and the GNU linker, a weak
|
|||
// definition followed by a regular definition causes the
|
|||
// regular definition to be ignored. We are currently
|
|||
// compatible with the GNU linker. In the future we should add
|
|||
// a target specific option to change this. FIXME.
|
|||
return; |
|||
|
|||
case DYN_DEF * 16 + DEF: |
|||
case DYN_WEAK_DEF * 16 + DEF: |
|||
case UNDEF * 16 + DEF: |
|||
case WEAK_UNDEF * 16 + DEF: |
|||
case DYN_UNDEF * 16 + DEF: |
|||
case DYN_WEAK_UNDEF * 16 + DEF: |
|||
case COMMON * 16 + DEF: |
|||
case WEAK_COMMON * 16 + DEF: |
|||
case DYN_COMMON * 16 + DEF: |
|||
case DYN_WEAK_COMMON * 16 + DEF: |
|||
|
|||
case DEF * 16 + WEAK_DEF: |
|||
case WEAK_DEF * 16 + WEAK_DEF: |
|||
case DYN_DEF * 16 + WEAK_DEF: |
|||
case DYN_WEAK_DEF * 16 + WEAK_DEF: |
|||
case UNDEF * 16 + WEAK_DEF: |
|||
case WEAK_UNDEF * 16 + WEAK_DEF: |
|||
case DYN_UNDEF * 16 + WEAK_DEF: |
|||
case DYN_WEAK_UNDEF * 16 + WEAK_DEF: |
|||
case COMMON * 16 + WEAK_DEF: |
|||
case WEAK_COMMON * 16 + WEAK_DEF: |
|||
case DYN_COMMON * 16 + WEAK_DEF: |
|||
case DYN_WEAK_COMMON * 16 + WEAK_DEF: |
|||
|
|||
case DEF * 16 + DYN_DEF: |
|||
case WEAK_DEF * 16 + DYN_DEF: |
|||
case DYN_DEF * 16 + DYN_DEF: |
|||
case DYN_WEAK_DEF * 16 + DYN_DEF: |
|||
case UNDEF * 16 + DYN_DEF: |
|||
case WEAK_UNDEF * 16 + DYN_DEF: |
|||
case DYN_UNDEF * 16 + DYN_DEF: |
|||
case DYN_WEAK_UNDEF * 16 + DYN_DEF: |
|||
case COMMON * 16 + DYN_DEF: |
|||
case WEAK_COMMON * 16 + DYN_DEF: |
|||
case DYN_COMMON * 16 + DYN_DEF: |
|||
case DYN_WEAK_COMMON * 16 + DYN_DEF: |
|||
|
|||
case DEF * 16 + DYN_WEAK_DEF: |
|||
case WEAK_DEF * 16 + DYN_WEAK_DEF: |
|||
case DYN_DEF * 16 + DYN_WEAK_DEF: |
|||
case DYN_WEAK_DEF * 16 + DYN_WEAK_DEF: |
|||
case UNDEF * 16 + DYN_WEAK_DEF: |
|||
case WEAK_UNDEF * 16 + DYN_WEAK_DEF: |
|||
case DYN_UNDEF * 16 + DYN_WEAK_DEF: |
|||
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF: |
|||
case COMMON * 16 + DYN_WEAK_DEF: |
|||
case WEAK_COMMON * 16 + DYN_WEAK_DEF: |
|||
case DYN_COMMON * 16 + DYN_WEAK_DEF: |
|||
case DYN_WEAK_COMMON * 16 + DYN_WEAK_DEF: |
|||
|
|||
case DEF * 16 + UNDEF: |
|||
case WEAK_DEF * 16 + UNDEF: |
|||
case DYN_DEF * 16 + UNDEF: |
|||
case DYN_WEAK_DEF * 16 + UNDEF: |
|||
case UNDEF * 16 + UNDEF: |
|||
case WEAK_UNDEF * 16 + UNDEF: |
|||
case DYN_UNDEF * 16 + UNDEF: |
|||
case DYN_WEAK_UNDEF * 16 + UNDEF: |
|||
case COMMON * 16 + UNDEF: |
|||
case WEAK_COMMON * 16 + UNDEF: |
|||
case DYN_COMMON * 16 + UNDEF: |
|||
case DYN_WEAK_COMMON * 16 + UNDEF: |
|||
|
|||
case DEF * 16 + WEAK_UNDEF: |
|||
case WEAK_DEF * 16 + WEAK_UNDEF: |
|||
case DYN_DEF * 16 + WEAK_UNDEF: |
|||
case DYN_WEAK_DEF * 16 + WEAK_UNDEF: |
|||
case UNDEF * 16 + WEAK_UNDEF: |
|||
case WEAK_UNDEF * 16 + WEAK_UNDEF: |
|||
case DYN_UNDEF * 16 + WEAK_UNDEF: |
|||
case DYN_WEAK_UNDEF * 16 + WEAK_UNDEF: |
|||
case COMMON * 16 + WEAK_UNDEF: |
|||
case WEAK_COMMON * 16 + WEAK_UNDEF: |
|||
case DYN_COMMON * 16 + WEAK_UNDEF: |
|||
case DYN_WEAK_COMMON * 16 + WEAK_UNDEF: |
|||
|
|||
case DEF * 16 + DYN_UNDEF: |
|||
case WEAK_DEF * 16 + DYN_UNDEF: |
|||
case DYN_DEF * 16 + DYN_UNDEF: |
|||
case DYN_WEAK_DEF * 16 + DYN_UNDEF: |
|||
case UNDEF * 16 + DYN_UNDEF: |
|||
case WEAK_UNDEF * 16 + DYN_UNDEF: |
|||
case DYN_UNDEF * 16 + DYN_UNDEF: |
|||
case DYN_WEAK_UNDEF * 16 + DYN_UNDEF: |
|||
case COMMON * 16 + DYN_UNDEF: |
|||
case WEAK_COMMON * 16 + DYN_UNDEF: |
|||
case DYN_COMMON * 16 + DYN_UNDEF: |
|||
case DYN_WEAK_COMMON * 16 + DYN_UNDEF: |
|||
|
|||
case DEF * 16 + DYN_WEAK_UNDEF: |
|||
case WEAK_DEF * 16 + DYN_WEAK_UNDEF: |
|||
case DYN_DEF * 16 + DYN_WEAK_UNDEF: |
|||
case DYN_WEAK_DEF * 16 + DYN_WEAK_UNDEF: |
|||
case UNDEF * 16 + DYN_WEAK_UNDEF: |
|||
case WEAK_UNDEF * 16 + DYN_WEAK_UNDEF: |
|||
case DYN_UNDEF * 16 + DYN_WEAK_UNDEF: |
|||
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_UNDEF: |
|||
case COMMON * 16 + DYN_WEAK_UNDEF: |
|||
case WEAK_COMMON * 16 + DYN_WEAK_UNDEF: |
|||
case DYN_COMMON * 16 + DYN_WEAK_UNDEF: |
|||
case DYN_WEAK_COMMON * 16 + DYN_WEAK_UNDEF: |
|||
|
|||
case DEF * 16 + COMMON: |
|||
case WEAK_DEF * 16 + COMMON: |
|||
case DYN_DEF * 16 + COMMON: |
|||
case DYN_WEAK_DEF * 16 + COMMON: |
|||
case UNDEF * 16 + COMMON: |
|||
case WEAK_UNDEF * 16 + COMMON: |
|||
case DYN_UNDEF * 16 + COMMON: |
|||
case DYN_WEAK_UNDEF * 16 + COMMON: |
|||
case COMMON * 16 + COMMON: |
|||
case WEAK_COMMON * 16 + COMMON: |
|||
case DYN_COMMON * 16 + COMMON: |
|||
case DYN_WEAK_COMMON * 16 + COMMON: |
|||
|
|||
case DEF * 16 + WEAK_COMMON: |
|||
case WEAK_DEF * 16 + WEAK_COMMON: |
|||
case DYN_DEF * 16 + WEAK_COMMON: |
|||
case DYN_WEAK_DEF * 16 + WEAK_COMMON: |
|||
case UNDEF * 16 + WEAK_COMMON: |
|||
case WEAK_UNDEF * 16 + WEAK_COMMON: |
|||
case DYN_UNDEF * 16 + WEAK_COMMON: |
|||
case DYN_WEAK_UNDEF * 16 + WEAK_COMMON: |
|||
case COMMON * 16 + WEAK_COMMON: |
|||
case WEAK_COMMON * 16 + WEAK_COMMON: |
|||
case DYN_COMMON * 16 + WEAK_COMMON: |
|||
case DYN_WEAK_COMMON * 16 + WEAK_COMMON: |
|||
|
|||
case DEF * 16 + DYN_COMMON: |
|||
case WEAK_DEF * 16 + DYN_COMMON: |
|||
case DYN_DEF * 16 + DYN_COMMON: |
|||
case DYN_WEAK_DEF * 16 + DYN_COMMON: |
|||
case UNDEF * 16 + DYN_COMMON: |
|||
case WEAK_UNDEF * 16 + DYN_COMMON: |
|||
case DYN_UNDEF * 16 + DYN_COMMON: |
|||
case DYN_WEAK_UNDEF * 16 + DYN_COMMON: |
|||
case COMMON * 16 + DYN_COMMON: |
|||
case WEAK_COMMON * 16 + DYN_COMMON: |
|||
case DYN_COMMON * 16 + DYN_COMMON: |
|||
case DYN_WEAK_COMMON * 16 + DYN_COMMON: |
|||
|
|||
case DEF * 16 + DYN_WEAK_COMMON: |
|||
case WEAK_DEF * 16 + DYN_WEAK_COMMON: |
|||
case DYN_DEF * 16 + DYN_WEAK_COMMON: |
|||
case DYN_WEAK_DEF * 16 + DYN_WEAK_COMMON: |
|||
case UNDEF * 16 + DYN_WEAK_COMMON: |
|||
case WEAK_UNDEF * 16 + DYN_WEAK_COMMON: |
|||
case DYN_UNDEF * 16 + DYN_WEAK_COMMON: |
|||
case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON: |
|||
case COMMON * 16 + DYN_WEAK_COMMON: |
|||
case WEAK_COMMON * 16 + DYN_WEAK_COMMON: |
|||
case DYN_COMMON * 16 + DYN_WEAK_COMMON: |
|||
case DYN_WEAK_COMMON * 16 + DYN_WEAK_COMMON: |
|||
|
|||
break; |
|||
} |
|||
} |
|||
|
|||
// Instantiate the templates we need. We could use the configure
|
|||
// script to restrict this to only the ones needed for implemented
|
|||
// targets.
|
|||
|
|||
template |
|||
void |
|||
Symbol_table::resolve<32, true>( |
|||
Symbol* to, |
|||
const elfcpp::Sym<32, true>& sym, |
|||
Object* object); |
|||
|
|||
template |
|||
void |
|||
Symbol_table::resolve<32, false>( |
|||
Symbol* to, |
|||
const elfcpp::Sym<32, false>& sym, |
|||
Object* object); |
|||
|
|||
template |
|||
void |
|||
Symbol_table::resolve<64, true>( |
|||
Symbol* to, |
|||
const elfcpp::Sym<64, true>& sym, |
|||
Object* object); |
|||
|
|||
template |
|||
void |
|||
Symbol_table::resolve<64, false>( |
|||
Symbol* to, |
|||
const elfcpp::Sym<64, false>& sym, |
|||
Object* object); |
|||
|
|||
} // End namespace gold.
|
|||
@ -0,0 +1,130 @@ |
|||
// stringpool.cc -- a string pool for gold
|
|||
|
|||
#include "gold.h" |
|||
|
|||
#include <cassert> |
|||
#include <cstring> |
|||
|
|||
#include "stringpool.h" |
|||
|
|||
namespace gold |
|||
{ |
|||
|
|||
Stringpool::Stringpool() |
|||
: string_set_(), strings_() |
|||
{ |
|||
} |
|||
|
|||
Stringpool::~Stringpool() |
|||
{ |
|||
for (std::list<stringdata*>::iterator p = this->strings_.begin(); |
|||
p != this->strings_.end(); |
|||
++p) |
|||
delete[] reinterpret_cast<char*>(*p); |
|||
} |
|||
|
|||
// Hash function.
|
|||
|
|||
size_t |
|||
Stringpool::Stringpool_hash::operator()(const char* s) const |
|||
{ |
|||
// Fowler/Noll/Vo (FNV) hash (type FNV-1a).
|
|||
if (sizeof(size_t) == 8) |
|||
{ |
|||
size_t result = 14695981039346656037ULL; |
|||
while (*s != '\0') |
|||
{ |
|||
result &= (size_t) *s++; |
|||
result *= 1099511628211ULL; |
|||
} |
|||
return result; |
|||
} |
|||
else |
|||
{ |
|||
size_t result = 2166136261UL; |
|||
while (*s != '\0') |
|||
{ |
|||
result ^= (size_t) *s++; |
|||
result *= 16777619UL; |
|||
} |
|||
return result; |
|||
} |
|||
} |
|||
|
|||
// Add a string to the list of canonical strings. Return a pointer to
|
|||
// the canonical string.
|
|||
|
|||
const char* |
|||
Stringpool::add_string(const char* s) |
|||
{ |
|||
const size_t buffer_size = 1000; |
|||
size_t len = strlen(s); |
|||
|
|||
size_t alc; |
|||
bool front = true; |
|||
if (len >= buffer_size) |
|||
{ |
|||
alc = sizeof(stringdata) + len; |
|||
front = false; |
|||
} |
|||
else if (this->strings_.empty()) |
|||
alc = sizeof(stringdata) + buffer_size; |
|||
else |
|||
{ |
|||
stringdata *psd = this->strings_.front(); |
|||
if (len >= psd->alc - psd->len) |
|||
alc = sizeof(stringdata) + buffer_size; |
|||
else |
|||
{ |
|||
char* ret = psd->data + psd->len; |
|||
memcpy(ret, s, len + 1); |
|||
psd->len += len + 1; |
|||
return ret; |
|||
} |
|||
} |
|||
|
|||
stringdata *psd = reinterpret_cast<stringdata*>(new char[alc]); |
|||
psd->alc = alc; |
|||
memcpy(psd->data, s, len + 1); |
|||
psd->len = len + 1; |
|||
if (front) |
|||
this->strings_.push_front(psd); |
|||
else |
|||
this->strings_.push_back(psd); |
|||
return psd->data; |
|||
} |
|||
|
|||
// Add a string to a string pool.
|
|||
|
|||
const char* |
|||
Stringpool::add(const char* s) |
|||
{ |
|||
// FIXME: This will look up the entry twice in the hash table. The
|
|||
// problem is that we can't insert S before we canonicalize it. I
|
|||
// don't think there is a way to handle this correct with
|
|||
// unordered_set, so this should be replaced with custom code to do
|
|||
// what we need, which is to return the empty slot.
|
|||
|
|||
String_set_type::const_iterator p = this->string_set_.find(s); |
|||
if (p != this->string_set_.end()) |
|||
return *p; |
|||
|
|||
const char* ret = this->add_string(s); |
|||
std::pair<String_set_type::iterator, bool> ins = |
|||
this->string_set_.insert(ret); |
|||
assert(ins.second); |
|||
return ret; |
|||
} |
|||
|
|||
// Add a prefix of a string to a string pool.
|
|||
|
|||
const char* |
|||
Stringpool::add(const char* s, size_t len) |
|||
{ |
|||
// FIXME: This implementation should be rewritten when we rewrite
|
|||
// the hash table to avoid copying.
|
|||
std::string st(s, len); |
|||
return this->add(st); |
|||
} |
|||
|
|||
} // End namespace gold.
|
|||
@ -0,0 +1,70 @@ |
|||
// stringpool.h -- a string pool for gold -*- C++ -*-
|
|||
|
|||
#include <string> |
|||
#include <list> |
|||
|
|||
// Stringpool
|
|||
// Manage a pool of unique strings.
|
|||
|
|||
#ifndef GOLD_STRINGPOOL_H |
|||
#define GOLD_STRINGPOOL_H |
|||
|
|||
namespace gold |
|||
{ |
|||
|
|||
class Stringpool |
|||
{ |
|||
public: |
|||
Stringpool(); |
|||
|
|||
~Stringpool(); |
|||
|
|||
// Add a string to the pool. This returns a canonical permanent
|
|||
// pointer to the string.
|
|||
const char* add(const char*); |
|||
|
|||
const char* add(const std::string& s) |
|||
{ return this->add(s.c_str()); } |
|||
|
|||
// Add the prefix of a string to the pool.
|
|||
const char* add(const char *, size_t); |
|||
|
|||
private: |
|||
Stringpool(const Stringpool&); |
|||
Stringpool& operator=(const Stringpool&); |
|||
|
|||
struct stringdata |
|||
{ |
|||
// Length of data in buffer.
|
|||
size_t len; |
|||
// Allocated size of buffer.
|
|||
size_t alc; |
|||
// Buffer.
|
|||
char data[1]; |
|||
}; |
|||
|
|||
const char* add_string(const char*); |
|||
|
|||
struct Stringpool_hash |
|||
{ |
|||
size_t |
|||
operator()(const char*) const; |
|||
}; |
|||
|
|||
struct Stringpool_eq |
|||
{ |
|||
bool |
|||
operator()(const char* p1, const char* p2) const |
|||
{ return strcmp(p1, p2) == 0; } |
|||
}; |
|||
|
|||
typedef Unordered_set<const char*, Stringpool_hash, Stringpool_eq, |
|||
std::allocator<const char*>, |
|||
true> String_set_type; |
|||
String_set_type string_set_; |
|||
std::list<stringdata*> strings_; |
|||
}; |
|||
|
|||
} // End namespace gold.
|
|||
|
|||
#endif // !defined(GOLD_STRINGPOOL_H)
|
|||
@ -0,0 +1,73 @@ |
|||
// strtab.h -- manage an ELF string table for gold -*- C++ -*-
|
|||
|
|||
#ifndef GOLD_STRTAB_H |
|||
#define GOLD_STRTAB_H |
|||
|
|||
#include <cstring> |
|||
#include <string> |
|||
|
|||
namespace gold |
|||
{ |
|||
|
|||
// This class holds an ELF string table. We keep a reference count
|
|||
// for each string, which we use to determine which strings are
|
|||
// actually required at the end. When all operations are done, the
|
|||
// string table is finalized, which sets the offsets to use for each
|
|||
// string.
|
|||
|
|||
class Strtab |
|||
{ |
|||
public: |
|||
Strtab(); |
|||
|
|||
~Strtab(); |
|||
|
|||
Strtab_ref* add(const char*); |
|||
|
|||
Strtab_ref* add(const std::string& s) |
|||
{ return this->add(s.c_str()); } |
|||
|
|||
private: |
|||
Strtab(const Strtab&); |
|||
Strtab& operator=(const Strtab&); |
|||
|
|||
struct strtab_hash |
|||
{ |
|||
std::size_t |
|||
operator()(const char*p); |
|||
}; |
|||
|
|||
struct strtab_eq |
|||
{ |
|||
bool |
|||
operator()(const char* p1, const char* p2) |
|||
{ return strcmp(p1, p2) == 0; } |
|||
}; |
|||
|
|||
Unordered_map<const char*, Strtab_ref*, strtab_hash, strtab_eq, |
|||
std::allocator<std::pair<const char* const, Strtab_ref*> >, |
|||
true> strings_; |
|||
}; |
|||
|
|||
// Users of Strtab work with pointers to Strtab_ref structures. These
|
|||
// are allocated via new and should be deleted if the string is no
|
|||
// longer needed.
|
|||
|
|||
class Strtab_ref |
|||
{ |
|||
public: |
|||
~Strtab_ref(); |
|||
|
|||
const char* |
|||
str() const; |
|||
|
|||
private: |
|||
Strtab_ref(const Strtab_ref&); |
|||
Strtab_ref& operator=(const Strtab_ref&); |
|||
|
|||
int refs_; |
|||
}; |
|||
|
|||
} // End namespace gold.
|
|||
|
|||
#endif // !defined(GOLD_STRTAB_H)
|
|||
@ -0,0 +1,358 @@ |
|||
// symtab.cc -- the gold symbol table
|
|||
|
|||
#include "gold.h" |
|||
|
|||
#include <cassert> |
|||
#include <stdint.h> |
|||
#include <string> |
|||
#include <utility> |
|||
|
|||
#include "object.h" |
|||
#include "symtab.h" |
|||
|
|||
namespace gold |
|||
{ |
|||
|
|||
// Class Symbol.
|
|||
|
|||
Symbol::~Symbol() |
|||
{ |
|||
} |
|||
|
|||
// Initialize the fields in the base class Symbol.
|
|||
|
|||
template<int size, bool big_endian> |
|||
void |
|||
Symbol::init_base(const char* name, const char* version, Object* object, |
|||
const elfcpp::Sym<size, big_endian>& sym) |
|||
{ |
|||
this->name_ = name; |
|||
this->version_ = version; |
|||
this->object_ = object; |
|||
this->shnum_ = sym.get_st_shndx(); // FIXME: Handle SHN_XINDEX.
|
|||
this->type_ = sym.get_st_type(); |
|||
this->binding_ = sym.get_st_bind(); |
|||
this->visibility_ = sym.get_st_visibility(); |
|||
this->other_ = sym.get_st_nonvis(); |
|||
this->special_ = false; |
|||
this->def_ = false; |
|||
this->forwarder_ = false; |
|||
} |
|||
|
|||
// Initialize the fields in Sized_symbol.
|
|||
|
|||
template<int size> |
|||
template<bool big_endian> |
|||
void |
|||
Sized_symbol<size>::init(const char* name, const char* version, Object* object, |
|||
const elfcpp::Sym<size, big_endian>& sym) |
|||
{ |
|||
this->init_base(name, version, object, sym); |
|||
this->value_ = sym.get_st_value(); |
|||
this->size_ = sym.get_st_size(); |
|||
} |
|||
|
|||
// Class Symbol_table.
|
|||
|
|||
Symbol_table::Symbol_table() |
|||
: size_(0), table_(), namepool_(), forwarders_() |
|||
{ |
|||
} |
|||
|
|||
Symbol_table::~Symbol_table() |
|||
{ |
|||
} |
|||
|
|||
// The hash function. The key is always canonicalized, so we use a
|
|||
// simple combination of the pointers.
|
|||
|
|||
size_t |
|||
Symbol_table::Symbol_table_hash::operator()(const Symbol_table_key& key) const |
|||
{ |
|||
return (reinterpret_cast<size_t>(key.first) |
|||
^ reinterpret_cast<size_t>(key.second)); |
|||
} |
|||
|
|||
// The symbol table key equality function. This is only called with
|
|||
// canonicalized name and version strings, so we can use pointer
|
|||
// comparison.
|
|||
|
|||
bool |
|||
Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1, |
|||
const Symbol_table_key& k2) const |
|||
{ |
|||
return k1.first == k2.first && k1.second == k2.second; |
|||
} |
|||
|
|||
// Make TO a symbol which forwards to FROM.
|
|||
|
|||
void |
|||
Symbol_table::make_forwarder(Symbol* from, Symbol* to) |
|||
{ |
|||
assert(!from->is_forwarder() && !to->is_forwarder()); |
|||
this->forwarders_[from] = to; |
|||
from->set_forwarder(); |
|||
} |
|||
|
|||
Symbol* |
|||
Symbol_table::resolve_forwards(Symbol* from) const |
|||
{ |
|||
assert(from->is_forwarder()); |
|||
Unordered_map<Symbol*, Symbol*>::const_iterator p = |
|||
this->forwarders_.find(from); |
|||
assert(p != this->forwarders_.end()); |
|||
return p->second; |
|||
} |
|||
|
|||
// Resolve a Symbol with another Symbol. This is only used in the
|
|||
// unusual case where there are references to both an unversioned
|
|||
// symbol and a symbol with a version, and we then discover that that
|
|||
// version is the default version.
|
|||
|
|||
void |
|||
Symbol_table::resolve(Symbol*, const Symbol*) |
|||
{ |
|||
} |
|||
|
|||
// Add one symbol from OBJECT to the symbol table. NAME is symbol
|
|||
// name and VERSION is the version; both are canonicalized. DEF is
|
|||
// whether this is the default version.
|
|||
|
|||
// If DEF is true, then this is the definition of a default version of
|
|||
// a symbol. That means that any lookup of NAME/NULL and any lookup
|
|||
// of NAME/VERSION should always return the same symbol. This is
|
|||
// obvious for references, but in particular we want to do this for
|
|||
// definitions: overriding NAME/NULL should also override
|
|||
// NAME/VERSION. If we don't do that, it would be very hard to
|
|||
// override functions in a shared library which uses versioning.
|
|||
|
|||
// We implement this by simply making both entries in the hash table
|
|||
// point to the same Symbol structure. That is easy enough if this is
|
|||
// the first time we see NAME/NULL or NAME/VERSION, but it is possible
|
|||
// that we have seen both already, in which case they will both have
|
|||
// independent entries in the symbol table. We can't simply change
|
|||
// the symbol table entry, because we have pointers to the entries
|
|||
// attached to the object files. So we mark the entry attached to the
|
|||
// object file as a forwarder, and record it in the forwarders_ map.
|
|||
// Note that entries in the hash table will never be marked as
|
|||
// forwarders.
|
|||
|
|||
template<int size, bool big_endian> |
|||
Symbol* |
|||
Symbol_table::add_from_object(Sized_object<size, big_endian>* object, |
|||
const char *name, |
|||
const char *version, bool def, |
|||
const elfcpp::Sym<size, big_endian>& sym) |
|||
{ |
|||
Symbol* const snull = NULL; |
|||
std::pair<typename Symbol_table_type::iterator, bool> ins = |
|||
this->table_.insert(std::make_pair(std::make_pair(name, version), snull)); |
|||
|
|||
std::pair<typename Symbol_table_type::iterator, bool> insdef = |
|||
std::make_pair(this->table_.end(), false); |
|||
if (def) |
|||
{ |
|||
const char* const vnull = NULL; |
|||
insdef = this->table_.insert(std::make_pair(std::make_pair(name, vnull), |
|||
snull)); |
|||
} |
|||
|
|||
// ins.first: an iterator, which is a pointer to a pair.
|
|||
// ins.first->first: the key (a pair of name and version).
|
|||
// ins.first->second: the value (Symbol*).
|
|||
// ins.second: true if new entry was inserted, false if not.
|
|||
|
|||
Symbol* ret; |
|||
if (!ins.second) |
|||
{ |
|||
// We already have an entry for NAME/VERSION.
|
|||
ret = ins.first->second; |
|||
assert(ret != NULL); |
|||
Symbol_table::resolve(ret, sym, object); |
|||
|
|||
if (def) |
|||
{ |
|||
if (insdef.second) |
|||
{ |
|||
// This is the first time we have seen NAME/NULL. Make
|
|||
// NAME/NULL point to NAME/VERSION.
|
|||
insdef.first->second = ret; |
|||
} |
|||
else |
|||
{ |
|||
// This is the unfortunate case where we already have
|
|||
// entries for both NAME/VERSION and NAME/NULL.
|
|||
Symbol_table::resolve(ret, insdef.first->second); |
|||
this->make_forwarder(insdef.first->second, ret); |
|||
insdef.first->second = ret; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// This is the first time we have seen NAME/VERSION.
|
|||
assert(ins.first->second == NULL); |
|||
if (def && !insdef.second) |
|||
{ |
|||
// We already have an entry for NAME/NULL. Make
|
|||
// NAME/VERSION point to it.
|
|||
ret = insdef.first->second; |
|||
Symbol_table::resolve(ret, sym, object); |
|||
ins.first->second = ret; |
|||
} |
|||
else |
|||
{ |
|||
Sized_symbol<size>* rs; |
|||
Sized_target<size, big_endian>* target = object->sized_target(); |
|||
if (target->has_make_symbol()) |
|||
{ |
|||
rs = target->make_symbol(); |
|||
if (rs == NULL) |
|||
{ |
|||
// This means that we don't want a symbol table
|
|||
// entry after all.
|
|||
if (!def) |
|||
this->table_.erase(ins.first); |
|||
else |
|||
{ |
|||
this->table_.erase(insdef.first); |
|||
// Inserting insdef invalidated ins.
|
|||
this->table_.erase(std::make_pair(name, version)); |
|||
} |
|||
return NULL; |
|||
} |
|||
} |
|||
else |
|||
rs = new Sized_symbol<size>(); |
|||
rs->init(name, version, object, sym); |
|||
|
|||
ret = rs; |
|||
ins.first->second = ret; |
|||
if (def) |
|||
{ |
|||
// This is the first time we have seen NAME/NULL. Point
|
|||
// it at the new entry for NAME/VERSION.
|
|||
assert(insdef.second); |
|||
insdef.first->second = ret; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
// Add all the symbols in an object to the hash table.
|
|||
|
|||
template<int size, bool big_endian> |
|||
void |
|||
Symbol_table::add_from_object( |
|||
Sized_object<size, big_endian>* object, |
|||
const elfcpp::Sym<size, big_endian>* syms, |
|||
size_t count, |
|||
const char* sym_names, |
|||
size_t sym_name_size, |
|||
Symbol** sympointers) |
|||
{ |
|||
// We take the size from the first object we see.
|
|||
if (this->get_size() == 0) |
|||
this->set_size(size); |
|||
|
|||
if (size != this->get_size() || size != object->target()->get_size()) |
|||
{ |
|||
fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"), |
|||
program_name, object->name().c_str()); |
|||
gold_exit(false); |
|||
} |
|||
|
|||
const unsigned char* p = reinterpret_cast<const unsigned char*>(syms); |
|||
for (size_t i = 0; i < count; ++i) |
|||
{ |
|||
elfcpp::Sym<size, big_endian> sym(p); |
|||
|
|||
unsigned int st_name = sym.get_st_name(); |
|||
if (st_name >= sym_name_size) |
|||
{ |
|||
fprintf(stderr, _("%s: %s: bad symbol name offset %u at %lu\n"), |
|||
program_name, object->name().c_str(), st_name, |
|||
static_cast<unsigned long>(i)); |
|||
gold_exit(false); |
|||
} |
|||
|
|||
const char* name = sym_names + st_name; |
|||
|
|||
// In an object file, an '@' in the name separates the symbol
|
|||
// name from the version name. If there are two '@' characters,
|
|||
// this is the default version.
|
|||
const char* ver = strchr(name, '@'); |
|||
|
|||
Symbol* res; |
|||
if (ver == NULL) |
|||
{ |
|||
name = this->namepool_.add(name); |
|||
res = this->add_from_object(object, name, NULL, false, sym); |
|||
} |
|||
else |
|||
{ |
|||
name = this->namepool_.add(name, ver - name); |
|||
bool def = false; |
|||
++ver; |
|||
if (*ver == '@') |
|||
{ |
|||
def = true; |
|||
++ver; |
|||
} |
|||
ver = this->namepool_.add(ver); |
|||
res = this->add_from_object(object, name, ver, def, sym); |
|||
} |
|||
|
|||
*sympointers++ = res; |
|||
|
|||
p += elfcpp::Elf_sizes<size>::sym_size; |
|||
} |
|||
} |
|||
|
|||
// Instantiate the templates we need. We could use the configure
|
|||
// script to restrict this to only the ones needed for implemented
|
|||
// targets.
|
|||
|
|||
template |
|||
void |
|||
Symbol_table::add_from_object<32, true>( |
|||
Sized_object<32, true>* object, |
|||
const elfcpp::Sym<32, true>* syms, |
|||
size_t count, |
|||
const char* sym_names, |
|||
size_t sym_name_size, |
|||
Symbol** sympointers); |
|||
|
|||
template |
|||
void |
|||
Symbol_table::add_from_object<32, false>( |
|||
Sized_object<32, false>* object, |
|||
const elfcpp::Sym<32, false>* syms, |
|||
size_t count, |
|||
const char* sym_names, |
|||
size_t sym_name_size, |
|||
Symbol** sympointers); |
|||
|
|||
template |
|||
void |
|||
Symbol_table::add_from_object<64, true>( |
|||
Sized_object<64, true>* object, |
|||
const elfcpp::Sym<64, true>* syms, |
|||
size_t count, |
|||
const char* sym_names, |
|||
size_t sym_name_size, |
|||
Symbol** sympointers); |
|||
|
|||
template |
|||
void |
|||
Symbol_table::add_from_object<64, false>( |
|||
Sized_object<64, false>* object, |
|||
const elfcpp::Sym<64, false>* syms, |
|||
size_t count, |
|||
const char* sym_names, |
|||
size_t sym_name_size, |
|||
Symbol** sympointers); |
|||
|
|||
} // End namespace gold.
|
|||
@ -0,0 +1,52 @@ |
|||
// target-select.cc -- select a target for an object file
|
|||
|
|||
#include "gold.h" |
|||
|
|||
#include "elfcpp.h" |
|||
#include "target-select.h" |
|||
|
|||
namespace |
|||
{ |
|||
|
|||
// The start of the list of target selectors.
|
|||
|
|||
gold::Target_selector* target_selectors; |
|||
|
|||
} // End anonymous namespace.
|
|||
|
|||
namespace gold |
|||
{ |
|||
|
|||
// Construct a Target_selector, which means adding it to the linked
|
|||
// list. This runs at global constructor time, so we want it to be
|
|||
// fast.
|
|||
|
|||
Target_selector::Target_selector(int machine, int size, bool big_endian) |
|||
: machine_(machine), size_(size), big_endian_(big_endian) |
|||
{ |
|||
this->next_ = target_selectors; |
|||
target_selectors = this; |
|||
} |
|||
|
|||
// Find the target for an ELF file.
|
|||
|
|||
extern Target* |
|||
select_target(int machine, int size, bool big_endian, int osabi, |
|||
int abiversion) |
|||
{ |
|||
for (const Target_selector* p = target_selectors; p != NULL; p = p->next()) |
|||
{ |
|||
int pmach = p->machine(); |
|||
if ((pmach == machine || pmach == elfcpp::EM_NONE) |
|||
&& p->size() == size |
|||
&& p->big_endian() ? big_endian : !big_endian) |
|||
{ |
|||
Target* ret = p->recognize(machine, osabi, abiversion); |
|||
if (ret != NULL) |
|||
return ret; |
|||
} |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
} // End namespace gold.
|
|||
@ -0,0 +1,69 @@ |
|||
// target-select.h -- select a target for an object file -*- C++ -*-
|
|||
|
|||
#ifndef GOLD_TARGET_SELECT_H |
|||
#define GOLD_TARGET_SELECT_H |
|||
|
|||
namespace gold |
|||
{ |
|||
|
|||
class Target; |
|||
|
|||
// We want to avoid a master list of targets, which implies using a
|
|||
// global constructor. And we also want the program to start up as
|
|||
// quickly as possible, which implies avoiding global constructors.
|
|||
// We compromise on a very simple global constructor. We use a target
|
|||
// selector, which specifies an ELF machine number and a recognition
|
|||
// function. We use global constructors to build a linked list of
|
|||
// target selectors--a simple pointer list, not a std::list.
|
|||
|
|||
class Target_selector |
|||
{ |
|||
public: |
|||
// Create a target selector for a specific machine number, size (32
|
|||
// or 64), and endianness. The machine number can be EM_NONE to
|
|||
// test for any machine number.
|
|||
Target_selector(int machine, int size, bool big_endian); |
|||
|
|||
virtual ~Target_selector() |
|||
{ } |
|||
|
|||
// If we can handle this target, return a pointer to a target
|
|||
// structure. The size and endianness are known.
|
|||
virtual Target* recognize(int machine, int osabi, int abiversion) const = 0; |
|||
|
|||
// Return the next Target_selector in the linked list.
|
|||
Target_selector* |
|||
next() const |
|||
{ return this->next_; } |
|||
|
|||
// Return the machine number this selector is looking for, which can
|
|||
// be EM_NONE to match any machine number.
|
|||
int |
|||
machine() const |
|||
{ return this->machine_; } |
|||
|
|||
// Return the size this is looking for (32 or 64).
|
|||
int |
|||
size() const |
|||
{ return this->size_; } |
|||
|
|||
// Return the endianness this is looking for.
|
|||
bool |
|||
big_endian() const |
|||
{ return this->big_endian_; } |
|||
|
|||
private: |
|||
int machine_; |
|||
int size_; |
|||
bool big_endian_; |
|||
Target_selector* next_; |
|||
}; |
|||
|
|||
// Select the target for an ELF file.
|
|||
|
|||
extern Target* select_target(int machine, int size, bool big_endian, |
|||
int osabi, int abiversion); |
|||
|
|||
} // End namespace gold.
|
|||
|
|||
#endif // !defined(GOLD_TARGET_SELECT_H)
|
|||
Loading…
Reference in new issue