diff options
-rw-r--r-- | elfcpp/elfcpp.h | 26 | ||||
-rw-r--r-- | elfcpp/elfcpp_file.h | 23 | ||||
-rw-r--r-- | elfcpp/elfcpp_swap.h | 34 | ||||
-rw-r--r-- | gold/common.cc | 6 | ||||
-rw-r--r-- | gold/dirsearch.cc | 7 | ||||
-rw-r--r-- | gold/dynobj.cc | 435 | ||||
-rw-r--r-- | gold/dynobj.h | 72 | ||||
-rw-r--r-- | gold/fileread.cc | 33 | ||||
-rw-r--r-- | gold/gold-threads.cc | 10 | ||||
-rw-r--r-- | gold/gold.cc | 16 | ||||
-rw-r--r-- | gold/gold.h | 16 | ||||
-rw-r--r-- | gold/i386.cc | 478 | ||||
-rw-r--r-- | gold/layout.cc | 328 | ||||
-rw-r--r-- | gold/layout.h | 44 | ||||
-rw-r--r-- | gold/object.cc | 31 | ||||
-rw-r--r-- | gold/object.h | 37 | ||||
-rw-r--r-- | gold/options.cc | 8 | ||||
-rw-r--r-- | gold/options.h | 7 | ||||
-rw-r--r-- | gold/output.cc | 253 | ||||
-rw-r--r-- | gold/output.h | 395 | ||||
-rw-r--r-- | gold/po/gold.pot | 174 | ||||
-rw-r--r-- | gold/readsyms.cc | 4 | ||||
-rw-r--r-- | gold/reloc.cc | 62 | ||||
-rw-r--r-- | gold/reloc.h | 8 | ||||
-rw-r--r-- | gold/resolve.cc | 8 | ||||
-rw-r--r-- | gold/script.cc | 19 | ||||
-rw-r--r-- | gold/stringpool.cc | 18 | ||||
-rw-r--r-- | gold/stringpool.h | 5 | ||||
-rw-r--r-- | gold/symtab.cc | 164 | ||||
-rw-r--r-- | gold/symtab.h | 119 | ||||
-rw-r--r-- | gold/target-reloc.h | 15 | ||||
-rw-r--r-- | gold/target.h | 14 | ||||
-rw-r--r-- | gold/workqueue.cc | 49 |
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(); |