aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2006-11-29 17:56:40 +0000
committerIan Lance Taylor <iant@google.com>2006-11-29 17:56:40 +0000
commita3ad94edd406b9abc26493761764d4034dda69fa (patch)
tree96485e8bba91a4aa51f34b0d3738ef3e7ddcbac3
parente1da3f5b9645750e966e471ff0db480d6450dcb7 (diff)
downloadgdb-a3ad94edd406b9abc26493761764d4034dda69fa.zip
gdb-a3ad94edd406b9abc26493761764d4034dda69fa.tar.gz
gdb-a3ad94edd406b9abc26493761764d4034dda69fa.tar.bz2
Hash tables, dynamic section, i386 PLT, gold_assert.
-rw-r--r--elfcpp/elfcpp.h26
-rw-r--r--elfcpp/elfcpp_file.h23
-rw-r--r--elfcpp/elfcpp_swap.h34
-rw-r--r--gold/common.cc6
-rw-r--r--gold/dirsearch.cc7
-rw-r--r--gold/dynobj.cc435
-rw-r--r--gold/dynobj.h72
-rw-r--r--gold/fileread.cc33
-rw-r--r--gold/gold-threads.cc10
-rw-r--r--gold/gold.cc16
-rw-r--r--gold/gold.h16
-rw-r--r--gold/i386.cc478
-rw-r--r--gold/layout.cc328
-rw-r--r--gold/layout.h44
-rw-r--r--gold/object.cc31
-rw-r--r--gold/object.h37
-rw-r--r--gold/options.cc8
-rw-r--r--gold/options.h7
-rw-r--r--gold/output.cc253
-rw-r--r--gold/output.h395
-rw-r--r--gold/po/gold.pot174
-rw-r--r--gold/readsyms.cc4
-rw-r--r--gold/reloc.cc62
-rw-r--r--gold/reloc.h8
-rw-r--r--gold/resolve.cc8
-rw-r--r--gold/script.cc19
-rw-r--r--gold/stringpool.cc18
-rw-r--r--gold/stringpool.h5
-rw-r--r--gold/symtab.cc164
-rw-r--r--gold/symtab.h119
-rw-r--r--gold/target-reloc.h15
-rw-r--r--gold/target.h14
-rw-r--r--gold/workqueue.cc49
33 files changed, 2287 insertions, 631 deletions
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index afbd74d..ba85b3d 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -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>
diff --git a/elfcpp/elfcpp_file.h b/elfcpp/elfcpp_file.h
index 043c269..c9563ee 100644
--- a/elfcpp/elfcpp_file.h
+++ b/elfcpp/elfcpp_file.h
@@ -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)
diff --git a/elfcpp/elfcpp_swap.h b/elfcpp/elfcpp_swap.h
index 979108e..71b02eb 100644
--- a/elfcpp/elfcpp_swap.h
+++ b/elfcpp/elfcpp_swap.h
@@ -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;
diff --git a/gold/common.cc b/gold/common.cc
index 7ba8adc..e83219c 100644
--- a/gold/common.cc
+++ b/gold/common.cc
@@ -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();
}
diff --git a/gold/dirsearch.cc b/gold/dirsearch.cc
index 5dec3f6..d1298d8 100644
--- a/gold/dirsearch.cc
+++ b/gold/dirsearch.cc
@@ -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))
diff --git a/gold/dynobj.cc b/gold/dynobj.cc
index ba1fb15..ac5a74b 100644
--- a/gold/dynobj.cc
+++ b/gold/dynobj.cc
@@ -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.
diff --git a/gold/dynobj.h b/gold/dynobj.h
index 04a2c63..bc877c4 100644
--- a/gold/dynobj.h
+++ b/gold/dynobj.h
@@ -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.
diff --git a/gold/fileread.cc b/gold/fileread.cc
index 43c69b3..e96476c 100644
--- a/gold/fileread.cc
+++ b/gold/fileread.cc
@@ -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();
}
diff --git a/gold/gold-threads.cc b/gold/gold-threads.cc
index c6e1170..5373739 100644
--- a/gold/gold-threads.cc
+++ b/gold/gold-threads.cc
@@ -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
diff --git a/gold/gold.cc b/gold/gold.cc
index 3073b18..7c8ed8f 100644
--- a/gold/gold.cc
+++ b/gold/gold.cc
@@ -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.
diff --git a/gold/gold.h b/gold/gold.h
index d55d1f6..78c106f 100644
--- a/gold/gold.h
+++ b/gold/gold.h
@@ -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
diff --git a/gold/i386.cc b/gold/i386.cc
index e6522e3..488da79 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -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 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_);
+
// The first three entries are reserved.
- this->got_->add_constant(0);
- this->got_->add_constant(0);
- this->got_->add_constant(0);
+ this->got_plt_->set_space_size(3 * 4);
- // Define _GLOBAL_OFFSET_TABLE_ at the start of the section.
- symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", this->got_,
+ // 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;
-
- 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;
- }
+ {
+ 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;
+ }
+ }
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>(
diff --git a/gold/layout.cc b/gold/layout.cc
index f9f5548..97917b0 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -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.
diff --git a/gold/layout.h b/gold/layout.h
index 759fd85..26948bb 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -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_;
};
diff --git a/gold/object.cc b/gold/object.cc
index 74c1347..2086fed 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -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);
}
diff --git a/gold/object.h b/gold/object.h
index b2f4706..cd2bc8d 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -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()
diff --git a/gold/options.cc b/gold/options.cc
index 6b88429..b8339e8 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -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;
}
diff --git a/gold/options.h b/gold/options.h
index ac51524..56907c0 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -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_;
}
diff --git a/gold/output.cc b/gold/output.cc
index 0330384..e4720df 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -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;
diff --git a/gold/output.h b/gold/output.h
index c31640f..c7d835d 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -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
+ 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* output);
+ 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;
}
diff --git a/gold/po/gold.pot b/gold/po/gold.pot
index b5725e5..5663031 100644
--- a/gold/po/gold.pot
+++ b/gold/po/gold.pot
@@ -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 ""
diff --git a/gold/readsyms.cc b/gold/readsyms.cc
index c301d16..2b200ba 100644
--- a/gold/readsyms.cc
+++ b/gold/readsyms.cc
@@ -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();
diff --git a/gold/reloc.cc b/gold/reloc.cc
index ce6af0b..35f262e 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -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.
diff --git a/gold/reloc.h b/gold/reloc.h
index 9b0518e..7829440 100644
--- a/gold/reloc.h
+++ b/gold/reloc.h
@@ -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.
diff --git a/gold/resolve.cc b/gold/resolve.cc
index 2b6d65c..891de8c 100644
--- a/gold/resolve.cc
+++ b/gold/resolve.cc
@@ -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();
}
}
diff --git a/gold/script.cc b/gold/script.cc
index b22611f..f5584d9 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -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:
{
diff --git a/gold/stringpool.cc b/gold/stringpool.cc
index 5b60259..d53cf77 100644
--- a/gold/stringpool.cc
+++ b/gold/stringpool.cc
@@ -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';
diff --git a/gold/stringpool.h b/gold/stringpool.h
index ed549b4..05c498e 100644
--- a/gold/stringpool.h
+++ b/gold/stringpool.h
@@ -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
diff --git a/gold/symtab.cc b/gold/symtab.cc
index 92d5583..4d2bb1a 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -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());
}
diff --git a/gold/symtab.h b/gold/symtab.h
index 06a4b6b..1350bf1 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -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);
}
diff --git a/gold/target-reloc.h b/gold/target-reloc.h
index 5b057ac..727de02 100644
--- a/gold/target-reloc.h
+++ b/gold/target-reloc.h
@@ -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);
diff --git a/gold/target.h b/gold/target.h
index 5a86c35..039b97d 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -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);
}
};
diff --git a/gold/workqueue.cc b/gold/workqueue.cc
index 3ef3422..9062118 100644
--- a/gold/workqueue.cc
+++ b/gold/workqueue.cc
@@ -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();