X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Foutput.h;h=be729655833dfe7191ba9fb55380b42bdccab7a9;hb=c7ad08e6e5ff0768f5f0aeed12864a7bab588386;hp=170f0ff890ef600868e844cc9f4c4da7ccec4833;hpb=81c82a68dc3bb09bd3b5b4101ed9737814023f1a;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/output.h b/gold/output.h index 170f0ff890..be72965583 100644 --- a/gold/output.h +++ b/gold/output.h @@ -1,6 +1,6 @@ // output.h -- manage the output file for gold -*- C++ -*- -// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Copyright (C) 2006-2015 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -92,7 +92,7 @@ class Output_data bool is_data_size_fixed() const { return this->is_data_size_fixed_; } - + // Return the file offset. This is only valid after // Layout::finalize is finished. For some non-allocated sections, // it may not be valid until near the end of the link. @@ -103,8 +103,8 @@ class Output_data return this->offset_; } - // Reset the address and file offset. This essentially disables the - // sanity testing about duplicate and unknown settings. + // Reset the address, file offset and data size. This essentially + // disables the sanity testing about duplicate and unknown settings. void reset_address_and_file_offset() { @@ -115,6 +115,14 @@ class Output_data this->do_reset_address_and_file_offset(); } + // As above, but just for data size. + void + reset_data_size() + { + if (!this->is_data_size_fixed_) + this->is_data_size_valid_ = false; + } + // Return true if address and file offset already have reset values. In // other words, calling reset_address_and_file_offset will not change them. bool @@ -406,7 +414,7 @@ class Output_data } // Fix the data size. Once it is fixed, it cannot be changed - // and the data size remains always valid. + // and the data size remains always valid. void fix_data_size() { @@ -564,7 +572,7 @@ class Output_segment_headers : public Output_data class Output_file_header : public Output_data { public: - Output_file_header(const Target*, + Output_file_header(Target*, const Symbol_table*, const Output_segment_headers*); @@ -608,7 +616,7 @@ class Output_file_header : public Output_data off_t do_size() const; - const Target* target_; + Target* target_; const Symbol_table* symtab_; const Output_segment_headers* segment_header_; const Output_section_headers* section_header_; @@ -667,13 +675,6 @@ class Output_section_data : public Output_data section_offset_type* poutput) const { return this->do_output_offset(object, shndx, offset, poutput); } - // Return whether this is the merge section for the input section - // SHNDX in OBJECT. This should return true when output_offset - // would return true for some values of OFFSET. - bool - is_merge_section_for(const Relobj* object, unsigned int shndx) const - { return this->do_is_merge_section_for(object, shndx); } - // Write the contents to a buffer. This is used for sections which // require postprocessing, such as compression. void @@ -707,11 +708,6 @@ class Output_section_data : public Output_data section_offset_type*) const { return false; } - // The child class may implement is_merge_section_for. - virtual bool - do_is_merge_section_for(const Relobj*, unsigned int) 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. @@ -1025,7 +1021,7 @@ class Output_reloc bool use_plt_offset); Output_reloc(Symbol* gsym, unsigned int type, - Sized_relobj* relobj, + Sized_relobj* relobj, unsigned int shndx, Address address, bool is_relative, bool is_symbolless, bool use_plt_offset); @@ -1034,30 +1030,31 @@ class Output_reloc Output_reloc(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, Output_data* od, Address address, bool is_relative, - bool is_symbolless, bool is_section_symbol, - bool use_plt_offset); + bool is_symbolless, bool is_section_symbol, + bool use_plt_offset); Output_reloc(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, unsigned int shndx, Address address, bool is_relative, - bool is_symbolless, bool is_section_symbol, - bool use_plt_offset); + bool is_symbolless, bool is_section_symbol, + bool use_plt_offset); // 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, bool is_relative); Output_reloc(Output_section* os, unsigned int type, - Sized_relobj* relobj, - unsigned int shndx, Address address); + Sized_relobj* relobj, unsigned int shndx, + Address address, bool is_relative); - // An absolute relocation with no symbol. + // An absolute or relative relocation with no symbol. - Output_reloc(unsigned int type, Output_data* od, Address address); + Output_reloc(unsigned int type, Output_data* od, Address address, + bool is_relative); Output_reloc(unsigned int type, Sized_relobj* relobj, - unsigned int shndx, Address address); + unsigned int shndx, Address address, bool is_relative); // A target specific relocation. The target will be called to get // the symbol index, passing ARG. The type and offset will be set @@ -1091,10 +1088,10 @@ class Output_reloc is_local_section_symbol() const { return (this->local_sym_index_ != GSYM_CODE - && this->local_sym_index_ != SECTION_CODE - && this->local_sym_index_ != INVALID_CODE + && this->local_sym_index_ != SECTION_CODE + && this->local_sym_index_ != INVALID_CODE && this->local_sym_index_ != TARGET_CODE - && this->is_section_symbol_); + && this->is_section_symbol_); } // Return whether this is a target specific relocation. @@ -1262,7 +1259,7 @@ class Output_reloc { } Output_reloc(Symbol* gsym, unsigned int type, - Sized_relobj* relobj, + Sized_relobj* relobj, unsigned int shndx, Address address, Addend addend, bool is_relative, bool is_symbolless, bool use_plt_offset) : rel_(gsym, type, relobj, shndx, address, is_relative, @@ -1278,7 +1275,7 @@ class Output_reloc bool is_symbolless, bool is_section_symbol, bool use_plt_offset) : rel_(relobj, local_sym_index, type, od, address, is_relative, - is_symbolless, is_section_symbol, use_plt_offset), + is_symbolless, is_section_symbol, use_plt_offset), addend_(addend) { } @@ -1289,33 +1286,35 @@ class Output_reloc bool is_symbolless, bool is_section_symbol, bool use_plt_offset) : rel_(relobj, local_sym_index, type, shndx, address, is_relative, - is_symbolless, is_section_symbol, use_plt_offset), + is_symbolless, is_section_symbol, use_plt_offset), addend_(addend) { } // A reloc against the STT_SECTION symbol of an output section. Output_reloc(Output_section* os, unsigned int type, Output_data* od, - Address address, Addend addend) - : rel_(os, type, od, address), addend_(addend) + Address address, Addend addend, bool is_relative) + : rel_(os, type, od, address, is_relative), addend_(addend) { } Output_reloc(Output_section* os, unsigned int type, - Sized_relobj* relobj, - unsigned int shndx, Address address, Addend addend) - : rel_(os, type, relobj, shndx, address), addend_(addend) + Sized_relobj* relobj, + unsigned int shndx, Address address, Addend addend, + bool is_relative) + : rel_(os, type, relobj, shndx, address, is_relative), addend_(addend) { } - // An absolute relocation with no symbol. + // An absolute or relative relocation with no symbol. Output_reloc(unsigned int type, Output_data* od, Address address, - Addend addend) - : rel_(type, od, address), addend_(addend) + Addend addend, bool is_relative) + : rel_(type, od, address, is_relative), addend_(addend) { } Output_reloc(unsigned int type, Sized_relobj* relobj, - unsigned int shndx, Address address, Addend addend) - : rel_(type, relobj, shndx, address), addend_(addend) + unsigned int shndx, Address address, Addend addend, + bool is_relative) + : rel_(type, relobj, shndx, address, is_relative), addend_(addend) { } // A target specific relocation. The target will be called to get @@ -1559,14 +1558,19 @@ 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, false, false, false)); } + { + this->add(od, Output_reloc_type(gsym, type, od, address, + false, false, false)); + } void add_global(Symbol* gsym, unsigned int type, Output_data* od, - Sized_relobj* relobj, + Sized_relobj* relobj, unsigned int shndx, Address address) - { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - false, false, false)); } + { + this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, + false, false, false)); + } void add_global_generic(Symbol* gsym, unsigned int type, Output_data* od, @@ -1596,17 +1600,19 @@ class Output_data_reloc 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, true, - false)); } + Address address) + { + this->add(od, Output_reloc_type(gsym, type, od, address, true, true, + false)); + } void add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, - Sized_relobj* relobj, - unsigned int shndx, Address address) + Sized_relobj* relobj, + unsigned int shndx, Address address) { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - true, true, false)); + true, true, false)); } // Add a global relocation which does not use a symbol for the relocation, @@ -1615,8 +1621,10 @@ class Output_data_reloc void add_symbolless_global_addend(Symbol* gsym, unsigned int type, Output_data* od, Address address) - { this->add(od, Output_reloc_type(gsym, type, od, address, false, true, - false)); } + { + this->add(od, Output_reloc_type(gsym, type, od, address, false, true, + false)); + } void add_symbolless_global_addend(Symbol* gsym, unsigned int type, @@ -1625,7 +1633,7 @@ class Output_data_reloc unsigned int shndx, Address address) { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - false, true, false)); + false, true, false)); } // Add a reloc against a local symbol. @@ -1636,7 +1644,7 @@ class Output_data_reloc Output_data* od, Address address) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, - address, false, false, false, false)); + address, false, false, false, false)); } void @@ -1678,22 +1686,33 @@ class Output_data_reloc void add_local_relative(Sized_relobj* relobj, - unsigned int local_sym_index, unsigned int type, - Output_data* od, Address address) + 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, true, false, false)); + address, true, true, false, false)); } void add_local_relative(Sized_relobj* relobj, - unsigned int local_sym_index, unsigned int type, - Output_data* od, unsigned int shndx, Address address) + 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, true, false, false)); } + void + add_local_relative(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + Output_data* od, unsigned int shndx, Address address, + bool use_plt_offset) + { + this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, + address, true, true, false, + use_plt_offset)); + } + // Add a local relocation which does not use a symbol for the relocation, // but which gets its addend from a symbol. @@ -1703,7 +1722,7 @@ class Output_data_reloc Output_data* od, Address address) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, - address, false, true, false, false)); + address, false, true, false, false)); } void @@ -1722,20 +1741,20 @@ class Output_data_reloc void add_local_section(Sized_relobj* relobj, - unsigned int input_shndx, unsigned int type, - Output_data* od, Address address) + unsigned int input_shndx, unsigned int type, + Output_data* od, Address address) { this->add(od, Output_reloc_type(relobj, input_shndx, type, od, - address, false, false, true, false)); + address, false, false, true, false)); } void add_local_section(Sized_relobj* relobj, - unsigned int input_shndx, unsigned int type, - Output_data* od, unsigned int shndx, Address address) + unsigned int input_shndx, unsigned int type, + Output_data* od, unsigned int shndx, Address address) { this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx, - address, false, false, true, false)); + address, false, false, true, false)); } // A reloc against the STT_SECTION symbol of an output section. @@ -1745,13 +1764,13 @@ class Output_data_reloc void add_output_section(Output_section* os, unsigned int type, Output_data* od, Address address) - { this->add(od, Output_reloc_type(os, type, od, address)); } + { this->add(od, Output_reloc_type(os, type, od, address, false)); } void add_output_section(Output_section* os, unsigned int type, Output_data* od, Sized_relobj* relobj, - unsigned int shndx, Address address) - { this->add(od, Output_reloc_type(os, type, relobj, shndx, address)); } + unsigned int shndx, Address address) + { this->add(od, Output_reloc_type(os, type, relobj, shndx, address, false)); } void add_output_section_generic(Output_section* os, unsigned int type, @@ -1760,7 +1779,8 @@ class Output_data_reloc { gold_assert(addend == 0); this->add(od, Output_reloc_type(os, type, od, - convert_types(address))); + convert_types(address), + false)); } void @@ -1773,20 +1793,47 @@ class Output_data_reloc Sized_relobj* sized_relobj = static_cast*>(relobj); this->add(od, Output_reloc_type(os, type, sized_relobj, shndx, - convert_types(address))); + convert_types(address), + false)); } + // As above, but the reloc TYPE is relative + + void + add_output_section_relative(Output_section* os, unsigned int type, + Output_data* od, Address address) + { this->add(od, Output_reloc_type(os, type, od, address, true)); } + + void + add_output_section_relative(Output_section* os, unsigned int type, + Output_data* od, + Sized_relobj* relobj, + unsigned int shndx, Address address) + { this->add(od, Output_reloc_type(os, type, relobj, shndx, address, true)); } + // Add an absolute relocation. void add_absolute(unsigned int type, Output_data* od, Address address) - { this->add(od, Output_reloc_type(type, od, address)); } + { this->add(od, Output_reloc_type(type, od, address, false)); } void add_absolute(unsigned int type, Output_data* od, Sized_relobj* relobj, unsigned int shndx, Address address) - { this->add(od, Output_reloc_type(type, relobj, shndx, address)); } + { this->add(od, Output_reloc_type(type, relobj, shndx, address, false)); } + + // Add a relative relocation + + void + add_relative(unsigned int type, Output_data* od, Address address) + { this->add(od, Output_reloc_type(type, od, address, true)); } + + void + add_relative(unsigned int type, Output_data* od, + Sized_relobj* relobj, + unsigned int shndx, Address address) + { this->add(od, Output_reloc_type(type, relobj, shndx, address, true)); } // Add a target specific relocation. A target which calls this must // define the reloc_symbol_index and reloc_addend virtual functions. @@ -1827,16 +1874,20 @@ 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, - false, false, false)); } + { + this->add(od, Output_reloc_type(gsym, type, od, address, addend, + false, false, false)); + } void add_global(Symbol* gsym, unsigned int type, Output_data* od, - Sized_relobj* relobj, + Sized_relobj* relobj, unsigned int shndx, Address address, Addend addend) - { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - addend, false, false, false)); } + { + this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, + addend, false, false, false)); + } void add_global_generic(Symbol* gsym, unsigned int type, Output_data* od, @@ -1868,17 +1919,21 @@ class Output_data_reloc void add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, - Address address, Addend addend, bool use_plt_offset) - { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true, - true, use_plt_offset)); } + Address address, Addend addend, bool use_plt_offset) + { + this->add(od, Output_reloc_type(gsym, type, od, address, addend, true, + true, use_plt_offset)); + } void add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, - Sized_relobj* relobj, - unsigned int shndx, Address address, Addend addend, + Sized_relobj* relobj, + unsigned int shndx, Address address, Addend addend, bool use_plt_offset) - { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - addend, true, true, use_plt_offset)); } + { + this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, + addend, true, true, use_plt_offset)); + } // Add a global relocation which does not use a symbol for the relocation, // but which gets its addend from a symbol. @@ -1886,16 +1941,21 @@ class Output_data_reloc void add_symbolless_global_addend(Symbol* gsym, unsigned int type, Output_data* od, Address address, Addend addend) - { this->add(od, Output_reloc_type(gsym, type, od, address, addend, - false, true, false)); } + { + this->add(od, Output_reloc_type(gsym, type, od, address, addend, + false, true, false)); + } void add_symbolless_global_addend(Symbol* gsym, unsigned int type, Output_data* od, Sized_relobj* relobj, - unsigned int shndx, Address address, Addend addend) - { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - addend, false, true, false)); } + unsigned int shndx, Address address, + Addend addend) + { + this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, + addend, false, true, false)); + } // Add a reloc against a local symbol. @@ -1915,8 +1975,8 @@ class Output_data_reloc Addend addend) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, - address, addend, false, false, false, - false)); + address, addend, false, false, false, + false)); } void @@ -1949,9 +2009,9 @@ class Output_data_reloc void add_local_relative(Sized_relobj* relobj, - unsigned int local_sym_index, unsigned int type, - Output_data* od, Address address, Addend addend, - bool use_plt_offset) + unsigned int local_sym_index, unsigned int type, + Output_data* od, Address address, Addend addend, + bool use_plt_offset) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address, addend, true, true, false, @@ -1960,13 +2020,13 @@ class Output_data_reloc 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, bool use_plt_offset) + unsigned int local_sym_index, unsigned int type, + Output_data* od, unsigned int shndx, Address address, + Addend addend, bool use_plt_offset) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, - address, addend, true, true, false, - use_plt_offset)); + address, addend, true, true, false, + use_plt_offset)); } // Add a local relocation which does not use a symbol for the relocation, @@ -1988,8 +2048,8 @@ class Output_data_reloc Address address, Addend addend) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, - address, addend, false, true, false, - false)); + address, addend, false, true, false, + false)); } // Add a reloc against a local section symbol. This will be @@ -1998,8 +2058,8 @@ class Output_data_reloc void add_local_section(Sized_relobj* relobj, - unsigned int input_shndx, unsigned int type, - Output_data* od, Address address, Addend addend) + unsigned int input_shndx, unsigned int type, + Output_data* od, Address address, Addend addend) { this->add(od, Output_reloc_type(relobj, input_shndx, type, od, address, addend, false, false, true, false)); @@ -2012,8 +2072,8 @@ class Output_data_reloc Addend addend) { this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx, - address, addend, false, false, true, - false)); + address, addend, false, false, true, + false)); } // A reloc against the STT_SECTION symbol of an output section. @@ -2021,14 +2081,16 @@ class Output_data_reloc void add_output_section(Output_section* os, unsigned int type, Output_data* od, Address address, Addend addend) - { this->add(od, Output_reloc_type(os, type, od, address, addend)); } + { this->add(od, Output_reloc_type(os, type, od, address, addend, false)); } void add_output_section(Output_section* os, unsigned int type, Output_data* od, - Sized_relobj* relobj, + Sized_relobj* relobj, unsigned int shndx, Address address, Addend addend) - { this->add(od, Output_reloc_type(os, type, relobj, shndx, address, - addend)); } + { + this->add(od, Output_reloc_type(os, type, relobj, shndx, address, + addend, false)); + } void add_output_section_generic(Output_section* os, unsigned int type, @@ -2037,7 +2099,8 @@ class Output_data_reloc { this->add(od, Output_reloc_type(os, type, od, convert_types(address), - convert_types(addend))); + convert_types(addend), + false)); } void @@ -2050,7 +2113,26 @@ class Output_data_reloc static_cast*>(relobj); this->add(od, Output_reloc_type(os, type, sized_relobj, shndx, convert_types(address), - convert_types(addend))); + convert_types(addend), + false)); + } + + // As above, but the reloc TYPE is relative + + void + add_output_section_relative(Output_section* os, unsigned int type, + Output_data* od, Address address, Addend addend) + { this->add(od, Output_reloc_type(os, type, od, address, addend, true)); } + + void + add_output_section_relative(Output_section* os, unsigned int type, + Output_data* od, + Sized_relobj* relobj, + unsigned int shndx, Address address, + Addend addend) + { + this->add(od, Output_reloc_type(os, type, relobj, shndx, + address, addend, true)); } // Add an absolute relocation. @@ -2058,13 +2140,32 @@ class Output_data_reloc void add_absolute(unsigned int type, Output_data* od, Address address, Addend addend) - { this->add(od, Output_reloc_type(type, od, address, addend)); } + { this->add(od, Output_reloc_type(type, od, address, addend, false)); } void add_absolute(unsigned int type, Output_data* od, Sized_relobj* relobj, unsigned int shndx, Address address, Addend addend) - { this->add(od, Output_reloc_type(type, relobj, shndx, address, addend)); } + { + this->add(od, Output_reloc_type(type, relobj, shndx, address, addend, + false)); + } + + // Add a relative relocation + + void + add_relative(unsigned int type, Output_data* od, Address address, + Addend addend) + { this->add(od, Output_reloc_type(type, od, address, addend, true)); } + + void + add_relative(unsigned int type, Output_data* od, + Sized_relobj* relobj, + unsigned int shndx, Address address, Addend addend) + { + this->add(od, Output_reloc_type(type, relobj, shndx, address, addend, + true)); + } // Add a target specific relocation. A target which calls this must // define the reloc_symbol_index and reloc_addend virtual functions. @@ -2086,7 +2187,7 @@ class Output_data_reloc // Output_relocatable_relocs represents a relocation section in a // relocatable link. The actual data is written out in the target -// hook relocate_for_relocatable. This just saves space for it. +// hook relocate_relocs. This just saves space for it. template class Output_relocatable_relocs : public Output_section_data @@ -2209,17 +2310,23 @@ class Output_data_got : public Output_data_got_base bool add_global_plt(Symbol* gsym, unsigned int got_type); + // Like add_global, but for a TLS symbol where the value will be + // offset using Target::tls_offset_for_global. + bool + add_global_tls(Symbol* gsym, unsigned int got_type) + { return add_global_plt(gsym, got_type); } + // 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, unsigned int got_type, - Output_data_reloc_generic* rel_dyn, unsigned int r_type); + Output_data_reloc_generic* rel_dyn, unsigned int r_type); // Add a pair of entries for a global symbol to the GOT, and add // dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively. void add_global_pair_with_rel(Symbol* gsym, unsigned int got_type, - Output_data_reloc_generic* rel_dyn, + Output_data_reloc_generic* rel_dyn, unsigned int r_type_1, unsigned int r_type_2); // Add an entry for a local symbol to the GOT. This returns true if @@ -2233,6 +2340,12 @@ class Output_data_got : public Output_data_got_base bool add_local_plt(Relobj* object, unsigned int sym_index, unsigned int got_type); + // Like add_local, but for a TLS symbol where the value will be + // offset using Target::tls_offset_for_local. + bool + add_local_tls(Relobj* object, unsigned int sym_index, unsigned int got_type) + { return add_local_plt(object, sym_index, got_type); } + // Add an entry for a local symbol to the GOT, and add a dynamic // relocation of type R_TYPE for the GOT entry. void @@ -2241,20 +2354,43 @@ class Output_data_got : public Output_data_got_base unsigned int r_type); // Add a pair of entries for a local symbol to the GOT, and add - // dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively. + // a dynamic relocation of type R_TYPE using the section symbol of + // the output section to which input section SHNDX maps, on the first. + // The first got entry will have a value of zero, the second the + // value of the local symbol. void add_local_pair_with_rel(Relobj* object, unsigned int sym_index, unsigned int shndx, unsigned int got_type, Output_data_reloc_generic* rel_dyn, - unsigned int r_type_1, unsigned int r_type_2); + unsigned int r_type); + + // Add a pair of entries for a local symbol to the GOT, and add + // a dynamic relocation of type R_TYPE using STN_UNDEF on the first. + // The first got entry will have a value of zero, the second the + // value of the local symbol offset by Target::tls_offset_for_local. + void + add_local_tls_pair(Relobj* object, unsigned int sym_index, + unsigned int got_type, + Output_data_reloc_generic* rel_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 add_constant(Valtype constant) + { return this->add_got_entry(Got_entry(constant)); } + + // Add a pair of constants to the GOT. This returns the offset of + // the new entry from the start of the GOT. + unsigned int + add_constant_pair(Valtype c1, Valtype c2) + { return this->add_got_entry_pair(Got_entry(c1), Got_entry(c2)); } + + // Replace GOT entry I with a new constant. + void + replace_constant(unsigned int i, Valtype constant) { - unsigned int got_offset = this->add_got_entry(Got_entry(constant)); - return got_offset; + this->replace_got_entry(i, Got_entry(constant)); } // Reserve a slot in the GOT for a local symbol. @@ -2281,6 +2417,16 @@ class Output_data_got : public Output_data_got_base do_reserve_slot(unsigned int i) { this->free_list_.remove(i * got_size / 8, (i + 1) * got_size / 8); } + // Return the number of words in the GOT. + unsigned int + num_entries () const + { return this->entries_.size(); } + + // Return the offset into the GOT of GOT entry I. + unsigned int + got_offset(unsigned int i) const + { return i * (got_size / 8); } + private: // This POD class holds a single GOT entry. class Got_entry @@ -2288,18 +2434,20 @@ class Output_data_got : public Output_data_got_base public: // Create a zero entry. Got_entry() - : local_sym_index_(RESERVED_CODE), use_plt_offset_(false) + : local_sym_index_(RESERVED_CODE), use_plt_or_tls_offset_(false) { this->u_.constant = 0; } // Create a global symbol entry. - Got_entry(Symbol* gsym, bool use_plt_offset) - : local_sym_index_(GSYM_CODE), use_plt_offset_(use_plt_offset) + Got_entry(Symbol* gsym, bool use_plt_or_tls_offset) + : local_sym_index_(GSYM_CODE), + use_plt_or_tls_offset_(use_plt_or_tls_offset) { this->u_.gsym = gsym; } // Create a local symbol entry. Got_entry(Relobj* object, unsigned int local_sym_index, - bool use_plt_offset) - : local_sym_index_(local_sym_index), use_plt_offset_(use_plt_offset) + bool use_plt_or_tls_offset) + : local_sym_index_(local_sym_index), + use_plt_or_tls_offset_(use_plt_or_tls_offset) { gold_assert(local_sym_index != GSYM_CODE && local_sym_index != CONSTANT_CODE @@ -2311,12 +2459,12 @@ class Output_data_got : public Output_data_got_base // Create a constant entry. The constant is a host value--it will // be swapped, if necessary, when it is written out. explicit Got_entry(Valtype constant) - : local_sym_index_(CONSTANT_CODE), use_plt_offset_(false) + : local_sym_index_(CONSTANT_CODE), use_plt_or_tls_offset_(false) { this->u_.constant = constant; } // Write the GOT entry to an output view. void - write(unsigned char* pov) const; + write(unsigned int got_indx, unsigned char* pov) const; private: enum @@ -2339,7 +2487,8 @@ class Output_data_got : public Output_data_got_base // for a global symbol, or CONSTANT_CODE for a constant. unsigned int local_sym_index_ : 31; // Whether to use the PLT offset of the symbol if it has one. - bool use_plt_offset_ : 1; + // For TLS symbols, whether to offset the symbol value. + bool use_plt_or_tls_offset_ : 1; }; typedef std::vector Got_entries; @@ -2352,20 +2501,19 @@ class Output_data_got : public Output_data_got_base unsigned int add_got_entry_pair(Got_entry got_entry_1, Got_entry got_entry_2); - // Return the offset into the GOT of GOT entry I. - unsigned int - got_offset(unsigned int i) const - { return i * (got_size / 8); } + // Replace GOT entry I with a new value. + void + replace_got_entry(unsigned int i, Got_entry got_entry); // Return the offset into the GOT of the last entry added. unsigned int last_got_offset() const - { return this->got_offset(this->entries_.size() - 1); } + { return this->got_offset(this->num_entries() - 1); } // Set the size of the section. void set_got_size() - { this->set_current_data_size(this->got_offset(this->entries_.size())); } + { this->set_current_data_size(this->got_offset(this->num_entries())); } // The list of GOT entries. Got_entries entries_; @@ -2400,7 +2548,7 @@ class Output_data_dynamic : public Output_section_data // plus a constant offset. void add_section_plus_offset(elfcpp::DT tag, const Output_data* od, - unsigned int offset) + unsigned int offset) { this->add_entry(Dynamic_entry(tag, od, offset)); } // Add a new dynamic entry with the size of output data. @@ -2428,6 +2576,11 @@ class Output_data_dynamic : public Output_section_data add_string(elfcpp::DT tag, const std::string& str) { this->add_string(tag, str.c_str()); } + // Add a new dynamic entry with custom value. + void + add_custom(elfcpp::DT tag) + { this->add_entry(Dynamic_entry(tag)); } + protected: // Adjust the output section to set the entry size. void @@ -2492,6 +2645,11 @@ class Output_data_dynamic : public Output_section_data : tag_(tag), offset_(DYNAMIC_STRING) { this->u_.str = str; } + // Create an entry with a custom value. + Dynamic_entry(elfcpp::DT tag) + : tag_(tag), offset_(DYNAMIC_CUSTOM) + { } + // Return the tag of this entry. elfcpp::DT tag() const @@ -2515,7 +2673,9 @@ class Output_data_dynamic : public Output_section_data // Symbol adress. DYNAMIC_SYMBOL = -3U, // String. - DYNAMIC_STRING = -4U + DYNAMIC_STRING = -4U, + // Custom value. + DYNAMIC_CUSTOM = -5U // Any other value indicates a section address plus OFFSET. }; @@ -2608,17 +2768,26 @@ class Output_relaxed_input_section : public Output_section_data_build uint64_t addralign) : Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx) { } - + // Return the Relobj of this relaxed input section. Relobj* relobj() const { return this->relobj_; } - + // Return the section index of this relaxed input section. unsigned int shndx() const { return this->shndx_; } + protected: + void + set_relobj(Relobj* relobj) + { this->relobj_ = relobj; } + + void + set_shndx(unsigned int shndx) + { this->shndx_ = shndx; } + private: Relobj* relobj_; unsigned int shndx_; @@ -2654,7 +2823,7 @@ class Merge_section_properties h = (h ^ static_cast(this->addralign_)) * prime; return h; } - + // Functors for associative containers. struct equal_to { @@ -2688,7 +2857,7 @@ class Output_section_lookup_maps public: Output_section_lookup_maps() : is_valid_(true), merge_sections_by_properties_(), - merge_sections_by_id_(), relaxed_input_sections_by_id_() + relaxed_input_sections_by_id_() { } // Whether the maps are valid. @@ -2706,12 +2875,11 @@ class Output_section_lookup_maps clear() { this->merge_sections_by_properties_.clear(); - this->merge_sections_by_id_.clear(); this->relaxed_input_sections_by_id_.clear(); // A cleared map is valid. this->is_valid_ = true; } - + // Find a merge section by merge section properties. Return NULL if none // is found. Output_merge_base* @@ -2723,17 +2891,6 @@ class Output_section_lookup_maps return p != this->merge_sections_by_properties_.end() ? p->second : NULL; } - // Find a merge section by section ID of a merge input section. Return NULL - // if none is found. - Output_merge_base* - find_merge_section(const Object* object, unsigned int shndx) const - { - gold_assert(this->is_valid_); - Merge_sections_by_id::const_iterator p = - this->merge_sections_by_id_.find(Const_section_id(object, shndx)); - return p != this->merge_sections_by_id_.end() ? p->second : NULL; - } - // Add a merge section pointed by POMB with properties MSP. void add_merge_section(const Merge_section_properties& msp, @@ -2744,23 +2901,10 @@ class Output_section_lookup_maps this->merge_sections_by_properties_.insert(value); gold_assert(result.second); } - - // Add a mapping from a merged input section in OBJECT with index SHNDX - // to a merge output section pointed by POMB. - void - add_merge_input_section(const Object* object, unsigned int shndx, - Output_merge_base* pomb) - { - Const_section_id csid(object, shndx); - std::pair value(csid, pomb); - std::pair result = - this->merge_sections_by_id_.insert(value); - gold_assert(result.second); - } // Find a relaxed input section of OBJECT with index SHNDX. Output_relaxed_input_section* - find_relaxed_input_section(const Object* object, unsigned int shndx) const + find_relaxed_input_section(const Relobj* object, unsigned int shndx) const { gold_assert(this->is_valid_); Relaxed_input_sections_by_id::const_iterator p = @@ -2783,10 +2927,6 @@ class Output_section_lookup_maps } private: - typedef Unordered_map - Merge_sections_by_id; - typedef Unordered_map @@ -2800,8 +2940,6 @@ class Output_section_lookup_maps bool is_valid_; // Merge sections by merge section properties. Merge_sections_by_properties merge_sections_by_properties_; - // Merge sections by section IDs. - Merge_sections_by_id merge_sections_by_id_; // Relaxed sections by section IDs. Relaxed_input_sections_by_id relaxed_input_sections_by_id_; }; @@ -2923,7 +3061,7 @@ class Output_section : public Output_data template off_t add_input_section(Layout* layout, Sized_relobj_file* object, - unsigned int shndx, const char* name, + unsigned int shndx, const char* name, const elfcpp::Shdr& shdr, unsigned int reloc_shndx, bool have_sections_script); @@ -3081,6 +3219,13 @@ class Output_section : public Output_data set_addralign(uint64_t v) { this->addralign_ = v; } + void + checkpoint_set_addralign(uint64_t val) + { + if (this->checkpoint_ != NULL) + this->checkpoint_->set_addralign(val); + } + // Whether the output section index has been set. bool has_out_shndx() const @@ -3138,6 +3283,10 @@ class Output_section : public Output_data this->dynsym_index_ = index; } + // Sort the attached input sections. + void + sort_attached_input_sections(); + // Return whether the input sections sections attachd to this output // section may require sorting. This is used to handle constructor // priorities compatibly with GNU ld. @@ -3249,6 +3398,28 @@ class Output_section : public Output_data requires_postprocessing() const { return this->requires_postprocessing_; } + bool + is_unique_segment() const + { return this->is_unique_segment_; } + + void + set_is_unique_segment() + { this->is_unique_segment_ = true; } + + uint64_t extra_segment_flags() const + { return this->extra_segment_flags_; } + + void + set_extra_segment_flags(uint64_t flags) + { this->extra_segment_flags_ = flags; } + + uint64_t segment_alignment() const + { return this->segment_alignment_; } + + void + set_segment_alignment(uint64_t align) + { this->segment_alignment_ = align; } + // If a section requires postprocessing, return the buffer to use. unsigned char* postprocessing_buffer() const @@ -3428,7 +3599,7 @@ class Output_section : public Output_data this->p2align_ = ffsll(static_cast(addralign)); } } - + // Return the current required size, without finalization. off_t current_data_size() const; @@ -3451,13 +3622,13 @@ class Output_section : public Output_data // parameters. bool is_merge_section(bool is_string, uint64_t entsize, - uint64_t addralign) const + uint64_t addralign) const { return (this->shndx_ == (is_string ? MERGE_STRING_SECTION_CODE : MERGE_DATA_SECTION_CODE) && this->u1_.entsize == entsize - && this->addralign() == addralign); + && this->addralign() == addralign); } // Return whether this is a merge section for some input section. @@ -3496,7 +3667,7 @@ class Output_section : public Output_data gold_assert(!this->is_input_section()); return this->u2_.posd; } - + // For a merge section, return the Output_merge_base pointer. Output_merge_base* output_merge_base() const @@ -3518,8 +3689,8 @@ class Output_section : public Output_data set_output_section(Output_section* os) { gold_assert(!this->is_input_section()); - Output_section_data* posd = - this->is_relaxed_input_section() ? this->u2_.poris : this->u2_.posd; + Output_section_data* posd = + this->is_relaxed_input_section() ? this->u2_.poris : this->u2_.posd; posd->set_output_section(os); } @@ -3559,11 +3730,6 @@ class Output_section : public Output_data section_offset_type offset, section_offset_type* poutput) const; - // Return whether this is the merge section for the input section - // SHNDX in OBJECT. - bool - is_merge_section_for(const Relobj* object, unsigned int shndx) const; - // Write out the data. This does nothing for an input section. void write(Output_file*); @@ -3680,7 +3846,7 @@ class Output_section : public Output_data // with index SHNDX. Return NULL if none is found. const Output_relaxed_input_section* find_relaxed_input_section(const Relobj* object, unsigned int shndx) const; - + // Whether section offsets need adjustment due to relaxation. bool section_offsets_need_adjustment() const @@ -3691,6 +3857,11 @@ class Output_section : public Output_data set_section_offsets_need_adjustment() { this->section_offsets_need_adjustment_ = true; } + // Set section_offsets_need_adjustment to be false. + void + clear_section_offsets_need_adjustment() + { this->section_offsets_need_adjustment_ = false; } + // Adjust section offsets of input sections in this. This is // requires if relaxation caused some input sections to change sizes. void @@ -3745,6 +3916,17 @@ class Output_section : public Output_data off_t allocate(off_t len, uint64_t addralign); + typedef std::vector Input_section_list; + + // Allow access to the input sections. + const Input_section_list& + input_sections() const + { return this->input_sections_; } + + Input_section_list& + input_sections() + { return this->input_sections_; } + protected: // Return the output section--i.e., the object itself. Output_section* @@ -3867,13 +4049,6 @@ class Output_section : public Output_data void write_to_postprocessing_buffer(); - typedef std::vector Input_section_list; - - // Allow a child class to access the input sections. - const Input_section_list& - input_sections() const - { return this->input_sections_; } - // Whether this always keeps an input section list bool always_keeps_input_sections() const @@ -3912,6 +4087,10 @@ class Output_section : public Output_data addralign() const { return this->addralign_; } + void + set_addralign(uint64_t val) + { this->addralign_ = val; } + // Return the section flags. elfcpp::Elf_Xword flags() const @@ -3999,6 +4178,23 @@ class Output_section : public Output_data const Input_section_sort_entry&) const; }; + // This is the sort comparison function for .text to sort sections with + // prefixes .text.{unlikely,exit,startup,hot} before other sections. + struct Input_section_sort_section_prefix_special_ordering_compare + { + bool + operator()(const Input_section_sort_entry&, + const Input_section_sort_entry&) const; + }; + + // This is the sort comparison function for sorting sections by name. + struct Input_section_sort_section_name_compare + { + bool + operator()(const Input_section_sort_entry&, + const Input_section_sort_entry&) const; + }; + // Fill data. This is used to fill in data between input sections. // It is also used for data statements (BYTE, WORD, etc.) in linker // scripts. When we have to keep track of the input sections, we @@ -4056,13 +4252,9 @@ class Output_section : public Output_data add_output_merge_section(Output_section_data* posd, bool is_string, uint64_t entsize); - // Sort the attached input sections. - void - sort_attached_input_sections(); - // Find the merge section into which an input section with index SHNDX in // OBJECT has been added. Return NULL if none found. - Output_section_data* + const Output_section_data* find_merge_section(const Relobj* object, unsigned int shndx) const; // Build a relaxation map. @@ -4200,9 +4392,17 @@ class Output_section : public Output_data bool has_fixed_layout_ : 1; // True if we can add patch space to this section. bool is_patch_space_allowed_ : 1; + // True if this output section goes into a unique segment. + bool is_unique_segment_ : 1; // For SHT_TLS sections, the offset of this section relative to the base // of the TLS segment. uint64_t tls_offset_; + // Additional segment flags, specified via linker plugin, when mapping some + // input sections to unique segments. + uint64_t extra_segment_flags_; + // Segment alignment specified via linker plugin, when mapping some + // input sections to unique segments. + uint64_t segment_alignment_; // Saved checkpoint. Checkpoint_output_section* checkpoint_; // Fast lookup maps for merged and relaxed input sections. @@ -4278,6 +4478,16 @@ class Output_segment set_is_large_data_segment() { this->is_large_data_segment_ = true; } + bool + is_unique_segment() const + { return this->is_unique_segment_; } + + // Mark segment as unique, happens when linker plugins request that + // certain input sections be mapped to unique segments. + void + set_is_unique_segment() + { this->is_unique_segment_ = true; } + // Return the maximum alignment of the Output_data. uint64_t maximum_alignment(); @@ -4313,9 +4523,17 @@ class Output_segment bool has_dynamic_reloc() const; + // Return the first section. + Output_section* + first_section() const; + // Return the address of the first section. uint64_t - first_section_load_address() const; + first_section_load_address() const + { + const Output_section* os = this->first_section(); + return os->has_load_address() ? os->load_address() : os->address(); + } // Return whether the addresses have been set already. bool @@ -4356,7 +4574,7 @@ class Output_segment // address of the immediately following segment. Update *POFF and // *PSHNDX. This should only be called for a PT_LOAD segment. uint64_t - set_section_addresses(Layout*, bool reset, uint64_t addr, + set_section_addresses(const Target*, Layout*, bool reset, uint64_t addr, unsigned int* increase_relro, bool* has_relro, off_t* poff, unsigned int* pshndx); @@ -4417,8 +4635,8 @@ class Output_segment // Set the section addresses in an Output_data_list. uint64_t set_section_list_addresses(Layout*, bool reset, Output_data_list*, - uint64_t addr, off_t* poff, unsigned int* pshndx, - bool* in_tls); + uint64_t addr, off_t* poff, unsigned int* pshndx, + bool* in_tls); // Return the number of Output_sections in an Output_data_list. unsigned int @@ -4454,7 +4672,7 @@ class Output_segment // NOTE: We want to use the copy constructor. Currently, shallow copy // works for us so we do not need to write our own copy constructor. - + // The list of output data attached to this segment. Output_data_list output_lists_[ORDER_MAX]; // The segment virtual address. @@ -4488,6 +4706,8 @@ class Output_segment bool are_addresses_set_ : 1; // Whether this segment holds large data sections. bool is_large_data_segment_ : 1; + // Whether this was marked as a unique segment via a linker plugin. + bool is_unique_segment_ : 1; }; // This class represents the output file. @@ -4549,7 +4769,7 @@ class Output_file get_output_view(off_t start, size_t size) { gold_assert(start >= 0 - && start + static_cast(size) <= this->file_size_); + && start + static_cast(size) <= this->file_size_); return this->base_ + start; }