X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Foutput.h;h=172be493d9dfee6fe75786793ecb29fda84d28de;hb=e8c846c359fda086b5e550fc795cc1c05b6ee003;hp=013a19f1b91028441bfafa2151eebef86db74674;hpb=14b317405813ed4aaf59235b5bfaf4f8decf1ad0;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/output.h b/gold/output.h index 013a19f1b9..172be493d9 100644 --- a/gold/output.h +++ b/gold/output.h @@ -1,5 +1,25 @@ // output.h -- manage the output file for gold -*- C++ -*- +// Copyright 2006, 2007 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + #ifndef GOLD_OUTPUT_H #define GOLD_OUTPUT_H @@ -29,31 +49,44 @@ class Sized_relobj; class Output_data { public: - explicit Output_data(off_t data_size = 0) - : address_(0), data_size_(data_size), offset_(-1) + explicit Output_data() + : address_(0), data_size_(0), offset_(-1), + is_address_valid_(false), is_data_size_valid_(false), + is_offset_valid_(false), + dynamic_reloc_count_(0) { } virtual ~Output_data(); - // Return the address. This is only valid after Layout::finalize is - // finished. + // Return the address. For allocated sections, this is only valid + // after Layout::finalize is finished. uint64_t address() const - { return this->address_; } + { + gold_assert(this->is_address_valid_); + return this->address_; + } - // Return the size of the data. This must be valid after - // Layout::finalize calls set_address, but need not be valid before - // then. + // Return the size of the data. For allocated sections, this must + // be valid after Layout::finalize calls set_address, but need not + // be valid before then. off_t data_size() const - { return this->data_size_; } + { + gold_assert(this->is_data_size_valid_); + return this->data_size_; + } // Return the file offset. This is only valid after - // Layout::finalize is finished. + // Layout::finalize is finished. For some non-allocated sections, + // it may not be valid until near the end of the link. off_t offset() const - { return this->offset_; } + { + gold_assert(this->is_offset_valid_); + return this->offset_; + } // Return the required alignment. uint64_t @@ -86,10 +119,57 @@ class Output_data set_out_shndx(unsigned int shndx) { this->do_set_out_shndx(shndx); } - // Set the address and file offset of this data. This is called - // during Layout::finalize. + // Set the address and file offset of this data, and finalize the + // size of the data. This is called during Layout::finalize for + // allocated sections. + void + set_address_and_file_offset(uint64_t addr, off_t off) + { + this->set_address(addr); + this->set_file_offset(off); + this->finalize_data_size(); + } + + // Set the address. + void + set_address(uint64_t addr) + { + gold_assert(!this->is_address_valid_); + this->address_ = addr; + this->is_address_valid_ = true; + } + + // Set the file offset. + void + set_file_offset(off_t off) + { + gold_assert(!this->is_offset_valid_); + this->offset_ = off; + this->is_offset_valid_ = true; + } + + // Finalize the data size. + void + finalize_data_size() + { + if (!this->is_data_size_valid_) + { + // Tell the child class to set the data size. + this->set_final_data_size(); + gold_assert(this->is_data_size_valid_); + } + } + + // Set the TLS offset. Called only for SHT_TLS sections. void - set_address(uint64_t addr, off_t off); + 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. @@ -97,11 +177,26 @@ 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. + // This is called by Layout::finalize to note that the sizes of + // allocated sections must now be fixed. static void layout_complete() - { Output_data::sizes_are_fixed = true; } + { Output_data::allocated_sizes_are_fixed = true; } + + // Used to check that layout has been done. + static bool + is_layout_complete() + { return Output_data::allocated_sizes_are_fixed; } + + // Count the number of dynamic relocations applied to this section. + void + add_dynamic_reloc() + { ++this->dynamic_reloc_count_; } + + // Return the number of dynamic relocations applied to this section. + unsigned int + dynamic_reloc_count() const + { return this->dynamic_reloc_count_; } protected: // Functions that child classes may or in some cases must implement. @@ -141,41 +236,96 @@ class Output_data do_set_out_shndx(unsigned int) { gold_unreachable(); } - // Set the address and file offset of the data. This only needs to - // be implemented if the child needs to know. The child class can - // set its size in this call. + // This is a hook for derived classes to set the data size. This is + // called by finalize_data_size, normally called during + // Layout::finalize, when the section address is set. virtual void - do_set_address(uint64_t, off_t) - { } + 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. + bool + is_address_valid() const + { return this->is_address_valid_; } + + // Whether the file offset is valid. + bool + is_offset_valid() const + { return this->is_offset_valid_; } + + // Whether the data size is valid. + bool + is_data_size_valid() const + { return this->is_data_size_valid_; } + // Set the size of the data. void set_data_size(off_t data_size) { - gold_assert(!Output_data::sizes_are_fixed); + gold_assert(!this->is_data_size_valid_); + this->data_size_ = data_size; + this->is_data_size_valid_ = true; + } + + // Get the current data size--this is for the convenience of + // sections which build up their size over time. + off_t + current_data_size_for_child() const + { return this->data_size_; } + + // Set the current data size--this is for the convenience of + // sections which build up their size over time. + void + set_current_data_size_for_child(off_t data_size) + { + gold_assert(!this->is_data_size_valid_); this->data_size_ = data_size; } - // Return default alignment for a size--32 or 64. + // Return default alignment for the target size. static uint64_t - default_alignment(int size); + default_alignment(); + + // Return default alignment for a specified size--32 or 64. + static uint64_t + default_alignment_for_size(int size); private: 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; + // change any sizes of allocated sections after we set the section + // addresses. + static bool allocated_sizes_are_fixed; - // Memory address in file (not always meaningful). + // Memory address in output file. uint64_t address_; - // Size of data in file. + // Size of data in output file. off_t data_size_; - // Offset within file. + // File offset of contents in output file. off_t offset_; + // Whether address_ is valid. + bool is_address_valid_; + // Whether data_size_ is valid. + bool is_data_size_valid_; + // Whether offset_ is valid. + bool is_offset_valid_; + // Count of dynamic relocations applied to this section. + unsigned int dynamic_reloc_count_; }; // Output the section headers. @@ -183,13 +333,12 @@ class Output_data class Output_section_headers : public Output_data { public: - Output_section_headers(int size, - bool big_endian, - const Layout*, + Output_section_headers(const Layout*, const Layout::Segment_list*, const Layout::Section_list*, const Stringpool*); + protected: // Write the data to the file. void do_write(Output_file*); @@ -197,7 +346,7 @@ class Output_section_headers : public Output_data // Return the required alignment. uint64_t do_addralign() const - { return Output_data::default_alignment(this->size_); } + { return Output_data::default_alignment(); } private: // Write the data to the file with the right size and endianness. @@ -205,8 +354,6 @@ class Output_section_headers : public Output_data void do_sized_write(Output_file*); - int size_; - bool big_endian_; const Layout* layout_; const Layout::Segment_list* segment_list_; const Layout::Section_list* unattached_section_list_; @@ -218,9 +365,9 @@ class Output_section_headers : public Output_data class Output_segment_headers : public Output_data { public: - Output_segment_headers(int size, bool big_endian, - const Layout::Segment_list& segment_list); + Output_segment_headers(const Layout::Segment_list& segment_list); + protected: // Write the data to the file. void do_write(Output_file*); @@ -228,7 +375,7 @@ class Output_segment_headers : public Output_data // Return the required alignment. uint64_t do_addralign() const - { return Output_data::default_alignment(this->size_); } + { return Output_data::default_alignment(); } private: // Write the data to the file with the right size and endianness. @@ -236,8 +383,6 @@ class Output_segment_headers : public Output_data void do_sized_write(Output_file*); - int size_; - bool big_endian_; const Layout::Segment_list& segment_list_; }; @@ -246,10 +391,7 @@ class Output_segment_headers : public Output_data class Output_file_header : public Output_data { public: - Output_file_header(int size, - bool big_endian, - const General_options&, - const Target*, + Output_file_header(const Target*, const Symbol_table*, const Output_segment_headers*); @@ -258,6 +400,7 @@ class Output_file_header : public Output_data void set_section_info(const Output_section_headers*, const Output_section* shstrtab); + protected: // Write the data to the file. void do_write(Output_file*); @@ -265,13 +408,7 @@ class Output_file_header : public Output_data // Return the required alignment. uint64_t do_addralign() const - { return Output_data::default_alignment(this->size_); } - - // Set the address and offset--we only implement this for error - // checking. - void - do_set_address(uint64_t, off_t off) const - { gold_assert(off == 0); } + { return Output_data::default_alignment(); } private: // Write the data to the file with the right size and endianness. @@ -279,9 +416,6 @@ class Output_file_header : public Output_data void do_sized_write(Output_file*); - int size_; - bool big_endian_; - const General_options& options_; const Target* target_; const Symbol_table* symtab_; const Output_segment_headers* segment_header_; @@ -298,11 +432,11 @@ class Output_section_data : public Output_data { public: Output_section_data(off_t data_size, uint64_t addralign) - : Output_data(data_size), output_section_(NULL), addralign_(addralign) - { } + : Output_data(), output_section_(NULL), addralign_(addralign) + { this->set_data_size(data_size); } Output_section_data(uint64_t addralign) - : Output_data(0), output_section_(NULL), addralign_(addralign) + : Output_data(), output_section_(NULL), addralign_(addralign) { } // Return the output section. @@ -314,6 +448,29 @@ class Output_section_data : public Output_data void set_output_section(Output_section* os); + // Add an input section, for SHF_MERGE sections. This returns true + // if the section was handled. + bool + add_input_section(Relobj* object, unsigned int shndx) + { return this->do_add_input_section(object, shndx); } + + // Given an input OBJECT, an input section index SHNDX within that + // object, and an OFFSET relative to the start of that input + // section, return whether or not the corresponding offset within + // the output section is known. If this function returns true, it + // sets *POUTPUT to the output offset. The value -1 indicates that + // this input offset is being discarded. + virtual bool + output_offset(const Relobj* object, unsigned int shndx, off_t offset, + 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. @@ -323,6 +480,24 @@ class Output_section_data : public Output_data do_adjust_output_section(Output_section*) { } + // May be implemented by child class. Return true if the section + // was handled. + virtual bool + do_add_input_section(Relobj*, unsigned int) + { gold_unreachable(); } + + // The child class may implement output_offset. + virtual bool + 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 @@ -344,6 +519,34 @@ class Output_section_data : public Output_data uint64_t addralign_; }; +// Some Output_section_data classes build up their data step by step, +// rather than all at once. This class provides an interface for +// them. + +class Output_section_data_build : public Output_section_data +{ + public: + Output_section_data_build(uint64_t addralign) + : Output_section_data(addralign) + { } + + // Get the current data size. + off_t + current_data_size() const + { return this->current_data_size_for_child(); } + + // Set the current data size. + void + set_current_data_size(off_t data_size) + { this->set_current_data_size_for_child(data_size); } + + protected: + // Set the final data size. + virtual void + set_final_data_size() + { this->set_data_size(this->current_data_size_for_child()); } +}; + // A simple case of Output_data in which we have constant data to // output. @@ -363,18 +566,16 @@ class Output_data_const : public Output_section_data data_(reinterpret_cast(p), len) { } - // Add more data. - void - add_data(const std::string& add) - { - this->data_.append(add); - this->set_data_size(this->data_.size()); - } - + protected: // Write the data to the output file. 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_; }; @@ -390,38 +591,56 @@ class Output_data_const_buffer : public Output_section_data : Output_section_data(len, addralign), p_(p) { } + protected: // Write the data the output file. 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_; }; -// A place holder for data written out via some other mechanism. +// A place holder for a fixed amount of data written out via some +// other mechanism. -class Output_data_space : public Output_section_data +class Output_data_fixed_space : public Output_section_data { public: - Output_data_space(off_t data_size, uint64_t addralign) + Output_data_fixed_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) + protected: + // Write out the data--the actual data must be written out + // elsewhere. + void + do_write(Output_file*) { } +}; - // Set the size. - void - set_space_size(off_t space_size) - { this->set_data_size(space_size); } +// A place holder for variable sized data written out via some other +// mechanism. + +class Output_data_space : public Output_section_data_build +{ + public: + explicit Output_data_space(uint64_t addralign) + : Output_section_data_build(addralign) + { } // Set the alignment. void set_space_alignment(uint64_t align) { this->set_addralign(align); } - // Write out the data--this must be handled elsewhere. + protected: + // Write out the data--the actual data must be written out + // elsewhere. void do_write(Output_file*) { } @@ -436,15 +655,21 @@ class Output_data_strtab : public Output_section_data : Output_section_data(1), strtab_(strtab) { } + protected: // 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); + set_final_data_size(); // Write out the 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_; }; @@ -478,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 @@ -602,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. @@ -627,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) { } @@ -686,7 +876,7 @@ class Output_reloc // the reloc type. template -class Output_data_reloc_base : public Output_section_data +class Output_data_reloc_base : public Output_section_data_build { public: typedef Output_reloc Output_reloc_type; @@ -696,24 +886,25 @@ class Output_data_reloc_base : public Output_section_data // Construct the section. Output_data_reloc_base() - : Output_section_data(Output_data::default_alignment(size)) + : Output_section_data_build(Output_data::default_alignment_for_size(size)) { } + protected: // Write out the data. void do_write(Output_file*); - protected: // Set the entry size and the link. void do_adjust_output_section(Output_section *os); // Add a relocation entry. void - add(const Output_reloc_type& reloc) + add(Output_data *od, const Output_reloc_type& reloc) { this->relocs_.push_back(reloc); - this->set_data_size(this->relocs_.size() * reloc_size); + this->set_current_data_size(this->relocs_.size() * reloc_size); + od->add_dynamic_reloc(); } private: @@ -749,12 +940,27 @@ class Output_data_reloc void add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address) - { this->add(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, Relobj* relobj, + add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj, unsigned int shndx, Address address) - { this->add(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. @@ -762,27 +968,45 @@ class Output_data_reloc add_local(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, Output_data* od, Address address) - { this->add(Output_reloc_type(relobj, local_sym_index, type, od, address)); } + { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, + address, false)); } void add_local(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, - unsigned int shndx, Address address) - { this->add(Output_reloc_type(relobj, local_sym_index, type, shndx, - address)); } + Output_data* od, unsigned int shndx, Address address) + { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, + 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 + // the Output_data object being relocated. void add_output_section(Output_section* os, unsigned int type, Output_data* od, Address address) - { this->add(Output_reloc_type(os, type, od, address)); } + { this->add(od, Output_reloc_type(os, type, od, address)); } void - add_output_section(Output_section* os, unsigned int type, + add_output_section(Output_section* os, unsigned int type, Output_data* od, Relobj* relobj, unsigned int shndx, Address address) - { this->add(Output_reloc_type(os, type, relobj, shndx, address)); } + { this->add(od, Output_reloc_type(os, type, relobj, shndx, address)); } }; // The SHT_RELA version of Output_data_reloc. @@ -809,12 +1033,32 @@ class Output_data_reloc void add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address, Addend addend) - { this->add(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, Relobj* relobj, - unsigned int shndx, Address address, Addend addend) - { this->add(Output_reloc_type(gsym, type, relobj, shndx, address, addend)); } + 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, 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. @@ -823,17 +1067,39 @@ class Output_data_reloc unsigned int local_sym_index, unsigned int type, Output_data* od, Address address, Addend addend) { - this->add(Output_reloc_type(relobj, local_sym_index, type, od, address, - addend)); + this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address, + addend, false)); } void add_local(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, - unsigned int shndx, Address address, Addend addend) + Output_data* od, unsigned int shndx, Address address, + Addend addend) { - this->add(Output_reloc_type(relobj, local_sym_index, type, shndx, address, - addend)); + this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, + 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. @@ -841,12 +1107,13 @@ class Output_data_reloc void 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)); } + { this->add(os, Output_reloc_type(os, type, od, address, addend)); } void add_output_section(Output_section* os, unsigned int type, Relobj* relobj, unsigned int shndx, Address address, Addend addend) - { this->add(Output_reloc_type(os, type, relobj, shndx, address, addend)); } + { this->add(os, Output_reloc_type(os, type, relobj, shndx, address, + addend)); } }; // Output_data_got is used to manage a GOT. Each entry in the GOT is @@ -855,14 +1122,16 @@ class Output_data_reloc // needed. template -class Output_data_got : public Output_section_data +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(const General_options* options) - : Output_section_data(Output_data::default_alignment(size)), - options_(options), entries_() + Output_data_got() + : Output_section_data_build(Output_data::default_alignment_for_size(size)), + entries_() { } // Add an entry for a global symbol to the GOT. Return true if this @@ -870,15 +1139,83 @@ class Output_data_got : public Output_section_data bool add_global(Symbol* gsym); - // Add an entry for a local symbol to the GOT. This returns the - // offset of the new entry from the start of the GOT. - unsigned int - add_local(Object* object, unsigned int sym_index) - { - this->entries_.push_back(Got_entry(object, sym_index)); - this->set_got_size(); - return this->last_got_offset(); - } + // 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. + bool + 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. @@ -890,6 +1227,7 @@ class Output_data_got : public Output_section_data return this->last_got_offset(); } + protected: // Write out the GOT table. void do_write(Output_file*); @@ -910,7 +1248,8 @@ class Output_data_got : public Output_section_data { this->u_.gsym = gsym; } // Create a local symbol entry. - Got_entry(Object* object, unsigned int local_sym_index) + Got_entry(Sized_relobj* object, + unsigned int local_sym_index) : local_sym_index_(local_sym_index) { gold_assert(local_sym_index != GSYM_CODE @@ -926,7 +1265,7 @@ class Output_data_got : public Output_section_data // Write the GOT entry to an output view. void - write(const General_options*, unsigned char* pov) const; + write(unsigned char* pov) const; private: enum @@ -938,7 +1277,7 @@ class Output_data_got : public Output_section_data union { // For a local symbol, the object. - Object* object; + Sized_relobj* object; // For a global symbol, the symbol. Symbol* gsym; // For a constant, the constant. @@ -964,10 +1303,8 @@ class Output_data_got : public Output_section_data // Set the size of the section. void set_got_size() - { this->set_data_size(this->got_offset(this->entries_.size())); } + { this->set_current_data_size(this->got_offset(this->entries_.size())); } - // Options. - const General_options* options_; // The list of GOT entries. Got_entries entries_; }; @@ -978,9 +1315,9 @@ class Output_data_got : public Output_section_data 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) + Output_data_dynamic(Stringpool* pool) + : Output_section_data(Output_data::default_alignment()), + entries_(), pool_(pool) { } // Add a new dynamic entry with a fixed numeric value. @@ -1006,21 +1343,25 @@ class Output_data_dynamic : public Output_section_data // 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))); } + { this->add_entry(Dynamic_entry(tag, this->pool_->add(str, true, NULL))); } - // Set the final data size. void - do_set_address(uint64_t, off_t); - - // Write out the dynamic entries. - void - do_write(Output_file*); + add_string(elfcpp::DT tag, const std::string& str) + { this->add_string(tag, str.c_str()); } protected: // Adjust the output section to set the entry size. void do_adjust_output_section(Output_section*); + // Set the final data size. + void + set_final_data_size(); + + // Write out the dynamic entries. + void + do_write(Output_file*); + private: // This POD class holds a single dynamic entry. class Dynamic_entry @@ -1099,8 +1440,6 @@ class Output_data_dynamic : public Output_section_data // The type of the list of entries. typedef std::vector Dynamic_entries; - // The target. - const Target* target_; // The entries. Dynamic_entries entries_; // The pool used for strings. @@ -1114,18 +1453,21 @@ class Output_section : public Output_data { public: // Create an output section, giving the name, type, and flags. - Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword, - bool may_add_data); + Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword); virtual ~Output_section(); // Add a new input section SHNDX, named NAME, with header SHDR, from - // object OBJECT. Return the offset within the output section. + // object OBJECT. RELOC_SHNDX is the index of a relocation section + // which applies to this section, or 0 if none, or -1U if more than + // one. Return the offset within the output section. template off_t - add_input_section(Relobj* object, unsigned int shndx, const char *name, - const elfcpp::Shdr& shdr); + add_input_section(Sized_relobj* object, unsigned int shndx, + const char *name, + const elfcpp::Shdr& shdr, + unsigned int reloc_shndx); - // Add generated data ODATA to this output section. + // Add generated data POSD to this output section. void add_output_section_data(Output_section_data* posd); @@ -1144,16 +1486,6 @@ class Output_section : public Output_data flags() const { return this->flags_; } - // Return the section index in the output file. - unsigned int - do_out_shndx() const - { return this->out_shndx_; } - - // Set the output section index. - void - do_set_out_shndx(unsigned int shndx) - { this->out_shndx_ = shndx; } - // Return the entsize field. uint64_t entsize() const @@ -1284,18 +1616,94 @@ class Output_section : public Output_data this->dynsym_index_ = index; } - // Set the address of the Output_section. For a typical + // Return whether this section should be written after all the input + // sections are complete. + bool + after_input_sections() const + { return this->after_input_sections_; } + + // Record that this section should be written after all the input + // sections are complete. + void + set_after_input_sections() + { this->after_input_sections_ = true; } + + // Return whether this section requires postprocessing after all + // relocations have been applied. + bool + requires_postprocessing() const + { return this->requires_postprocessing_; } + + // 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 + 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. + bool + is_input_address_mapped(const Relobj* object, unsigned int shndx, + off_t offset) const; + + // Return the offset within the output section of OFFSET relative to + // the start of input section SHNDX in object OBJECT. + off_t + output_offset(const Relobj* object, unsigned int shndx, off_t offset) const; + + // Return the output virtual address of OFFSET relative to the start + // of input section SHNDX in object OBJECT. + uint64_t + output_address(const Relobj* object, unsigned int shndx, + off_t offset) const; + + // Write the section header into *OPHDR. + template + void + write_header(const Layout*, const Stringpool*, + elfcpp::Shdr_write*) const; + + protected: + // Return the section index in the output file. + unsigned int + do_out_shndx() const + { + gold_assert(this->out_shndx_ != -1U); + return this->out_shndx_; + } + + // Set the output section index. + void + do_set_out_shndx(unsigned int shndx) + { + gold_assert(this->out_shndx_ == -1U); + this->out_shndx_ = shndx; + } + + // Set the final data size of the Output_section. For a typical // Output_section, there is nothing to do, but if there are any - // Output_section_data objects we need to set the final addresses + // Output_section_data objects we need to set their final addresses // here. - void - do_set_address(uint64_t, off_t); + 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. @@ -1318,11 +1726,45 @@ class Output_section : public Output_data do_is_section_flag_set(elfcpp::Elf_Xword flag) const { return (this->flags_ & flag) != 0; } - // Write the section header into *OPHDR. - template + // Set the TLS offset. Called only for SHT_TLS sections. void - write_header(const Layout*, const Stringpool*, - elfcpp::Shdr_write*) const; + 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 @@ -1339,24 +1781,44 @@ class Output_section : public Output_data { public: Input_section() - : shndx_(0), p2align_(0), data_size_(0) - { this->u_.object = NULL; } + : shndx_(0), p2align_(0) + { + this->u1_.data_size = 0; + this->u2_.object = NULL; + } + // For an ordinary input section. Input_section(Relobj* object, unsigned int shndx, off_t data_size, uint64_t addralign) : shndx_(shndx), - p2align_(ffsll(static_cast(addralign))), - data_size_(data_size) + p2align_(ffsll(static_cast(addralign))) { - gold_assert(shndx != -1U); - this->u_.object = object; + gold_assert(shndx != OUTPUT_SECTION_CODE + && shndx != MERGE_DATA_SECTION_CODE + && shndx != MERGE_STRING_SECTION_CODE); + this->u1_.data_size = data_size; + this->u2_.object = object; } + // For a non-merge output section. Input_section(Output_section_data* posd) - : shndx_(-1U), - p2align_(ffsll(static_cast(posd->addralign()))), - data_size_(0) - { this->u_.posd = posd; } + : shndx_(OUTPUT_SECTION_CODE), + p2align_(ffsll(static_cast(posd->addralign()))) + { + this->u1_.data_size = 0; + this->u2_.posd = posd; + } + + // For a merge section. + Input_section(Output_section_data* posd, bool is_string, uint64_t entsize) + : shndx_(is_string + ? MERGE_STRING_SECTION_CODE + : MERGE_DATA_SECTION_CODE), + p2align_(ffsll(static_cast(posd->addralign()))) + { + this->u1_.entsize = entsize; + this->u2_.posd = posd; + } // The required alignment. uint64_t @@ -1371,41 +1833,167 @@ class Output_section : public Output_data off_t data_size() const; + // Return whether this is a merge section which matches the + // parameters. + bool + is_merge_section(bool is_string, uint64_t entsize, + uint64_t addralign) const + { + return (this->shndx_ == (is_string + ? MERGE_STRING_SECTION_CODE + : MERGE_DATA_SECTION_CODE) + && this->u1_.entsize == entsize + && this->addralign() == addralign); + } + + // Set the output section. + void + set_output_section(Output_section* os) + { + gold_assert(!this->is_input_section()); + this->u2_.posd->set_output_section(os); + } + // 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 + add_input_section(Relobj* object, unsigned int shndx) + { + gold_assert(this->shndx_ == MERGE_DATA_SECTION_CODE + || this->shndx_ == MERGE_STRING_SECTION_CODE); + return this->u2_.posd->add_input_section(object, shndx); + } + + // Given an input OBJECT, an input section index SHNDX within that + // object, and an OFFSET relative to the start of that input + // section, return whether or not the output offset is known. If + // this function returns true, it sets *POUTPUT to the output + // offset. + bool + output_offset(const Relobj* object, unsigned int shndx, off_t offset, + off_t *poutput) const; // Write out the data. This does nothing for an input section. 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. + enum + { + // An Output_section_data. + OUTPUT_SECTION_CODE = -1U, + // An Output_section_data for an SHF_MERGE section with + // SHF_STRINGS not set. + MERGE_DATA_SECTION_CODE = -2U, + // An Output_section_data for an SHF_MERGE section with + // SHF_STRINGS set. + MERGE_STRING_SECTION_CODE = -3U + }; + // Whether this is an input section. bool is_input_section() const - { return this->shndx_ != -1U; } + { + return (this->shndx_ != OUTPUT_SECTION_CODE + && this->shndx_ != MERGE_DATA_SECTION_CODE + && this->shndx_ != MERGE_STRING_SECTION_CODE); + } - // For an ordinary input section, this is the section index in - // the input file. For an Output_section_data, this is -1U. + // For an ordinary input section, this is the section index in the + // input file. For an Output_section_data, this is + // OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or + // MERGE_STRING_SECTION_CODE. unsigned int shndx_; // The required alignment, stored as a power of 2. unsigned int p2align_; - // For an ordinary input section, the section size. - off_t data_size_; union { - // If shndx_ != -1U, this points to the object which holds the + // For an ordinary input section, the section size. + off_t data_size; + // For OUTPUT_SECTION_CODE, this is not used. For + // MERGE_DATA_SECTION_CODE or MERGE_STRING_SECTION_CODE, the + // entity size. + uint64_t entsize; + } u1_; + union + { + // For an ordinary input section, the object which holds the // input section. Relobj* object; - // If shndx_ == -1U, this is the data to write out. + // For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or + // MERGE_STRING_SECTION_CODE, the data. Output_section_data* posd; - } u_; + } u2_; }; typedef std::vector Input_section_list; + // Fill data. This is used to fill in data between input sections. + // When we have to keep track of the input sections, we can use an + // Output_data_const, but we don't want to have to keep track of + // input sections just to implement fills. For a fill we record the + // offset, and the actual data to be written out. + class Fill + { + public: + Fill(off_t section_offset, off_t length) + : section_offset_(section_offset), length_(length) + { } + + // Return section offset. + off_t + section_offset() const + { return this->section_offset_; } + + // Return fill length. + off_t + length() const + { return this->length_; } + + private: + // The offset within the output section. + off_t section_offset_; + // The length of the space to fill. + off_t length_; + }; + + typedef std::vector Fill_list; + + // Add a new output section by Input_section. + void + add_output_section_data(Input_section*); + + // Add an SHF_MERGE input section. Returns true if the section was + // handled. + bool + add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags, + uint64_t entsize, uint64_t addralign); + + // Add an output SHF_MERGE section POSD to this output section. + // IS_STRING indicates whether it is a SHF_STRINGS section, and + // ENTSIZE is the entity size. This returns the entry added to + // input_sections_. + void + add_output_merge_section(Output_section_data* posd, bool is_string, + uint64_t entsize); + // Most of these fields are only valid after layout. // The name of the section. This will point into a Stringpool. @@ -1425,9 +2013,9 @@ class Output_section : public Output_data // If info_section_ is NULL, this is the section info field. unsigned int info_; // The section type. - elfcpp::Elf_Word type_; + const elfcpp::Elf_Word type_; // The section flags. - elfcpp::Elf_Xword flags_; + const elfcpp::Elf_Xword flags_; // The section index. unsigned int out_shndx_; // If there is a STT_SECTION for this output section in the normal @@ -1445,8 +2033,13 @@ class Output_section : public Output_data Input_section_list input_sections_; // The offset of the first entry in input_sections_. off_t first_input_offset_; - // Whether we permit adding data. - bool may_add_data_ : 1; + // The fill data. This is separate from input_sections_ because we + // 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. @@ -1461,6 +2054,15 @@ class Output_section : public Output_data // Whether the link field of this output section should point to the // dynamic symbol table. bool should_link_to_dynsym_ : 1; + // Whether this section should be written after all the input + // sections are complete. + bool after_input_sections_ : 1; + // 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 @@ -1522,6 +2124,10 @@ class Output_segment void add_initial_output_data(Output_data*); + // Return the number of dynamic relocations applied to this segment. + unsigned int + dynamic_reloc_count() const; + // Set the address of the segment to ADDR and the offset to *POFF // (aligned if necessary), and set the addresses and offsets of all // contained output sections accordingly. Set the section indexes @@ -1531,11 +2137,24 @@ class Output_segment uint64_t set_section_addresses(uint64_t addr, off_t* poff, unsigned int* pshndx); + // Set the minimum alignment of this segment. This may be adjusted + // upward based on the section alignments. + void + set_minimum_addralign(uint64_t align) + { + gold_assert(!this->is_align_known_); + this->align_ = align; + } + // Set the offset of this segment based on the section. This should // only be called for a non-PT_LOAD 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; @@ -1575,6 +2194,10 @@ class Output_segment unsigned int output_section_count_list(const Output_data_list*) const; + // Return the number of dynamic relocs in an Output_data_list. + unsigned int + dynamic_reloc_count_list(const Output_data_list*) const; + // Write the section headers in the list into V. template unsigned char* @@ -1592,7 +2215,9 @@ class Output_segment uint64_t paddr_; // The size of the segment in memory. uint64_t memsz_; - // The segment alignment. + // The segment alignment. The is_align_known_ field indicates + // whether this has been finalized. It can be set to a minimum + // value before it is finalized. uint64_t align_; // The offset of the segment data within the file. off_t offset_; @@ -1602,7 +2227,7 @@ class Output_segment elfcpp::Elf_Word type_; // The segment flags. elfcpp::Elf_Word flags_; - // Whether we have set align_. + // Whether we have finalized align_. bool is_align_known_; }; @@ -1611,13 +2236,23 @@ class Output_segment class Output_file { public: - Output_file(const General_options& options); + Output_file(const General_options& options, Target*); + + // Get a pointer to the target. + Target* + target() const + { return this->target_; } // Open the output file. FILE_SIZE is the final size of the file. void open(off_t file_size); - // Close the output file and make sure there are no error. + // Resize the output file. + void + resize(off_t file_size); + + // Close the output file (flushing all buffered data) and make sure + // there are no errors. void close(); @@ -1644,9 +2279,42 @@ class Output_file write_output_view(off_t, off_t, unsigned char*) { } + // Get a read/write buffer. This is used when we want to write part + // of the file, read it in, and write it again. + unsigned char* + get_input_output_view(off_t start, off_t size) + { return this->get_output_view(start, size); } + + // Write a read/write buffer back to the file. + void + write_input_output_view(off_t, off_t, unsigned char*) + { } + + // Get a read buffer. This is used when we just want to read part + // of the file back it in. + const unsigned char* + get_input_view(off_t start, off_t size) + { return this->get_output_view(start, size); } + + // Release a read bfufer. + void + free_input_view(off_t, off_t, const unsigned char*) + { } + private: + // 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. + Target* target_; // File name. const char* name_; // File descriptor. @@ -1655,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.