template<int size, bool big_endian>
class Sized_relobj;
-// This class specifies an input section. It is used as a key type
-// for maps.
-
-class Input_section_specifier
-{
- public:
- Input_section_specifier(const Relobj* relobj, unsigned int shndx)
- : relobj_(relobj), shndx_(shndx)
- { }
-
- // Return Relobj of this.
- const Relobj*
- relobj() const
- { return this->relobj_; }
-
- // Return section index of this.
- unsigned int
- shndx() const
- { return this->shndx_; }
-
- // Whether this equals to another specifier ISS.
- bool
- eq(const Input_section_specifier& iss) const
- { return this->relobj_ == iss.relobj_ && this->shndx_ == iss.shndx_; }
-
- // Compute a hash value of this.
- size_t
- hash_value() const
- {
- return (gold::string_hash<char>(this->relobj_->name().c_str())
- ^ this->shndx_);
- }
-
- // Functors for containers.
- struct equal_to
- {
- bool
- operator()(const Input_section_specifier& iss1,
- const Input_section_specifier& iss2) const
- { return iss1.eq(iss2); }
- };
-
- struct hash
- {
- size_t
- operator()(const Input_section_specifier& iss) const
- { return iss.hash_value(); }
- };
-
- private:
- // An object.
- const Relobj* relobj_;
- // A section index.
- unsigned int shndx_;
-};
-
// An abtract class for data which has to go into the output file.
class Output_data
// A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
- Address address, bool is_relative);
+ Address address, bool is_relative, bool is_symbolless);
Output_reloc(Symbol* gsym, unsigned int type,
Sized_relobj<size, big_endian>* relobj,
- unsigned int shndx, Address address, bool is_relative);
+ unsigned int shndx, Address address, bool is_relative,
+ bool is_symbolless);
// A reloc against a local symbol or local section symbol.
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address, bool is_relative,
- bool is_section_symbol);
+ bool is_symbolless, bool is_section_symbol);
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
unsigned int shndx, Address address, bool is_relative,
- bool is_section_symbol);
+ bool is_symbolless, bool is_section_symbol);
// A reloc against the STT_SECTION symbol of an output section.
is_relative() const
{ return this->is_relative_; }
+ // Return whether this is a relocation which should not use
+ // a symbol, but which obtains its addend from a symbol.
+ bool
+ is_symbolless() const
+ { return this->is_symbolless_; }
+
// Return whether this is against a local section symbol.
bool
is_local_section_symbol() const
// input file.
unsigned int local_sym_index_;
// The reloc type--a processor specific code.
- unsigned int type_ : 30;
+ unsigned int type_ : 29;
// True if the relocation is a RELATIVE relocation.
bool is_relative_ : 1;
+ // True if the relocation is one which should not use
+ // a symbol, but which obtains its addend from a symbol.
+ bool is_symbolless_ : 1;
// True if the relocation is against a section symbol.
bool is_section_symbol_ : 1;
// If the reloc address is an input section in an object, the
// A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
- Address address, Addend addend, bool is_relative)
- : rel_(gsym, type, od, address, is_relative), addend_(addend)
+ Address address, Addend addend, bool is_relative,
+ bool is_symbolless)
+ : rel_(gsym, type, od, address, is_relative, is_symbolless),
+ addend_(addend)
{ }
Output_reloc(Symbol* gsym, unsigned int type,
Sized_relobj<size, big_endian>* relobj,
unsigned int shndx, Address address, Addend addend,
- bool is_relative)
- : rel_(gsym, type, relobj, shndx, address, is_relative), addend_(addend)
+ bool is_relative, bool is_symbolless)
+ : rel_(gsym, type, relobj, shndx, address, is_relative,
+ is_symbolless), addend_(addend)
{ }
// A reloc against a local symbol.
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address,
- Addend addend, bool is_relative, bool is_section_symbol)
+ Addend addend, bool is_relative,
+ bool is_symbolless, bool is_section_symbol)
: rel_(relobj, local_sym_index, type, od, address, is_relative,
- is_section_symbol),
+ is_symbolless, is_section_symbol),
addend_(addend)
{ }
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
unsigned int shndx, Address address,
- Addend addend, bool is_relative, bool is_section_symbol)
+ Addend addend, bool is_relative,
+ bool is_symbolless, bool is_section_symbol)
: rel_(relobj, local_sym_index, type, shndx, address, is_relative,
- is_section_symbol),
+ is_symbolless, is_section_symbol),
addend_(addend)
{ }
is_relative() const
{ return this->rel_.is_relative(); }
+ // Return whether this is a relocation which should not use
+ // a symbol, but which obtains its addend from a symbol.
+ bool
+ is_symbolless() const
+ { return this->rel_.is_symbolless(); }
+
// Write the reloc entry to an output view.
void
write(unsigned char* pov) const;
void
add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
- { this->add(od, Output_reloc_type(gsym, type, od, address, false)); }
+ { this->add(od, Output_reloc_type(gsym, type, od, address, false, false)); }
void
add_global(Symbol* gsym, unsigned int type, Output_data* od,
Sized_relobj<size, big_endian>* relobj,
unsigned int shndx, Address address)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
- false)); }
+ false, false)); }
// These are to simplify the Copy_relocs class.
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)); }
+ { this->add(od, Output_reloc_type(gsym, type, od, address, true, true)); }
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
- true));
+ true, true));
+ }
+
+ // Add a global relocation which does not use a symbol for the relocation,
+ // but which gets its addend from a symbol.
+
+ 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)); }
+
+ void
+ add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+ Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address)
+ {
+ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ false, true));
}
// Add a reloc against a local symbol.
Output_data* od, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
- address, false, false));
+ address, false, false, false));
}
void
Output_data* od, unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- address, false, false));
+ address, false, false, false));
}
// Add a RELATIVE reloc against a local symbol.
Output_data* od, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
- address, true, false));
+ address, true, true, false));
}
void
Output_data* od, unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- address, true, false));
+ address, true, true, false));
+ }
+
+ // Add a local relocation which does not use a symbol for the relocation,
+ // but which gets its addend from a symbol.
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* 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, false, true, false));
+ }
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* 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, false, true, false));
}
// Add a reloc against a local section symbol. This will be
Output_data* od, Address address)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, od,
- address, false, true));
+ address, false, false, true));
}
void
Output_data* od, unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
- address, false, true));
+ address, false, false, true));
}
// A reloc against the STT_SECTION symbol of an output section.
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)); }
void
add_global(Symbol* gsym, unsigned int type, Output_data* od,
unsigned int shndx, Address address,
Addend addend)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
- addend, false)); }
+ addend, false, false)); }
// Add a RELATIVE reloc against a global symbol. The final output
// relocation will not reference the symbol, but we must keep the symbol
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)); }
+ { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true,
+ true)); }
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
Sized_relobj<size, big_endian>* relobj,
unsigned int shndx, Address address, Addend addend)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
- addend, true)); }
+ addend, true, true)); }
+
+ // Add a global relocation which does not use a symbol for the relocation,
+ // but which gets its addend from a symbol.
+
+ 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)); }
+
+ void
+ add_symbolless_global_addend(Symbol* gsym, unsigned int type,
+ Output_data* od,
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int shndx, Address address, Addend addend)
+ { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+ addend, false, true)); }
// Add a reloc against a local symbol.
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
- addend, false, false));
+ addend, false, false, false));
}
void
Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- address, addend, false, false));
+ address, addend, false, false, false));
}
// Add a RELATIVE reloc against a local symbol.
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
- addend, true, false));
+ addend, true, true, false));
}
void
Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
- address, addend, true, false));
+ address, addend, true, true, false));
+ }
+
+ // Add a local relocation which does not use a symbol for the relocation,
+ // but which gets it's addend from a symbol.
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* 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, false, true, false));
+ }
+
+ void
+ add_symbolless_local_addend(Sized_relobj<size, big_endian>* 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, false, true, false));
}
// Add a reloc against a local section symbol. This will be
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, od, address,
- addend, false, true));
+ addend, false, false, true));
}
void
Addend addend)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
- address, addend, false, true));
+ address, addend, false, false, true));
}
// A reloc against the STT_SECTION symbol of an output section.
add_section_size(elfcpp::DT tag, const Output_data* od)
{ this->add_entry(Dynamic_entry(tag, od, true)); }
+ // Add a new dynamic entry with the total size of two output datas.
+ void
+ add_section_size(elfcpp::DT tag, const Output_data* od,
+ const Output_data* od2)
+ { this->add_entry(Dynamic_entry(tag, od, od2)); }
+
// Add a new dynamic entry with the address of a symbol.
void
add_symbol(elfcpp::DT tag, const Symbol* sym)
offset_(section_size
? DYNAMIC_SECTION_SIZE
: DYNAMIC_SECTION_ADDRESS)
- { this->u_.od = od; }
+ {
+ this->u_.od = od;
+ this->od2 = NULL;
+ }
+
+ // Create an entry with the size of two sections.
+ Dynamic_entry(elfcpp::DT tag, const Output_data* od, const Output_data* od2)
+ : tag_(tag),
+ offset_(DYNAMIC_SECTION_SIZE)
+ {
+ this->u_.od = od;
+ this->od2 = od2;
+ }
// Create an entry with the address of a section plus a constant offset.
Dynamic_entry(elfcpp::DT tag, const Output_data* od, unsigned int offset)
// For DYNAMIC_STRING.
const char* str;
} u_;
+ // For DYNAMIC_SYMBOL with two sections.
+ const Output_data* od2;
// The dynamic tag.
elfcpp::DT tag_;
// The type of entry (Classification) or offset within a section.
get_input_sections(uint64_t address, const std::string& fill,
std::list<Simple_input_section>*);
- // Add an input section from a script.
+ // Add a simple input section.
void
- add_input_section_for_script(const Simple_input_section& input_section,
- off_t data_size, uint64_t addralign);
+ add_simple_input_section(const Simple_input_section& input_section,
+ off_t data_size, uint64_t addralign);
// Set the current size of the output section.
void
void
restore_states();
+ // Discard states.
+ void
+ discard_states();
+
// Convert existing input sections to relaxed input sections.
void
convert_input_sections_to_relaxed_sections(
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
+ { return this->section_offsets_need_adjustment_; }
+
+ // Set section_offsets_need_adjustment to be true.
+ void
+ set_section_offsets_need_adjustment()
+ { this->section_offsets_need_adjustment_ = true; }
+
+ // Adjust section offsets of input sections in this. This is
+ // requires if relaxation caused some input sections to change sizes.
+ void
+ adjust_section_offsets();
+
// Print merge statistics to stderr.
void
print_merge_stats();
// This class is used to sort the input sections.
class Input_section_sort_entry;
- // This is the sort comparison function.
+ // This is the sort comparison function for ctors and dtors.
struct Input_section_sort_compare
{
bool
const Input_section_sort_entry&) const;
};
+ // This is the sort comparison function for .init_array and .fini_array.
+ struct Input_section_sort_init_fini_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
Merge_section_properties::equal_to>
Merge_section_by_properties_map;
- // Map that link Input_section_specifier to Output_section_data.
- typedef Unordered_map<Input_section_specifier, Output_section_data*,
- Input_section_specifier::hash,
- Input_section_specifier::equal_to>
+ // Map that link Const_section_id to Output_section_data.
+ typedef Unordered_map<Const_section_id, Output_section_data*,
+ Const_section_id_hash>
Output_section_data_by_input_section_map;
- // Map that link Input_section_specifier to Output_relaxed_input_section.
- typedef Unordered_map<Input_section_specifier, Output_relaxed_input_section*,
- Input_section_specifier::hash,
- Input_section_specifier::equal_to>
+ // Map that link Const_section_id to Output_relaxed_input_section.
+ typedef Unordered_map<Const_section_id, Output_relaxed_input_section*,
+ Const_section_id_hash>
Output_relaxed_input_section_by_input_section_map;
// Map used during relaxation of existing sections. This map
- // an input section specifier to an input section list index.
- // We assume that Input_section_list is a vector.
- typedef Unordered_map<Input_section_specifier, size_t,
- Input_section_specifier::hash,
- Input_section_specifier::equal_to>
- Relaxation_map;
+ // a section id an input section list index. We assume that
+ // Input_section_list is a vector.
+ typedef Unordered_map<Section_id, size_t, Section_id_hash> Relaxation_map;
// Add a new output section by Input_section.
void
bool generate_code_fills_at_write_ : 1;
// Whether the entry size field should be zero.
bool is_entsize_zero_ : 1;
+ // Whether section offsets need adjustment due to relaxation.
+ bool section_offsets_need_adjustment_ : 1;
// For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment.
uint64_t tls_offset_;