Implement -q/--emit-relocs.

This commit is contained in:
Ian Lance Taylor 2008-02-27 22:38:18 +00:00
parent 20b4711e05
commit 7019cd2565
12 changed files with 293 additions and 41 deletions

View File

@ -2297,7 +2297,7 @@ Target_i386::scan_relocatable_relocs(const General_options& options,
typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_REL,
Relocatable_size_for_reloc> Scan_relocatable_relocs;
gold::scan_relocatable_relocs<32, false, Target_i386, elfcpp::SHT_REL,
gold::scan_relocatable_relocs<32, false, elfcpp::SHT_REL,
Scan_relocatable_relocs>(
options,
symtab,
@ -2332,7 +2332,7 @@ Target_i386::relocate_for_relocatable(
{
gold_assert(sh_type == elfcpp::SHT_REL);
gold::relocate_for_relocatable<32, false, Target_i386, elfcpp::SHT_REL>(
gold::relocate_for_relocatable<32, false, elfcpp::SHT_REL>(
relinfo,
prelocs,
reloc_count,

View File

@ -155,8 +155,10 @@ Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
case elfcpp::SHT_RELA:
case elfcpp::SHT_REL:
case elfcpp::SHT_GROUP:
// For a relocatable link these should be handled elsewhere.
gold_assert(!parameters->output_is_object());
// If we are emitting relocations these should be handled
// elsewhere.
gold_assert(!parameters->output_is_object()
&& !parameters->emit_relocs());
return false;
case elfcpp::SHT_PROGBITS:
@ -370,7 +372,7 @@ Layout::layout_reloc(Sized_relobj<size, big_endian>* object,
Output_section* data_section,
Relocatable_relocs* rr)
{
gold_assert(parameters->output_is_object());
gold_assert(parameters->output_is_object() || parameters->emit_relocs());
int sh_type = shdr.get_sh_type();

View File

@ -593,8 +593,9 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
// Keep track of which sections to omit.
std::vector<bool> omit(shnum, false);
// Keep track of reloc sections when doing a relocatable link.
// Keep track of reloc sections when emitting relocations.
const bool output_is_object = parameters->output_is_object();
const bool emit_relocs = output_is_object || parameters->emit_relocs();
std::vector<unsigned int> reloc_sections;
// Keep track of .eh_frame sections.
@ -660,7 +661,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
// ones associated with sections which are not being discarded.
// However, we don't know that yet for all sections. So save
// reloc sections and process them later.
if (output_is_object
if (emit_relocs
&& (shdr.get_sh_type() == elfcpp::SHT_REL
|| shdr.get_sh_type() == elfcpp::SHT_RELA))
{
@ -704,7 +705,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
// When doing a relocatable link handle the reloc sections at the
// end.
if (output_is_object)
if (emit_relocs)
this->size_relocatable_relocs();
for (std::vector<unsigned int>::const_iterator p = reloc_sections.begin();
p != reloc_sections.end();

View File

@ -111,6 +111,8 @@ struct Section_relocs
Output_section* output_section;
// Whether this section has special handling for offsets.
bool needs_special_offset_handling;
// Whether the data section is allocated (has the SHF_ALLOC flag set).
bool is_data_section_allocated;
};
// Relocations in an object file. This is read in read_relocs and
@ -1312,6 +1314,42 @@ class Sized_relobj : public Relobj
relocate_sections(const General_options& options, const Symbol_table*,
const Layout*, const unsigned char* pshdrs, Views*);
// Scan the input relocations for --emit-relocs.
void
emit_relocs_scan(const General_options&, Symbol_table*, Layout*,
const unsigned char* plocal_syms,
const Read_relocs_data::Relocs_list::iterator&);
// Scan the input relocations for --emit-relocs, templatized on the
// type of the relocation section.
template<int sh_type>
void
emit_relocs_scan_reltype(const General_options&, Symbol_table*, Layout*,
const unsigned char* plocal_syms,
const Read_relocs_data::Relocs_list::iterator&,
Relocatable_relocs*);
// Emit the relocs for --emit-relocs.
void
emit_relocs(const Relocate_info<size, big_endian>*, unsigned int,
unsigned int sh_type, const unsigned char* prelocs,
size_t reloc_count, Output_section*, off_t output_offset,
unsigned char* view, Address address,
section_size_type view_size,
unsigned char* reloc_view, section_size_type reloc_view_size);
// Emit the relocs for --emit-relocs, templatized on the type of the
// relocation section.
template<int sh_type>
void
emit_relocs_reltype(const Relocate_info<size, big_endian>*, unsigned int,
const unsigned char* prelocs, size_t reloc_count,
Output_section*, off_t output_offset,
unsigned char* view, Address address,
section_size_type view_size,
unsigned char* reloc_view,
section_size_type reloc_view_size);
// Initialize input to output maps for section symbols in merged
// sections.
void

View File

@ -530,8 +530,10 @@ options::Command_line_options::options[] =
GENERAL_ARG('\0', "oformat", N_("Set output format (only binary supported)"),
N_("--oformat FORMAT"), EXACTLY_TWO_DASHES,
&General_options::set_oformat),
GENERAL_NOARG('q', "emit-relocs", N_("Generate relocations in output"),
NULL, TWO_DASHES, &General_options::set_emit_relocs),
GENERAL_NOARG('r', "relocatable", N_("Generate relocatable output"), NULL,
ONE_DASH, &General_options::set_relocatable),
TWO_DASHES, &General_options::set_relocatable),
// -R really means -rpath, but can mean --just-symbols for
// compatibility with GNU ld. -rpath is always -rpath, so we list
// it separately.
@ -672,6 +674,7 @@ General_options::General_options()
output_file_name_("a.out"),
oformat_(OBJECT_FORMAT_ELF),
oformat_string_(NULL),
emit_relocs_(false),
is_relocatable_(false),
strip_(STRIP_NONE),
allow_shlib_undefined_(false),

View File

@ -167,6 +167,11 @@ class General_options
Target*
default_target() const;
// -q: Whether to emit relocations.
bool
emit_relocs() const
{ return this->emit_relocs_; }
// -r: Whether we are doing a relocatable link.
bool
relocatable() const
@ -408,6 +413,10 @@ class General_options
void
set_oformat(const char*);
void
set_emit_relocs(bool value)
{ this->emit_relocs_ = value; }
void
set_relocatable(bool value)
{ this->is_relocatable_ = value; }
@ -615,6 +624,7 @@ class General_options
const char* output_file_name_;
Object_format oformat_;
const char* oformat_string_;
bool emit_relocs_;
bool is_relocatable_;
Strip strip_;
bool allow_shlib_undefined_;

View File

@ -33,7 +33,7 @@ namespace gold
Parameters::Parameters(Errors* errors)
: errors_(errors), threads_(false), output_file_name_(NULL),
output_file_type_(OUTPUT_INVALID), sysroot_(),
output_file_type_(OUTPUT_INVALID), emit_relocs_(false), sysroot_(),
strip_(STRIP_INVALID), allow_shlib_undefined_(false),
symbolic_(false), demangle_(false), detect_odr_violations_(false),
optimization_level_(0), export_dynamic_(false), debug_(0),
@ -50,6 +50,7 @@ Parameters::set_from_options(const General_options* options)
{
this->threads_ = options->threads();
this->output_file_name_ = options->output_file_name();
this->emit_relocs_ = options->emit_relocs();
this->sysroot_ = options->sysroot();
this->allow_shlib_undefined_ = options->allow_shlib_undefined();
this->symbolic_ = options->Bsymbolic();

View File

@ -102,6 +102,11 @@ class Parameters
output_is_position_independent() const
{ return output_is_shared(); }
// Whether to emit relocations in the output.
bool
emit_relocs() const
{ return this->emit_relocs_; }
// The target system root directory. This is NULL if there isn't
// one.
const std::string&
@ -298,6 +303,8 @@ class Parameters
const char* output_file_name_;
// The type of the output file.
Output_file_type output_file_type_;
// Whether to emit relocations (-q/--emit-relocs).
bool emit_relocs_;
// The target system root directory.
std::string sysroot_;
// Which symbols to strip.

View File

@ -29,6 +29,7 @@
#include "output.h"
#include "merge.h"
#include "object.h"
#include "target-reloc.h"
#include "reloc.h"
namespace gold
@ -223,13 +224,14 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
// PLT sections. Relocations for sections which are not
// allocated (typically debugging sections) should not add new
// GOT and PLT entries. So we skip them unless this is a
// relocatable link.
if (!parameters->output_is_object())
{
typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size);
if ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
continue;
}
// relocatable link or we need to emit relocations.
typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size);
bool is_section_allocated = ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC)
!= 0);
if (!is_section_allocated
&& !parameters->output_is_object()
&& !parameters->emit_relocs())
continue;
if (shdr.get_sh_link() != this->symtab_shndx_)
{
@ -272,6 +274,7 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
sr.reloc_count = reloc_count;
sr.output_section = os;
sr.needs_special_offset_handling = map_sections[shndx].offset == -1;
sr.is_data_section_allocated = is_section_allocated;
}
// Read the local symbols.
@ -315,12 +318,20 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
++p)
{
if (!parameters->output_is_object())
target->scan_relocs(options, symtab, layout, this, p->data_shndx,
p->sh_type, p->contents->data(), p->reloc_count,
p->output_section,
p->needs_special_offset_handling,
this->local_symbol_count_,
local_symbols);
{
// As noted above, when not generating an object file, we
// only scan allocated sections. We may see a non-allocated
// section here if we are emitting relocs.
if (p->is_data_section_allocated)
target->scan_relocs(options, symtab, layout, this, p->data_shndx,
p->sh_type, p->contents->data(),
p->reloc_count, p->output_section,
p->needs_special_offset_handling,
this->local_symbol_count_,
local_symbols);
if (parameters->emit_relocs())
this->emit_relocs_scan(options, symtab, layout, local_symbols, p);
}
else
{
Relocatable_relocs* rr = this->relocatable_relocs(p->reloc_shndx);
@ -348,6 +359,98 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
}
}
// This is a strategy class we use when scanning for --emit-relocs.
template<int sh_type>
class Emit_relocs_strategy
{
public:
// A local non-section symbol.
inline Relocatable_relocs::Reloc_strategy
local_non_section_strategy(unsigned int, Relobj*)
{ return Relocatable_relocs::RELOC_COPY; }
// A local section symbol.
inline Relocatable_relocs::Reloc_strategy
local_section_strategy(unsigned int, Relobj*)
{
if (sh_type == elfcpp::SHT_RELA)
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
else
{
// The addend is stored in the section contents. Since this
// is not a relocatable link, we are going to apply the
// relocation contents to the section as usual. This means
// that we have no way to record the original addend. If the
// original addend is not zero, there is basically no way for
// the user to handle this correctly. Caveat emptor.
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0;
}
}
// A global symbol.
inline Relocatable_relocs::Reloc_strategy
global_strategy(unsigned int, Relobj*, unsigned int)
{ return Relocatable_relocs::RELOC_COPY; }
};
// Scan the input relocations for --emit-relocs.
template<int size, bool big_endian>
void
Sized_relobj<size, big_endian>::emit_relocs_scan(
const General_options& options,
Symbol_table* symtab,
Layout* layout,
const unsigned char* plocal_syms,
const Read_relocs_data::Relocs_list::iterator& p)
{
Relocatable_relocs* rr = this->relocatable_relocs(p->reloc_shndx);
gold_assert(rr != NULL);
rr->set_reloc_count(p->reloc_count);
if (p->sh_type == elfcpp::SHT_REL)
this->emit_relocs_scan_reltype<elfcpp::SHT_REL>(options, symtab, layout,
plocal_syms, p, rr);
else
{
gold_assert(p->sh_type == elfcpp::SHT_RELA);
this->emit_relocs_scan_reltype<elfcpp::SHT_RELA>(options, symtab,
layout, plocal_syms, p,
rr);
}
}
// Scan the input relocation for --emit-relocs, templatized on the
// type of the relocation section.
template<int size, bool big_endian>
template<int sh_type>
void
Sized_relobj<size, big_endian>::emit_relocs_scan_reltype(
const General_options& options,
Symbol_table* symtab,
Layout* layout,
const unsigned char* plocal_syms,
const Read_relocs_data::Relocs_list::iterator& p,
Relocatable_relocs* rr)
{
scan_relocatable_relocs<size, big_endian, sh_type,
Emit_relocs_strategy<sh_type> >(
options,
symtab,
layout,
this,
p->data_shndx,
p->contents->data(),
p->reloc_count,
p->output_section,
p->needs_special_offset_handling,
this->local_symbol_count_,
plocal_syms,
rr);
}
// Relocate the input sections and write out the local symbols.
template<int size, bool big_endian>
@ -452,14 +555,15 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
continue;
if (parameters->output_is_object()
if ((parameters->output_is_object() || parameters->emit_relocs())
&& (shdr.get_sh_type() == elfcpp::SHT_REL
|| shdr.get_sh_type() == elfcpp::SHT_RELA)
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
{
// This is a reloc section in a relocatable link. We don't
// need to read the input file. The size and file offset
// are stored in the Relocatable_relocs structure.
// This is a reloc section in a relocatable link or when
// emitting relocs. We don't need to read the input file.
// The size and file offset are stored in the
// Relocatable_relocs structure.
Relocatable_relocs* rr = this->relocatable_relocs(i);
gold_assert(rr != NULL);
Output_data* posd = rr->output_data();
@ -670,15 +774,25 @@ Sized_relobj<size, big_endian>::relocate_sections(
relinfo.reloc_shndx = i;
relinfo.data_shndx = index;
if (!parameters->output_is_object())
target->relocate_section(&relinfo,
sh_type,
prelocs,
reloc_count,
os,
output_offset == -1,
(*pviews)[index].view,
(*pviews)[index].address,
(*pviews)[index].view_size);
{
target->relocate_section(&relinfo,
sh_type,
prelocs,
reloc_count,
os,
output_offset == -1,
(*pviews)[index].view,
(*pviews)[index].address,
(*pviews)[index].view_size);
if (parameters->emit_relocs())
this->emit_relocs(&relinfo, i, sh_type, prelocs, reloc_count,
os, output_offset,
(*pviews)[index].view,
(*pviews)[index].address,
(*pviews)[index].view_size,
(*pviews)[i].view,
(*pviews)[i].view_size);
}
else
{
Relocatable_relocs* rr = this->relocatable_relocs(i);
@ -698,6 +812,75 @@ Sized_relobj<size, big_endian>::relocate_sections(
}
}
// Emit the relocs for --emit-relocs.
template<int size, bool big_endian>
void
Sized_relobj<size, big_endian>::emit_relocs(
const Relocate_info<size, big_endian>* relinfo,
unsigned int i,
unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
off_t offset_in_output_section,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr address,
section_size_type view_size,
unsigned char* reloc_view,
section_size_type reloc_view_size)
{
if (sh_type == elfcpp::SHT_REL)
this->emit_relocs_reltype<elfcpp::SHT_REL>(relinfo, i, prelocs,
reloc_count, output_section,
offset_in_output_section,
view, address, view_size,
reloc_view, reloc_view_size);
else
{
gold_assert(sh_type == elfcpp::SHT_RELA);
this->emit_relocs_reltype<elfcpp::SHT_RELA>(relinfo, i, prelocs,
reloc_count, output_section,
offset_in_output_section,
view, address, view_size,
reloc_view, reloc_view_size);
}
}
// Emit the relocs for --emit-relocs, templatized on the type of the
// relocation section.
template<int size, bool big_endian>
template<int sh_type>
void
Sized_relobj<size, big_endian>::emit_relocs_reltype(
const Relocate_info<size, big_endian>* relinfo,
unsigned int i,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
off_t offset_in_output_section,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr address,
section_size_type view_size,
unsigned char* reloc_view,
section_size_type reloc_view_size)
{
const Relocatable_relocs* rr = this->relocatable_relocs(i);
relocate_for_relocatable<size, big_endian, sh_type>(
relinfo,
prelocs,
reloc_count,
output_section,
offset_in_output_section,
rr,
view,
address,
view_size,
reloc_view,
reloc_view_size);
}
// Create merge hash tables for the local symbols. These are used to
// speed up relocations.

View File

@ -194,6 +194,9 @@ class Relocatable_relocs
// SHT_RELA reloc and the contents of the data section do not need
// to be changed.
RELOC_ADJUST_FOR_SECTION_RELA,
// Like RELOC_ADJUST_FOR_SECTION_RELA but the addend should not be
// adjusted.
RELOC_ADJUST_FOR_SECTION_0,
// Like RELOC_ADJUST_FOR_SECTION_RELA but the contents of the
// section need to be changed. The number indicates the number of
// bytes in the addend in the section contents.

View File

@ -256,7 +256,7 @@ class Default_scan_relocatable_relocs
switch (classify.get_size_for_reloc(r_type, object))
{
case 0:
return Relocatable_relocs::RELOC_COPY;
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0;
case 1:
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1;
case 2:
@ -286,7 +286,7 @@ class Default_scan_relocatable_relocs
// local_section_strategy. Most targets should be able to use
// Default_scan_relocatable_relocs as this class.
template<int size, bool big_endian, typename Target_type, int sh_type,
template<int size, bool big_endian, int sh_type,
typename Scan_relocatable_reloc>
void
scan_relocatable_relocs(
@ -365,7 +365,7 @@ scan_relocatable_relocs(
// Relocate relocs during a relocatable link. This is a default
// definition which should work for most targets.
template<int size, bool big_endian, typename Target_type, int sh_type>
template<int size, bool big_endian, int sh_type>
void
relocate_for_relocatable(
const Relocate_info<size, big_endian>* relinfo,
@ -416,6 +416,7 @@ relocate_for_relocatable(
break;
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA:
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0:
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1:
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2:
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4:
@ -503,6 +504,9 @@ relocate_for_relocatable(
}
break;
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0:
break;
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1:
Relocate_functions<size, big_endian>::rel8(padd, object,
psymval);

View File

@ -2087,7 +2087,7 @@ Target_x86_64::scan_relocatable_relocs(const General_options& options,
typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
Relocatable_size_for_reloc> Scan_relocatable_relocs;
gold::scan_relocatable_relocs<64, false, Target_x86_64, elfcpp::SHT_RELA,
gold::scan_relocatable_relocs<64, false, elfcpp::SHT_RELA,
Scan_relocatable_relocs>(
options,
symtab,
@ -2122,7 +2122,7 @@ Target_x86_64::relocate_for_relocatable(
{
gold_assert(sh_type == elfcpp::SHT_RELA);
gold::relocate_for_relocatable<64, false, Target_x86_64, elfcpp::SHT_RELA>(
gold::relocate_for_relocatable<64, false, elfcpp::SHT_RELA>(
relinfo,
prelocs,
reloc_count,