diff --git a/gold/i386.cc b/gold/i386.cc index 4a6aa7353f..e37e41ff13 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -288,7 +288,7 @@ class Target_i386 : public Sized_target<32, false> void copy_reloc(const General_options*, Symbol_table*, Layout*, Sized_relobj<32, false>*, unsigned int, - Symbol*, const elfcpp::Rel<32, false>&); + Output_section*, Symbol*, const elfcpp::Rel<32, false>&); // Information about this specific target which we pass to the // general Target structure. @@ -652,7 +652,9 @@ Target_i386::copy_reloc(const General_options* options, Symbol_table* symtab, Layout* layout, Sized_relobj<32, false>* object, - unsigned int data_shndx, Symbol* gsym, + unsigned int data_shndx, + Output_section* output_section, + Symbol* gsym, const elfcpp::Rel<32, false>& rel) { Sized_symbol<32>* ssym; @@ -667,7 +669,7 @@ Target_i386::copy_reloc(const General_options* options, // symbol, then we will emit the relocation. if (this->copy_relocs_ == NULL) this->copy_relocs_ = new Copy_relocs<32, false>(); - this->copy_relocs_->save(ssym, object, data_shndx, rel); + this->copy_relocs_->save(ssym, object, data_shndx, output_section, rel); } else { @@ -809,10 +811,8 @@ Target_i386::Scan::local(const General_options&, if (parameters->output_is_position_independent()) { Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx, - reloc.get_r_offset()); - if (!output_section->is_section_flag_set(elfcpp::SHF_WRITE)) - layout->set_have_textrel(); + rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, output_section, + data_shndx, reloc.get_r_offset()); } break; @@ -827,10 +827,8 @@ Target_i386::Scan::local(const General_options&, { Reloc_section* rel_dyn = target->rel_dyn_section(layout); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - rel_dyn->add_local(object, r_sym, r_type, data_shndx, + rel_dyn->add_local(object, r_sym, r_type, output_section, data_shndx, reloc.get_r_offset()); - if (!output_section->is_section_flag_set(elfcpp::SHF_WRITE)) - layout->set_have_textrel(); } break; @@ -863,9 +861,8 @@ Target_i386::Scan::local(const General_options&, { Reloc_section* rel_dyn = target->rel_dyn_section(layout); rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, - data_shndx, reloc.get_r_offset()); - if (!output_section->is_section_flag_set(elfcpp::SHF_WRITE)) - layout->set_have_textrel(); + output_section, data_shndx, + reloc.get_r_offset()); } } } @@ -1064,24 +1061,21 @@ Target_i386::Scan::global(const General_options& options, if (target->may_need_copy_reloc(gsym)) { target->copy_reloc(&options, symtab, layout, object, - data_shndx, gsym, reloc); + data_shndx, output_section, gsym, reloc); } else if (r_type == elfcpp::R_386_32 && gsym->can_use_relative_reloc(false)) { Reloc_section* rel_dyn = target->rel_dyn_section(layout); rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, - data_shndx, reloc.get_r_offset()); - if (!output_section->is_section_flag_set(elfcpp::SHF_WRITE)) - layout->set_have_textrel(); + output_section, data_shndx, + reloc.get_r_offset()); } else { Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_global(gsym, r_type, object, data_shndx, - reloc.get_r_offset()); - if (!output_section->is_section_flag_set(elfcpp::SHF_WRITE)) - layout->set_have_textrel(); + rel_dyn->add_global(gsym, r_type, output_section, object, + data_shndx, reloc.get_r_offset()); } } } @@ -1101,15 +1095,13 @@ Target_i386::Scan::global(const General_options& options, if (target->may_need_copy_reloc(gsym)) { target->copy_reloc(&options, symtab, layout, object, - data_shndx, gsym, reloc); + data_shndx, output_section, gsym, reloc); } else { Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_global(gsym, r_type, object, data_shndx, - reloc.get_r_offset()); - if (!output_section->is_section_flag_set(elfcpp::SHF_WRITE)) - layout->set_have_textrel(); + rel_dyn->add_global(gsym, r_type, output_section, object, + data_shndx, reloc.get_r_offset()); } } } diff --git a/gold/layout.cc b/gold/layout.cc index d3c5d6902e..8cb945bd6d 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -70,8 +70,7 @@ Layout::Layout(const General_options& options) eh_frame_section_(NULL), output_file_size_(-1), input_requires_executable_stack_(false), input_with_gnu_stack_note_(false), - input_without_gnu_stack_note_(false), - have_textrel_(false) + input_without_gnu_stack_note_(false) { // Make space for more than enough segments for a typical file. // This is just for efficiency--it's OK if we wind up needing more. @@ -1618,13 +1617,27 @@ Layout::finish_dynamic_section(const Input_objects* input_objects, odyn->add_string(elfcpp::DT_RPATH, rpath_val); } - - // Add a DT_FLAGS entry. We add it even if no flags are set so that - // post-link tools can easily modify these flags if desired. - unsigned int flags = 0; - if (this->have_textrel_) - flags |= elfcpp::DF_TEXTREL; - odyn->add_constant(elfcpp::DT_FLAGS, flags); + + // Look for text segments that have dynamic relocations. + bool have_textrel = false; + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + if (((*p)->flags() & elfcpp::PF_W) == 0 + && (*p)->dynamic_reloc_count() > 0) + { + have_textrel = true; + break; + } + } + + // Add a DT_FLAGS entry. We add it even if no flags are set so that + // post-link tools can easily modify these flags if desired. + unsigned int flags = 0; + if (have_textrel) + flags |= elfcpp::DF_TEXTREL; + odyn->add_constant(elfcpp::DT_FLAGS, flags); } // The mapping of .gnu.linkonce section names to real section names. diff --git a/gold/layout.h b/gold/layout.h index cc07fa3d42..5b9f28defe 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -170,11 +170,6 @@ class Layout off_t finalize(const Input_objects*, Symbol_table*); - // Record that we have seen a relocation in the text section. - void - set_have_textrel() - { this->have_textrel_ = true; } - // Return the size of the output file. off_t output_file_size() const @@ -439,8 +434,6 @@ class Layout // Whether we have seen at least one object file without an // executable stack marker. bool input_without_gnu_stack_note_; - // Whether we have seen a relocation in the text section. - bool have_textrel_; }; // This task handles writing out data in output sections which is not diff --git a/gold/output.cc b/gold/output.cc index ef5c5097c6..5832ded910 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -1580,6 +1580,28 @@ Output_segment::maximum_alignment(const Output_data_list* pdl) return ret; } +// Return the number of dynamic relocs applied to this segment. + +unsigned int +Output_segment::dynamic_reloc_count() const +{ + return (this->dynamic_reloc_count_list(&this->output_data_) + + this->dynamic_reloc_count_list(&this->output_bss_)); +} + +// Return the number of dynamic relocs applied to an Output_data_list. + +unsigned int +Output_segment::dynamic_reloc_count_list(const Output_data_list* pdl) const +{ + unsigned int count = 0; + for (Output_data_list::const_iterator p = pdl->begin(); + p != pdl->end(); + ++p) + count += (*p)->dynamic_reloc_count(); + return count; +} + // Set the section addresses for an Output_segment. ADDR is the // address and *POFF is the file offset. Set the section indexes // starting with *PSHNDX. Return the address of the immediately diff --git a/gold/output.h b/gold/output.h index e90077ac2a..5239b60f7e 100644 --- a/gold/output.h +++ b/gold/output.h @@ -50,7 +50,8 @@ class Output_data { public: explicit Output_data(off_t data_size = 0) - : address_(0), data_size_(data_size), offset_(-1) + : address_(0), data_size_(data_size), offset_(-1), + dynamic_reloc_count_(0) { } virtual @@ -128,6 +129,16 @@ class Output_data is_layout_complete() { return Output_data::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. @@ -205,6 +216,8 @@ class Output_data off_t data_size_; // Offset within file. off_t offset_; + // Count of dynamic relocations applied to this section. + unsigned int dynamic_reloc_count_; }; // Output the section headers. @@ -754,10 +767,11 @@ class Output_data_reloc_base : public Output_section_data // 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); + od->add_dynamic_reloc(); } private: @@ -793,12 +807,12 @@ 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)); } 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)); } // Add a reloc against a local symbol. @@ -806,27 +820,30 @@ 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)); } 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)); } // 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. @@ -853,12 +870,14 @@ 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)); } 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)); } // Add a reloc against a local symbol. @@ -867,17 +886,18 @@ 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)); } 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)); } // A reloc against the STT_SECTION symbol of an output section. @@ -885,12 +905,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 @@ -1755,6 +1776,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 @@ -1817,6 +1842,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* diff --git a/gold/reloc.cc b/gold/reloc.cc index 7a95deea59..ab74498d24 100644 --- a/gold/reloc.cc +++ b/gold/reloc.cc @@ -556,8 +556,8 @@ Copy_relocs::Copy_reloc_entry::emit( Output_data_reloc* reloc_data) { this->sym_->set_needs_dynsym_entry(); - reloc_data->add_global(this->sym_, this->reloc_type_, this->relobj_, - this->shndx_, this->address_); + reloc_data->add_global(this->sym_, this->reloc_type_, this->output_section_, + this->relobj_, this->shndx_, this->address_); } // Emit a reloc into a SHT_RELA section. @@ -568,8 +568,9 @@ Copy_relocs::Copy_reloc_entry::emit( Output_data_reloc* reloc_data) { this->sym_->set_needs_dynsym_entry(); - reloc_data->add_global(this->sym_, this->reloc_type_, this->relobj_, - this->shndx_, this->address_, this->addend_); + reloc_data->add_global(this->sym_, this->reloc_type_, this->output_section_, + this->relobj_, this->shndx_, this->address_, + this->addend_); } // Copy_relocs methods. @@ -606,11 +607,13 @@ Copy_relocs::save( Symbol* sym, Relobj* relobj, unsigned int shndx, + Output_section* output_section, const elfcpp::Rel& rel) { unsigned int reloc_type = elfcpp::elf_r_type(rel.get_r_info()); this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, relobj, shndx, - rel.get_r_offset(), 0)); + output_section, + rel.get_r_offset(), 0)); } // Save a Rela reloc. @@ -621,10 +624,12 @@ Copy_relocs::save( Symbol* sym, Relobj* relobj, unsigned int shndx, + Output_section* output_section, const elfcpp::Rela& rela) { unsigned int reloc_type = elfcpp::elf_r_type(rela.get_r_info()); this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, relobj, shndx, + output_section, rela.get_r_offset(), rela.get_r_addend())); } diff --git a/gold/reloc.h b/gold/reloc.h index 51b6143b8d..2ff49d84bf 100644 --- a/gold/reloc.h +++ b/gold/reloc.h @@ -37,6 +37,7 @@ class Relobj; class Read_relocs_data; class Symbol; class Layout; +class Output_section; template class Sized_symbol; @@ -539,12 +540,12 @@ class Copy_relocs // index of the section to which the reloc is being applied. void save(Symbol* sym, Relobj*, unsigned int shndx, - const elfcpp::Rel&); + Output_section* output_section, const elfcpp::Rel&); // Save a Rela against SYM for possible emission later. void save(Symbol* sym, Relobj*, unsigned int shndx, - const elfcpp::Rela&); + Output_section* output_section, const elfcpp::Rela&); // Return whether there are any relocs to emit. This also discards // entries which need not be emitted. @@ -567,9 +568,11 @@ class Copy_relocs public: Copy_reloc_entry(Symbol* sym, unsigned int reloc_type, Relobj* relobj, unsigned int shndx, + Output_section* output_section, Address address, Addend addend) : sym_(sym), reloc_type_(reloc_type), relobj_(relobj), - shndx_(shndx), address_(address), addend_(addend) + shndx_(shndx), output_section_(output_section), + address_(address), addend_(addend) { } // Return whether we should emit this reloc. If we should not @@ -590,6 +593,7 @@ class Copy_relocs unsigned int reloc_type_; Relobj* relobj_; unsigned int shndx_; + Output_section* output_section_; Address address_; Addend addend_; }; diff --git a/gold/x86_64.cc b/gold/x86_64.cc index 992b8bf24c..5ccde57f83 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -272,7 +272,7 @@ class Target_x86_64 : public Sized_target<64, false> void copy_reloc(const General_options*, Symbol_table*, Layout*, Sized_relobj<64, false>*, unsigned int, - Symbol*, const elfcpp::Rela<64, false>&); + Output_section*, Symbol*, const elfcpp::Rela<64, false>&); // Information about this specific target which we pass to the // general Target structure. @@ -606,7 +606,9 @@ Target_x86_64::copy_reloc(const General_options* options, Symbol_table* symtab, Layout* layout, Sized_relobj<64, false>* object, - unsigned int data_shndx, Symbol* gsym, + unsigned int data_shndx, + Output_section* output_section, + Symbol* gsym, const elfcpp::Rela<64, false>& rela) { Sized_symbol<64>* ssym; @@ -621,7 +623,7 @@ Target_x86_64::copy_reloc(const General_options* options, // symbol, then we will emit the relocation. if (this->copy_relocs_ == NULL) this->copy_relocs_ = new Copy_relocs<64, false>(); - this->copy_relocs_->save(ssym, object, data_shndx, rela); + this->copy_relocs_->save(ssym, object, data_shndx, output_section, rela); } else { @@ -740,7 +742,7 @@ Target_x86_64::Scan::local(const General_options&, Target_x86_64* target, Sized_relobj<64, false>* object, unsigned int data_shndx, - Output_section*, + Output_section* output_section, const elfcpp::Rela<64, false>& reloc, unsigned int r_type, const elfcpp::Sym<64, false>&) @@ -763,7 +765,8 @@ Target_x86_64::Scan::local(const General_options&, { Reloc_section* rela_dyn = target->rela_dyn_section(layout); rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, - data_shndx, reloc.get_r_offset(), 0); + output_section, data_shndx, + reloc.get_r_offset(), 0); } break; @@ -781,8 +784,8 @@ Target_x86_64::Scan::local(const General_options&, { Reloc_section* rela_dyn = target->rela_dyn_section(layout); unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info()); - rela_dyn->add_local(object, r_sym, r_type, data_shndx, - reloc.get_r_offset(), + rela_dyn->add_local(object, r_sym, r_type, output_section, + data_shndx, reloc.get_r_offset(), reloc.get_r_addend()); } break; @@ -828,7 +831,8 @@ Target_x86_64::Scan::local(const General_options&, Reloc_section* rela_dyn = target->rela_dyn_section(layout); rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, - data_shndx, reloc.get_r_offset(), 0); + output_section, data_shndx, + reloc.get_r_offset(), 0); } } // For GOTPLT64, we'd normally want a PLT section, but since @@ -930,7 +934,7 @@ Target_x86_64::Scan::global(const General_options& options, Target_x86_64* target, Sized_relobj<64, false>* object, unsigned int data_shndx, - Output_section*, + Output_section* output_section, const elfcpp::Rela<64, false>& reloc, unsigned int r_type, Symbol* gsym) @@ -965,21 +969,21 @@ Target_x86_64::Scan::global(const General_options& options, if (target->may_need_copy_reloc(gsym)) { target->copy_reloc(&options, symtab, layout, object, data_shndx, - gsym, reloc); + output_section, gsym, reloc); } else if (r_type == elfcpp::R_X86_64_64 && gsym->can_use_relative_reloc(false)) { Reloc_section* rela_dyn = target->rela_dyn_section(layout); rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, - data_shndx, + output_section, data_shndx, reloc.get_r_offset(), 0); } else { Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_global(gsym, r_type, object, data_shndx, - reloc.get_r_offset(), + rela_dyn->add_global(gsym, r_type, output_section, object, + data_shndx, reloc.get_r_offset(), reloc.get_r_addend()); } } @@ -1001,13 +1005,13 @@ Target_x86_64::Scan::global(const General_options& options, if (target->may_need_copy_reloc(gsym)) { target->copy_reloc(&options, symtab, layout, object, data_shndx, - gsym, reloc); + output_section, gsym, reloc); } else { Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_global(gsym, r_type, object, data_shndx, - reloc.get_r_offset(), + rela_dyn->add_global(gsym, r_type, output_section, object, + data_shndx, reloc.get_r_offset(), reloc.get_r_addend()); } }