setting a flag as we add each reloc in the target code.
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.
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;
// 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
{
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;
{
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;
{
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());
}
}
}
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());
}
}
}
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());
}
}
}
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.
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.
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
// 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
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
{
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
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.
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.
// 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:
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.
add_local(Sized_relobj<size, big_endian>* 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<size, big_endian>* 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.
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.
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<size, big_endian>* 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.
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
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
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<int size, bool big_endian>
unsigned char*
Output_data_reloc<elfcpp::SHT_REL, true, size, big_endian>* 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.
Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>* 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.
Symbol* sym,
Relobj* relobj,
unsigned int shndx,
+ Output_section* output_section,
const elfcpp::Rel<size, big_endian>& rel)
{
unsigned int reloc_type = elfcpp::elf_r_type<size>(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.
Symbol* sym,
Relobj* relobj,
unsigned int shndx,
+ Output_section* output_section,
const elfcpp::Rela<size, big_endian>& rela)
{
unsigned int reloc_type = elfcpp::elf_r_type<size>(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()));
}
class Read_relocs_data;
class Symbol;
class Layout;
+class Output_section;
template<int size>
class Sized_symbol;
// index of the section to which the reloc is being applied.
void
save(Symbol* sym, Relobj*, unsigned int shndx,
- const elfcpp::Rel<size, big_endian>&);
+ Output_section* output_section, const elfcpp::Rel<size, big_endian>&);
// Save a Rela against SYM for possible emission later.
void
save(Symbol* sym, Relobj*, unsigned int shndx,
- const elfcpp::Rela<size, big_endian>&);
+ Output_section* output_section, const elfcpp::Rela<size, big_endian>&);
// Return whether there are any relocs to emit. This also discards
// entries which need not be emitted.
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
unsigned int reloc_type_;
Relobj* relobj_;
unsigned int shndx_;
+ Output_section* output_section_;
Address address_;
Addend addend_;
};
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.
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;
// 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
{
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>&)
{
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;
{
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;
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
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)
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());
}
}
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());
}
}