diff options
Diffstat (limited to 'gold/symtab.h')
-rw-r--r-- | gold/symtab.h | 422 |
1 files changed, 401 insertions, 21 deletions
diff --git a/gold/symtab.h b/gold/symtab.h index 2c5fbc9..40a9e57 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -5,6 +5,7 @@ #include <string> #include <utility> +#include <vector> #include <cassert> #include "elfcpp.h" @@ -17,6 +18,8 @@ namespace gold { class Object; +class Output_data; +class Output_segment; class Output_file; class Target; @@ -31,6 +34,37 @@ class Sized_object; class Symbol { public: + // Because we want the class to be small, we don't use any virtual + // functions. But because symbols can be defined in different + // places, we need to classify them. This enum is the different + // sources of symbols we support. + enum Source + { + // Symbol defined in an input file--this is the most common case. + FROM_OBJECT, + // Symbol defined in an Output_data, a special section created by + // the target. + IN_OUTPUT_DATA, + // Symbol defined in an Output_segment, with no associated + // section. + IN_OUTPUT_SEGMENT, + // Symbol value is constant. + CONSTANT + }; + + // When the source is IN_OUTPUT_SEGMENT, we need to describe what + // the offset means. + enum Segment_offset_base + { + // From the start of the segment. + SEGMENT_START, + // From the end of the segment. + SEGMENT_END, + // From the filesz of the segment--i.e., after the loaded bytes + // but before the bytes which are allocated but zeroed. + SEGMENT_BSS + }; + // Return the symbol name. const char* name() const @@ -42,10 +76,64 @@ class Symbol version() const { return this->version_; } + // Return the symbol source. + Source + source() const + { return this->source_; } + // Return the object with which this symbol is associated. Object* object() const - { return this->object_; } + { + assert(this->source_ == FROM_OBJECT); + return this->u_.from_object.object; + } + + // Return the index of the section in the input object file. + unsigned int + shnum() const + { + assert(this->source_ == FROM_OBJECT); + return this->u_.from_object.shnum; + } + + // Return the output data section with which this symbol is + // associated, if the symbol was specially defined with respect to + // an output data section. + Output_data* + output_data() const + { + assert(this->source_ == IN_OUTPUT_DATA); + return this->u_.in_output_data.output_data; + } + + // If this symbol was defined with respect to an output data + // section, return whether the value is an offset from end. + bool + offset_is_from_end() const + { + assert(this->source_ == IN_OUTPUT_DATA); + return this->u_.in_output_data.offset_is_from_end; + } + + // Return the output segment with which this symbol is associated, + // if the symbol was specially defined with respect to an output + // segment. + Output_segment* + output_segment() const + { + assert(this->source_ == IN_OUTPUT_SEGMENT); + return this->u_.in_output_segment.output_segment; + } + + // If this symbol was defined with respect to an output segment, + // return the offset base. + Segment_offset_base + offset_base() const + { + assert(this->source_ == IN_OUTPUT_SEGMENT); + return this->u_.in_output_segment.offset_base; + } // Return the symbol binding. elfcpp::STB @@ -64,13 +152,8 @@ class Symbol // Return the non-visibility part of the st_other field. unsigned char - other() const - { return this->other_; } - - // Return the section index. - unsigned int - shnum() const - { return this->shnum_; } + nonvis() const + { return this->nonvis_; } // Return whether this symbol is a forwarder. This will never be // true of a symbol found in the hash table, but may be true of @@ -94,11 +177,49 @@ class Symbol set_in_dyn() { this->in_dyn_ = true; } - // Return whether this symbol needs an entry in the dynamic symbol - // table. FIXME: Needs to be fleshed out. + // Return whether this symbol has an entry in the GOT section. bool - in_dynsym() const - { return this->in_dyn_; } + has_got_offset() const + { return this->has_got_offset_; } + + // Return the offset into the GOT section of this symbol. + unsigned int + got_offset() const + { + assert(this->has_got_offset()); + return this->got_offset_; + } + + // Set the GOT offset of this symbol. + void + set_got_offset(unsigned int got_offset) + { + this->has_got_offset_ = true; + 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. + bool + is_resolved_locally() const + { return !this->in_dyn_; } + + // Return whether this is an undefined symbol. + bool + is_undefined() const + { + return this->source_ == FROM_OBJECT && this->shnum() == elfcpp::SHN_UNDEF; + } + + // Return whether this is a common symbol. + bool + is_common() const + { + return this->source_ == FROM_OBJECT && this->shnum() == elfcpp::SHN_COMMON; + } protected: // Instances of this class should always be created at a specific @@ -106,12 +227,34 @@ class Symbol Symbol() { } + // Initialize the general fields. + void + init_fields(const char* name, const char* version, + elfcpp::STT type, elfcpp::STB binding, + elfcpp::STV visibility, unsigned char nonvis); + // Initialize fields from an ELF symbol in OBJECT. template<int size, bool big_endian> void init_base(const char *name, const char* version, Object* object, const elfcpp::Sym<size, big_endian>&); + // Initialize fields for an Output_data. + void + init_base(const char* name, Output_data*, elfcpp::STT, elfcpp::STB, + elfcpp::STV, unsigned char nonvis, bool offset_is_from_end); + + // Initialize fields for an Output_segment. + void + init_base(const char* name, Output_segment* os, elfcpp::STT type, + elfcpp::STB binding, elfcpp::STV visibility, + unsigned char nonvis, Segment_offset_base offset_base); + + // Initialize fields for a constant. + void + init_base(const char* name, elfcpp::STT type, elfcpp::STB binding, + elfcpp::STV visibility, unsigned char nonvis); + // Override existing symbol. template<int size, bool big_endian> void @@ -126,10 +269,45 @@ class Symbol // Symbol version (expected to point into a Stringpool). This may // be NULL. const char* version_; - // Object in which symbol is defined, or in which it was first seen. - Object* object_; - // Section number in object_ in which symbol is defined. - unsigned int shnum_; + + union + { + // This struct is used if SOURCE_ == FROM_OBJECT. + struct + { + // Object in which symbol is defined, or in which it was first + // seen. + Object* object; + // Section number in object_ in which symbol is defined. + unsigned int shnum; + } from_object; + + // This struct is used if SOURCE_ == IN_OUTPUT_DATA. + struct + { + // Output_data in which symbol is defined. Before + // Layout::finalize the symbol's value is an offset within the + // Output_data. + Output_data* output_data; + // True if the offset is from the end, false if the offset is + // from the beginning. + bool offset_is_from_end; + } in_output_data; + + // This struct is used if SOURCE_ == IN_OUTPUT_SEGMENT. + struct + { + // Output_segment in which the symbol is defined. Before + // Layout::finalize the symbol's value is an offset. + Output_segment* output_segment; + // The base to use for the offset before Layout::finalize. + Segment_offset_base offset_base; + } in_output_segment; + } u_; + + // If this symbol has an entry in the GOT section (has_got_offset_ + // is true), this is the offset. + unsigned int got_offset_; // Symbol type. elfcpp::STT type_ : 4; // Symbol binding. @@ -137,10 +315,12 @@ class Symbol // Symbol visibility. elfcpp::STV visibility_ : 2; // Rest of symbol st_other field. - unsigned int other_ : 6; + unsigned int nonvis_ : 6; + // The type of symbol. + Source source_ : 2; // True if this symbol always requires special target-specific // handling. - bool is_special_ : 1; + bool is_target_special_ : 1; // True if this is the default version of the symbol. bool is_def_ : 1; // True if this symbol really forwards to another symbol. This is @@ -153,6 +333,8 @@ class Symbol bool is_forwarder_ : 1; // True if we've seen this symbol in a dynamic object. bool in_dyn_ : 1; + // True if the symbol has an entry in the GOT section. + bool has_got_offset_ : 1; }; // The parts of a symbol which are size specific. Using a template @@ -174,6 +356,23 @@ class Sized_symbol : public Symbol init(const char *name, const char* version, Object* object, const elfcpp::Sym<size, big_endian>&); + // Initialize fields for an Output_data. + void + init(const char* name, Output_data*, Value_type value, Size_type symsize, + elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis, + bool offset_is_from_end); + + // Initialize fields for an Output_segment. + void + init(const char* name, Output_segment*, Value_type value, Size_type symsize, + elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis, + Segment_offset_base offset_base); + + // Initialize fields for a constant. + void + init(const char* name, Value_type value, Size_type symsize, + elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis); + // Override existing symbol. template<bool big_endian> void @@ -188,7 +387,12 @@ class Sized_symbol : public Symbol // is a template parameter). Size_type symsize() const - { return this->size_; } + { return this->symsize_; } + + // Set the symbol size. This is used when resolving common symbols. + void + set_symsize(Size_type symsize) + { this->symsize_ = symsize; } // Set the symbol value. This is called when we store the final // values of the symbols into the symbol table. @@ -200,10 +404,84 @@ class Sized_symbol : public Symbol Sized_symbol(const Sized_symbol&); Sized_symbol& operator=(const Sized_symbol&); - // Symbol value. + // Symbol value. Before Layout::finalize this is the offset in the + // input section. This is set to the final value during + // Layout::finalize. Value_type value_; // Symbol size. - Size_type size_; + Size_type symsize_; +}; + +// A struct describing a symbol defined by the linker, where the value +// of the symbol is defined based on an output section. This is used +// for symbols defined by the linker, like "_init_array_start". + +struct Define_symbol_in_section +{ + // The symbol name. + const char* name; + // The name of the output section with which this symbol should be + // associated. If there is no output section with that name, the + // symbol will be defined as zero. + const char* output_section; + // The offset of the symbol within the output section. This is an + // offset from the start of the output section, unless start_at_end + // is true, in which case this is an offset from the end of the + // output section. + uint64_t value; + // The size of the symbol. + uint64_t size; + // The symbol type. + elfcpp::STT type; + // The symbol binding. + elfcpp::STB binding; + // The symbol visibility. + elfcpp::STV visibility; + // The rest of the st_other field. + unsigned char nonvis; + // If true, the value field is an offset from the end of the output + // section. + bool offset_is_from_end; + // If true, this symbol is defined only if we see a reference to it. + bool only_if_ref; +}; + +// A struct describing a symbol defined by the linker, where the value +// of the symbol is defined based on a segment. This is used for +// symbols defined by the linker, like "_end". We describe the +// segment with which the symbol should be associated by its +// characteristics. If no segment meets these characteristics, the +// symbol will be defined as zero. If there is more than one segment +// which meets these characteristics, we will use the first one. + +struct Define_symbol_in_segment +{ + // The symbol name. + const char* name; + // The segment type where the symbol should be defined, typically + // PT_LOAD. + elfcpp::PT segment_type; + // Bitmask of segment flags which must be set. + elfcpp::PF segment_flags_set; + // Bitmask of segment flags which must be clear. + elfcpp::PF segment_flags_clear; + // The offset of the symbol within the segment. The offset is + // calculated from the position set by offset_base. + uint64_t value; + // The size of the symbol. + uint64_t size; + // The symbol type. + elfcpp::STT type; + // The symbol binding. + elfcpp::STB binding; + // The symbol visibility. + elfcpp::STV visibility; + // The rest of the st_other field. + unsigned char nonvis; + // The base from which we compute the offset. + Symbol::Segment_offset_base offset_base; + // If true, this symbol is defined only if we see a reference to it. + bool only_if_ref; }; // The main linker symbol table. @@ -226,6 +504,47 @@ class Symbol_table size_t count, const char* sym_names, size_t sym_name_size, Symbol** sympointers); + // Define a special symbol. + template<int size, bool big_endian> + Sized_symbol<size>* + define_special_symbol(Target* target, const char* name, bool only_if_ref); + + // Define a special symbol based on an Output_data. It is a + // multiple definition error if this symbol is already defined. + void + define_in_output_data(Target*, const char* name, Output_data*, + uint64_t value, uint64_t symsize, + elfcpp::STT type, elfcpp::STB binding, + elfcpp::STV visibility, unsigned char nonvis, + bool offset_is_from_end, bool only_if_ref); + + // Define a special symbol based on an Output_segment. It is a + // multiple definition error if this symbol is already defined. + void + define_in_output_segment(Target*, const char* name, Output_segment*, + uint64_t value, uint64_t symsize, + elfcpp::STT type, elfcpp::STB binding, + elfcpp::STV visibility, unsigned char nonvis, + Symbol::Segment_offset_base, bool only_if_ref); + + // Define a special symbol with a constant value. It is a multiple + // definition error if this symbol is already defined. + void + define_as_constant(Target*, const char* name, uint64_t value, + uint64_t symsize, elfcpp::STT type, elfcpp::STB binding, + elfcpp::STV visibility, unsigned char nonvis, + bool only_if_ref); + + // Define a set of symbols in output sections. + void + define_symbols(const Layout*, Target*, int count, + const Define_symbol_in_section*); + + // Define a set of symbols in output segments. + void + define_symbols(const Layout*, Target*, int count, + const Define_symbol_in_segment*); + // Look up a symbol. Symbol* lookup(const char*, const char* version = NULL) const; @@ -248,6 +567,15 @@ class Symbol_table const Sized_symbol<size>* get_sized_symbol(const Symbol* ACCEPT_SIZE) const; + // Return the count of undefined symbols seen. + int + saw_undefined() const + { return this->saw_undefined_; } + + // Allocate the common symbols + void + allocate_commons(const General_options&, Layout*); + // Finalize the symbol table after we have set the final addresses // of all the input sections. This sets the final symbol values and // adds the names to *POOL. It records the file offset OFF, and @@ -291,6 +619,43 @@ class Symbol_table resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from ACCEPT_SIZE_ENDIAN); + // Define a symbol in an Output_data, sized version. + template<int size> + void + do_define_in_output_data(Target*, const char* name, Output_data*, + typename elfcpp::Elf_types<size>::Elf_Addr value, + typename elfcpp::Elf_types<size>::Elf_WXword ssize, + elfcpp::STT type, elfcpp::STB binding, + elfcpp::STV visibility, unsigned char nonvis, + bool offset_is_from_end, bool only_if_ref); + + // Define a symbol in an Output_segment, sized version. + template<int size> + void + do_define_in_output_segment( + Target*, const char* name, Output_segment* os, + typename elfcpp::Elf_types<size>::Elf_Addr value, + typename elfcpp::Elf_types<size>::Elf_WXword ssize, + elfcpp::STT type, elfcpp::STB binding, + elfcpp::STV visibility, unsigned char nonvis, + Symbol::Segment_offset_base offset_base, bool only_if_ref); + + // Define a symbol as a constant, sized version. + template<int size> + void + do_define_as_constant( + Target*, const char* name, + typename elfcpp::Elf_types<size>::Elf_Addr value, + typename elfcpp::Elf_types<size>::Elf_WXword ssize, + elfcpp::STT type, elfcpp::STB binding, + elfcpp::STV visibility, unsigned char nonvis, + bool only_if_ref); + + // Allocate the common symbols, sized version. + template<int size> + void + do_allocate_commons(const General_options&, Layout*); + // Finalize symbols specialized for size. template<int size> off_t @@ -320,9 +685,17 @@ class Symbol_table typedef Unordered_map<Symbol_table_key, Symbol*, Symbol_table_hash, Symbol_table_eq> Symbol_table_type; + // The type of the list of common symbols. + + typedef std::vector<Symbol*> Commons_type; + // The size of the symbols in the symbol table (32 or 64). int size_; + // We increment this every time we see a new undefined symbol, for + // use in archive groups. + int saw_undefined_; + // The file offset within the output symtab section where we should // write the table. off_t offset_; @@ -339,6 +712,13 @@ class Symbol_table // Forwarding symbols. Unordered_map<Symbol*, Symbol*> forwarders_; + + // We don't expect there to be very many common symbols, so we keep + // a list of them. When we find a common symbol we add it to this + // list. It is possible that by the time we process the list the + // symbol is no longer a common symbol. It may also have become a + // forwarder. + Commons_type commons_; }; // We inline get_sized_symbol for efficiency. |