X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Foutput.h;h=172be493d9dfee6fe75786793ecb29fda84d28de;hb=e8c846c359fda086b5e550fc795cc1c05b6ee003;hp=05ed1f87a5dec511d81030880566293aa9f6b91a;hpb=27bc2bce094e3a3ef536c5b8c2a38470bd7f3217;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/output.h b/gold/output.h index 05ed1f87a5..172be493d9 100644 --- a/gold/output.h +++ b/gold/output.h @@ -160,6 +160,17 @@ class Output_data } } + // Set the TLS offset. Called only for SHT_TLS sections. + void + set_tls_offset(uint64_t tls_base) + { this->do_set_tls_offset(tls_base); } + + // Return the TLS offset, relative to the base of the TLS segment. + // Valid only for SHT_TLS sections. + uint64_t + tls_offset() const + { return this->do_tls_offset(); } + // Write the data to the output file. This is called after // Layout::finalize is complete. void @@ -232,6 +243,17 @@ class Output_data set_final_data_size() { gold_unreachable(); } + // Set the TLS offset. Called only for SHT_TLS sections. + virtual void + do_set_tls_offset(uint64_t) + { gold_unreachable(); } + + // Return the TLS offset, relative to the base of the TLS segment. + // Valid only for SHT_TLS sections. + virtual uint64_t + do_tls_offset() const + { gold_unreachable(); } + // Functions that child classes may call. // Whether the address is valid. @@ -443,6 +465,12 @@ class Output_section_data : public Output_data off_t *poutput) const { return this->do_output_offset(object, shndx, offset, poutput); } + // Write the contents to a buffer. This is used for sections which + // require postprocessing, such as compression. + void + write_to_buffer(unsigned char* buffer) + { this->do_write_to_buffer(buffer); } + protected: // The child class must implement do_write. @@ -463,6 +491,13 @@ class Output_section_data : public Output_data do_output_offset(const Relobj*, unsigned int, off_t, off_t*) const { return false; } + // The child class may implement write_to_buffer. Most child + // classes can not appear in a compressed section, and they do not + // implement this. + virtual void + do_write_to_buffer(unsigned char*) + { gold_unreachable(); } + // Return the required alignment. uint64_t do_addralign() const @@ -536,6 +571,11 @@ class Output_data_const : public Output_section_data void do_write(Output_file*); + // Write the data to a buffer. + void + do_write_to_buffer(unsigned char* buffer) + { memcpy(buffer, this->data_.data(), this->data_.size()); } + private: std::string data_; }; @@ -556,6 +596,11 @@ class Output_data_const_buffer : public Output_section_data void do_write(Output_file*); + // Write the data to a buffer. + void + do_write_to_buffer(unsigned char* buffer) + { memcpy(buffer, this->p_, this->data_size()); } + private: const unsigned char* p_; }; @@ -620,6 +665,11 @@ class Output_data_strtab : public Output_section_data void do_write(Output_file*); + // Write the data to a buffer. + void + do_write_to_buffer(unsigned char* buffer) + { this->strtab_->write_to_buffer(buffer, this->data_size()); } + private: Stringpool* strtab_; }; @@ -653,75 +703,38 @@ class Output_reloc // A reloc against a global symbol. Output_reloc(Symbol* gsym, unsigned int type, Output_data* od, - Address address) - : address_(address), local_sym_index_(GSYM_CODE), type_(type), - shndx_(INVALID_CODE) - { - this->u1_.gsym = gsym; - this->u2_.od = od; - } + Address address, bool is_relative); Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj, - unsigned int shndx, Address address) - : address_(address), local_sym_index_(GSYM_CODE), type_(type), - shndx_(shndx) - { - gold_assert(shndx != INVALID_CODE); - this->u1_.gsym = gsym; - this->u2_.relobj = relobj; - } + unsigned int shndx, Address address, bool is_relative); // A reloc against a local symbol. Output_reloc(Sized_relobj* relobj, - unsigned int local_sym_index, - unsigned int type, - Output_data* od, - Address address) - : address_(address), local_sym_index_(local_sym_index), type_(type), - shndx_(INVALID_CODE) - { - gold_assert(local_sym_index != GSYM_CODE - && local_sym_index != INVALID_CODE); - this->u1_.relobj = relobj; - this->u2_.od = od; - } + unsigned int local_sym_index, unsigned int type, + Output_data* od, Address address, bool is_relative); Output_reloc(Sized_relobj* relobj, - unsigned int local_sym_index, - unsigned int type, - unsigned int shndx, - Address address) - : address_(address), local_sym_index_(local_sym_index), type_(type), - shndx_(shndx) - { - gold_assert(local_sym_index != GSYM_CODE - && local_sym_index != INVALID_CODE); - gold_assert(shndx != INVALID_CODE); - this->u1_.relobj = relobj; - this->u2_.relobj = relobj; - } + unsigned int local_sym_index, unsigned int type, + unsigned int shndx, Address address, bool is_relative); // A reloc against the STT_SECTION symbol of an output section. Output_reloc(Output_section* os, unsigned int type, Output_data* od, - Address address) - : address_(address), local_sym_index_(SECTION_CODE), type_(type), - shndx_(INVALID_CODE) - { - this->u1_.os = os; - this->u2_.od = od; - } + Address address); Output_reloc(Output_section* os, unsigned int type, Relobj* relobj, - unsigned int shndx, Address address) - : address_(address), local_sym_index_(SECTION_CODE), type_(type), - shndx_(shndx) - { - gold_assert(shndx != INVALID_CODE); - this->u1_.os = os; - this->u2_.relobj = relobj; - } + unsigned int shndx, Address address); + + // Return TRUE if this is a RELATIVE relocation. + bool + is_relative() const + { return this->is_relative_; } + + // Get the value of the symbol referred to by a Rel relocation. + + Address + symbol_value() const; // Write the reloc entry to an output view. void @@ -777,7 +790,9 @@ class Output_reloc // 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_; + unsigned int type_ : 31; + // True if the relocation is a RELATIVE relocation. + bool is_relative_ : 1; // If the reloc address is an input section in an object, the // section index. This is INVALID_CODE if the reloc address is // specified in some other way. @@ -802,31 +817,31 @@ class Output_reloc // A reloc against a global symbol. Output_reloc(Symbol* gsym, unsigned int type, Output_data* od, - Address address, Addend addend) - : rel_(gsym, type, od, address), addend_(addend) + Address address, Addend addend, bool is_relative) + : rel_(gsym, type, od, address, is_relative), addend_(addend) { } Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj, - unsigned int shndx, Address address, Addend addend) - : rel_(gsym, type, relobj, shndx, address), addend_(addend) + unsigned int shndx, Address address, Addend addend, + bool is_relative) + : rel_(gsym, type, relobj, shndx, address, is_relative), addend_(addend) { } // A reloc against a local symbol. Output_reloc(Sized_relobj* relobj, - unsigned int local_sym_index, - unsigned int type, Output_data* od, Address address, - Addend addend) - : rel_(relobj, local_sym_index, type, od, address), addend_(addend) + unsigned int local_sym_index, unsigned int type, + Output_data* od, Address address, + Addend addend, bool is_relative) + : rel_(relobj, local_sym_index, type, od, address, is_relative), + addend_(addend) { } Output_reloc(Sized_relobj* relobj, - unsigned int local_sym_index, - unsigned int type, - unsigned int shndx, - Address address, - Addend addend) - : rel_(relobj, local_sym_index, type, shndx, address), + unsigned int local_sym_index, unsigned int type, + unsigned int shndx, Address address, + Addend addend, bool is_relative) + : rel_(relobj, local_sym_index, type, shndx, address, is_relative), addend_(addend) { } @@ -925,12 +940,27 @@ class Output_data_reloc void add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address) - { this->add(od, Output_reloc_type(gsym, type, od, address)); } + { this->add(od, Output_reloc_type(gsym, type, od, address, false)); } void add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj, unsigned int shndx, Address address) - { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address)); } + { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, + false)); } + + // Add a RELATIVE reloc against a global symbol. The final relocation + // will not reference the symbol. + + void + add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, + Address address) + { this->add(od, Output_reloc_type(gsym, type, od, address, true)); } + + void + add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, + Relobj* relobj, unsigned int shndx, Address address) + { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, + true)); } // Add a reloc against a local symbol. @@ -939,15 +969,30 @@ class Output_data_reloc unsigned int local_sym_index, unsigned int type, Output_data* od, Address address) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, - address)); } + address, false)); } void add_local(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, Output_data* od, unsigned int shndx, Address address) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, - address)); } + address, false)); } + + // Add a RELATIVE reloc against a local symbol. + + void + add_local_relative(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + Output_data* od, Address address) + { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, + address, true)); } + void + add_local_relative(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + Output_data* od, unsigned int shndx, Address address) + { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, + address, true)); } // A reloc against the STT_SECTION symbol of an output section. // OS is the Output_section that the relocation refers to; OD is @@ -988,14 +1033,32 @@ class Output_data_reloc void add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address, Addend addend) - { this->add(od, Output_reloc_type(gsym, type, od, address, addend)); } + { this->add(od, Output_reloc_type(gsym, type, od, address, addend, + false)); } void add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj, unsigned int shndx, Address address, Addend addend) { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - addend)); } + addend, false)); } + + // Add a RELATIVE reloc against a global symbol. The final output + // relocation will not reference the symbol, but we must keep the symbol + // information long enough to set the addend of the relocation correctly + // when it is written. + + void + add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, + Address address, Addend addend) + { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true)); } + + void + add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, + Relobj* relobj, unsigned int shndx, Address address, + Addend addend) + { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, + addend, true)); } // Add a reloc against a local symbol. @@ -1005,7 +1068,7 @@ class Output_data_reloc Output_data* od, Address address, Addend addend) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address, - addend)); + addend, false)); } void @@ -1015,7 +1078,28 @@ class Output_data_reloc Addend addend) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, - address, addend)); + address, addend, false)); + } + + // Add a RELATIVE reloc against a local symbol. + + void + add_local_relative(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + Output_data* od, Address address, Addend addend) + { + this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address, + addend, true)); + } + + void + add_local_relative(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + Output_data* od, unsigned int shndx, Address address, + Addend addend) + { + this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, + address, addend, true)); } // A reloc against the STT_SECTION symbol of an output section. @@ -1042,6 +1126,8 @@ class Output_data_got : public Output_section_data_build { public: typedef typename elfcpp::Elf_types::Elf_Addr Valtype; + typedef Output_data_reloc Rel_dyn; + typedef Output_data_reloc Rela_dyn; Output_data_got() : Output_section_data_build(Output_data::default_alignment_for_size(size)), @@ -1053,18 +1139,60 @@ class Output_data_got : public Output_section_data_build bool add_global(Symbol* gsym); + // Add an entry for a global symbol to the GOT, and add a dynamic + // relocation of type R_TYPE for the GOT entry. + void + add_global_with_rel(Symbol* gsym, Rel_dyn* rel_dyn, unsigned int r_type); + + void + add_global_with_rela(Symbol* gsym, Rela_dyn* rela_dyn, unsigned int r_type); + // Add an entry for a local symbol to the GOT. This returns true if // this is a new GOT entry, false if the symbol already has a GOT // entry. bool add_local(Sized_relobj* object, unsigned int sym_index); + // Add an entry for a global symbol to the GOT, and add a dynamic + // relocation of type R_TYPE for the GOT entry. + void + add_local_with_rel(Sized_relobj* object, + unsigned int sym_index, Rel_dyn* rel_dyn, + unsigned int r_type); + + void + add_local_with_rela(Sized_relobj* object, + unsigned int sym_index, Rela_dyn* rela_dyn, + unsigned int r_type); + // Add an entry (or pair of entries) for a global TLS symbol to the GOT. // Return true if this is a new GOT entry, false if the symbol was // already in the GOT. bool add_global_tls(Symbol* gsym, bool need_pair); + // Add an entry for a global TLS symbol to the GOT, and add a dynamic + // relocation of type R_TYPE. + void + add_global_tls_with_rel(Symbol* gsym, Rel_dyn* rel_dyn, + unsigned int r_type); + + void + add_global_tls_with_rela(Symbol* gsym, Rela_dyn* rela_dyn, + unsigned int r_type); + + // Add a pair of entries for a global TLS symbol to the GOT, and add + // dynamic relocations of type MOD_R_TYPE and DTV_R_TYPE, respectively. + void + add_global_tls_with_rel(Symbol* gsym, Rel_dyn* rel_dyn, + unsigned int mod_r_type, + unsigned int dtv_r_type); + + void + add_global_tls_with_rela(Symbol* gsym, Rela_dyn* rela_dyn, + unsigned int mod_r_type, + unsigned int dtv_r_type); + // Add an entry (or pair of entries) for a local TLS symbol to the GOT. // This returns true if this is a new GOT entry, false if the symbol // already has a GOT entry. @@ -1072,6 +1200,23 @@ class Output_data_got : public Output_section_data_build add_local_tls(Sized_relobj* object, unsigned int sym_index, bool need_pair); + // Add an entry (or pair of entries) for a local TLS symbol to the GOT, + // and add a dynamic relocation of type R_TYPE for the first GOT entry. + // Because this is a local symbol, the first GOT entry can be relocated + // relative to a section symbol, and the second GOT entry will have an + // dtv-relative value that can be computed at link time. + void + add_local_tls_with_rel(Sized_relobj* object, + unsigned int sym_index, unsigned int shndx, + bool need_pair, Rel_dyn* rel_dyn, + unsigned int r_type); + + void + add_local_tls_with_rela(Sized_relobj* object, + unsigned int sym_index, unsigned int shndx, + bool need_pair, Rela_dyn* rela_dyn, + unsigned int r_type); + // Add a constant to the GOT. This returns the offset of the new // entry from the start of the GOT. unsigned int @@ -1489,11 +1634,23 @@ class Output_section : public Output_data requires_postprocessing() const { return this->requires_postprocessing_; } - // Record that this section requires postprocessing after all - // relocations have been applied. + // If a section requires postprocessing, return the buffer to use. + unsigned char* + postprocessing_buffer() const + { + gold_assert(this->postprocessing_buffer_ != NULL); + return this->postprocessing_buffer_; + } + + // If a section requires postprocessing, create the buffer to use. void - set_requires_postprocessing() - { this->requires_postprocessing_ = true; } + create_postprocessing_buffer(); + + // If a section requires postprocessing, this is the size of the + // buffer to which relocations should be applied. + off_t + postprocessing_buffer_size() const + { return this->current_data_size_for_child(); } // Return whether the offset OFFSET in the input section SHNDX in // object OBJECT is being included in the link. @@ -1539,14 +1696,14 @@ class Output_section : public Output_data // Output_section, there is nothing to do, but if there are any // Output_section_data objects we need to set their final addresses // here. - void + virtual void set_final_data_size(); // Write the data to the file. For a typical Output_section, this // 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. - void + virtual void do_write(Output_file*); // Return the address alignment--function required by parent class. @@ -1569,6 +1726,46 @@ class Output_section : public Output_data do_is_section_flag_set(elfcpp::Elf_Xword flag) const { return (this->flags_ & flag) != 0; } + // Set the TLS offset. Called only for SHT_TLS sections. + void + do_set_tls_offset(uint64_t tls_base); + + // Return the TLS offset, relative to the base of the TLS segment. + // Valid only for SHT_TLS sections. + uint64_t + do_tls_offset() const + { return this->tls_offset_; } + + // Modify the section name. This is only permitted for an + // unallocated section, and only before the size has been finalized. + // Otherwise the name will not get into Layout::namepool_. + void + set_name(const char* newname) + { + gold_assert((this->flags_ & elfcpp::SHF_ALLOC) == 0); + gold_assert(!this->is_data_size_valid()); + this->name_ = newname; + } + + // This may be implemented by a child class. + virtual void + do_finalize_name(Layout*) + { } + + // Record that this section requires postprocessing after all + // relocations have been applied. This is called by a child class. + void + set_requires_postprocessing() + { + this->requires_postprocessing_ = true; + this->after_input_sections_ = true; + } + + // Write all the data of an Output_section into the postprocessing + // buffer. + void + write_to_postprocessing_buffer(); + private: // In some cases we need to keep a list of the input sections // associated with this output section. We only need the list if we @@ -1658,10 +1855,15 @@ class Output_section : public Output_data } // Set the address and file offset. This is called during - // Layout::finalize. SECOFF is the file offset of the enclosing - // section. + // Layout::finalize. SECTION_FILE_OFFSET is the file offset of + // the enclosing section. + void + set_address_and_file_offset(uint64_t address, off_t file_offset, + off_t section_file_offset); + + // Finalize the data size. void - set_address(uint64_t addr, off_t off, off_t secoff); + finalize_data_size(); // Add an input section, for SHF_MERGE sections. bool @@ -1685,6 +1887,11 @@ class Output_section : public Output_data void write(Output_file*); + // Write the data to a buffer. This does nothing for an input + // section. + void + write_to_buffer(unsigned char*); + private: // Code values which appear in shndx_. If the value is not one of // these codes, it is the input section index in the object file. @@ -1790,7 +1997,7 @@ class Output_section : public Output_data // Most of these fields are only valid after layout. // The name of the section. This will point into a Stringpool. - const char* const name_; + const char* name_; // The section address is in the parent class. // The section alignment. uint64_t addralign_; @@ -1830,6 +2037,9 @@ class Output_section : public Output_data // often will need fill sections without needing to keep track of // input sections. Fill_list fills_; + // If the section requires postprocessing, this buffer holds the + // section contents during relocation. + unsigned char* postprocessing_buffer_; // Whether this output section needs a STT_SECTION symbol in the // normal symbol table. This will be true if there is a relocation // which needs it. @@ -1850,6 +2060,9 @@ class Output_section : public Output_data // Whether this section requires post processing after all // relocations have been applied. bool requires_postprocessing_ : 1; + // For SHT_TLS sections, the offset of this section relative to the base + // of the TLS segment. + uint64_t tls_offset_; }; // An output segment. PT_LOAD segments are built from collections of @@ -1938,6 +2151,10 @@ class Output_segment void set_offset(); + // Set the TLS offsets of the sections contained in the PT_TLS segment. + void + set_tls_offsets(); + // Return the number of output sections. unsigned int output_section_count() const; @@ -2034,7 +2251,8 @@ class Output_file void resize(off_t file_size); - // Close the output file and make sure there are no error. + // Close the output file (flushing all buffered data) and make sure + // there are no errors. void close(); @@ -2084,10 +2302,15 @@ class Output_file { } private: - // Map the file into memory. + // Map the file into memory and return a pointer to the map. void map(); + // Unmap the file from memory (and flush to disk buffers). + void + unmap(); + + // General options. const General_options& options_; // Target. @@ -2100,6 +2323,8 @@ class Output_file off_t file_size_; // Base of file mapped into memory. unsigned char* base_; + // True iff base_ points to a memory buffer rather than an output file. + bool map_is_anonymous_; }; } // End namespace gold.