Hash tables, dynamic section, i386 PLT, gold_assert.

This commit is contained in:
Ian Lance Taylor 2006-11-29 17:56:40 +00:00
parent e1da3f5b96
commit a3ad94edd4
33 changed files with 2287 additions and 631 deletions

View File

@ -1304,6 +1304,32 @@ class Dyn
const internal::Dyn_data<size>* p_;
};
// Write class for an entry in the SHT_DYNAMIC section.
template<int size, bool big_endian>
class Dyn_write
{
public:
Dyn_write(unsigned char* p)
: p_(reinterpret_cast<internal::Dyn_data<size>*>(p))
{ }
void
put_d_tag(typename Elf_types<size>::Elf_Swxword v)
{ this->p_->d_tag = Convert<size, big_endian>::convert_host(v); }
void
put_d_val(typename Elf_types<size>::Elf_WXword v)
{ this->p_->d_val = Convert<size, big_endian>::convert_host(v); }
void
put_d_ptr(typename Elf_types<size>::Elf_Addr v)
{ this->p_->d_val = Convert<size, big_endian>::convert_host(v); }
private:
internal::Dyn_data<size>* p_;
};
// Accessor classes for entries in the ELF SHT_GNU_verdef section.
template<int size, bool big_endian>

View File

@ -102,6 +102,10 @@ class Elf_file
typename File::Location
section_contents(unsigned int shndx);
// Return the flags of section SHNDX.
typename Elf_types<size>::Elf_WXword
section_flags(unsigned int shndx);
private:
// Shared constructor code.
void
@ -250,6 +254,25 @@ Elf_file<size, big_endian, File>::section_contents(unsigned int shndx)
return typename File::Location(shdr.get_sh_offset(), shdr.get_sh_size());
}
// Return the section flags of section SHNDX.
template<int size, bool big_endian, typename File>
typename Elf_types<size>::Elf_WXword
Elf_file<size, big_endian, File>::section_flags(unsigned int shndx)
{
File* const file = this->file_;
if (shndx >= this->shnum())
file->error(_("section_flags: bad shndx %u >= %u"),
shndx, this->shnum());
typename File::View v(file->view(this->section_header_offset(shndx),
This::shdr_size));
Ef_shdr shdr(v.data());
return shdr.get_sh_flags();
}
} // End namespace elfcpp.
#endif // !defined(ELFCPP_FILE_H)

View File

@ -180,9 +180,9 @@ struct Swap<8, big_endian>
// Swap_unaligned is a template based on size and on whether the
// target is big endian. It defines the type Valtype and the
// functions readval_unaligned and writeval_unaligned. The functions
// read and write values of the appropriate size out of buffers which
// may be misaligned.
// functions readval and writeval. The functions read and write
// values of the appropriate size out of buffers which may be
// misaligned.
template<int size, bool big_endian>
struct Swap_unaligned;
@ -193,11 +193,11 @@ struct Swap_unaligned<8, big_endian>
typedef typename Valtype_base<8>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
readval(const unsigned char* wv)
{ return *wv; }
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
writeval(unsigned char* wv, Valtype v)
{ *wv = v; }
};
@ -207,13 +207,13 @@ struct Swap_unaligned<16, false>
typedef Valtype_base<16>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
readval(const unsigned char* wv)
{
return (wv[1] << 8) | wv[0];
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
writeval(unsigned char* wv, Valtype v)
{
wv[1] = v >> 8;
wv[0] = v;
@ -226,13 +226,13 @@ struct Swap_unaligned<16, true>
typedef Valtype_base<16>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
readval(const unsigned char* wv)
{
return (wv[0] << 8) | wv[1];
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
writeval(unsigned char* wv, Valtype v)
{
wv[0] = v >> 8;
wv[1] = v;
@ -245,13 +245,13 @@ struct Swap_unaligned<32, false>
typedef Valtype_base<32>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
readval(const unsigned char* wv)
{
return (wv[3] << 24) | (wv[2] << 16) | (wv[1] << 8) | wv[0];
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
writeval(unsigned char* wv, Valtype v)
{
wv[3] = v >> 24;
wv[2] = v >> 16;
@ -266,13 +266,13 @@ struct Swap_unaligned<32, true>
typedef Valtype_base<32>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
readval(const unsigned char* wv)
{
return (wv[0] << 24) | (wv[1] << 16) | (wv[2] << 8) | wv[3];
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
writeval(unsigned char* wv, Valtype v)
{
wv[0] = v >> 24;
wv[1] = v >> 16;
@ -287,7 +287,7 @@ struct Swap_unaligned<64, false>
typedef Valtype_base<64>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
readval(const unsigned char* wv)
{
return ((static_cast<Valtype>(wv[7]) << 56)
| (static_cast<Valtype>(wv[6]) << 48)
@ -300,7 +300,7 @@ struct Swap_unaligned<64, false>
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
writeval(unsigned char* wv, Valtype v)
{
wv[7] = v >> 56;
wv[6] = v >> 48;
@ -319,7 +319,7 @@ struct Swap_unaligned<64, true>
typedef Valtype_base<64>::Valtype Valtype;
static inline Valtype
readval_unaligned(const unsigned char* wv)
readval(const unsigned char* wv)
{
return ((static_cast<Valtype>(wv[0]) << 56)
| (static_cast<Valtype>(wv[1]) << 48)
@ -332,7 +332,7 @@ struct Swap_unaligned<64, true>
}
static inline void
writeval_unaligned(unsigned char* wv, Valtype v)
writeval(unsigned char* wv, Valtype v)
{
wv[7] = v >> 56;
wv[6] = v >> 48;

View File

@ -120,7 +120,7 @@ Symbol_table::allocate_commons(const General_options& options, Layout* layout)
else if (this->get_size() == 64)
this->do_allocate_commons<64>(options, layout);
else
abort();
gold_unreachable();
}
// Allocated the common symbols, sized version.
@ -171,7 +171,7 @@ Symbol_table::do_allocate_commons(const General_options&,
// Place them in a newly allocated .bss section.
Output_data_common *poc = new Output_data_common(addralign);
Output_data_space *poc = new Output_data_space(addralign);
layout->add_output_section_data(".bss", elfcpp::SHT_NOBITS,
elfcpp::SHF_WRITE | elfcpp::SHF_ALLOC,
@ -202,7 +202,7 @@ Symbol_table::do_allocate_commons(const General_options&,
off += symsize;
}
poc->set_common_size(off);
poc->set_space_size(off);
this->commons_.clear();
}

View File

@ -3,7 +3,6 @@
#include "gold.h"
#include <cerrno>
#include <cassert>
#include <sys/types.h>
#include <dirent.h>
@ -125,7 +124,7 @@ Dir_caches::add(const char* dirname)
std::pair<const char*, Dir_cache*> v(dirname, cache);
std::pair<Cache_hash::iterator, bool> p = this->caches_.insert(v);
assert(p.second);
gold_assert(p.second);
}
}
@ -217,14 +216,14 @@ Dirsearch::add(Workqueue* workqueue, const General_options::Dir_list& list)
std::string
Dirsearch::find(const std::string& n1, const std::string& n2) const
{
assert(!this->token_.is_blocked());
gold_assert(!this->token_.is_blocked());
for (std::list<const char*>::const_iterator p = this->directories_.begin();
p != this->directories_.end();
++p)
{
Dir_cache* pdc = caches.lookup(*p);
assert(pdc != NULL);
gold_assert(pdc != NULL);
if (pdc->find(n1))
return std::string(*p) + '/' + n1;
if (!n2.empty() && pdc->find(n2))

View File

@ -5,12 +5,25 @@
#include <vector>
#include <cstring>
#include "elfcpp.h"
#include "symtab.h"
#include "dynobj.h"
namespace gold
{
// Class Dynobj.
// Return the string to use in a DT_NEEDED entry.
const char*
Dynobj::soname() const
{
if (!this->soname_.empty())
return this->soname_.c_str();
return this->name().c_str();
}
// Class Sized_dynobj.
template<int size, bool big_endian>
@ -20,8 +33,7 @@ Sized_dynobj<size, big_endian>::Sized_dynobj(
off_t offset,
const elfcpp::Ehdr<size, big_endian>& ehdr)
: Dynobj(name, input_file, offset),
elf_file_(this, ehdr),
soname_()
elf_file_(this, ehdr)
{
}
@ -130,7 +142,7 @@ Sized_dynobj<size, big_endian>::read_dynsym_section(
typename This::Shdr shdr(pshdrs + shndx * This::shdr_size);
assert(shdr.get_sh_type() == type);
gold_assert(shdr.get_sh_type() == type);
if (shdr.get_sh_link() != link)
{
@ -146,11 +158,11 @@ Sized_dynobj<size, big_endian>::read_dynsym_section(
*view_info = shdr.get_sh_info();
}
// Set soname_ if this shared object has a DT_SONAME tag. PSHDRS
// points to the section headers. DYNAMIC_SHNDX is the section index
// of the SHT_DYNAMIC section. STRTAB_SHNDX, STRTAB, and STRTAB_SIZE
// are the section index and contents of a string table which may be
// the one associated with the SHT_DYNAMIC section.
// Set the soname field if this shared object has a DT_SONAME tag.
// PSHDRS points to the section headers. DYNAMIC_SHNDX is the section
// index of the SHT_DYNAMIC section. STRTAB_SHNDX, STRTAB, and
// STRTAB_SIZE are the section index and contents of a string table
// which may be the one associated with the SHT_DYNAMIC section.
template<int size, bool big_endian>
void
@ -161,7 +173,7 @@ Sized_dynobj<size, big_endian>::set_soname(const unsigned char* pshdrs,
off_t strtab_size)
{
typename This::Shdr dynamicshdr(pshdrs + dynamic_shndx * This::shdr_size);
assert(dynamicshdr.get_sh_type() == elfcpp::SHT_DYNAMIC);
gold_assert(dynamicshdr.get_sh_type() == elfcpp::SHT_DYNAMIC);
const off_t dynamic_size = dynamicshdr.get_sh_size();
const unsigned char* pdynamic = this->get_view(dynamicshdr.get_sh_offset(),
@ -214,7 +226,7 @@ Sized_dynobj<size, big_endian>::set_soname(const unsigned char* pshdrs,
}
const char* strtab = reinterpret_cast<const char*>(strtabu);
this->soname_ = std::string(strtab + val);
this->set_soname_string(strtab + val);
return;
}
@ -259,7 +271,7 @@ Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
{
// Get the dynamic symbols.
typename This::Shdr dynsymshdr(pshdrs + dynsym_shndx * This::shdr_size);
assert(dynsymshdr.get_sh_type() == elfcpp::SHT_DYNSYM);
gold_assert(dynsymshdr.get_sh_type() == elfcpp::SHT_DYNSYM);
sd->symbols = this->get_lasting_view(dynsymshdr.get_sh_offset(),
dynsymshdr.get_sh_size());
@ -380,7 +392,7 @@ Sized_dynobj<size, big_endian>::set_version_map(
unsigned int ndx,
const char* name) const
{
assert(ndx < version_map->size());
gold_assert(ndx < version_map->size());
if ((*version_map)[ndx] != NULL)
{
fprintf(stderr, _("%s: %s: duplicate definition for version %u\n"),
@ -602,8 +614,9 @@ Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
{
if (sd->symbols == NULL)
{
assert(sd->symbol_names == NULL);
assert(sd->versym == NULL && sd->verdef == NULL && sd->verneed == NULL);
gold_assert(sd->symbol_names == NULL);
gold_assert(sd->versym == NULL && sd->verdef == NULL
&& sd->verneed == NULL);
return;
}
@ -652,6 +665,400 @@ Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
}
}
// Given a vector of hash codes, compute the number of hash buckets to
// use.
unsigned int
Dynobj::compute_bucket_count(const std::vector<uint32_t>& hashcodes,
bool for_gnu_hash_table)
{
// FIXME: Implement optional hash table optimization.
// Array used to determine the number of hash table buckets to use
// based on the number of symbols there are. If there are fewer
// than 3 symbols we use 1 bucket, fewer than 17 symbols we use 3
// buckets, fewer than 37 we use 17 buckets, and so forth. We never
// use more than 32771 buckets. This is straight from the old GNU
// linker.
static const unsigned int buckets[] =
{
1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
16411, 32771
};
const int buckets_count = sizeof buckets / sizeof buckets[0];
unsigned int symcount = hashcodes.size();
unsigned int ret = 1;
for (int i = 0; i < buckets_count; ++i)
{
if (symcount < buckets[i])
break;
ret = buckets[i];
}
if (for_gnu_hash_table && ret < 2)
ret = 2;
return ret;
}
// The standard ELF hash function. This hash function must not
// change, as the dynamic linker uses it also.
uint32_t
Dynobj::elf_hash(const char* name)
{
const unsigned char* nameu = reinterpret_cast<const unsigned char*>(name);
uint32_t h = 0;
unsigned char c;
while ((c = *nameu++) != '\0')
{
h = (h << 4) + c;
uint32_t g = h & 0xf0000000;
if (g != 0)
{
h ^= g >> 24;
// The ELF ABI says h &= ~g, but using xor is equivalent in
// this case (since g was set from h) and may save one
// instruction.
h ^= g;
}
}
return h;
}
// Create a standard ELF hash table, setting *PPHASH and *PHASHLEN.
// DYNSYMS is a vector with all the global dynamic symbols.
// LOCAL_DYNSYM_COUNT is the number of local symbols in the dynamic
// symbol table.
void
Dynobj::create_elf_hash_table(const Target* target,
const std::vector<Symbol*>& dynsyms,
unsigned int local_dynsym_count,
unsigned char** pphash,
unsigned int* phashlen)
{
unsigned int dynsym_count = dynsyms.size();
// Get the hash values for all the symbols.
std::vector<uint32_t> dynsym_hashvals(dynsym_count);
for (unsigned int i = 0; i < dynsym_count; ++i)
dynsym_hashvals[i] = Dynobj::elf_hash(dynsyms[i]->name());
const unsigned int bucketcount =
Dynobj::compute_bucket_count(dynsym_hashvals, false);
std::vector<uint32_t> bucket(bucketcount);
std::vector<uint32_t> chain(local_dynsym_count + dynsym_count);
for (unsigned int i = 0; i < dynsym_count; ++i)
{
unsigned int dynsym_index = dynsyms[i]->dynsym_index();
unsigned int bucketpos = dynsym_hashvals[i] % bucketcount;
chain[dynsym_index] = bucket[bucketpos];
bucket[bucketpos] = dynsym_index;
}
unsigned int hashlen = ((2
+ bucketcount
+ local_dynsym_count
+ dynsym_count)
* 4);
unsigned char* phash = new unsigned char[hashlen];
if (target->is_big_endian())
Dynobj::sized_create_elf_hash_table<true>(bucket, chain, phash, hashlen);
else
Dynobj::sized_create_elf_hash_table<false>(bucket, chain, phash, hashlen);
*pphash = phash;
*phashlen = hashlen;
}
// Fill in an ELF hash table.
template<bool big_endian>
void
Dynobj::sized_create_elf_hash_table(const std::vector<uint32_t>& bucket,
const std::vector<uint32_t>& chain,
unsigned char* phash,
unsigned int hashlen)
{
unsigned char* p = phash;
const unsigned int bucketcount = bucket.size();
const unsigned int chaincount = chain.size();
elfcpp::Swap<32, big_endian>::writeval(p, bucketcount);
p += 4;
elfcpp::Swap<32, big_endian>::writeval(p, chaincount);
p += 4;
for (unsigned int i = 0; i < bucketcount; ++i)
{
elfcpp::Swap<32, big_endian>::writeval(p, bucket[i]);
p += 4;
}
for (unsigned int i = 0; i < chaincount; ++i)
{
elfcpp::Swap<32, big_endian>::writeval(p, chain[i]);
p += 4;
}
gold_assert(static_cast<unsigned int>(p - phash) == hashlen);
}
// The hash function used for the GNU hash table. This hash function
// must not change, as the dynamic linker uses it also.
uint32_t
Dynobj::gnu_hash(const char* name)
{
const unsigned char* nameu = reinterpret_cast<const unsigned char*>(name);
uint32_t h = 5381;
unsigned char c;
while ((c = *nameu++) != '\0')
h = (h << 5) + h + c;
return h;
}
// Create a GNU hash table, setting *PPHASH and *PHASHLEN. GNU hash
// tables are an extension to ELF which are recognized by the GNU
// dynamic linker. They are referenced using dynamic tag DT_GNU_HASH.
// TARGET is the target. DYNSYMS is a vector with all the global
// symbols which will be going into the dynamic symbol table.
// LOCAL_DYNSYM_COUNT is the number of local symbols in the dynamic
// symbol table.
void
Dynobj::create_gnu_hash_table(const Target* target,
const std::vector<Symbol*>& dynsyms,
unsigned int local_dynsym_count,
unsigned char** pphash,
unsigned int* phashlen)
{
const unsigned int count = dynsyms.size();
// Sort the dynamic symbols into two vectors. Symbols which we do
// not want to put into the hash table we store into
// UNHASHED_DYNSYMS. Symbols which we do want to store we put into
// HASHED_DYNSYMS. DYNSYM_HASHVALS is parallel to HASHED_DYNSYMS,
// and records the hash codes.
std::vector<Symbol*> unhashed_dynsyms;
unhashed_dynsyms.reserve(count);
std::vector<Symbol*> hashed_dynsyms;
hashed_dynsyms.reserve(count);
std::vector<uint32_t> dynsym_hashvals;
dynsym_hashvals.reserve(count);
for (unsigned int i = 0; i < count; ++i)
{
Symbol* sym = dynsyms[i];
// FIXME: Should put on unhashed_dynsyms if the symbol is
// hidden.
if (sym->is_undefined())
unhashed_dynsyms.push_back(sym);
else
{
hashed_dynsyms.push_back(sym);
dynsym_hashvals.push_back(Dynobj::gnu_hash(sym->name()));
}
}
// Put the unhashed symbols at the start of the global portion of
// the dynamic symbol table.
const unsigned int unhashed_count = unhashed_dynsyms.size();
unsigned int unhashed_dynsym_index = local_dynsym_count;
for (unsigned int i = 0; i < unhashed_count; ++i)
{
unhashed_dynsyms[i]->set_dynsym_index(unhashed_dynsym_index);
++unhashed_dynsym_index;
}
// For the actual data generation we call out to a templatized
// function.
int size = target->get_size();
bool big_endian = target->is_big_endian();
if (size == 32)
{
if (big_endian)
Dynobj::sized_create_gnu_hash_table<32, true>(hashed_dynsyms,
dynsym_hashvals,
unhashed_dynsym_index,
pphash,
phashlen);
else
Dynobj::sized_create_gnu_hash_table<32, false>(hashed_dynsyms,
dynsym_hashvals,
unhashed_dynsym_index,
pphash,
phashlen);
}
else if (size == 64)
{
if (big_endian)
Dynobj::sized_create_gnu_hash_table<64, true>(hashed_dynsyms,
dynsym_hashvals,
unhashed_dynsym_index,
pphash,
phashlen);
else
Dynobj::sized_create_gnu_hash_table<64, false>(hashed_dynsyms,
dynsym_hashvals,
unhashed_dynsym_index,
pphash,
phashlen);
}
else
gold_unreachable();
}
// Create the actual data for a GNU hash table. This is just a copy
// of the code from the old GNU linker.
template<int size, bool big_endian>
void
Dynobj::sized_create_gnu_hash_table(
const std::vector<Symbol*>& hashed_dynsyms,
const std::vector<uint32_t>& dynsym_hashvals,
unsigned int unhashed_dynsym_count,
unsigned char** pphash,
unsigned int* phashlen)
{
if (hashed_dynsyms.empty())
{
// Special case for the empty hash table.
unsigned int hashlen = 5 * 4 + size / 8;
unsigned char* phash = new unsigned char[hashlen];
// One empty bucket.
elfcpp::Swap<32, big_endian>::writeval(phash, 1);
// Symbol index above unhashed symbols.
elfcpp::Swap<32, big_endian>::writeval(phash + 4, unhashed_dynsym_count);
// One word for bitmask.
elfcpp::Swap<32, big_endian>::writeval(phash + 8, 1);
// Only bloom filter.
elfcpp::Swap<32, big_endian>::writeval(phash + 12, 0);
// No valid hashes.
elfcpp::Swap<size, big_endian>::writeval(phash + 16, 0);
// No hashes in only bucket.
elfcpp::Swap<32, big_endian>::writeval(phash + 16 + size / 8, 0);
*phashlen = hashlen;
*pphash = phash;
return;
}
const unsigned int bucketcount =
Dynobj::compute_bucket_count(dynsym_hashvals, true);
const unsigned int nsyms = hashed_dynsyms.size();
uint32_t maskbitslog2 = 1;
uint32_t x = nsyms >> 1;
while (x != 0)
{
++maskbitslog2;
x >>= 1;
}
if (maskbitslog2 < 3)
maskbitslog2 = 5;
else if (((1U << (maskbitslog2 - 2)) & nsyms) != 0)
maskbitslog2 += 3;
else
maskbitslog2 += 2;
uint32_t shift1;
if (size == 32)
shift1 = 5;
else
{
if (maskbitslog2 == 5)
maskbitslog2 = 6;
shift1 = 6;
}
uint32_t mask = (1U << shift1) - 1U;
uint32_t shift2 = maskbitslog2;
uint32_t maskbits = 1U << maskbitslog2;
uint32_t maskwords = 1U << (maskbitslog2 - shift1);
typedef typename elfcpp::Elf_types<size>::Elf_WXword Word;
std::vector<Word> bitmask(maskwords);
std::vector<uint32_t> counts(bucketcount);
std::vector<uint32_t> indx(bucketcount);
uint32_t symindx = unhashed_dynsym_count;
// Count the number of times each hash bucket is used.
for (unsigned int i = 0; i < nsyms; ++i)
++counts[dynsym_hashvals[i] % bucketcount];
unsigned int cnt = symindx;
for (unsigned int i = 0; i < bucketcount; ++i)
{
indx[i] = cnt;
cnt += counts[i];
}
unsigned int hashlen = (4 + bucketcount + nsyms) * 4;
hashlen += maskbits / 8;
unsigned char* phash = new unsigned char[hashlen];
elfcpp::Swap<32, big_endian>::writeval(phash, bucketcount);
elfcpp::Swap<32, big_endian>::writeval(phash + 4, symindx);
elfcpp::Swap<32, big_endian>::writeval(phash + 8, maskwords);
elfcpp::Swap<32, big_endian>::writeval(phash + 12, shift2);
unsigned char* p = phash + 16 + maskbits / 8;
for (unsigned int i = 0; i < bucketcount; ++i)
{
if (counts[i] == 0)
elfcpp::Swap<32, big_endian>::writeval(p, 0);
else
elfcpp::Swap<32, big_endian>::writeval(p, indx[i]);
p += 4;
}
for (unsigned int i = 0; i < nsyms; ++i)
{
Symbol* sym = hashed_dynsyms[i];
uint32_t hashval = dynsym_hashvals[i];
unsigned int bucket = hashval % bucketcount;
unsigned int val = ((hashval >> shift1)
& ((maskbits >> shift1) - 1));
bitmask[val] |= (static_cast<Word>(1U)) << (hashval & mask);
bitmask[val] |= (static_cast<Word>(1U)) << ((hashval >> shift2) & mask);
val = hashval & ~ 1U;
if (counts[bucket] == 1)
{
// Last element terminates the chain.
val |= 1;
}
elfcpp::Swap<32, big_endian>::writeval(p + (indx[bucket] - symindx) * 4,
val);
--counts[bucket];
sym->set_dynsym_index(indx[bucket]);
++indx[bucket];
}
p = phash + 16;
for (unsigned int i = 0; i < maskwords; ++i)
{
elfcpp::Swap<size, big_endian>::writeval(p, bitmask[i]);
p += size / 8;
}
*phashlen = hashlen;
*pphash = phash;
}
// Instantiate the templates we need. We could use the configure
// script to restrict this to only the ones for implemented targets.

View File

@ -17,8 +17,71 @@ class Dynobj : public Object
{
public:
Dynobj(const std::string& name, Input_file* input_file, off_t offset = 0)
: Object(name, input_file, true, offset)
: Object(name, input_file, true, offset), soname_()
{ }
// Return the name to use in a DT_NEEDED entry for this object.
const char*
soname() const;
// Create a standard ELF hash table, setting *PPHASH and *PHASHLEN.
// DYNSYMS is the global dynamic symbols. LOCAL_DYNSYM_COUNT is the
// number of local dynamic symbols, which is the index of the first
// dynamic gobal symbol.
static void
create_elf_hash_table(const Target*, const std::vector<Symbol*>& dynsyms,
unsigned int local_dynsym_count,
unsigned char** pphash,
unsigned int* phashlen);
// Create a GNU hash table, setting *PPHASH and *PHASHLEN. DYNSYMS
// is the global dynamic symbols. LOCAL_DYNSYM_COUNT is the number
// of local dynamic symbols, which is the index of the first dynamic
// gobal symbol.
static void
create_gnu_hash_table(const Target*, const std::vector<Symbol*>& dynsyms,
unsigned int local_dynsym_count,
unsigned char** pphash, unsigned int* phashlen);
protected:
// Set the DT_SONAME string.
void
set_soname_string(const char* s)
{ this->soname_.assign(s); }
private:
// Compute the ELF hash code for a string.
static uint32_t
elf_hash(const char*);
// Compute the GNU hash code for a string.
static uint32_t
gnu_hash(const char*);
// Compute the number of hash buckets to use.
static unsigned int
compute_bucket_count(const std::vector<uint32_t>& hashcodes,
bool for_gnu_hash_table);
// Sized version of create_elf_hash_table.
template<bool big_endian>
static void
sized_create_elf_hash_table(const std::vector<uint32_t>& bucket,
const std::vector<uint32_t>& chain,
unsigned char* phash,
unsigned int hashlen);
// Sized version of create_gnu_hash_table.
template<int size, bool big_endian>
static void
sized_create_gnu_hash_table(const std::vector<Symbol*>& hashed_dynsyms,
const std::vector<uint32_t>& dynsym_hashvals,
unsigned int unhashed_dynsym_count,
unsigned char** pphash,
unsigned int* phashlen);
// The DT_SONAME name, if any.
std::string soname_;
};
// A dynamic object, size and endian specific version.
@ -58,6 +121,11 @@ class Sized_dynobj : public Dynobj
do_section_contents(unsigned int shndx)
{ return this->elf_file_.section_contents(shndx); }
// Return section flags.
uint64_t
do_section_flags(unsigned int shndx)
{ return this->elf_file_.section_flags(shndx); }
private:
// For convenience.
typedef Sized_dynobj<size, big_endian> This;
@ -104,8 +172,6 @@ class Sized_dynobj : public Dynobj
// General access to the ELF file.
elfcpp::Elf_file<size, big_endian, Object> elf_file_;
// The DT_SONAME name, if any.
std::string soname_;
};
} // End namespace gold.

View File

@ -2,7 +2,6 @@
#include "gold.h"
#include <cassert>
#include <cstring>
#include <cerrno>
#include <fcntl.h>
@ -19,7 +18,7 @@ namespace gold
File_read::View::~View()
{
assert(!this->is_locked());
gold_assert(!this->is_locked());
delete[] this->data_;
}
@ -32,7 +31,7 @@ File_read::View::lock()
void
File_read::View::unlock()
{
assert(this->lock_count_ > 0);
gold_assert(this->lock_count_ > 0);
--this->lock_count_;
}
@ -49,7 +48,7 @@ File_read::View::is_locked()
File_read::~File_read()
{
assert(this->lock_count_ == 0);
gold_assert(this->lock_count_ == 0);
if (this->descriptor_ >= 0)
{
if (close(this->descriptor_) < 0)
@ -64,9 +63,9 @@ File_read::~File_read()
bool
File_read::open(const std::string& name)
{
assert(this->lock_count_ == 0
&& this->descriptor_ < 0
&& this->name_.empty());
gold_assert(this->lock_count_ == 0
&& this->descriptor_ < 0
&& this->name_.empty());
this->name_ = name;
this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY);
++this->lock_count_;
@ -76,7 +75,7 @@ File_read::open(const std::string& name)
int
File_read::get_descriptor()
{
assert(this->lock_count_ > 0);
gold_assert(this->lock_count_ > 0);
return this->descriptor_;
}
@ -89,7 +88,7 @@ File_read::lock()
void
File_read::unlock()
{
assert(this->lock_count_ > 0);
gold_assert(this->lock_count_ > 0);
--this->lock_count_;
}
@ -121,7 +120,7 @@ File_read::find_view(off_t start, off_t size)
off_t
File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes)
{
assert(this->lock_count_ > 0);
gold_assert(this->lock_count_ > 0);
int o = this->descriptor_;
if (lseek(o, start, SEEK_SET) < 0)
@ -161,7 +160,7 @@ File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes)
void
File_read::read(off_t start, off_t size, void* p, off_t* pbytes)
{
assert(this->lock_count_ > 0);
gold_assert(this->lock_count_ > 0);
File_read::View* pv = this->find_view(start, size);
if (pv != NULL)
@ -180,7 +179,7 @@ File_read::read(off_t start, off_t size, void* p, off_t* pbytes)
File_read::View*
File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
{
assert(this->lock_count_ > 0);
gold_assert(this->lock_count_ > 0);
off_t poff = File_read::page_offset(start);
@ -244,7 +243,7 @@ File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes)
const unsigned char*
File_read::get_view(off_t start, off_t size, off_t* pbytes)
{
assert(this->lock_count_ > 0);
gold_assert(this->lock_count_ > 0);
File_read::View* pv = this->find_or_make_view(start, size, pbytes);
return pv->data() + (start - pv->start());
}
@ -252,7 +251,7 @@ File_read::get_view(off_t start, off_t size, off_t* pbytes)
File_view*
File_read::get_lasting_view(off_t start, off_t size, off_t* pbytes)
{
assert(this->lock_count_ > 0);
gold_assert(this->lock_count_ > 0);
File_read::View* pv = this->find_or_make_view(start, size, pbytes);
pv->lock();
return new File_view(*this, pv, pv->data() + (start - pv->start()));
@ -271,7 +270,7 @@ File_read::clear_views(bool destroying)
delete p->second;
else
{
assert(!destroying);
gold_assert(!destroying);
this->saved_views_.push_back(p->second);
}
}
@ -287,7 +286,7 @@ File_read::clear_views(bool destroying)
}
else
{
assert(!destroying);
gold_assert(!destroying);
++p;
}
}
@ -297,7 +296,7 @@ File_read::clear_views(bool destroying)
File_view::~File_view()
{
assert(this->file_.is_locked());
gold_assert(this->file_.is_locked());
this->view_->unlock();
}

View File

@ -1,7 +1,5 @@
// gold-threads.cc -- thread support for gold
#include <cassert>
#include "gold.h"
#ifdef ENABLE_THREADS
@ -87,20 +85,20 @@ Lock_impl::Lock_impl()
Lock_impl::~Lock_impl()
{
assert(!this->acquired_);
gold_assert(!this->acquired_);
}
void
Lock_impl::acquire()
{
assert(!this->acquired_);
gold_assert(!this->acquired_);
this->acquired_ = true;
}
void
Lock_impl::release()
{
assert(this->acquired_);
gold_assert(this->acquired_);
this->acquired_ = false;
}
@ -192,7 +190,7 @@ Condvar_impl::~Condvar_impl()
void
Condvar_impl::wait(Lock_impl* li)
{
assert(li->acquired_);
gold_assert(li->acquired_);
}
void

View File

@ -52,10 +52,14 @@ gold_nomem()
gold_exit(false);
}
// Handle an unreachable case.
void
gold_unreachable()
do_gold_unreachable(const char* filename, int lineno, const char* function)
{
abort();
fprintf(stderr, "%s: internal error in %s, at %s:%d\n",
program_name, function, filename, lineno);
gold_exit(false);
}
// This class arranges to run the functions done in the middle of the
@ -136,6 +140,10 @@ queue_middle_tasks(const General_options& options,
Layout* layout,
Workqueue* workqueue)
{
// Define some sections and symbols needed for a dynamic link. This
// handles some cases we want to see before we read the relocs.
layout->create_initial_dynamic_sections(input_objects, symtab);
// Predefine standard symbols. This should be fast, so we don't
// bother to create a task for it.
define_standard_symbols(symtab, layout, input_objects->target());
@ -215,7 +223,9 @@ queue_final_tasks(const General_options& options,
// Queue a task to write out everything else.
final_blocker->add_blocker();
workqueue->queue(new Write_data_task(layout, of, final_blocker));
workqueue->queue(new Write_data_task(layout, symtab,
input_objects->target(),
of, final_blocker));
// Queue a task to close the output file. This will be blocked by
// FINAL_BLOCKER.

View File

@ -163,10 +163,18 @@ gold_fatal(const char* msg, bool perrno) ATTRIBUTE_NORETURN;
extern void
gold_nomem() ATTRIBUTE_NORETURN;
// This function is called in cases which can not arise if the code is
// written correctly.
extern void
gold_unreachable() ATTRIBUTE_NORETURN;
// This macro and function are used in cases which can not arise if
// the code is written correctly.
#define gold_unreachable() \
(gold::do_gold_unreachable(__FILE__, __LINE__, __FUNCTION__))
extern void do_gold_unreachable(const char*, int, const char*)
ATTRIBUTE_NORETURN;
// Assertion check.
#define gold_assert(expr) ((void)(!(expr) ? gold_unreachable(), 0 : 0))
// Queue up the first set of tasks.
extern void

View File

@ -20,6 +20,8 @@ namespace
using namespace gold;
class Output_data_plt_i386;
// The i386 target class.
class Target_i386 : public Sized_target<32, false>
@ -27,7 +29,7 @@ class Target_i386 : public Sized_target<32, false>
public:
Target_i386()
: Sized_target<32, false>(&i386_info),
got_(NULL)
got_(NULL), plt_(NULL), got_plt_(NULL)
{ }
// Scan the relocations to look for symbol adjustments.
@ -36,6 +38,7 @@ class Target_i386 : public Sized_target<32, false>
Symbol_table* symtab,
Layout* layout,
Sized_relobj<32, false>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
@ -61,6 +64,7 @@ class Target_i386 : public Sized_target<32, false>
local(const General_options& options, Symbol_table* symtab,
Layout* layout, Target_i386* target,
Sized_relobj<32, false>* object,
unsigned int data_shndx,
const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
const elfcpp::Sym<32, false>& lsym);
@ -68,6 +72,7 @@ class Target_i386 : public Sized_target<32, false>
global(const General_options& options, Symbol_table* symtab,
Layout* layout, Target_i386* target,
Sized_relobj<32, false>* object,
unsigned int data_shndx,
const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
Symbol* gsym);
};
@ -146,11 +151,29 @@ class Target_i386 : public Sized_target<32, false>
// Adjust TLS relocation type based on the options and whether this
// is a local symbol.
static unsigned int
optimize_tls_reloc(const General_options*, bool is_local, int r_type);
optimize_tls_reloc(const General_options*, bool is_final, int r_type);
// Get the GOT section, creating it if necessary.
Output_data_got<32, false>*
got_section(Symbol_table*, Layout*);
got_section(const General_options*, Symbol_table*, Layout*);
// Create a PLT entry for a global symbol.
void
make_plt_entry(const General_options* options, Symbol_table*,
Layout*, Symbol*);
// Get the PLT section.
Output_data_plt_i386*
plt_section() const
{
gold_assert(this->plt_ != NULL);
return this->plt_;
}
// Copy a relocation against a global symbol.
void
copy_reloc(const General_options*, Sized_relobj<32, false>*, unsigned int,
Symbol*, const elfcpp::Rel<32, false>&);
// Information about this specific target which we pass to the
// general Target structure.
@ -158,6 +181,10 @@ class Target_i386 : public Sized_target<32, false>
// The GOT section.
Output_data_got<32, false>* got_;
// The PLT section.
Output_data_plt_i386* plt_;
// The GOT PLT section.
Output_data_space* got_plt_;
};
const Target::Target_info Target_i386::i386_info =
@ -176,37 +203,317 @@ const Target::Target_info Target_i386::i386_info =
// Get the GOT section, creating it if necessary.
Output_data_got<32, false>*
Target_i386::got_section(Symbol_table* symtab, Layout* layout)
Target_i386::got_section(const General_options* options, Symbol_table* symtab,
Layout* layout)
{
if (this->got_ == NULL)
{
this->got_ = new Output_data_got<32, false>();
gold_assert(options != NULL && symtab != NULL && layout != NULL);
this->got_ = new Output_data_got<32, false>(options);
assert(symtab != NULL && layout != NULL);
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC, this->got_);
// The first three entries are reserved.
this->got_->add_constant(0);
this->got_->add_constant(0);
this->got_->add_constant(0);
// The old GNU linker creates a .got.plt section. We just
// create another set of data in the .got section. Note that we
// always create a PLT if we create a GOT, although the PLT
// might be empty.
this->got_plt_ = new Output_data_space(4);
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC, this->got_plt_);
// Define _GLOBAL_OFFSET_TABLE_ at the start of the section.
symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", this->got_,
// The first three entries are reserved.
this->got_plt_->set_space_size(3 * 4);
// Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_",
this->got_plt_,
0, 0, elfcpp::STT_OBJECT,
elfcpp::STB_GLOBAL,
elfcpp::STV_HIDDEN, 0,
false, false);
}
return this->got_;
}
// A class to handle the PLT data.
class Output_data_plt_i386 : public Output_section_data
{
public:
typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
Output_data_plt_i386(Layout*, Output_data_space*, bool is_shared);
// Add an entry to the PLT.
void
add_entry(Symbol* gsym);
private:
// The size of an entry in the PLT.
static const int plt_entry_size = 16;
// The first entry in the PLT for an executable.
static unsigned char exec_first_plt_entry[plt_entry_size];
// The first entry in the PLT for a shared object.
static unsigned char dyn_first_plt_entry[plt_entry_size];
// Other entries in the PLT for an executable.
static unsigned char exec_plt_entry[plt_entry_size];
// Other entries in the PLT for a shared object.
static unsigned char dyn_plt_entry[plt_entry_size];
// Set the final size.
void
do_set_address(uint64_t, off_t)
{ this->set_data_size((this->count_ + 1) * plt_entry_size); }
// Write out the PLT data.
void
do_write(Output_file*);
// The reloc section.
Reloc_section* rel_;
// The .got.plt section.
Output_data_space* got_plt_;
// The number of PLT entries.
unsigned int count_;
// Whether we are generated a shared object.
bool is_shared_;
};
// Create the PLT section. The ordinary .got section is an argument,
// since we need to refer to the start. We also create our own .got
// section just for PLT entries.
Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
Output_data_space* got_plt,
bool is_shared)
: Output_section_data(4), got_plt_(got_plt), is_shared_(is_shared)
{
this->rel_ = new Reloc_section();
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
elfcpp::SHF_ALLOC, this->rel_);
}
// Add an entry to the PLT.
void
Output_data_plt_i386::add_entry(Symbol* gsym)
{
gold_assert(!gsym->has_plt_offset());
// Note that when setting the PLT offset we skip the initial
// reserved PLT entry.
gsym->set_plt_offset((this->count_ + 1) * plt_entry_size);
++this->count_;
off_t got_offset = this->got_plt_->data_size();
// Every PLT entry needs a GOT entry which points back to the PLT
// entry (this will be changed by the dynamic linker, normally
// lazily when the function is called).
this->got_plt_->set_space_size(got_offset + 4);
// Every PLT entry needs a reloc.
this->rel_->add_global(gsym, elfcpp::R_386_JUMP_SLOT, this->got_plt_,
got_offset);
// Note that we don't need to save the symbol. The contents of the
// PLT are independent of which symbols are used. The symbols only
// appear in the relocations.
}
// The first entry in the PLT for an executable.
unsigned char Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
{
0xff, 0x35, // pushl contents of memory address
0, 0, 0, 0, // replaced with address of .got + 4
0xff, 0x25, // jmp indirect
0, 0, 0, 0, // replaced with address of .got + 8
0, 0, 0, 0 // unused
};
// The first entry in the PLT for a shared object.
unsigned char Output_data_plt_i386::dyn_first_plt_entry[plt_entry_size] =
{
0xff, 0xb3, 4, 0, 0, 0, // pushl 4(%ebx)
0xff, 0xa3, 8, 0, 0, 0, // jmp *8(%ebx)
0, 0, 0, 0 // unused
};
// Subsequent entries in the PLT for an executable.
unsigned char Output_data_plt_i386::exec_plt_entry[plt_entry_size] =
{
0xff, 0x25, // jmp indirect
0, 0, 0, 0, // replaced with address of symbol in .got
0x68, // pushl immediate
0, 0, 0, 0, // replaced with offset into relocation table
0xe9, // jmp relative
0, 0, 0, 0 // replaced with offset to start of .plt
};
// Subsequent entries in the PLT for a shared object.
unsigned char Output_data_plt_i386::dyn_plt_entry[plt_entry_size] =
{
0xff, 0xa3, // jmp *offset(%ebx)
0, 0, 0, 0, // replaced with offset of symbol in .got
0x68, // pushl immediate
0, 0, 0, 0, // replaced with offset into relocation table
0xe9, // jmp relative
0, 0, 0, 0 // replaced with offset to start of .plt
};
// Write out the PLT. This uses the hand-coded instructions above,
// and adjusts them as needed. This is all specified by the i386 ELF
// Processor Supplement.
void
Output_data_plt_i386::do_write(Output_file* of)
{
const off_t offset = this->offset();
const off_t oview_size = this->data_size();
unsigned char* const oview = of->get_output_view(offset, oview_size);
const off_t got_file_offset = this->got_plt_->offset();
const off_t got_size = this->got_plt_->data_size();
unsigned char* const got_view = of->get_output_view(got_file_offset,
got_size);
unsigned char* pov = oview;
elfcpp::Elf_types<32>::Elf_Addr plt_address = this->address();
elfcpp::Elf_types<32>::Elf_Addr got_address = this->got_plt_->address();
if (this->is_shared_)
memcpy(pov, dyn_first_plt_entry, plt_entry_size);
else
{
memcpy(pov, exec_first_plt_entry, plt_entry_size);
elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_address + 4);
elfcpp::Swap<32, false>::writeval(pov + 8, got_address + 8);
}
pov += plt_entry_size;
unsigned char* got_pov = got_view;
memset(got_pov, 0, 12);
got_pov += 12;
const int rel_size = elfcpp::Elf_sizes<32>::rel_size;
unsigned int plt_offset = plt_entry_size;
unsigned int plt_rel_offset = 0;
unsigned int got_offset = 12;
const unsigned int count = this->count_;
for (unsigned int i = 0;
i < count;
++i,
pov += plt_entry_size,
got_pov += 4,
plt_offset += plt_entry_size,
plt_rel_offset += rel_size,
got_offset += 4)
{
// Set and adjust the PLT entry itself.
if (this->is_shared_)
{
memcpy(pov, dyn_plt_entry, plt_entry_size);
elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
}
else
{
memcpy(pov, exec_plt_entry, plt_entry_size);
elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
(got_address
+ got_offset));
}
elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_rel_offset);
elfcpp::Swap<32, false>::writeval(pov + 12,
- (plt_offset + plt_entry_size));
// Set the entry in the GOT.
elfcpp::Swap<32, false>::writeval(got_pov, plt_address + plt_offset + 6);
}
gold_assert(pov - oview == oview_size);
gold_assert(got_pov - got_view == got_size);
of->write_output_view(offset, oview_size, oview);
of->write_output_view(got_file_offset, got_size, got_view);
}
// Create a PLT entry for a global symbol.
void
Target_i386::make_plt_entry(const General_options* options,
Symbol_table* symtab, Layout* layout, Symbol* gsym)
{
if (gsym->has_plt_offset())
return;
if (this->plt_ == NULL)
{
// Create the GOT sections first.
this->got_section(options, symtab, layout);
this->plt_ = new Output_data_plt_i386(layout, this->got_plt_,
options->is_shared());
}
this->plt_->add_entry(gsym);
}
// Handle a relocation against a non-function symbol defined in a
// dynamic object. The traditional way to handle this is to generate
// a COPY relocation to copy the variable at runtime from the shared
// object into the executable's data segment. However, this is
// undesirable in general, as if the size of the object changes in the
// dynamic object, the executable will no longer work correctly. If
// this relocation is in a writable section, then we can create a
// dynamic reloc and the dynamic linker will resolve it to the correct
// address at runtime. However, we do not want do that if the
// relocation is in a read-only section, as it would prevent the
// readonly segment from being shared. And if we have to eventually
// generate a COPY reloc, then any dynamic relocations will be
// useless. So this means that if this is a writable section, we need
// to save the relocation until we see whether we have to create a
// COPY relocation for this symbol for any other relocation.
void
Target_i386::copy_reloc(const General_options* options,
Sized_relobj<32, false>* object,
unsigned int data_shndx, Symbol* gsym,
const elfcpp::Rel<32, false>&)
{
if (!Relocate_functions<32, false>::need_copy_reloc(options, object,
data_shndx, gsym))
{
// So far we do not need a COPY reloc. Save this relocation.
// If it turns out that we never a COPY reloc for this symbol,
// then we emit the relocation.
}
}
// Optimize the TLS relocation type based on what we know about the
// symbol. IS_LOCAL is true if this symbol can be resolved entirely
// locally--i.e., does not have to be in the dynamic symbol table.
// symbol. IS_FINAL is true if the final address of this symbol is
// known at link time.
unsigned int
Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
Target_i386::optimize_tls_reloc(const General_options* options,
bool is_final,
int r_type)
{
// If we are generating a shared library, then we can't do anything
@ -223,7 +530,7 @@ Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
// access. Since we know that we are generating an executable,
// we can convert this to Initial-Exec. If we also know that
// this is a local symbol, we can further switch to Local-Exec.
if (is_local)
if (is_final)
return elfcpp::R_386_TLS_LE_32;
return elfcpp::R_386_TLS_IE_32;
@ -244,7 +551,7 @@ Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
// from the GOT. If we know that we are linking against the
// local symbol, we can switch to Local-Exec, which links the
// thread offset into the instruction.
if (is_local)
if (is_final)
return elfcpp::R_386_TLS_LE_32;
return r_type;
@ -255,7 +562,7 @@ Target_i386::optimize_tls_reloc(const General_options* options, bool is_local,
return r_type;
default:
abort();
gold_unreachable();
}
}
@ -267,7 +574,9 @@ Target_i386::Scan::local(const General_options& options,
Layout* layout,
Target_i386* target,
Sized_relobj<32, false>* object,
const elfcpp::Rel<32, false>&, unsigned int r_type,
unsigned int,
const elfcpp::Rel<32, false>&,
unsigned int r_type,
const elfcpp::Sym<32, false>&)
{
switch (r_type)
@ -282,6 +591,7 @@ Target_i386::Scan::local(const General_options& options,
case elfcpp::R_386_8:
// FIXME: If we are generating a shared object we need to copy
// this relocation into the object.
gold_assert(!options.is_shared());
break;
case elfcpp::R_386_PC32:
@ -292,7 +602,7 @@ Target_i386::Scan::local(const General_options& options,
case elfcpp::R_386_GOTOFF:
case elfcpp::R_386_GOTPC:
// We need a GOT section.
target->got_section(symtab, layout);
target->got_section(&options, symtab, layout);
break;
case elfcpp::R_386_COPY:
@ -319,13 +629,16 @@ Target_i386::Scan::local(const General_options& options,
case elfcpp::R_386_TLS_LE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
r_type = Target_i386::optimize_tls_reloc(&options, true, r_type);
r_type = Target_i386::optimize_tls_reloc(&options,
!options.is_shared(),
r_type);
switch (r_type)
{
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_LE_32:
// FIXME: If generating a shared object, we need to copy
// this relocation into the object.
gold_assert(!options.is_shared());
break;
case elfcpp::R_386_TLS_IE:
@ -370,7 +683,9 @@ Target_i386::Scan::global(const General_options& options,
Layout* layout,
Target_i386* target,
Sized_relobj<32, false>* object,
const elfcpp::Rel<32, false>&, unsigned int r_type,
unsigned int data_shndx,
const elfcpp::Rel<32, false>& reloc,
unsigned int r_type,
Symbol* gsym)
{
switch (r_type)
@ -390,32 +705,44 @@ Target_i386::Scan::global(const General_options& options,
// copy this relocation into the object. If this symbol is
// defined in a shared object, we may need to copy this
// relocation in order to avoid a COPY relocation.
gold_assert(!options.is_shared());
if (gsym->is_defined_in_dynobj())
{
// This symbol is defined in a dynamic object. If it is a
// function, we make a PLT entry. Otherwise we need to
// either generate a COPY reloc or copy this reloc.
if (gsym->type() == elfcpp::STT_FUNC)
target->make_plt_entry(&options, symtab, layout, gsym);
else
target->copy_reloc(&options, object, data_shndx, gsym, reloc);
}
break;
case elfcpp::R_386_GOT32:
// The symbol requires a GOT entry.
if (target->got_section(symtab, layout)->add_global(gsym))
if (target->got_section(&options, symtab, layout)->add_global(gsym))
{
// If this symbol is not resolved locally, we need to add a
// If this symbol is not fully resolved, we need to add a
// dynamic relocation for it.
if (!gsym->is_resolved_locally())
abort();
if (!gsym->final_value_is_known(&options))
gold_unreachable();
}
break;
case elfcpp::R_386_PLT32:
// If the symbol is resolved locally, this is just a PC32 reloc.
if (gsym->is_resolved_locally())
// If the symbol is fully resolved, this is just a PC32 reloc.
// Otherwise we need a PLT entry.
if (gsym->final_value_is_known(&options))
break;
fprintf(stderr,
_("%s: %s: unsupported reloc %u against global symbol %s\n"),
program_name, object->name().c_str(), r_type, gsym->name());
target->make_plt_entry(&options, symtab, layout, gsym);
break;
case elfcpp::R_386_GOTOFF:
case elfcpp::R_386_GOTPC:
// We need a GOT section.
target->got_section(symtab, layout);
target->got_section(&options, symtab, layout);
break;
case elfcpp::R_386_COPY:
@ -442,30 +769,34 @@ Target_i386::Scan::global(const General_options& options,
case elfcpp::R_386_TLS_LE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
r_type = Target_i386::optimize_tls_reloc(&options,
gsym->is_resolved_locally(),
r_type);
switch (r_type)
{
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_LE_32:
// FIXME: If generating a shared object, we need to copy
// this relocation into the object.
break;
{
const bool is_final = gsym->final_value_is_known(&options);
r_type = Target_i386::optimize_tls_reloc(&options, is_final, r_type);
switch (r_type)
{
case elfcpp::R_386_TLS_LE:
case elfcpp::R_386_TLS_LE_32:
// FIXME: If generating a shared object, we need to copy
// this relocation into the object.
gold_assert(!options.is_shared());
break;
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_LDM:
case elfcpp::R_386_TLS_LDO_32:
case elfcpp::R_386_TLS_IE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
fprintf(stderr,
_("%s: %s: unsupported reloc %u against global symbol %s\n"),
program_name, object->name().c_str(), r_type, gsym->name());
break;
}
case elfcpp::R_386_TLS_IE:
case elfcpp::R_386_TLS_GOTIE:
case elfcpp::R_386_TLS_GD:
case elfcpp::R_386_TLS_LDM:
case elfcpp::R_386_TLS_LDO_32:
case elfcpp::R_386_TLS_IE_32:
case elfcpp::R_386_TLS_GOTDESC:
case elfcpp::R_386_TLS_DESC_CALL:
fprintf(stderr,
_("%s: %s: unsupported reloc %u "
"against global symbol %s\n"),
program_name, object->name().c_str(), r_type,
gsym->name());
break;
}
}
break;
case elfcpp::R_386_32PLT:
@ -493,6 +824,7 @@ Target_i386::scan_relocs(const General_options& options,
Symbol_table* symtab,
Layout* layout,
Sized_relobj<32, false>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
@ -514,6 +846,7 @@ Target_i386::scan_relocs(const General_options& options,
layout,
this,
object,
data_shndx,
prelocs,
reloc_count,
local_symbol_count,
@ -552,6 +885,15 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
return false;
}
// Pick the value to use for symbols defined in shared objects.
if (gsym != NULL && gsym->is_defined_in_dynobj())
{
if (gsym->has_plt_offset())
address = target->plt_section()->address() + gsym->plt_offset();
else
gold_unreachable();
}
switch (r_type)
{
case elfcpp::R_386_NONE:
@ -584,30 +926,26 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
break;
case elfcpp::R_386_PLT32:
if (gsym->is_resolved_locally())
Relocate_functions<32, false>::pcrel32(view, value, address);
else
fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
program_name,
relinfo->location(relnum, rel.get_r_offset()).c_str(),
r_type);
gold_assert(gsym->has_plt_offset()
|| gsym->final_value_is_known(relinfo->options));
Relocate_functions<32, false>::pcrel32(view, value, address);
break;
case elfcpp::R_386_GOT32:
// Local GOT offsets not yet supported.
assert(gsym);
assert(gsym->has_got_offset());
gold_assert(gsym);
gold_assert(gsym->has_got_offset());
value = gsym->got_offset();
Relocate_functions<32, false>::rel32(view, value);
break;
case elfcpp::R_386_GOTOFF:
value -= target->got_section(NULL, NULL)->address();
value -= target->got_section(NULL, NULL, NULL)->address();
Relocate_functions<32, false>::rel32(view, value);
break;
case elfcpp::R_386_GOTPC:
value = target->got_section(NULL, NULL)->address();
value = target->got_section(NULL, NULL, NULL)->address();
Relocate_functions<32, false>::pcrel32(view, value, address);
break;
@ -685,9 +1023,11 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
gold_exit(false);
}
const bool is_local = gsym == NULL || gsym->is_resolved_locally();
const bool is_final = (gsym == NULL
? !relinfo->options->is_shared()
: gsym->final_value_is_known(relinfo->options));
const unsigned int opt_r_type =
Target_i386::optimize_tls_reloc(relinfo->options, is_local, r_type);
Target_i386::optimize_tls_reloc(relinfo->options, is_final, r_type);
switch (r_type)
{
case elfcpp::R_386_TLS_LE_32:
@ -955,7 +1295,7 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
elfcpp::Elf_types<32>::Elf_Addr address,
off_t view_size)
{
assert(sh_type == elfcpp::SHT_REL);
gold_assert(sh_type == elfcpp::SHT_REL);
gold::relocate_section<32, false, Target_i386, elfcpp::SHT_REL,
Target_i386::Relocate>(

View File

@ -2,7 +2,6 @@
#include "gold.h"
#include <cassert>
#include <cstring>
#include <algorithm>
#include <iostream>
@ -10,6 +9,7 @@
#include "output.h"
#include "symtab.h"
#include "dynobj.h"
#include "layout.h"
namespace gold
@ -39,13 +39,18 @@ Layout_task_runner::run(Workqueue* workqueue)
// Layout methods.
Layout::Layout(const General_options& options)
: options_(options), namepool_(), sympool_(), signatures_(),
: options_(options), namepool_(), sympool_(), dynpool_(), signatures_(),
section_name_map_(), segment_list_(), section_list_(),
special_output_list_(), tls_segment_(NULL)
unattached_section_list_(), special_output_list_(),
tls_segment_(NULL), symtab_section_(NULL), dynsym_section_(NULL)
{
// Make space for more than enough segments for a typical file.
// This is just for efficiency--it's OK if we wind up needing more.
segment_list_.reserve(12);
this->segment_list_.reserve(12);
// We expect three unattached Output_data objects: the file header,
// the segment headers, and the section headers.
this->special_output_list_.reserve(3);
}
// Hash a key we use to look up an output section mapping.
@ -219,9 +224,10 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
{
Output_section* os = new Output_section(name, type, flags, true);
this->section_list_.push_back(os);
if ((flags & elfcpp::SHF_ALLOC) == 0)
this->section_list_.push_back(os);
this->unattached_section_list_.push_back(os);
else
{
// This output section goes into a PT_LOAD segment.
@ -299,6 +305,28 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
return os;
}
// Create the dynamic sections which are needed before we read the
// relocs.
void
Layout::create_initial_dynamic_sections(const Input_objects* input_objects,
Symbol_table* symtab)
{
if (!input_objects->any_dynamic())
return;
const char* dynamic_name = this->namepool_.add(".dynamic", NULL);
this->dynamic_section_ = this->make_output_section(dynamic_name,
elfcpp::SHT_DYNAMIC,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE));
symtab->define_in_output_data(input_objects->target(), "_DYNAMIC",
this->dynamic_section_, 0, 0,
elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
elfcpp::STV_HIDDEN, 0, false, false);
}
// Find the first read-only PT_LOAD segment, creating one if
// necessary.
@ -355,7 +383,8 @@ Layout::find_first_load_seg()
off_t
Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
{
const int size = input_objects->target()->get_size();
const Target* const target = input_objects->target();
const int size = target->get_size();
Output_segment* phdr_seg = NULL;
if (input_objects->any_dynamic())
@ -368,17 +397,22 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
this->segment_list_.push_back(phdr_seg);
// This holds the dynamic tags.
Output_data_dynamic* odyn;
odyn = new Output_data_dynamic(input_objects->target(),
&this->dynpool_);
// Create the dynamic symbol table, including the hash table,
// the dynamic relocations, and the version sections.
this->create_dynamic_symtab(size, symtab);
// Create the .dynamic section to hold the dynamic data, and put
// it in a PT_DYNAMIC segment.
this->create_dynamic_section();
this->create_dynamic_symtab(target, odyn, symtab);
// Create the .interp section to hold the name of the
// interpreter, and put it in a PT_INTERP segment.
this->create_interp(input_objects->target());
this->create_interp(target);
// Finish the .dynamic section to hold the dynamic data, and put
// it in a PT_DYNAMIC segment.
this->finish_dynamic_section(input_objects, symtab, odyn);
}
// FIXME: Handle PT_GNU_STACK.
@ -386,7 +420,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
Output_segment* load_seg = this->find_first_load_seg();
// Lay out the segment headers.
bool big_endian = input_objects->target()->is_big_endian();
bool big_endian = target->is_big_endian();
Output_segment_headers* segment_headers;
segment_headers = new Output_segment_headers(size, big_endian,
this->segment_list_);
@ -400,7 +434,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
file_header = new Output_file_header(size,
big_endian,
this->options_,
input_objects->target(),
target,
symtab,
segment_headers);
load_seg->add_initial_output_data(file_header);
@ -412,15 +446,13 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
// Set the file offsets of all the segments, and all the sections
// they contain.
off_t off = this->set_segment_offsets(input_objects->target(), load_seg,
&shndx);
off_t off = this->set_segment_offsets(target, load_seg, &shndx);
// Create the symbol table sections.
// FIXME: We don't need to do this if we are stripping symbols.
Output_section* osymtab;
Output_section* ostrtab;
this->create_symtab_sections(size, input_objects, symtab, &off,
&osymtab, &ostrtab);
&ostrtab);
// Create the .shstrtab section.
Output_section* shstrtab_section = this->create_shstrtab();
@ -430,7 +462,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
off = this->set_section_offsets(off, &shndx);
// Now the section index of OSTRTAB is set.
osymtab->set_link(ostrtab->out_shndx());
this->symtab_section_->set_link(ostrtab->out_shndx());
// Create the section table header.
Output_section_headers* oshdrs = this->create_shdrs(size, big_endian, &off);
@ -438,6 +470,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
file_header->set_section_info(oshdrs, shstrtab_section);
// Now we know exactly where everything goes in the output file.
Output_data::layout_complete();
return off;
}
@ -457,7 +490,7 @@ Layout::segment_precedes(const Output_segment* seg1,
// segment. We simply make it always first.
if (type1 == elfcpp::PT_PHDR)
{
assert(type2 != elfcpp::PT_PHDR);
gold_assert(type2 != elfcpp::PT_PHDR);
return true;
}
if (type2 == elfcpp::PT_PHDR)
@ -467,7 +500,7 @@ Layout::segment_precedes(const Output_segment* seg1,
// segment. We simply make it always second.
if (type1 == elfcpp::PT_INTERP)
{
assert(type2 != elfcpp::PT_INTERP);
gold_assert(type2 != elfcpp::PT_INTERP);
return true;
}
if (type2 == elfcpp::PT_INTERP)
@ -497,7 +530,7 @@ Layout::segment_precedes(const Output_segment* seg1,
{
if (type1 != type2)
return type1 < type2;
assert(flags1 != flags2);
gold_assert(flags1 != flags2);
return flags1 < flags2;
}
@ -522,7 +555,7 @@ Layout::segment_precedes(const Output_segment* seg1,
uint64_t paddr1 = seg1->paddr();
uint64_t paddr2 = seg2->paddr();
assert(paddr1 != paddr2);
gold_assert(paddr1 != paddr2);
return paddr1 < paddr2;
}
@ -550,7 +583,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
if ((*p)->type() == elfcpp::PT_LOAD)
{
if (load_seg != NULL && load_seg != *p)
abort();
gold_unreachable();
load_seg = NULL;
// If the last segment was readonly, and this one is not,
@ -630,8 +663,8 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
off_t
Layout::set_section_offsets(off_t off, unsigned int* pshndx)
{
for (Layout::Section_list::iterator p = this->section_list_.begin();
p != this->section_list_.end();
for (Section_list::iterator p = this->unattached_section_list_.begin();
p != this->unattached_section_list_.end();
++p)
{
(*p)->set_out_shndx(*pshndx);
@ -651,7 +684,6 @@ void
Layout::create_symtab_sections(int size, const Input_objects* input_objects,
Symbol_table* symtab,
off_t* poff,
Output_section** posymtab,
Output_section** postrtab)
{
int symsize;
@ -667,7 +699,7 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
align = 8;
}
else
abort();
gold_unreachable();
off_t off = *poff;
off = align_address(off, align);
@ -678,6 +710,21 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
off += symsize;
unsigned int local_symbol_index = 1;
// Add STT_SECTION symbols for each Output section which needs one.
for (Section_list::iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
{
if (!(*p)->needs_symtab_index())
(*p)->set_symtab_index(-1U);
else
{
(*p)->set_symtab_index(local_symbol_index);
++local_symbol_index;
off += symsize;
}
}
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
p != input_objects->relobj_end();
++p)
@ -691,30 +738,35 @@ Layout::create_symtab_sections(int size, const Input_objects* input_objects,
}
unsigned int local_symcount = local_symbol_index;
assert(local_symcount * symsize == off - startoff);
gold_assert(local_symcount * symsize == off - startoff);
off = symtab->finalize(local_symcount, off, &this->sympool_);
this->sympool_.set_string_offsets();
const char* symtab_name = this->namepool_.add(".symtab", NULL);
Output_section* osymtab = new Output_section_symtab(symtab_name,
off - startoff);
this->section_list_.push_back(osymtab);
Output_section* osymtab = this->make_output_section(symtab_name,
elfcpp::SHT_SYMTAB,
0);
this->symtab_section_ = osymtab;
Output_section_data* pos = new Output_data_space(off - startoff,
align);
osymtab->add_output_section_data(pos);
const char* strtab_name = this->namepool_.add(".strtab", NULL);
Output_section *ostrtab = new Output_section_strtab(strtab_name,
&this->sympool_);
this->section_list_.push_back(ostrtab);
this->special_output_list_.push_back(ostrtab);
Output_section* ostrtab = this->make_output_section(strtab_name,
elfcpp::SHT_STRTAB,
0);
Output_section_data* pstr = new Output_data_strtab(&this->sympool_);
ostrtab->add_output_section_data(pstr);
osymtab->set_address(0, startoff);
osymtab->set_info(local_symcount);
osymtab->set_entsize(symsize);
osymtab->set_addralign(align);
*poff = off;
*posymtab = osymtab;
*postrtab = ostrtab;
}
@ -732,10 +784,10 @@ Layout::create_shstrtab()
this->namepool_.set_string_offsets();
Output_section* os = new Output_section_strtab(name, &this->namepool_);
Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0);
this->section_list_.push_back(os);
this->special_output_list_.push_back(os);
Output_section_data* posd = new Output_data_strtab(&this->namepool_);
os->add_output_section_data(posd);
return os;
}
@ -748,7 +800,7 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
{
Output_section_headers* oshdrs;
oshdrs = new Output_section_headers(size, big_endian, this->segment_list_,
this->section_list_,
this->unattached_section_list_,
&this->namepool_);
off_t off = align_address(*poff, oshdrs->addralign());
oshdrs->set_address(0, off);
@ -761,17 +813,109 @@ Layout::create_shdrs(int size, bool big_endian, off_t* poff)
// Create the dynamic symbol table.
void
Layout::create_dynamic_symtab(int, Symbol_table*)
Layout::create_dynamic_symtab(const Target* target, Output_data_dynamic* odyn,
Symbol_table* symtab)
{
abort();
}
// Count all the symbols in the dynamic symbol table, and set the
// dynamic symbol indexes.
// Create the .dynamic section and PT_DYNAMIC segment.
// Skip symbol 0, which is always all zeroes.
unsigned int index = 1;
void
Layout::create_dynamic_section()
{
abort();
// Add STT_SECTION symbols for each Output section which needs one.
for (Section_list::iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
{
if (!(*p)->needs_dynsym_index())
(*p)->set_dynsym_index(-1U);
else
{
(*p)->set_dynsym_index(index);
++index;
}
}
// FIXME: Some targets apparently require local symbols in the
// dynamic symbol table. Here is where we will have to count them,
// and set the dynamic symbol indexes, and add the names to
// this->dynpool_.
unsigned int local_symcount = index;
std::vector<Symbol*> dynamic_symbols;
// FIXME: We have to tell set_dynsym_indexes whether the
// -E/--export-dynamic option was used.
index = symtab->set_dynsym_indexes(index, &dynamic_symbols,
&this->dynpool_);
int symsize;
unsigned int align;
const int size = target->get_size();
if (size == 32)
{
symsize = elfcpp::Elf_sizes<32>::sym_size;
align = 4;
}
else if (size == 64)
{
symsize = elfcpp::Elf_sizes<64>::sym_size;
align = 8;
}
else
gold_unreachable();
const char* dynsym_name = this->namepool_.add(".dynsym", NULL);
Output_section* dynsym = this->make_output_section(dynsym_name,
elfcpp::SHT_DYNSYM,
elfcpp::SHF_ALLOC);
Output_section_data* odata = new Output_data_space(index * symsize,
align);
dynsym->add_output_section_data(odata);
dynsym->set_info(local_symcount);
dynsym->set_entsize(symsize);
dynsym->set_addralign(align);
this->dynsym_section_ = dynsym;
odyn->add_section_address(elfcpp::DT_SYMTAB, dynsym);
odyn->add_constant(elfcpp::DT_SYMENT, symsize);
const char* dynstr_name = this->namepool_.add(".dynstr", NULL);
Output_section* dynstr = this->make_output_section(dynstr_name,
elfcpp::SHT_STRTAB,
elfcpp::SHF_ALLOC);
Output_section_data* strdata = new Output_data_strtab(&this->dynpool_);
dynstr->add_output_section_data(strdata);
odyn->add_section_address(elfcpp::DT_STRTAB, dynstr);
odyn->add_section_size(elfcpp::DT_STRSZ, dynstr);
// FIXME: We need an option to create a GNU hash table.
unsigned char* phash;
unsigned int hashlen;
Dynobj::create_elf_hash_table(target, dynamic_symbols, local_symcount,
&phash, &hashlen);
const char* hash_name = this->namepool_.add(".hash", NULL);
Output_section* hashsec = this->make_output_section(hash_name,
elfcpp::SHT_HASH,
elfcpp::SHF_ALLOC);
Output_section_data* hashdata = new Output_data_const_buffer(phash,
hashlen,
align);
hashsec->add_output_section_data(hashdata);
hashsec->set_entsize(4);
// FIXME: .hash should link to .dynsym.
odyn->add_section_address(elfcpp::DT_HASH, hashsec);
}
// Create the .interp section and PT_INTERP segment.
@ -783,7 +927,7 @@ Layout::create_interp(const Target* target)
if (interp == NULL)
{
interp = target->dynamic_linker();
assert(interp != NULL);
gold_assert(interp != NULL);
}
size_t len = strlen(interp) + 1;
@ -801,6 +945,41 @@ Layout::create_interp(const Target* target)
oseg->add_initial_output_section(osec, elfcpp::PF_R);
}
// Finish the .dynamic section and PT_DYNAMIC segment.
void
Layout::finish_dynamic_section(const Input_objects* input_objects,
const Symbol_table* symtab,
Output_data_dynamic* odyn)
{
this->dynamic_section_->add_output_section_data(odyn);
Output_segment* oseg = new Output_segment(elfcpp::PT_DYNAMIC,
elfcpp::PF_R | elfcpp::PF_W);
this->segment_list_.push_back(oseg);
oseg->add_initial_output_section(this->dynamic_section_,
elfcpp::PF_R | elfcpp::PF_W);
for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
p != input_objects->dynobj_end();
++p)
{
// FIXME: Handle --as-needed.
odyn->add_string(elfcpp::DT_NEEDED, (*p)->soname());
}
// FIXME: Support --init and --fini.
Symbol* sym = symtab->lookup("_init");
if (sym != NULL && sym->is_defined() && !sym->is_defined_in_dynobj())
odyn->add_symbol(elfcpp::DT_INIT, sym);
sym = symtab->lookup("_fini");
if (sym != NULL && sym->is_defined() && !sym->is_defined_in_dynobj())
odyn->add_symbol(elfcpp::DT_FINI, sym);
// FIXME: Support DT_INIT_ARRAY and DT_FINI_ARRAY.
}
// The mapping of .gnu.linkonce section names to real section names.
#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
@ -950,8 +1129,51 @@ Layout::add_comdat(const char* signature, bool group)
// Write out data not associated with a section or the symbol table.
void
Layout::write_data(Output_file* of) const
Layout::write_data(const Symbol_table* symtab, const Target* target,
Output_file* of) const
{
const Output_section* symtab_section = this->symtab_section_;
for (Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
{
if ((*p)->needs_symtab_index())
{
gold_assert(symtab_section != NULL);
unsigned int index = (*p)->symtab_index();
gold_assert(index > 0 && index != -1U);
off_t off = (symtab_section->offset()
+ index * symtab_section->entsize());
symtab->write_section_symbol(target, *p, of, off);
}
}
const Output_section* dynsym_section = this->dynsym_section_;
for (Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
{
if ((*p)->needs_dynsym_index())
{
gold_assert(dynsym_section != NULL);
unsigned int index = (*p)->dynsym_index();
gold_assert(index > 0 && index != -1U);
off_t off = (dynsym_section->offset()
+ index * dynsym_section->entsize());
symtab->write_section_symbol(target, *p, of, off);
}
}
// Write out the Output_sections. Most won't have anything to
// write, since most of the data will come from input sections which
// are handled elsewhere. But some Output_sections do have
// Output_data.
for (Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
(*p)->write(of);
// Write out the Output_data which are not in an Output_section.
for (Data_list::const_iterator p = this->special_output_list_.begin();
p != this->special_output_list_.end();
++p)
@ -981,7 +1203,7 @@ Write_data_task::locks(Workqueue* workqueue)
void
Write_data_task::run(Workqueue*)
{
this->layout_->write_data(this->of_);
this->layout_->write_data(this->symtab_, this->target_, this->of_);
}
// Write_symbols_task methods.

View File

@ -20,10 +20,10 @@ class Input_objects;
class Symbol_table;
class Output_section_data;
class Output_section;
class Output_section_symtab;
class Output_section_headers;
class Output_segment;
class Output_data;
class Output_data_dynamic;
class Target;
// This task function handles mapping the input sections to output
@ -80,6 +80,10 @@ class Layout
elfcpp::Elf_Xword flags,
Output_section_data*);
// Create dynamic sections if necessary.
void
create_initial_dynamic_sections(const Input_objects*, Symbol_table*);
// Return the Stringpool used for symbol names.
const Stringpool*
sympool() const
@ -110,7 +114,7 @@ class Layout
// Write out data not associated with an input file or the symbol
// table.
void
write_data(Output_file*) const;
write_data(const Symbol_table*, const Target*, Output_file*) const;
// Return an output section named NAME, or NULL if there is none.
Output_section*
@ -128,11 +132,11 @@ class Layout
// The list of sections not attached to a segment.
typedef std::list<Output_section*> Section_list;
typedef std::vector<Output_section*> Section_list;
// The list of information to write out which is not attached to
// either a section or a segment.
typedef std::list<Output_data*> Data_list;
typedef std::vector<Output_data*> Data_list;
private:
Layout(const Layout&);
@ -157,7 +161,6 @@ class Layout
// Create the output sections for the symbol table.
void
create_symtab_sections(int size, const Input_objects*, Symbol_table*, off_t*,
Output_section** osymtab,
Output_section** ostrtab);
// Create the .shstrtab section.
@ -170,11 +173,12 @@ class Layout
// Create the dynamic symbol table.
void
create_dynamic_symtab(int size, Symbol_table*);
create_dynamic_symtab(const Target*, Output_data_dynamic*, Symbol_table*);
// Create the .dynamic section and PT_DYNAMIC segment.
// Finish the .dynamic section and PT_DYNAMIC segment.
void
create_dynamic_section();
finish_dynamic_section(const Input_objects*, const Symbol_table*,
Output_data_dynamic*);
// Create the .interp section and PT_INTERP segment.
void
@ -256,20 +260,30 @@ class Layout
Stringpool namepool_;
// The output symbol names.
Stringpool sympool_;
// The dynamic strings, if needed.
Stringpool dynpool_;
// The list of group sections and linkonce sections which we have seen.
Signatures signatures_;
// The mapping from input section name/type/flags to output sections.
Section_name_map section_name_map_;
// The list of output segments.
Segment_list segment_list_;
// The list of output sections.
Section_list section_list_;
// The list of output sections which are not attached to any output
// segment.
Section_list section_list_;
// The list of sections which require special output because they
// are not comprised of input sections.
Section_list unattached_section_list_;
// The list of unattached Output_data objects which require special
// handling because they are not Output_sections.
Data_list special_output_list_;
// A pointer to the PT_TLS segment if there is one.
Output_segment* tls_segment_;
// The SHT_SYMTAB output section.
Output_section* symtab_section_;
// The SHT_DYNSYM output section if there is one.
Output_section* dynsym_section_;
// The SHT_DYNAMIC output section if there is one.
Output_section* dynamic_section_;
};
// This task handles writing out data which is not part of a section
@ -278,9 +292,11 @@ class Layout
class Write_data_task : public Task
{
public:
Write_data_task(const Layout* layout, Output_file* of,
Write_data_task(const Layout* layout, const Symbol_table* symtab,
const Target* target, Output_file* of,
Task_token* final_blocker)
: layout_(layout), of_(of), final_blocker_(final_blocker)
: layout_(layout), symtab_(symtab), target_(target), of_(of),
final_blocker_(final_blocker)
{ }
// The standard Task methods.
@ -296,6 +312,8 @@ class Write_data_task : public Task
private:
const Layout* layout_;
const Symbol_table* symtab_;
const Target* target_;
Output_file* of_;
Task_token* final_blocker_;
};

View File

@ -4,7 +4,6 @@
#include <cerrno>
#include <cstring>
#include <cassert>
#include <cstdarg>
#include "target-select.h"
@ -210,7 +209,7 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
// Get the symbol table section header.
typename This::Shdr symtabshdr(pshdrs
+ this->symtab_shndx_ * This::shdr_size);
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
// We only need the external symbols.
const int sym_size = This::sym_size;
@ -477,7 +476,7 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
{
if (sd->symbols == NULL)
{
assert(sd->symbol_names == NULL);
gold_assert(sd->symbol_names == NULL);
return;
}
@ -517,14 +516,14 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
off_t off,
Stringpool* pool)
{
assert(this->symtab_shndx_ != -1U);
gold_assert(this->symtab_shndx_ != -1U);
if (this->symtab_shndx_ == 0)
{
// This object has no symbols. Weird but legal.
return index;
}
assert(off == static_cast<off_t>(align_address(off, size >> 3)));
gold_assert(off == static_cast<off_t>(align_address(off, size >> 3)));
this->local_symbol_offset_ = off;
@ -532,12 +531,12 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
const unsigned int symtab_shndx = this->symtab_shndx_;
typename This::Shdr symtabshdr(this,
this->elf_file_.section_header(symtab_shndx));
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
// Read the local symbols.
const int sym_size = This::sym_size;
const unsigned int loccount = this->local_symbol_count_;
assert(loccount == symtabshdr.get_sh_info());
gold_assert(loccount == symtabshdr.get_sh_info());
off_t locsize = loccount * sym_size;
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
locsize);
@ -641,7 +640,7 @@ void
Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
const Stringpool* sympool)
{
assert(this->symtab_shndx_ != -1U);
gold_assert(this->symtab_shndx_ != -1U);
if (this->symtab_shndx_ == 0)
{
// This object has no symbols. Weird but legal.
@ -652,9 +651,9 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
const unsigned int symtab_shndx = this->symtab_shndx_;
typename This::Shdr symtabshdr(this,
this->elf_file_.section_header(symtab_shndx));
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
const unsigned int loccount = this->local_symbol_count_;
assert(loccount == symtabshdr.get_sh_info());
gold_assert(loccount == symtabshdr.get_sh_info());
// Read the local symbols.
const int sym_size = This::sym_size;
@ -676,8 +675,8 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
const std::vector<Map_to_output>& mo(this->map_to_output());
assert(this->local_values_.size() == loccount);
assert(this->local_indexes_.size() == loccount);
gold_assert(this->local_values_.size() == loccount);
gold_assert(this->local_indexes_.size() == loccount);
unsigned char* ov = oview;
psyms += sym_size;
@ -687,12 +686,12 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
if (this->local_indexes_[i] == -1U)
continue;
assert(this->local_indexes_[i] != 0);
gold_assert(this->local_indexes_[i] != 0);
unsigned int st_shndx = isym.get_st_shndx();
if (st_shndx < elfcpp::SHN_LORESERVE)
{
assert(st_shndx < mo.size());
gold_assert(st_shndx < mo.size());
if (mo[st_shndx].output_section == NULL)
continue;
st_shndx = mo[st_shndx].output_section->out_shndx();
@ -700,7 +699,7 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
elfcpp::Sym_write<size, big_endian> osym(ov);
assert(isym.get_st_name() < strtab_size);
gold_assert(isym.get_st_name() < strtab_size);
const char* name = pnames + isym.get_st_name();
osym.put_st_name(sympool->get_offset(name));
osym.put_st_value(this->local_values_[i]);
@ -712,7 +711,7 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
ov += sym_size;
}
assert(ov - oview == output_size);
gold_assert(ov - oview == output_size);
of->write_output_view(this->local_symbol_offset_, output_size, oview);
}

View File

@ -3,7 +3,6 @@
#ifndef GOLD_OBJECT_H
#define GOLD_OBJECT_H
#include <cassert>
#include <string>
#include <vector>
@ -166,8 +165,13 @@ class Object
// Return the name of a section given a section index. This is only
// used for error messages.
std::string
section_name(unsigned int shnum)
{ return this->do_section_name(shnum); }
section_name(unsigned int shndx)
{ return this->do_section_name(shndx); }
// Return the section flags given a section index.
uint64_t
section_flags(unsigned int shndx)
{ return this->do_section_flags(shndx); }
// Functions and types for the elfcpp::Elf_file interface. This
// permit us to use Object as the File template parameter for
@ -233,11 +237,15 @@ class Object
// Return the location of the contents of a section. Implemented by
// child class.
virtual Location
do_section_contents(unsigned int shnum) = 0;
do_section_contents(unsigned int shndx) = 0;
// Get the name of a section--implemented by child class.
virtual std::string
do_section_name(unsigned int shnum) = 0;
do_section_name(unsigned int shndx) = 0;
// Get section flags--implemented by child class.
virtual uint64_t
do_section_flags(unsigned int shndx) = 0;
// Get the file.
Input_file*
@ -324,8 +332,8 @@ template<int size, bool big_endian>
inline Sized_target<size, big_endian>*
Object::sized_target(ACCEPT_SIZE_ENDIAN_ONLY)
{
assert(this->target_->get_size() == size);
assert(this->target_->is_big_endian() ? big_endian : !big_endian);
gold_assert(this->target_->get_size() == size);
gold_assert(this->target_->is_big_endian() ? big_endian : !big_endian);
return static_cast<Sized_target<size, big_endian>*>(this->target_);
}
@ -367,7 +375,7 @@ class Relobj : public Object
bool
is_section_included(unsigned int shnum) const
{
assert(shnum < this->map_to_output_.size());
gold_assert(shnum < this->map_to_output_.size());
return this->map_to_output_[shnum].output_section != NULL;
}
@ -381,7 +389,7 @@ class Relobj : public Object
void
set_section_offset(unsigned int shndx, off_t off)
{
assert(shndx < this->map_to_output_.size());
gold_assert(shndx < this->map_to_output_.size());
this->map_to_output_[shndx].offset = off;
}
@ -431,7 +439,7 @@ class Relobj : public Object
inline Output_section*
Relobj::output_section(unsigned int shnum, off_t* poff)
{
assert(shnum < this->map_to_output_.size());
gold_assert(shnum < this->map_to_output_.size());
const Map_to_output& mo(this->map_to_output_[shnum]);
*poff = mo.offset;
return mo.output_section;
@ -460,8 +468,8 @@ class Sized_relobj : public Relobj
unsigned int
symtab_index(unsigned int sym) const
{
assert(sym < this->local_indexes_.size());
assert(this->local_indexes_[sym] != 0);
gold_assert(sym < this->local_indexes_.size());
gold_assert(this->local_indexes_[sym] != 0);
return this->local_indexes_[sym];
}
@ -506,6 +514,11 @@ class Sized_relobj : public Relobj
do_section_contents(unsigned int shndx)
{ return this->elf_file_.section_contents(shndx); }
// Return section flags.
uint64_t
do_section_flags(unsigned int shndx)
{ return this->elf_file_.section_flags(shndx); }
// Return the appropriate Sized_target structure.
Sized_target<size, big_endian>*
sized_target()

View File

@ -291,8 +291,8 @@ Input_arguments::add_file(const Input_file_argument& file)
this->input_argument_list_.push_back(Input_argument(file));
else
{
assert(!this->input_argument_list_.empty());
assert(this->input_argument_list_.back().is_group());
gold_assert(!this->input_argument_list_.empty());
gold_assert(this->input_argument_list_.back().is_group());
this->input_argument_list_.back().group()->add_file(file);
}
}
@ -302,7 +302,7 @@ Input_arguments::add_file(const Input_file_argument& file)
void
Input_arguments::start_group()
{
assert(!this->in_group_);
gold_assert(!this->in_group_);
Input_file_group* group = new Input_file_group();
this->input_argument_list_.push_back(Input_argument(group));
this->in_group_ = true;
@ -313,7 +313,7 @@ Input_arguments::start_group()
void
Input_arguments::end_group()
{
assert(this->in_group_);
gold_assert(this->in_group_);
this->in_group_ = false;
}

View File

@ -15,7 +15,6 @@
#include <list>
#include <string>
#include <vector>
#include <cassert>
namespace gold
{
@ -218,7 +217,7 @@ class Input_argument
const Input_file_argument&
file() const
{
assert(this->is_file_);
gold_assert(this->is_file_);
return this->file_;
}
@ -226,14 +225,14 @@ class Input_argument
const Input_file_group*
group() const
{
assert(!this->is_file_);
gold_assert(!this->is_file_);
return this->group_;
}
Input_file_group*
group()
{
assert(!this->is_file_);
gold_assert(!this->is_file_);
return this->group_;
}

View File

@ -17,6 +17,10 @@
namespace gold
{
// Output_data variables.
bool Output_data::sizes_are_fixed;
// Output_data methods.
Output_data::~Output_data()
@ -45,7 +49,7 @@ Output_data::default_alignment(int size)
else if (size == 64)
return 8;
else
abort();
gold_unreachable();
}
// Output_section_header methods. This currently assumes that the
@ -55,12 +59,12 @@ Output_section_headers::Output_section_headers(
int size,
bool big_endian,
const Layout::Segment_list& segment_list,
const Layout::Section_list& section_list,
const Layout::Section_list& unattached_section_list,
const Stringpool* secnamepool)
: size_(size),
big_endian_(big_endian),
segment_list_(segment_list),
section_list_(section_list),
unattached_section_list_(unattached_section_list),
secnamepool_(secnamepool)
{
// Count all the sections. Start with 1 for the null section.
@ -70,7 +74,7 @@ Output_section_headers::Output_section_headers(
++p)
if ((*p)->type() == elfcpp::PT_LOAD)
count += (*p)->output_section_count();
count += section_list.size();
count += unattached_section_list.size();
int shdr_size;
if (size == 32)
@ -78,7 +82,7 @@ Output_section_headers::Output_section_headers(
else if (size == 64)
shdr_size = elfcpp::Elf_sizes<64>::shdr_size;
else
abort();
gold_unreachable();
this->set_data_size(count * shdr_size);
}
@ -103,7 +107,7 @@ Output_section_headers::do_write(Output_file* of)
this->do_sized_write<64, false>(of);
}
else
abort();
gold_unreachable();
}
template<int size, bool big_endian>
@ -139,11 +143,12 @@ Output_section_headers::do_sized_write(Output_file* of)
v = (*p)->write_section_headers SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
this->secnamepool_, v, &shndx
SELECT_SIZE_ENDIAN(size, big_endian));
for (Layout::Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
for (Layout::Section_list::const_iterator p =
this->unattached_section_list_.begin();
p != this->unattached_section_list_.end();
++p)
{
assert(shndx == (*p)->out_shndx());
gold_assert(shndx == (*p)->out_shndx());
elfcpp::Shdr_write<size, big_endian> oshdr(v);
(*p)->write_header(this->secnamepool_, &oshdr);
v += shdr_size;
@ -167,7 +172,7 @@ Output_segment_headers::Output_segment_headers(
else if (size == 64)
phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
else
abort();
gold_unreachable();
this->set_data_size(segment_list.size() * phdr_size);
}
@ -190,7 +195,7 @@ Output_segment_headers::do_write(Output_file* of)
this->do_sized_write<64, false>(of);
}
else
abort();
gold_unreachable();
}
template<int size, bool big_endian>
@ -237,7 +242,7 @@ Output_file_header::Output_file_header(int size,
else if (size == 64)
ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
else
abort();
gold_unreachable();
this->set_data_size(ehdr_size);
}
@ -272,7 +277,7 @@ Output_file_header::do_write(Output_file* of)
this->do_sized_write<64, false>(of);
}
else
abort();
gold_unreachable();
}
// Write out the file header with appropriate size and endianess.
@ -281,7 +286,7 @@ template<int size, bool big_endian>
void
Output_file_header::do_sized_write(Output_file* of)
{
assert(this->offset() == 0);
gold_assert(this->offset() == 0);
int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
unsigned char* view = of->get_output_view(0, ehdr_size);
@ -298,7 +303,7 @@ Output_file_header::do_sized_write(Output_file* of)
else if (size == 64)
e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS64;
else
abort();
gold_unreachable();
e_ident[elfcpp::EI_DATA] = (big_endian
? elfcpp::ELFDATA2MSB
: elfcpp::ELFDATA2LSB);
@ -352,9 +357,17 @@ Output_file_header::do_sized_write(Output_file* of)
// Output_data_const methods.
void
Output_data_const::do_write(Output_file* output)
Output_data_const::do_write(Output_file* of)
{
output->write(this->offset(), data_.data(), data_.size());
of->write(this->offset(), this->data_.data(), this->data_.size());
}
// Output_data_const_buffer methods.
void
Output_data_const_buffer::do_write(Output_file* of)
{
of->write(this->offset(), this->p_, this->data_size());
}
// Output_section_data methods.
@ -362,10 +375,30 @@ Output_data_const::do_write(Output_file* output)
unsigned int
Output_section_data::do_out_shndx() const
{
assert(this->output_section_ != NULL);
gold_assert(this->output_section_ != NULL);
return this->output_section_->out_shndx();
}
// Output_data_strtab methods.
// Set the address. We don't actually care about the address, but we
// do set our final size.
void
Output_data_strtab::do_set_address(uint64_t, off_t)
{
this->strtab_->set_string_offsets();
this->set_data_size(this->strtab_->get_strtab_size());
}
// Write out a string table.
void
Output_data_strtab::do_write(Output_file* of)
{
this->strtab_->write(of, this->offset());
}
// Output_reloc methods.
// Get the symbol index of a relocation.
@ -379,7 +412,7 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
switch (this->local_sym_index_)
{
case INVALID_CODE:
abort();
gold_unreachable();
case GSYM_CODE:
if (this->u_.gsym == NULL)
@ -403,13 +436,13 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
// FIXME: It seems that some targets may need to generate
// dynamic relocations against local symbols for some
// reasons. This will have to be addressed at some point.
abort();
gold_unreachable();
}
else
index = this->u_.object->symtab_index(this->local_sym_index_);
break;
}
assert(index != -1U);
gold_assert(index != -1U);
return index;
}
@ -422,7 +455,10 @@ void
Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
Write_rel* wr) const
{
wr->put_r_offset(this->address_);
Address address = this->address_;
if (this->od_ != NULL)
address += this->od_->address();
wr->put_r_offset(address);
wr->put_r_info(elfcpp::elf_r_info<size>(this->get_symbol_index(),
this->type_));
}
@ -472,7 +508,7 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
pov += reloc_size;
}
assert(pov - oview == oview_size);
gold_assert(pov - oview == oview_size);
of->write_output_view(off, oview_size, oview);
@ -486,8 +522,9 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
template<int size, bool big_endian>
void
Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov)
const
Output_data_got<size, big_endian>::Got_entry::write(
const General_options* options,
unsigned char* pov) const
{
Valtype val = 0;
@ -501,7 +538,7 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov)
// value. Otherwise we just write zero. The target code is
// responsible for creating a relocation entry to fill in the
// value at runtime.
if (gsym->is_resolved_locally())
if (gsym->final_value_is_known(options))
{
Sized_symbol<size>* sgsym;
// This cast is a bit ugly. We don't want to put a
@ -518,11 +555,10 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov)
break;
default:
abort();
gold_unreachable();
}
Valtype* povv = reinterpret_cast<Valtype*>(pov);
elfcpp::Swap<size, big_endian>::writeval(povv, val);
elfcpp::Swap<size, big_endian>::writeval(pov, val);
}
// Output_data_got methods.
@ -561,11 +597,11 @@ Output_data_got<size, big_endian>::do_write(Output_file* of)
p != this->entries_.end();
++p)
{
p->write(pov);
p->write(this->options_, pov);
pov += add;
}
assert(pov - oview == oview_size);
gold_assert(pov - oview == oview_size);
of->write_output_view(off, oview_size, oview);
@ -573,6 +609,121 @@ Output_data_got<size, big_endian>::do_write(Output_file* of)
this->entries_.clear();
}
// Output_data_dynamic::Dynamic_entry methods.
// Write out the entry.
template<int size, bool big_endian>
void
Output_data_dynamic::Dynamic_entry::write(
unsigned char* pov,
const Stringpool* pool) const
{
typename elfcpp::Elf_types<size>::Elf_WXword val;
switch (this->classification_)
{
case DYNAMIC_NUMBER:
val = this->u_.val;
break;
case DYNAMIC_SECTION_ADDRESS:
val = this->u_.os->address();
break;
case DYNAMIC_SECTION_SIZE:
val = this->u_.os->data_size();
break;
case DYNAMIC_SYMBOL:
{
Sized_symbol<size>* s = static_cast<Sized_symbol<size>*>(this->u_.sym);
val = s->value();
}
break;
case DYNAMIC_STRING:
val = pool->get_offset(this->u_.str);
break;
default:
gold_unreachable();
}
elfcpp::Dyn_write<size, big_endian> dw(pov);
dw.put_d_tag(this->tag_);
dw.put_d_val(val);
}
// Output_data_dynamic methods.
// Set the final data size.
void
Output_data_dynamic::do_set_address(uint64_t, off_t)
{
// Add the terminating entry.
this->add_constant(elfcpp::DT_NULL, 0);
int dyn_size;
if (this->target_->get_size() == 32)
dyn_size = elfcpp::Elf_sizes<32>::dyn_size;
else if (this->target_->get_size() == 64)
dyn_size = elfcpp::Elf_sizes<64>::dyn_size;
else
gold_unreachable();
this->set_data_size(this->entries_.size() * dyn_size);
}
// Write out the dynamic entries.
void
Output_data_dynamic::do_write(Output_file* of)
{
if (this->target_->get_size() == 32)
{
if (this->target_->is_big_endian())
this->sized_write<32, true>(of);
else
this->sized_write<32, false>(of);
}
else if (this->target_->get_size() == 64)
{
if (this->target_->is_big_endian())
this->sized_write<64, true>(of);
else
this->sized_write<64, false>(of);
}
else
gold_unreachable();
}
template<int size, bool big_endian>
void
Output_data_dynamic::sized_write(Output_file* of)
{
const int dyn_size = elfcpp::Elf_sizes<size>::dyn_size;
const off_t offset = this->offset();
const off_t oview_size = this->data_size();
unsigned char* const oview = of->get_output_view(offset, oview_size);
unsigned char* pov = oview;
for (typename Dynamic_entries::const_iterator p = this->entries_.begin();
p != this->entries_.end();
++p)
{
p->write<size, big_endian>(pov, this->pool_);
pov += dyn_size;
}
gold_assert(pov - oview == oview_size);
of->write_output_view(offset, oview_size, oview);
// We no longer need the dynamic entries.
this->entries_.clear();
}
// Output_section::Input_section methods.
// Return the data size. For an input section we store the size here.
@ -628,7 +779,9 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
dynsym_index_(0),
input_sections_(),
first_input_offset_(0),
may_add_data_(may_add_data)
may_add_data_(may_add_data),
needs_symtab_index_(false),
needs_dynsym_index_(false)
{
}
@ -648,7 +801,7 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
const char* secname,
const elfcpp::Shdr<size, big_endian>& shdr)
{
assert(this->may_add_data_);
gold_assert(this->may_add_data_);
elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
if ((addralign & (addralign - 1)) != 0)
@ -682,7 +835,7 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
void
Output_section::add_output_section_data(Output_section_data* posd)
{
assert(this->may_add_data_);
gold_assert(this->may_add_data_);
if (this->input_sections_.empty())
this->first_input_offset_ = this->data_size();
@ -750,22 +903,6 @@ Output_section::do_write(Output_file* of)
p->write(of);
}
// Output_section_strtab methods.
Output_section_strtab::Output_section_strtab(const char* name,
Stringpool* contents)
: Output_section(name, elfcpp::SHT_STRTAB, 0, false),
contents_(contents)
{
this->set_data_size(contents->get_strtab_size());
}
void
Output_section_strtab::do_write(Output_file* of)
{
this->contents_->write(of, this->offset());
}
// Output segment methods.
Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
@ -790,8 +927,8 @@ Output_segment::add_output_section(Output_section* os,
elfcpp::Elf_Word seg_flags,
bool front)
{
assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
assert(!this->is_align_known_);
gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
gold_assert(!this->is_align_known_);
// Update the segment flags.
this->flags_ |= seg_flags;
@ -817,7 +954,7 @@ Output_segment::add_output_section(Output_section* os,
if (os->type() == elfcpp::SHT_NOTE && !pdl->empty())
{
Layout::Data_list::iterator p = pdl->end();
Output_segment::Output_data_list::iterator p = pdl->end();
do
{
--p;
@ -842,7 +979,7 @@ Output_segment::add_output_section(Output_section* os,
pdl = &this->output_data_;
bool nobits = os->type() == elfcpp::SHT_NOBITS;
bool sawtls = false;
Layout::Data_list::iterator p = pdl->end();
Output_segment::Output_data_list::iterator p = pdl->end();
do
{
--p;
@ -888,7 +1025,7 @@ Output_segment::add_output_section(Output_section* os,
void
Output_segment::add_initial_output_data(Output_data* od)
{
assert(!this->is_align_known_);
gold_assert(!this->is_align_known_);
this->output_data_.push_front(od);
}
@ -942,7 +1079,7 @@ uint64_t
Output_segment::set_section_addresses(uint64_t addr, off_t* poff,
unsigned int* pshndx)
{
assert(this->type_ == elfcpp::PT_LOAD);
gold_assert(this->type_ == elfcpp::PT_LOAD);
this->vaddr_ = addr;
this->paddr_ = addr;
@ -1011,7 +1148,7 @@ Output_segment::set_section_list_addresses(Output_data_list* pdl,
void
Output_segment::set_offset()
{
assert(this->type_ != elfcpp::PT_LOAD);
gold_assert(this->type_ != elfcpp::PT_LOAD);
if (this->output_data_.empty() && this->output_bss_.empty())
{
@ -1136,7 +1273,7 @@ Output_segment::write_section_headers_list(const Stringpool* secnamepool,
if ((*p)->is_section())
{
const Output_section* ps = static_cast<const Output_section*>(*p);
assert(*pshndx == ps->out_shndx());
gold_assert(*pshndx == ps->out_shndx());
elfcpp::Shdr_write<size, big_endian> oshdr(v);
ps->write_header(secnamepool, &oshdr);
v += shdr_size;

View File

@ -3,7 +3,6 @@
#ifndef GOLD_OUTPUT_H
#define GOLD_OUTPUT_H
#include <cassert>
#include <list>
#include <vector>
@ -16,8 +15,10 @@ namespace gold
class General_options;
class Object;
class Symbol;
class Output_file;
class Output_section;
class Target;
template<int size, bool big_endian>
class Sized_target;
template<int size, bool big_endian>
@ -96,6 +97,12 @@ class Output_data
write(Output_file* file)
{ this->do_write(file); }
// This is called by Layout::finalize to note that all sizes must
// now be fixed.
static void
layout_complete()
{ Output_data::sizes_are_fixed = true; }
protected:
// Functions that child classes may or in some cases must implement.
@ -127,15 +134,16 @@ class Output_data
// Return the output section index, if there is an output section.
virtual unsigned int
do_out_shndx() const
{ abort(); }
{ gold_unreachable(); }
// Set the output section index, if this is an output section.
virtual void
do_set_out_shndx(unsigned int)
{ abort(); }
{ gold_unreachable(); }
// Set the address and file offset of the data. This only needs to
// be implemented if the child needs to know.
// be implemented if the child needs to know. The child class can
// set its size in this call.
virtual void
do_set_address(uint64_t, off_t)
{ }
@ -145,7 +153,10 @@ class Output_data
// Set the size of the data.
void
set_data_size(off_t data_size)
{ this->data_size_ = data_size; }
{
gold_assert(!Output_data::sizes_are_fixed);
this->data_size_ = data_size;
}
// Return default alignment for a size--32 or 64.
static uint64_t
@ -155,6 +166,10 @@ class Output_data
Output_data(const Output_data&);
Output_data& operator=(const Output_data&);
// This is used for verification, to make sure that we don't try to
// change any sizes after we set the section addresses.
static bool sizes_are_fixed;
// Memory address in file (not always meaningful).
uint64_t address_;
// Size of data in file.
@ -192,7 +207,7 @@ class Output_section_headers : public Output_data
int size_;
bool big_endian_;
const Layout::Segment_list& segment_list_;
const Layout::Section_list& section_list_;
const Layout::Section_list& unattached_section_list_;
const Stringpool* secnamepool_;
};
@ -254,7 +269,7 @@ class Output_file_header : public Output_data
// checking.
void
do_set_address(uint64_t, off_t off) const
{ assert(off == 0); }
{ gold_assert(off == 0); }
private:
// Write the data to the file with the right size and endianness.
@ -292,7 +307,7 @@ class Output_section_data : public Output_data
void
set_output_section(Output_section* os)
{
assert(this->output_section_ == NULL);
gold_assert(this->output_section_ == NULL);
this->output_section_ = os;
}
@ -334,36 +349,87 @@ class Output_data_const : public Output_section_data
data_(reinterpret_cast<const char*>(p), len)
{ }
// Write the data to the file.
// Add more data.
void
do_write(Output_file* output);
add_data(const std::string& add)
{
this->data_.append(add);
this->set_data_size(this->data_.size());
}
// Write the data to the output file.
void
do_write(Output_file*);
private:
std::string data_;
};
// Output_data_common is used to handle the common symbols. This is
// quite simple.
// Another version of Output_data with constant data, in which the
// buffer is allocated by the caller.
class Output_data_common : public Output_section_data
class Output_data_const_buffer : public Output_section_data
{
public:
Output_data_common(uint64_t addralign)
Output_data_const_buffer(const unsigned char* p, off_t len,
uint64_t addralign)
: Output_section_data(len, addralign), p_(p)
{ }
// Write the data the output file.
void
do_write(Output_file*);
private:
const unsigned char* p_;
};
// A place holder for data written out via some other mechanism.
class Output_data_space : public Output_section_data
{
public:
Output_data_space(off_t data_size, uint64_t addralign)
: Output_section_data(data_size, addralign)
{ }
explicit Output_data_space(uint64_t addralign)
: Output_section_data(addralign)
{ }
// Set the size.
void
set_common_size(off_t common_size)
{ this->set_data_size(common_size); }
set_space_size(off_t space_size)
{ this->set_data_size(space_size); }
// Write out the data--there is nothing to do, as common symbols are
// always zero and are stored in the BSS.
// Write out the data--this must be handled elsewhere.
void
do_write(Output_file*)
{ }
};
// A string table which goes into an output section.
class Output_data_strtab : public Output_section_data
{
public:
Output_data_strtab(Stringpool* strtab)
: Output_section_data(1), strtab_(strtab)
{ }
// This is called to set the address and file offset. Here we make
// sure that the Stringpool is finalized.
void
do_set_address(uint64_t, off_t);
// Write out the data.
void
do_write(Output_file*);
private:
Stringpool* strtab_;
};
// This POD class is used to represent a single reloc in the output
// file. This could be a private class within Output_data_reloc, but
// the templatization is complex enough that I broke it out into a
@ -391,23 +457,29 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
{ }
// A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Address address)
: local_sym_index_(GSYM_CODE), type_(type), address_(address)
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
Address address)
: local_sym_index_(GSYM_CODE), type_(type), od_(od), address_(address)
{ this->u_.gsym = gsym; }
// A reloc against a local symbol.
Output_reloc(Sized_relobj<size, big_endian>* object,
unsigned int local_sym_index,
unsigned int type, Address address)
: local_sym_index_(local_sym_index), type_(type), address_(address)
unsigned int type,
Output_data* od,
Address address)
: local_sym_index_(local_sym_index), type_(type), od_(od),
address_(address)
{
assert(local_sym_index != GSYM_CODE && local_sym_index != INVALID_CODE);
gold_assert(local_sym_index != GSYM_CODE
&& local_sym_index != INVALID_CODE);
this->u_.object = object;
}
// A reloc against the STT_SECTION symbol of an output section.
Output_reloc(Output_section* os, unsigned int type, Address address)
: local_sym_index_(SECTION_CODE), type_(type), address_(address)
Output_reloc(Output_section* os, unsigned int type, Output_data* od,
Address address)
: local_sym_index_(SECTION_CODE), type_(type), od_(od), address_(address)
{ this->u_.os = os; }
// Write the reloc entry to an output view.
@ -451,7 +523,13 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
// For a local symbol, the local symbol index. This is GSYM_CODE
// for a global symbol, or INVALID_CODE for an uninitialized value.
unsigned int local_sym_index_;
// The reloc type--a processor specific code.
unsigned int type_;
// If this is not NULL, then the relocation is against the contents
// of this output data.
Output_data* od_;
// The reloc address--if od_ is not NULL, this is the offset from
// the start of od_.
Address address_;
};
@ -471,21 +549,23 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
{ }
// A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Address address, Addend addend)
: rel_(gsym, type, address), addend_(addend)
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
Address address, Addend addend)
: rel_(gsym, type, od, address), addend_(addend)
{ }
// A reloc against a local symbol.
Output_reloc(Sized_relobj<size, big_endian>* object,
unsigned int local_sym_index,
unsigned int type, Address address, Addend addend)
: rel_(object, local_sym_index, type, address), addend_(addend)
unsigned int type, Output_data* od, Address address,
Addend addend)
: rel_(object, local_sym_index, type, od, address), addend_(addend)
{ }
// A reloc against the STT_SECTION symbol of an output section.
Output_reloc(Output_section* os, unsigned int type, Address address,
Addend addend)
: rel_(os, type, address), addend_(addend)
Output_reloc(Output_section* os, unsigned int type, Output_data* od,
Address address, Addend addend)
: rel_(os, type, od, address), addend_(addend)
{ }
// Write the reloc entry to an output view.
@ -564,19 +644,21 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
// Add a reloc against a global symbol.
void
add_global(Symbol* gsym, unsigned int type, Address address)
{ this->add(Output_reloc_type(gsym, type, address)); }
add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
{ this->add(Output_reloc_type(gsym, type, od, address)); }
// Add a reloc against a local symbol.
void
add_local(Sized_relobj<size, big_endian>* object,
unsigned int local_sym_index, unsigned int type, Address address)
{ this->add(Output_reloc_type(object, local_sym_index, type, address)); }
unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address)
{ this->add(Output_reloc_type(object, local_sym_index, type, od, address)); }
// A reloc against the STT_SECTION symbol of an output section.
void
add_output_section(Output_section* os, unsigned int type, Address address)
{ this->add(Output_reloc_type(os, type, address)); }
add_output_section(Output_section* os, unsigned int type,
Output_data* od, Address address)
{ this->add(Output_reloc_type(os, type, od, address)); }
};
// The SHT_RELA version of Output_data_reloc.
@ -600,24 +682,25 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
// Add a reloc against a global symbol.
void
add_global(Symbol* gsym, unsigned int type, Address address, Addend addend)
{ this->add(Output_reloc_type(gsym, type, address, addend)); }
add_global(Symbol* gsym, unsigned int type, Output_data* od,
Address address, Addend addend)
{ this->add(Output_reloc_type(gsym, type, od, address, addend)); }
// Add a reloc against a local symbol.
void
add_local(Sized_relobj<size, big_endian>* object,
unsigned int local_sym_index, unsigned int type,
Address address, Addend addend)
Output_data* od, Address address, Addend addend)
{
this->add(Output_reloc_type(object, local_sym_index, type, address,
this->add(Output_reloc_type(object, local_sym_index, type, od, address,
addend));
}
// A reloc against the STT_SECTION symbol of an output section.
void
add_output_section(Output_section* os, unsigned int type, Address address,
Addend addend)
{ this->add(Output_reloc_type(os, type, address, addend)); }
add_output_section(Output_section* os, unsigned int type, Output_data* od,
Address address, Addend addend)
{ this->add(Output_reloc_type(os, type, od, address, addend)); }
};
// Output_data_got is used to manage a GOT. Each entry in the GOT is
@ -631,9 +714,9 @@ class Output_data_got : public Output_section_data
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
Output_data_got()
Output_data_got(const General_options* options)
: Output_section_data(Output_data::default_alignment(size)),
entries_()
options_(options), entries_()
{ }
// Add an entry for a global symbol to the GOT. Return true if this
@ -676,7 +759,7 @@ class Output_data_got : public Output_section_data
{ this->u_.constant = 0; }
// Create a global symbol entry.
Got_entry(Symbol* gsym)
explicit Got_entry(Symbol* gsym)
: local_sym_index_(GSYM_CODE)
{ this->u_.gsym = gsym; }
@ -684,20 +767,20 @@ class Output_data_got : public Output_section_data
Got_entry(Object* object, unsigned int local_sym_index)
: local_sym_index_(local_sym_index)
{
assert(local_sym_index != GSYM_CODE
&& local_sym_index != CONSTANT_CODE);
gold_assert(local_sym_index != GSYM_CODE
&& local_sym_index != CONSTANT_CODE);
this->u_.object = object;
}
// Create a constant entry. The constant is a host value--it will
// be swapped, if necessary, when it is written out.
Got_entry(Valtype constant)
explicit Got_entry(Valtype constant)
: local_sym_index_(CONSTANT_CODE)
{ this->u_.constant = constant; }
// Write the GOT entry to an output view.
void
write(unsigned char* pov) const;
write(const General_options*, unsigned char* pov) const;
private:
enum
@ -737,10 +820,142 @@ class Output_data_got : public Output_section_data
set_got_size()
{ this->set_data_size(this->got_offset(this->entries_.size())); }
// Options.
const General_options* options_;
// The list of GOT entries.
Got_entries entries_;
};
// Output_data_dynamic is used to hold the data in SHT_DYNAMIC
// section.
class Output_data_dynamic : public Output_section_data
{
public:
Output_data_dynamic(const Target* target, Stringpool* pool)
: Output_section_data(Output_data::default_alignment(target->get_size())),
target_(target), entries_(), pool_(pool)
{ }
// Add a new dynamic entry with a fixed numeric value.
void
add_constant(elfcpp::DT tag, unsigned int val)
{ this->add_entry(Dynamic_entry(tag, val)); }
// Add a new dynamic entry with the address of a section.
void
add_section_address(elfcpp::DT tag, Output_section* os)
{ this->add_entry(Dynamic_entry(tag, os, false)); }
// Add a new dynamic entry with the size of a section.
void
add_section_size(elfcpp::DT tag, Output_section* os)
{ this->add_entry(Dynamic_entry(tag, os, true)); }
// Add a new dynamic entry with the address of a symbol.
void
add_symbol(elfcpp::DT tag, Symbol* sym)
{ this->add_entry(Dynamic_entry(tag, sym)); }
// Add a new dynamic entry with a string.
void
add_string(elfcpp::DT tag, const char* str)
{ this->add_entry(Dynamic_entry(tag, this->pool_->add(str, NULL))); }
// Set the final data size.
void
do_set_address(uint64_t, off_t);
// Write out the dynamic entries.
void
do_write(Output_file*);
private:
// This POD class holds a single dynamic entry.
class Dynamic_entry
{
public:
// Create an entry with a fixed numeric value.
Dynamic_entry(elfcpp::DT tag, unsigned int val)
: tag_(tag), classification_(DYNAMIC_NUMBER)
{ this->u_.val = val; }
// Create an entry with the size or address of a section.
Dynamic_entry(elfcpp::DT tag, Output_section* os, bool section_size)
: tag_(tag),
classification_(section_size
? DYNAMIC_SECTION_SIZE
: DYNAMIC_SECTION_ADDRESS)
{ this->u_.os = os; }
// Create an entry with the address of a symbol.
Dynamic_entry(elfcpp::DT tag, Symbol* sym)
: tag_(tag), classification_(DYNAMIC_SYMBOL)
{ this->u_.sym = sym; }
// Create an entry with a string.
Dynamic_entry(elfcpp::DT tag, const char* str)
: tag_(tag), classification_(DYNAMIC_STRING)
{ this->u_.str = str; }
// Write the dynamic entry to an output view.
template<int size, bool big_endian>
void
write(unsigned char* pov, const Stringpool*) const;
private:
enum Classification
{
// Number.
DYNAMIC_NUMBER,
// Section address.
DYNAMIC_SECTION_ADDRESS,
// Section size.
DYNAMIC_SECTION_SIZE,
// Symbol adress.
DYNAMIC_SYMBOL,
// String.
DYNAMIC_STRING
};
union
{
// For DYNAMIC_NUMBER.
unsigned int val;
// For DYNAMIC_SECTION_ADDRESS and DYNAMIC_SECTION_SIZE.
Output_section* os;
// For DYNAMIC_SYMBOL.
Symbol* sym;
// For DYNAMIC_STRING.
const char* str;
} u_;
// The dynamic tag.
elfcpp::DT tag_;
// The type of entry.
Classification classification_;
};
// Add an entry to the list.
void
add_entry(const Dynamic_entry& entry)
{ this->entries_.push_back(entry); }
// Sized version of write function.
template<int size, bool big_endian>
void
sized_write(Output_file* of);
// The type of the list of entries.
typedef std::vector<Dynamic_entry> Dynamic_entries;
// The target.
const Target* target_;
// The entries.
Dynamic_entries entries_;
// The pool used for strings.
Stringpool* pool_;
};
// An output section. We don't expect to have too many output
// sections, so we don't bother to do a template on the size.
@ -788,6 +1003,11 @@ class Output_section : public Output_data
do_set_out_shndx(unsigned int shndx)
{ this->out_shndx_ = shndx; }
// Return the entsize field.
uint64_t
entsize() const
{ return this->entsize_; }
// Set the entsize field.
void
set_entsize(uint64_t v)
@ -822,7 +1042,7 @@ class Output_section : public Output_data
unsigned int
symtab_index() const
{
assert(this->symtab_index_ != 0);
gold_assert(this->symtab_index_ != 0);
return this->symtab_index_;
}
@ -830,7 +1050,7 @@ class Output_section : public Output_data
void
set_symtab_index(unsigned int index)
{
assert(index != 0);
gold_assert(index != 0);
this->symtab_index_ = index;
}
@ -848,7 +1068,7 @@ class Output_section : public Output_data
unsigned int
dynsym_index() const
{
assert(this->dynsym_index_ != 0);
gold_assert(this->dynsym_index_ != 0);
return this->dynsym_index_;
}
@ -856,7 +1076,7 @@ class Output_section : public Output_data
void
set_dynsym_index(unsigned int index)
{
assert(index != 0);
gold_assert(index != 0);
this->dynsym_index_ = index;
}
@ -871,7 +1091,7 @@ class Output_section : public Output_data
// does nothing: the data is written out by calling Object::Relocate
// on each input object. But if there are any Output_section_data
// objects we do need to write them out here.
virtual void
void
do_write(Output_file*);
// Return the address alignment--function required by parent class.
@ -923,7 +1143,7 @@ class Output_section : public Output_data
p2align_(ffsll(static_cast<long long>(addralign))),
data_size_(data_size)
{
assert(shndx != -1U);
gold_assert(shndx != -1U);
this->u_.object = object;
}
@ -936,7 +1156,11 @@ class Output_section : public Output_data
// The required alignment.
uint64_t
addralign() const
{ return static_cast<uint64_t>(1) << this->p2align_; }
{
return (this->p2align_ == 0
? 0
: static_cast<uint64_t>(1) << (this->p2align_ - 1));
}
// Return the required size.
off_t
@ -1024,57 +1248,6 @@ class Output_section : public Output_data
bool needs_dynsym_index_ : 1;
};
// A special Output_section which represents the symbol table
// (SHT_SYMTAB). The actual data is written out by
// Symbol_table::write_globals.
class Output_section_symtab : public Output_section
{
public:
Output_section_symtab(const char* name, off_t data_size)
: Output_section(name, elfcpp::SHT_SYMTAB, 0, false)
{ this->set_data_size(data_size); }
// The data is written out by Symbol_table::write_globals. We don't
// do anything here.
void
do_write(Output_file*)
{ }
};
// A special Output_section which represents the dynamic symbol table
// (SHT_DYNSYM). The actual data is written out by
// Symbol_table::write_globals.
class Output_section_dynsym : public Output_section
{
public:
Output_section_dynsym(const char* name, off_t data_size)
: Output_section(name, elfcpp::SHT_DYNSYM, 0, false)
{ this->set_data_size(data_size); }
// The data is written out by Symbol_table::write_globals. We don't
// do anything here.
void
do_write(Output_file*)
{ }
};
// A special Output_section which holds a string table.
class Output_section_strtab : public Output_section
{
public:
Output_section_strtab(const char* name, Stringpool* contents);
// Write out the data.
void
do_write(Output_file*);
private:
Stringpool* contents_;
};
// An output segment. PT_LOAD segments are built from collections of
// output sections. Other segments typically point within PT_LOAD
// segments, and are built directly as needed.
@ -1247,7 +1420,7 @@ class Output_file
unsigned char*
get_output_view(off_t start, off_t size)
{
assert(start >= 0 && size >= 0 && start + size <= this->file_size_);
gold_assert(start >= 0 && size >= 0 && start + size <= this->file_size_);
return this->base_ + start;
}

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-11-15 16:35-0800\n"
"POT-Creation-Date: 2006-11-29 09:53-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -56,331 +56,331 @@ msgstr ""
msgid "%s: %s: member at %ld is not an ELF object"
msgstr ""
#: dirsearch.cc:51
#: dirsearch.cc:50
#, c-format
msgid "can not read directory %s"
msgstr ""
#: dynobj.cc:97
#: dynobj.cc:109
#, c-format
msgid "%s: %s: unexpected duplicate type %u section: %u, %u\n"
msgstr ""
#: dynobj.cc:138
#: dynobj.cc:150
#, c-format
msgid "%s: %s: unexpected link in section %u header: %u != %u\n"
msgstr ""
#: dynobj.cc:176
#: dynobj.cc:188
#, c-format
msgid "%s: %s: DYNAMIC section %u link out of range: %u\n"
msgstr ""
#: dynobj.cc:186
#: dynobj.cc:198
#, c-format
msgid "%s: %s: DYNAMIC section %u link %u is not a strtab\n"
msgstr ""
#: dynobj.cc:208
#: dynobj.cc:220
#, c-format
msgid "%s: %s: DT_SONAME value out of range: %lld >= %lld\n"
msgstr ""
#: dynobj.cc:225
#: dynobj.cc:237
#, c-format
msgid "%s: %s: missing DT_NULL in dynamic segment\n"
msgstr ""
#: dynobj.cc:273
#: dynobj.cc:285
#, c-format
msgid "%s: %s: invalid dynamic symbol table name index: %u\n"
msgstr ""
#: dynobj.cc:281
#: dynobj.cc:293
#, c-format
msgid "%s: %s: dynamic symbol table name section has wrong type: %u\n"
msgstr ""
#: dynobj.cc:356 object.cc:422
#: dynobj.cc:368 object.cc:421
#, c-format
msgid "%s: %s: bad section name offset for section %u: %lu\n"
msgstr ""
#: dynobj.cc:386
#: dynobj.cc:398
#, c-format
msgid "%s: %s: duplicate definition for version %u\n"
msgstr ""
#: dynobj.cc:430 dynobj.cc:549
#: dynobj.cc:442 dynobj.cc:561
#, c-format
msgid "%s: %s: verdef vd_next field out of range: %u\n"
msgstr ""
#: dynobj.cc:454
#: dynobj.cc:466
#, c-format
msgid "%s: %s: verneed vn_aux field out of range: %u\n"
msgstr ""
#: dynobj.cc:473
#: dynobj.cc:485
#, c-format
msgid "%s: %s: verneed vna_next field out of range: %u\n"
msgstr ""
#: dynobj.cc:486
#: dynobj.cc:498
#, c-format
msgid "%s: %s: verneed vn_next field out of range: %u\n"
msgstr ""
#: dynobj.cc:516
#: dynobj.cc:528
#, c-format
msgid "%s: %s: verdef vd_cnt field too small: %u\n"
msgstr ""
#: dynobj.cc:525
#: dynobj.cc:537
#, c-format
msgid "%s: %s: verdef vd_aux field out of range: %u\n"
msgstr ""
#: dynobj.cc:537
#: dynobj.cc:549
#, c-format
msgid "%s: %s: verdaux vda_name field out of range: %u\n"
msgstr ""
#: dynobj.cc:579
#: dynobj.cc:591
#, c-format
msgid "%s: %s: vernaux vna_name field out of range: %u\n"
msgstr ""
#: dynobj.cc:615
#: dynobj.cc:628
#, c-format
msgid "%s: %s: size of dynamic symbols is not multiple of symbol size\n"
msgstr ""
#: fileread.cc:56
#: fileread.cc:55
#, c-format
msgid "%s: warning: close(%s) failed: %s"
msgstr ""
#: fileread.cc:129
#: fileread.cc:128
#, c-format
msgid "%s: %s: lseek to %lld failed: %s"
msgstr ""
#: fileread.cc:139
#: fileread.cc:138
#, c-format
msgid "%s: %s: read failed: %s\n"
msgstr ""
#: fileread.cc:149 fileread.cc:232
#: fileread.cc:148 fileread.cc:231
#, c-format
msgid "%s: %s: file too short: read only %lld of %lld bytes at %lld\n"
msgstr ""
#: fileread.cc:327
#: fileread.cc:326
#, c-format
msgid "%s: cannot find %s\n"
msgstr ""
#: fileread.cc:335
#: fileread.cc:334
#, c-format
msgid "%s: cannot open %s: %s\n"
msgstr ""
#: gold.cc:102
#: gold.cc:106
msgid "no input files"
msgstr ""
#: gold-threads.cc:48
#: gold-threads.cc:46
msgid "pthead_mutextattr_init failed"
msgstr ""
#: gold-threads.cc:51
#: gold-threads.cc:49
msgid "pthread_mutextattr_settype failed"
msgstr ""
#: gold-threads.cc:55
#: gold-threads.cc:53
msgid "pthread_mutex_init failed"
msgstr ""
#: gold-threads.cc:58
#: gold-threads.cc:56
msgid "pthread_mutexattr_destroy failed"
msgstr ""
#: gold-threads.cc:64
#: gold-threads.cc:62
msgid "pthread_mutex_destroy failed"
msgstr ""
#: gold-threads.cc:71
#: gold-threads.cc:69
msgid "pthread_mutex_lock failed"
msgstr ""
#: gold-threads.cc:78
#: gold-threads.cc:76
msgid "pthread_mutex_unlock failed"
msgstr ""
#: gold-threads.cc:159
#: gold-threads.cc:157
msgid "pthread_cond_init failed"
msgstr ""
#: gold-threads.cc:165
#: gold-threads.cc:163
msgid "pthread_cond_destroy failed"
msgstr ""
#: gold-threads.cc:172
#: gold-threads.cc:170
msgid "pthread_cond_wait failed"
msgstr ""
#: gold-threads.cc:179
#: gold-threads.cc:177
msgid "pthread_cond_signal failed"
msgstr ""
#. FIXME: This needs to specify the location somehow.
#: i386.cc:88
#: i386.cc:93
#, c-format
msgid "%s: missing expected TLS relocation\n"
msgstr ""
#: i386.cc:307 i386.cc:430 i386.cc:623
#: i386.cc:617 i386.cc:757 i386.cc:961
#, c-format
msgid "%s: %s: unexpected reloc %u in object file\n"
msgstr ""
#: i386.cc:340 i386.cc:359
#: i386.cc:653 i386.cc:672
#, c-format
msgid "%s: %s: unsupported reloc %u against local symbol\n"
msgstr ""
#: i386.cc:411 i386.cc:465 i386.cc:483
#: i386.cc:793 i386.cc:814
#, c-format
msgid "%s: %s: unsupported reloc %u against global symbol %s\n"
msgstr ""
#: i386.cc:505
#: i386.cc:837
#, c-format
msgid "%s: %s: unsupported RELA reloc section\n"
msgstr ""
#: i386.cc:544
#: i386.cc:877
#, c-format
msgid "%s: %s: missing expected TLS relocation\n"
msgstr ""
#: i386.cc:590 i386.cc:655 i386.cc:728 i386.cc:739
#: i386.cc:993 i386.cc:1068 i386.cc:1079
#, c-format
msgid "%s: %s: unsupported reloc %u\n"
msgstr ""
#: i386.cc:682
#: i386.cc:1020
#, c-format
msgid "%s: %s: TLS reloc but no TLS segment\n"
msgstr ""
#: i386.cc:713
#: i386.cc:1053
#, c-format
msgid "%s: %s: unsupported reloc type %u\n"
msgstr ""
#: i386.cc:922
#: i386.cc:1262
#, c-format
msgid "%s: %s: TLS relocation out of range\n"
msgstr ""
#: i386.cc:940
#: i386.cc:1280
#, c-format
msgid "%s: %s: TLS relocation against invalid instruction\n"
msgstr ""
#: object.cc:31
#: object.cc:30
#, c-format
msgid "%s: %s: unsupported ELF machine number %d\n"
msgstr ""
#: object.cc:87
#: object.cc:86
#, c-format
msgid "%s: %s: section name section has wrong type: %u\n"
msgstr ""
#: object.cc:230
#: object.cc:229
#, c-format
msgid "%s: %s: invalid symbol table name index: %u\n"
msgstr ""
#: object.cc:238
#: object.cc:237
#, c-format
msgid "%s: %s: symbol table name section has wrong type: %u\n"
msgstr ""
#: object.cc:294
#: object.cc:293
#, c-format
msgid "%s: %s: section group %u info %u out of range\n"
msgstr ""
#: object.cc:311
#: object.cc:310
#, c-format
msgid "%s: %s: symbol %u name offset %u out of range\n"
msgstr ""
#: object.cc:345
#: object.cc:344
#, c-format
msgid "%s: %s: section %u in section group %u out of range"
msgstr ""
#: object.cc:489
#: object.cc:488
#, c-format
msgid "%s: %s: size of symbols is not multiple of symbol size\n"
msgstr ""
#: object.cc:576
#: object.cc:575
#, c-format
msgid "%s: %s: unknown section index %u for local symbol %u\n"
msgstr ""
#: object.cc:587
#: object.cc:586
#, c-format
msgid "%s: %s: local symbol %u section index %u out of range\n"
msgstr ""
#: object.cc:616
#: object.cc:615
#, c-format
msgid "%s: %s: local symbol %u section name out of range: %u >= %u\n"
msgstr ""
#: object.cc:800
#: object.cc:799
#, c-format
msgid "%s: %s: unsupported ELF file type %d\n"
msgstr ""
#: object.cc:819 object.cc:872 object.cc:893
#: object.cc:818 object.cc:871 object.cc:892
#, c-format
msgid "%s: %s: ELF file too short\n"
msgstr ""
#: object.cc:828
#: object.cc:827
#, c-format
msgid "%s: %s: invalid ELF version 0\n"
msgstr ""
#: object.cc:831
#: object.cc:830
#, c-format
msgid "%s: %s: unsupported ELF version %d\n"
msgstr ""
#: object.cc:839
#: object.cc:838
#, c-format
msgid "%s: %s: invalid ELF class 0\n"
msgstr ""
#: object.cc:846
#: object.cc:845
#, c-format
msgid "%s: %s: unsupported ELF class %d\n"
msgstr ""
#: object.cc:854
#: object.cc:853
#, c-format
msgid "%s: %s: invalid ELF data encoding\n"
msgstr ""
#: object.cc:861
#: object.cc:860
#, c-format
msgid "%s: %s: unsupported ELF data encoding %d\n"
msgstr ""
@ -486,7 +486,7 @@ msgstr ""
msgid "%s: use the --help option for usage information\n"
msgstr ""
#: options.cc:565 script.cc:1128
#: options.cc:565 script.cc:1133
#, c-format
msgid "%s: %s: %s\n"
msgstr ""
@ -496,37 +496,37 @@ msgstr ""
msgid "%s: -%c: %s\n"
msgstr ""
#: output.cc:656
#: output.cc:809
#, c-format
msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
msgstr ""
#: output.cc:1171
#: output.cc:1308
#, c-format
msgid "%s: %s: open: %s\n"
msgstr ""
#: output.cc:1180
#: output.cc:1317
#, c-format
msgid "%s: %s: lseek: %s\n"
msgstr ""
#: output.cc:1187
#: output.cc:1324
#, c-format
msgid "%s: %s: write: %s\n"
msgstr ""
#: output.cc:1197
#: output.cc:1334
#, c-format
msgid "%s: %s: mmap: %s\n"
msgstr ""
#: output.cc:1211
#: output.cc:1348
#, c-format
msgid "%s: %s: munmap: %s\n"
msgstr ""
#: output.cc:1219
#: output.cc:1356
#, c-format
msgid "%s: %s: close: %s\n"
msgstr ""
@ -577,52 +577,52 @@ msgstr ""
msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
msgstr ""
#: symtab.cc:446 symtab.cc:543
#: symtab.cc:445 symtab.cc:542
#, c-format
msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
msgstr ""
#: symtab.cc:463
#: symtab.cc:462
#, c-format
msgid "%s: %s: bad global symbol name offset %u at %lu\n"
msgstr ""
#: symtab.cc:550
#: symtab.cc:549
#, c-format
msgid "%s: %s: too few symbol versions\n"
msgstr ""
#: symtab.cc:570
#: symtab.cc:569
#, c-format
msgid "%s: %s: bad symbol name offset %u at %lu\n"
msgstr ""
#: symtab.cc:614
#: symtab.cc:613
#, c-format
msgid "%s: %s: versym for symbol %zu out of range: %u\n"
msgstr ""
#: symtab.cc:622
#: symtab.cc:621
#, c-format
msgid "%s: %s: versym for symbol %zu has no name: %u\n"
msgstr ""
#: symtab.cc:1019 symtab.cc:1158
#: symtab.cc:1050 symtab.cc:1201
#, c-format
msgid "%s: %s: unsupported symbol section 0x%x\n"
msgstr ""
#: symtab.cc:1274
#: symtab.cc:1364
#, c-format
msgid "%s: %s: warning: %s\n"
msgstr ""
#: target-reloc.h:163
#: target-reloc.h:164
#, c-format
msgid "%s: %s: reloc has bad offset %zu\n"
msgstr ""
#: target-reloc.h:173
#: target-reloc.h:174
#, c-format
msgid "%s: %s: undefined reference to '%s'\n"
msgstr ""

View File

@ -56,7 +56,7 @@ Read_symbols::run(Workqueue* workqueue)
{
if (this->input_argument_->is_group())
{
assert(this->input_group_ == NULL);
gold_assert(this->input_group_ == NULL);
this->do_group(workqueue);
return;
}
@ -170,7 +170,7 @@ Read_symbols::do_group(Workqueue* workqueue)
++p)
{
const Input_argument* arg = &*p;
assert(arg->is_file());
gold_assert(arg->is_file());
Task_token* next_blocker = new Task_token();
next_blocker->add_blocker();

View File

@ -227,17 +227,17 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
}
// Read the local symbols.
assert(this->symtab_shndx_ != -1U);
gold_assert(this->symtab_shndx_ != -1U);
if (this->symtab_shndx_ == 0 || this->local_symbol_count_ == 0)
rd->local_symbols = NULL;
else
{
typename This::Shdr symtabshdr(pshdrs
+ this->symtab_shndx_ * This::shdr_size);
assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
const int sym_size = This::sym_size;
const unsigned int loccount = this->local_symbol_count_;
assert(loccount == symtabshdr.get_sh_info());
gold_assert(loccount == symtabshdr.get_sh_info());
off_t locsize = loccount * sym_size;
rd->local_symbols = this->get_lasting_view(symtabshdr.get_sh_offset(),
locsize);
@ -266,8 +266,8 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
p != rd->relocs.end();
++p)
{
target->scan_relocs(options, symtab, layout, this, p->sh_type,
p->contents->data(), p->reloc_count,
target->scan_relocs(options, symtab, layout, this, p->data_shndx,
p->sh_type, p->contents->data(), p->reloc_count,
this->local_symbol_count_,
local_symbols,
this->symbols_);
@ -357,8 +357,8 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
if (sh_size == 0)
continue;
assert(map_sections[i].offset >= 0
&& map_sections[i].offset + sh_size <= os->data_size());
gold_assert(map_sections[i].offset >= 0
&& map_sections[i].offset + sh_size <= os->data_size());
unsigned char* view = of->get_output_view(start, sh_size);
this->read(shdr.get_sh_offset(), sh_size, view);
@ -418,7 +418,7 @@ Sized_relobj<size, big_endian>::relocate_sections(
continue;
}
assert((*pviews)[index].view != NULL);
gold_assert((*pviews)[index].view != NULL);
if (shdr.get_sh_link() != this->symtab_shndx_)
{
@ -471,6 +471,29 @@ Sized_relobj<size, big_endian>::relocate_sections(
}
}
// Relocate_functions functions.
// Return whether we need a COPY reloc for a relocation against GSYM.
// The relocation is being applied to section SHNDX in OBJECT.
template<int size, bool big_endian>
bool
Relocate_functions<size, big_endian>::need_copy_reloc(
const General_options*,
Relobj* object,
unsigned int shndx,
Symbol*)
{
// FIXME: Handle -z nocopyrelocs.
// If this is a readonly section, then we need a COPY reloc.
// Otherwise we can use a dynamic reloc.
if ((object->section_flags(shndx) & elfcpp::SHF_WRITE) == 0)
return true;
return false;
}
// Instantiate the templates we need. We could use the configure
// script to restrict this to only the ones for implemented targets.
@ -546,5 +569,28 @@ Sized_relobj<64, true>::do_relocate(const General_options& options,
const Layout* layout,
Output_file* of);
template
bool
Relocate_functions<32, false>::need_copy_reloc(const General_options*,
Relobj*, unsigned int,
Symbol*);
template
bool
Relocate_functions<32, true>::need_copy_reloc(const General_options*,
Relobj*, unsigned int,
Symbol*);
template
bool
Relocate_functions<64, false>::need_copy_reloc(const General_options*,
Relobj*, unsigned int,
Symbol*);
template
bool
Relocate_functions<64, true>::need_copy_reloc(const General_options*,
Relobj*, unsigned int,
Symbol*);
} // End namespace gold.

View File

@ -10,9 +10,11 @@
namespace gold
{
class General_options;
class Relobj;
class Read_relocs_data;
class Stringpool;
class Symbol;
class Layout;
// A class to read the relocations for an object file, and then queue
@ -227,6 +229,12 @@ public:
{
This::template pcrel<64>(view, value, address);
}
// Return whether we need a COPY reloc for a reloc against GSYM,
// which is being applied to section SHNDX in OBJECT.
static bool
need_copy_reloc(const General_options*, Relobj* object, unsigned int shndx,
Symbol* gsym);
};
} // End namespace gold.

View File

@ -19,7 +19,7 @@ void
Symbol::override_base(const elfcpp::Sym<size, big_endian>& sym,
Object* object)
{
assert(this->source_ == FROM_OBJECT);
gold_assert(this->source_ == FROM_OBJECT);
this->u_.from_object.object = object;
// FIXME: Handle SHN_XINDEX.
this->u_.from_object.shnum = sym.get_st_shndx();
@ -98,12 +98,12 @@ Symbol_table::resolve(Sized_symbol<size>* to,
case elfcpp::STB_LOCAL:
// We should only see externally visible symbols in the symbol
// table.
abort();
gold_unreachable();
default:
// Any target which wants to handle STB_LOOS, etc., needs to
// define a resolve method.
abort();
gold_unreachable();
}
if (to->source() == Symbol::FROM_OBJECT
@ -507,7 +507,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
return;
default:
abort();
gold_unreachable();
}
}

View File

@ -4,7 +4,6 @@
#include <string>
#include <vector>
#include <cassert>
#include <cstdio>
#include <cstdlib>
@ -50,14 +49,20 @@ class Token
Token(Classification classification, int lineno, int charpos)
: classification_(classification), value_(), opcode_(0),
lineno_(lineno), charpos_(charpos)
{ assert(classification == TOKEN_INVALID || classification == TOKEN_EOF); }
{
gold_assert(classification == TOKEN_INVALID
|| classification == TOKEN_EOF);
}
// A general token with a value.
Token(Classification classification, const std::string& value,
int lineno, int charpos)
: classification_(classification), value_(value), opcode_(0),
lineno_(lineno), charpos_(charpos)
{ assert(classification != TOKEN_INVALID && classification != TOKEN_EOF); }
{
gold_assert(classification != TOKEN_INVALID
&& classification != TOKEN_EOF);
}
// A token representing a string of characters.
Token(const std::string& s, int lineno, int charpos)
@ -101,21 +106,21 @@ class Token
const std::string&
string_value() const
{
assert(this->classification_ == TOKEN_STRING);
gold_assert(this->classification_ == TOKEN_STRING);
return this->value_;
}
int
operator_value() const
{
assert(this->classification_ == TOKEN_OPERATOR);
gold_assert(this->classification_ == TOKEN_OPERATOR);
return this->opcode_;
}
int64_t
integer_value() const
{
assert(this->classification_ == TOKEN_INTEGER);
gold_assert(this->classification_ == TOKEN_INTEGER);
return strtoll(this->value_.c_str(), NULL, 0);
}
@ -1097,7 +1102,7 @@ yylex(YYSTYPE* lvalp, void* closurev)
default:
case Token::TOKEN_INVALID:
case Token::TOKEN_EOF:
abort();
gold_unreachable();
case Token::TOKEN_STRING:
{

View File

@ -2,7 +2,6 @@
#include "gold.h"
#include <cassert>
#include <cstring>
#include <algorithm>
#include <vector>
@ -60,12 +59,15 @@ Stringpool::Stringpool_hash::operator()(const char* s) const
const char*
Stringpool::add_string(const char* s, Key* pkey)
{
// We are in trouble if we've already computed the string offsets.
gold_assert(this->strtab_size_ == 0);
// The size we allocate for a new Stringdata.
const size_t buffer_size = 1000;
// The amount we multiply the Stringdata index when calculating the
// key.
const size_t key_mult = 1024;
assert(key_mult >= buffer_size);
gold_assert(key_mult >= buffer_size);
size_t len = strlen(s);
@ -141,7 +143,7 @@ Stringpool::add(const char* s, Key* pkey)
std::pair<const char*, Val> element(ret, std::make_pair(k, ozero));
std::pair<String_set_type::iterator, bool> ins =
this->string_set_.insert(element);
assert(ins.second);
gold_assert(ins.second);
if (pkey != NULL)
*pkey = k;
@ -222,6 +224,12 @@ Stringpool::is_suffix(const char* s1, const char* s2)
void
Stringpool::set_string_offsets()
{
if (this->strtab_size_ != 0)
{
// We've already computed the offsets.
return;
}
size_t count = this->string_set_.size();
std::vector<String_set_type::iterator> v;
@ -260,10 +268,11 @@ Stringpool::set_string_offsets()
off_t
Stringpool::get_offset(const char* s) const
{
gold_assert(this->strtab_size_ != 0);
String_set_type::const_iterator p = this->string_set_.find(s);
if (p != this->string_set_.end())
return p->second.second;
abort();
gold_unreachable();
}
// Write the ELF strtab into the output file at the specified offset.
@ -271,6 +280,7 @@ Stringpool::get_offset(const char* s) const
void
Stringpool::write(Output_file* of, off_t offset)
{
gold_assert(this->strtab_size_ != 0);
unsigned char* viewu = of->get_output_view(offset, this->strtab_size_);
char* view = reinterpret_cast<char*>(viewu);
view[0] = '\0';

View File

@ -63,7 +63,10 @@ class Stringpool
// Get the size of the ELF strtab.
off_t
get_strtab_size() const
{ return this->strtab_size_; }
{
gold_assert(this->strtab_size_ != 0);
return this->strtab_size_;
}
// Write the strtab into the output file at the specified offset.
void

View File

@ -2,7 +2,6 @@
#include "gold.h"
#include <cassert>
#include <stdint.h>
#include <string>
#include <utility>
@ -198,8 +197,8 @@ Symbol_table::Symbol_table_eq::operator()(const Symbol_table_key& k1,
void
Symbol_table::make_forwarder(Symbol* from, Symbol* to)
{
assert(from != to);
assert(!from->is_forwarder() && !to->is_forwarder());
gold_assert(from != to);
gold_assert(!from->is_forwarder() && !to->is_forwarder());
this->forwarders_[from] = to;
from->set_forwarder();
}
@ -209,10 +208,10 @@ Symbol_table::make_forwarder(Symbol* from, Symbol* to)
Symbol*
Symbol_table::resolve_forwards(const Symbol* from) const
{
assert(from->is_forwarder());
gold_assert(from->is_forwarder());
Unordered_map<const Symbol*, Symbol*>::const_iterator p =
this->forwarders_.find(from);
assert(p != this->forwarders_.end());
gold_assert(p != this->forwarders_.end());
return p->second;
}
@ -324,7 +323,7 @@ Symbol_table::add_from_object(Object* object,
// We already have an entry for NAME/VERSION.
ret = this->get_sized_symbol SELECT_SIZE_NAME(size) (ins.first->second
SELECT_SIZE(size));
assert(ret != NULL);
gold_assert(ret != NULL);
was_undefined = ret->is_undefined();
was_common = ret->is_common();
@ -357,7 +356,7 @@ Symbol_table::add_from_object(Object* object,
else
{
// This is the first time we have seen NAME/VERSION.
assert(ins.first->second == NULL);
gold_assert(ins.first->second == NULL);
was_undefined = false;
was_common = false;
@ -406,7 +405,7 @@ Symbol_table::add_from_object(Object* object,
{
// This is the first time we have seen NAME/NULL. Point
// it at the new entry for NAME/VERSION.
assert(insdef.second);
gold_assert(insdef.second);
insdef.first->second = ret;
}
}
@ -654,7 +653,7 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
bool only_if_ref
ACCEPT_SIZE_ENDIAN)
{
assert(this->size_ == size);
gold_assert(this->size_ == size);
Symbol* oldsym;
Sized_symbol<size>* sym;
@ -685,20 +684,20 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
{
// We already have a symbol table entry for NAME.
oldsym = ins.first->second;
assert(oldsym != NULL);
gold_assert(oldsym != NULL);
sym = NULL;
}
else
{
// We haven't seen this symbol before.
assert(ins.first->second == NULL);
gold_assert(ins.first->second == NULL);
if (!target->has_make_symbol())
sym = new Sized_symbol<size>();
else
{
assert(target->get_size() == size);
assert(target->is_big_endian() ? big_endian : !big_endian);
gold_assert(target->get_size() == size);
gold_assert(target->is_big_endian() ? big_endian : !big_endian);
typedef Sized_target<size, big_endian> My_target;
My_target* sized_target = static_cast<My_target*>(target);
sym = sized_target->make_symbol();
@ -713,11 +712,11 @@ Symbol_table::define_special_symbol(Target* target, const char* name,
if (oldsym != NULL)
{
assert(sym == NULL);
gold_assert(sym == NULL);
sym = this->get_sized_symbol SELECT_SIZE_NAME(size) (oldsym
SELECT_SIZE(size));
assert(sym->source() == Symbol::FROM_OBJECT);
gold_assert(sym->source() == Symbol::FROM_OBJECT);
const int old_shnum = sym->shnum();
if (old_shnum != elfcpp::SHN_UNDEF
&& old_shnum != elfcpp::SHN_COMMON
@ -748,7 +747,7 @@ Symbol_table::define_in_output_data(Target* target, const char* name,
bool offset_is_from_end,
bool only_if_ref)
{
assert(target->get_size() == this->size_);
gold_assert(target->get_size() == this->size_);
if (this->size_ == 32)
this->do_define_in_output_data<32>(target, name, od, value, symsize,
type, binding, visibility, nonvis,
@ -758,7 +757,7 @@ Symbol_table::define_in_output_data(Target* target, const char* name,
type, binding, visibility, nonvis,
offset_is_from_end, only_if_ref);
else
abort();
gold_unreachable();
}
// Define a symbol in an Output_data, sized version.
@ -808,7 +807,7 @@ Symbol_table::define_in_output_segment(Target* target, const char* name,
Symbol::Segment_offset_base offset_base,
bool only_if_ref)
{
assert(target->get_size() == this->size_);
gold_assert(target->get_size() == this->size_);
if (this->size_ == 32)
this->do_define_in_output_segment<32>(target, name, os, value, symsize,
type, binding, visibility, nonvis,
@ -818,7 +817,7 @@ Symbol_table::define_in_output_segment(Target* target, const char* name,
type, binding, visibility, nonvis,
offset_base, only_if_ref);
else
abort();
gold_unreachable();
}
// Define a symbol in an Output_segment, sized version.
@ -866,7 +865,7 @@ Symbol_table::define_as_constant(Target* target, const char* name,
elfcpp::STV visibility, unsigned char nonvis,
bool only_if_ref)
{
assert(target->get_size() == this->size_);
gold_assert(target->get_size() == this->size_);
if (this->size_ == 32)
this->do_define_as_constant<32>(target, name, value, symsize,
type, binding, visibility, nonvis,
@ -876,7 +875,7 @@ Symbol_table::define_as_constant(Target* target, const char* name,
type, binding, visibility, nonvis,
only_if_ref);
else
abort();
gold_unreachable();
}
// Define a symbol as a constant, sized version.
@ -955,6 +954,33 @@ Symbol_table::define_symbols(const Layout* layout, Target* target, int count,
}
}
// Set the dynamic symbol indexes. INDEX is the index of the first
// global dynamic symbol. Pointers to the symbols are stored into the
// vector SYMS. The names are added to DYNPOOL. This returns an
// updated dynamic symbol index.
unsigned int
Symbol_table::set_dynsym_indexes(unsigned int index,
std::vector<Symbol*>* syms,
Stringpool* dynpool)
{
for (Symbol_table_type::iterator p = this->table_.begin();
p != this->table_.end();
++p)
{
Symbol* sym = p->second;
if (sym->needs_dynsym_entry())
{
sym->set_dynsym_index(index);
++index;
syms->push_back(sym);
dynpool->add(sym->name(), NULL);
}
}
return index;
}
// Set the final values for all the symbols. The index of the first
// global symbol in the output file is INDEX. Record the file offset
// OFF. Add their names to POOL. Return the new file offset.
@ -964,7 +990,7 @@ Symbol_table::finalize(unsigned int index, off_t off, Stringpool* pool)
{
off_t ret;
assert(index != 0);
gold_assert(index != 0);
this->first_global_index_ = index;
if (this->size_ == 32)
@ -972,7 +998,7 @@ Symbol_table::finalize(unsigned int index, off_t off, Stringpool* pool)
else if (this->size_ == 64)
ret = this->sized_finalize<64>(index, off, pool);
else
abort();
gold_unreachable();
// Now that we have the final symbol table, we can reliably note
// which symbols should get warnings.
@ -1002,7 +1028,12 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
// FIXME: Here we need to decide which symbols should go into
// the output file.
// the output file, based on --strip.
// The default version of a symbol may appear twice in the
// symbol table. We only need to finalize it once.
if (sym->has_symtab_index())
continue;
typename Sized_symbol<size>::Value_type value;
@ -1072,7 +1103,7 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
value += os->filesz();
break;
default:
abort();
gold_unreachable();
}
}
break;
@ -1082,7 +1113,7 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
break;
default:
abort();
gold_unreachable();
}
sym->set_value(value);
@ -1118,7 +1149,7 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
this->sized_write_globals<64, false>(target, sympool, of);
}
else
abort();
gold_unreachable();
}
// Write out the global symbols.
@ -1141,8 +1172,20 @@ Symbol_table::sized_write_globals(const Target*,
{
Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
if (sym->symtab_index() == -1U)
continue;
unsigned int sym_index = sym->symtab_index();
if (sym_index == -1U)
{
// This symbol is not included in the output file.
continue;
}
if (sym_index != index)
{
// We have already seen this symbol, because it has a
// default version.
gold_assert(sym_index < index);
continue;
}
++index;
unsigned int shndx;
switch (sym->source())
@ -1173,7 +1216,7 @@ Symbol_table::sized_write_globals(const Target*,
Relobj* relobj = static_cast<Relobj*>(symobj);
off_t secoff;
Output_section* os = relobj->output_section(shnum, &secoff);
assert(os != NULL);
gold_assert(os != NULL);
shndx = os->out_shndx();
}
}
@ -1192,12 +1235,9 @@ Symbol_table::sized_write_globals(const Target*,
break;
default:
abort();
gold_unreachable();
}
assert(sym->symtab_index() == index);
++index;
elfcpp::Sym_write<size, big_endian> osym(ps);
osym.put_st_name(sympool->get_offset(sym->name()));
osym.put_st_value(sym->value());
@ -1210,11 +1250,61 @@ Symbol_table::sized_write_globals(const Target*,
ps += sym_size;
}
assert(ps - psyms == oview_size);
gold_assert(ps - psyms == oview_size);
of->write_output_view(this->offset_, oview_size, psyms);
}
// Write out a section symbol. Return the update offset.
void
Symbol_table::write_section_symbol(const Target* target,
const Output_section *os,
Output_file* of,
off_t offset) const
{
if (this->size_ == 32)
{
if (target->is_big_endian())
this->sized_write_section_symbol<32, true>(os, of, offset);
else
this->sized_write_section_symbol<32, false>(os, of, offset);
}
else if (this->size_ == 64)
{
if (target->is_big_endian())
this->sized_write_section_symbol<64, true>(os, of, offset);
else
this->sized_write_section_symbol<64, false>(os, of, offset);
}
else
gold_unreachable();
}
// Write out a section symbol, specialized for size and endianness.
template<int size, bool big_endian>
void
Symbol_table::sized_write_section_symbol(const Output_section* os,
Output_file* of,
off_t offset) const
{
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
unsigned char* pov = of->get_output_view(offset, sym_size);
elfcpp::Sym_write<size, big_endian> osym(pov);
osym.put_st_name(0);
osym.put_st_value(os->address());
osym.put_st_size(0);
osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL,
elfcpp::STT_SECTION));
osym.put_st_other(elfcpp::elf_st_other(elfcpp::STV_DEFAULT, 0));
osym.put_st_shndx(os->out_shndx());
of->write_output_view(offset, sym_size, pov);
}
// Warnings functions.
// Add a new warning.
@ -1268,9 +1358,9 @@ Warnings::note_warnings(Symbol_table* symtab)
void
Warnings::issue_warning(const Symbol* sym, const std::string& location) const
{
assert(sym->has_warning());
gold_assert(sym->has_warning());
Warning_table::const_iterator p = this->warnings_.find(sym->name());
assert(p != this->warnings_.end());
gold_assert(p != this->warnings_.end());
fprintf(stderr, _("%s: %s: warning: %s\n"), program_name, location.c_str(),
p->second.text.c_str());
}

View File

@ -6,7 +6,6 @@
#include <string>
#include <utility>
#include <vector>
#include <cassert>
#include "elfcpp.h"
#include "stringpool.h"
@ -26,6 +25,7 @@ class Dynobj;
template<int size, bool big_endian>
class Sized_dynobj;
class Output_data;
class Output_section;
class Output_segment;
class Output_file;
class Target;
@ -90,7 +90,7 @@ class Symbol
Object*
object() const
{
assert(this->source_ == FROM_OBJECT);
gold_assert(this->source_ == FROM_OBJECT);
return this->u_.from_object.object;
}
@ -99,7 +99,7 @@ class Symbol
unsigned int
shnum() const
{
assert(this->source_ == FROM_OBJECT);
gold_assert(this->source_ == FROM_OBJECT);
return this->u_.from_object.shnum;
}
@ -109,7 +109,7 @@ class Symbol
Output_data*
output_data() const
{
assert(this->source_ == IN_OUTPUT_DATA);
gold_assert(this->source_ == IN_OUTPUT_DATA);
return this->u_.in_output_data.output_data;
}
@ -118,7 +118,7 @@ class Symbol
bool
offset_is_from_end() const
{
assert(this->source_ == IN_OUTPUT_DATA);
gold_assert(this->source_ == IN_OUTPUT_DATA);
return this->u_.in_output_data.offset_is_from_end;
}
@ -128,7 +128,7 @@ class Symbol
Output_segment*
output_segment() const
{
assert(this->source_ == IN_OUTPUT_SEGMENT);
gold_assert(this->source_ == IN_OUTPUT_SEGMENT);
return this->u_.in_output_segment.output_segment;
}
@ -137,7 +137,7 @@ class Symbol
Segment_offset_base
offset_base() const
{
assert(this->source_ == IN_OUTPUT_SEGMENT);
gold_assert(this->source_ == IN_OUTPUT_SEGMENT);
return this->u_.in_output_segment.offset_base;
}
@ -184,11 +184,6 @@ class Symbol
set_needs_dynsym_entry()
{ this->needs_dynsym_entry_ = true; }
// Return whether this symbol was ever seen in a dynamic object.
bool
in_dyn() const
{ return this->in_dyn_; }
// Mark this symbol as having been seen in a dynamic object.
void
set_in_dyn()
@ -202,7 +197,7 @@ class Symbol
unsigned int
symtab_index() const
{
assert(this->symtab_index_ != 0);
gold_assert(this->symtab_index_ != 0);
return this->symtab_index_;
}
@ -210,10 +205,16 @@ class Symbol
void
set_symtab_index(unsigned int index)
{
assert(index != 0);
gold_assert(index != 0);
this->symtab_index_ = index;
}
// Return whether this symbol already has an index in the output
// file symbol table.
bool
has_symtab_index() const
{ return this->symtab_index_ != 0; }
// Return the index of this symbol in the dynamic symbol table. A
// value of -1U means that this symbol is not going into the dynamic
// symbol table. This starts out as zero, and is set to a non-zero
@ -222,7 +223,7 @@ class Symbol
unsigned int
dynsym_index() const
{
assert(this->dynsym_index_ != 0);
gold_assert(this->dynsym_index_ != 0);
return this->dynsym_index_;
}
@ -230,7 +231,7 @@ class Symbol
void
set_dynsym_index(unsigned int index)
{
assert(index != 0);
gold_assert(index != 0);
this->dynsym_index_ = index;
}
@ -243,7 +244,7 @@ class Symbol
unsigned int
got_offset() const
{
assert(this->has_got_offset());
gold_assert(this->has_got_offset());
return this->got_offset_;
}
@ -255,14 +256,36 @@ class Symbol
this->got_offset_ = got_offset;
}
// Return whether this symbol is resolved locally. This is always
// true when linking statically. It is true for a symbol defined in
// this object when using -Bsymbolic. It is true for a symbol
// marked local in a version file. FIXME: This needs to be
// completed.
// Return whether this symbol has an entry in the PLT section.
bool
is_resolved_locally() const
{ return !this->in_dyn_; }
has_plt_offset() const
{ return this->has_plt_offset_; }
// Return the offset into the PLT section of this symbol.
unsigned int
plt_offset() const
{
gold_assert(this->has_plt_offset());
return this->plt_offset_;
}
// Set the PLT offset of this symbol.
void
set_plt_offset(unsigned int plt_offset)
{
this->has_plt_offset_ = true;
this->plt_offset_ = plt_offset;
}
// Return true if the final value of this symbol is known at link
// time.
bool
final_value_is_known(const General_options* options) const
{
if (options->is_shared())
return false;
return this->source_ != FROM_OBJECT || !this->object()->is_dynamic();
}
// Return whether this is a defined symbol (not undefined or
// common).
@ -270,8 +293,17 @@ class Symbol
is_defined() const
{
return (this->source_ != FROM_OBJECT
|| (this->u_.from_object.shnum != elfcpp::SHN_UNDEF
&& this->u_.from_object.shnum != elfcpp::SHN_COMMON));
|| (this->shnum() != elfcpp::SHN_UNDEF
&& this->shnum() != elfcpp::SHN_COMMON));
}
// Return whether this symbol is defined in a dynamic object.
bool
is_defined_in_dynobj() const
{
return (this->source_ == FROM_OBJECT
&& this->object()->is_dynamic()
&& this->is_defined());
}
// Return whether this is an undefined symbol.
@ -286,7 +318,7 @@ class Symbol
is_common() const
{
return (this->source_ == FROM_OBJECT
&& (this->u_.from_object.shnum == elfcpp::SHN_COMMON
&& (this->shnum() == elfcpp::SHN_COMMON
|| this->type_ == elfcpp::STT_COMMON));
}
@ -401,6 +433,11 @@ class Symbol
// is true), this is the offset from the start of the GOT section.
unsigned int got_offset_;
// If this symbol has an entry in the PLT section (has_plt_offset_
// is true), then this is the offset from the start of the PLT
// section.
unsigned int plt_offset_;
// Symbol type.
elfcpp::STT type_ : 4;
// Symbol binding.
@ -430,6 +467,8 @@ class Symbol
bool in_dyn_ : 1;
// True if the symbol has an entry in the GOT section.
bool has_got_offset_ : 1;
// True if the symbol has an entry in the PLT section.
bool has_plt_offset_ : 1;
// True if there is a warning for this symbol.
bool has_warning_ : 1;
};
@ -735,7 +774,7 @@ class Symbol_table
Symbol*
resolve_forwards(const Symbol* from) const;
// Return the size of the symbols in the table.
// Return the bitsize (32 or 64) of the symbols in the table.
int
get_size() const
{ return this->size_; }
@ -774,6 +813,14 @@ class Symbol_table
issue_warning(const Symbol* sym, const std::string& location) const
{ this->warnings_.issue_warning(sym, location); }
// Set the dynamic symbol indexes. INDEX is the index of the first
// global dynamic symbol. Pointers to the symbols are stored into
// the vector. The names are stored into the Stringpool. This
// returns an updated dynamic symbol index.
unsigned int
set_dynsym_indexes(unsigned int index, std::vector<Symbol*>*,
Stringpool*);
// Finalize the symbol table after we have set the final addresses
// of all the input sections. This sets the final symbol indexes,
// values and adds the names to *POOL. INDEX is the index of the
@ -786,11 +833,16 @@ class Symbol_table
void
write_globals(const Target*, const Stringpool*, Output_file*) const;
// Write out a section symbol. Return the updated offset.
void
write_section_symbol(const Target*, const Output_section*, Output_file*,
off_t) const;
private:
Symbol_table(const Symbol_table&);
Symbol_table& operator=(const Symbol_table&);
// Set the size of the symbols in the table.
// Set the size (32 or 64) of the symbols in the table.
void
set_size(int size)
{ this->size_ = size; }
@ -865,6 +917,11 @@ class Symbol_table
void
sized_write_globals(const Target*, const Stringpool*, Output_file*) const;
// Write out a section symbol, specialized for size and endianness.
template<int size, bool big_endian>
void
sized_write_section_symbol(const Output_section*, Output_file*, off_t) const;
// The type of the symbol hash table.
typedef std::pair<Stringpool::Key, Stringpool::Key> Symbol_table_key;
@ -932,7 +989,7 @@ template<int size>
Sized_symbol<size>*
Symbol_table::get_sized_symbol(Symbol* sym ACCEPT_SIZE) const
{
assert(size == this->get_size());
gold_assert(size == this->get_size());
return static_cast<Sized_symbol<size>*>(sym);
}
@ -940,7 +997,7 @@ template<int size>
const Sized_symbol<size>*
Symbol_table::get_sized_symbol(const Symbol* sym ACCEPT_SIZE) const
{
assert(size == this->get_size());
gold_assert(size == this->get_size());
return static_cast<const Sized_symbol<size>*>(sym);
}

View File

@ -26,6 +26,7 @@ scan_relocs(
Layout* layout,
Target_type* target,
Sized_relobj<size, big_endian>* object,
unsigned int data_shndx,
const unsigned char* prelocs,
size_t reloc_count,
size_t local_count,
@ -47,7 +48,7 @@ scan_relocs(
if (r_sym < local_count)
{
assert(plocal_syms != NULL);
gold_assert(plocal_syms != NULL);
typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
+ r_sym * sym_size);
const unsigned int shndx = lsym.get_st_shndx();
@ -73,18 +74,18 @@ scan_relocs(
continue;
}
scan.local(options, symtab, layout, target, object, reloc, r_type,
lsym);
scan.local(options, symtab, layout, target, object, data_shndx,
reloc, r_type, lsym);
}
else
{
Symbol* gsym = global_syms[r_sym - local_count];
assert(gsym != NULL);
gold_assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = symtab->resolve_forwards(gsym);
scan.global(options, symtab, layout, target, object, reloc, r_type,
gsym);
scan.global(options, symtab, layout, target, object, data_shndx,
reloc, r_type, gsym);
}
}
}
@ -146,7 +147,7 @@ relocate_section(
else
{
const Symbol* gsym = global_syms[r_sym - local_count];
assert(gsym != NULL);
gold_assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = relinfo->symtab->resolve_forwards(gsym);

View File

@ -13,8 +13,6 @@
#ifndef GOLD_TARGET_H
#define GOLD_TARGET_H
#include <cassert>
#include "elfcpp.h"
namespace gold
@ -137,7 +135,7 @@ class Sized_target : public Target
// returns true.
virtual Sized_symbol<size>*
make_symbol()
{ abort(); }
{ gold_unreachable(); }
// Resolve a symbol for the target. This should be overridden by a
// target which needs to take special action. TO is the
@ -145,12 +143,13 @@ class Sized_target : public Target
// This will only be called if has_resolve() returns true.
virtual void
resolve(Symbol*, const elfcpp::Sym<size, big_endian>&, Object*)
{ abort(); }
{ gold_unreachable(); }
// Scan the relocs for a section, and record any information
// required for the symbol. OPTIONS is the command line options.
// SYMTAB is the symbol table. OBJECT is the object in which the
// section appears. SH_TYPE is the type of the relocation section,
// section appears. DATA_SHNDX is the section index that these
// relocs apply to. SH_TYPE is the type of the relocation section,
// SHT_REL or SHT_RELA. PRELOCS points to the relocation data.
// RELOC_COUNT is the number of relocs. LOCAL_SYMBOL_COUNT is the
// number of local symbols. PLOCAL_SYMBOLS points to the local
@ -161,6 +160,7 @@ class Sized_target : public Target
Symbol_table* symtab,
Layout* layout,
Sized_relobj<size, big_endian>* object,
unsigned int data_shndx,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
@ -187,8 +187,8 @@ class Sized_target : public Target
Sized_target(const Target::Target_info* pti)
: Target(pti)
{
assert(pti->size == size);
assert(pti->is_big_endian ? big_endian : !big_endian);
gold_assert(pti->size == size);
gold_assert(pti->is_big_endian ? big_endian : !big_endian);
}
};

View File

@ -2,8 +2,6 @@
#include "gold.h"
#include <cassert>
#include "workqueue.h"
namespace gold
@ -18,59 +16,59 @@ Task_token::Task_token()
Task_token::~Task_token()
{
assert(this->readers_ == 0 && this->writer_ == NULL);
gold_assert(this->readers_ == 0 && this->writer_ == NULL);
}
bool
Task_token::is_readable() const
{
assert(!this->is_blocker_);
gold_assert(!this->is_blocker_);
return this->writer_ == NULL;
}
void
Task_token::add_reader()
{
assert(!this->is_blocker_);
assert(this->is_readable());
gold_assert(!this->is_blocker_);
gold_assert(this->is_readable());
++this->readers_;
}
void
Task_token::remove_reader()
{
assert(!this->is_blocker_);
assert(this->readers_ > 0);
gold_assert(!this->is_blocker_);
gold_assert(this->readers_ > 0);
--this->readers_;
}
bool
Task_token::is_writable() const
{
assert(!this->is_blocker_);
gold_assert(!this->is_blocker_);
return this->writer_ == NULL && this->readers_ == 0;
}
void
Task_token::add_writer(const Task* t)
{
assert(!this->is_blocker_);
assert(this->is_writable());
gold_assert(!this->is_blocker_);
gold_assert(this->is_writable());
this->writer_ = t;
}
void
Task_token::remove_writer(const Task* t)
{
assert(!this->is_blocker_);
assert(this->writer_ == t);
gold_assert(!this->is_blocker_);
gold_assert(this->writer_ == t);
this->writer_ = NULL;
}
bool
Task_token::has_write_lock(const Task* t)
{
assert(!this->is_blocker_);
gold_assert(!this->is_blocker_);
return this->writer_ == t;
}
@ -82,14 +80,14 @@ Task_token::add_blocker()
if (this->readers_ == 0 && this->writer_ == NULL)
this->is_blocker_ = true;
else
assert(this->is_blocker_);
gold_assert(this->is_blocker_);
++this->readers_;
}
bool
Task_token::remove_blocker()
{
assert(this->is_blocker_ && this->readers_ > 0);
gold_assert(this->is_blocker_ && this->readers_ > 0);
--this->readers_;
return this->readers_ == 0;
}
@ -97,7 +95,8 @@ Task_token::remove_blocker()
bool
Task_token::is_blocked() const
{
assert(this->is_blocker_ || (this->readers_ == 0 && this->writer_ == NULL));
gold_assert(this->is_blocker_
|| (this->readers_ == 0 && this->writer_ == NULL));
return this->readers_ > 0;
}
@ -109,7 +108,7 @@ Task_block_token::Task_block_token(Task_token& token, Workqueue* workqueue)
// We must increment the block count when the task is created and
// put on the queue. This object is created when the task is run,
// so we don't increment the block count here.
assert(this->token_.is_blocked());
gold_assert(this->token_.is_blocked());
}
Task_block_token::~Task_block_token()
@ -187,9 +186,9 @@ Workqueue::Workqueue(const General_options&)
Workqueue::~Workqueue()
{
assert(this->tasks_.empty());
assert(this->completed_.empty());
assert(this->running_ == 0);
gold_assert(this->tasks_.empty());
gold_assert(this->completed_.empty());
gold_assert(this->running_ == 0);
}
// Add a task to the queue.
@ -263,7 +262,7 @@ Workqueue::find_runnable(Task_list& tasks, bool* all_blocked)
{
// There had better be some tasks running, or we will
// never find a runnable task.
assert(this->running_ > 0);
gold_assert(this->running_ > 0);
// We couldn't find any runnable tasks, and we
// couldn't release any locks.
@ -322,7 +321,7 @@ Workqueue::process()
// There must be something for us to wait for, or we won't
// be able to make progress.
assert(this->running_ > 0 || !this->completed_.empty());
gold_assert(this->running_ > 0 || !this->completed_.empty());
if (all_blocked)
{
@ -330,7 +329,7 @@ Workqueue::process()
this->clear_completed();
while (this->cleared_blockers_ == 0)
{
assert(this->running_ > 0);
gold_assert(this->running_ > 0);
this->completed_condvar_.wait();
this->clear_completed();
}
@ -385,7 +384,7 @@ Workqueue::completed(Task* t, Task_locker* tl)
{
{
Hold_lock hl(this->completed_lock_);
assert(this->running_ > 0);
gold_assert(this->running_ > 0);
--this->running_;
this->completed_.push_back(tl);
this->completed_condvar_.signal();