Initial -r support.
This commit is contained in:
parent
0797561a54
commit
6a74a71947
18 changed files with 1696 additions and 90 deletions
27
gold/gold.cc
27
gold/gold.cc
|
@ -182,6 +182,9 @@ queue_middle_tasks(const General_options& options,
|
|||
gold_error(_("cannot mix -static with dynamic object %s"),
|
||||
(*input_objects->dynobj_begin())->name().c_str());
|
||||
}
|
||||
if (!doing_static_link && parameters->output_is_object())
|
||||
gold_error(_("cannot mix -r with dynamic object %s"),
|
||||
(*input_objects->dynobj_begin())->name().c_str());
|
||||
|
||||
if (is_debugging_enabled(DEBUG_SCRIPT))
|
||||
layout->script_options()->print(stderr);
|
||||
|
@ -201,12 +204,15 @@ queue_middle_tasks(const General_options& options,
|
|||
// Define symbols from any linker scripts.
|
||||
layout->define_script_symbols(symtab);
|
||||
|
||||
// Predefine standard symbols.
|
||||
define_standard_symbols(symtab, layout);
|
||||
if (!parameters->output_is_object())
|
||||
{
|
||||
// Predefine standard symbols.
|
||||
define_standard_symbols(symtab, layout);
|
||||
|
||||
// Define __start and __stop symbols for output sections where
|
||||
// appropriate.
|
||||
layout->define_section_symbols(symtab);
|
||||
// Define __start and __stop symbols for output sections where
|
||||
// appropriate.
|
||||
layout->define_section_symbols(symtab);
|
||||
}
|
||||
|
||||
// Read the relocations of the input files. We do this to find
|
||||
// which symbols are used by relocations which require a GOT and/or
|
||||
|
@ -237,9 +243,14 @@ queue_middle_tasks(const General_options& options,
|
|||
|
||||
// Allocate common symbols. This requires write access to the
|
||||
// symbol table, but is independent of the relocation processing.
|
||||
blocker->add_blocker();
|
||||
workqueue->queue(new Allocate_commons_task(options, symtab, layout,
|
||||
symtab_lock, blocker));
|
||||
// FIXME: We should have an option to do this even for a relocatable
|
||||
// link.
|
||||
if (!parameters->output_is_object())
|
||||
{
|
||||
blocker->add_blocker();
|
||||
workqueue->queue(new Allocate_commons_task(options, symtab, layout,
|
||||
symtab_lock, blocker));
|
||||
}
|
||||
|
||||
// When all those tasks are complete, we can start laying out the
|
||||
// output file.
|
||||
|
|
182
gold/i386.cc
182
gold/i386.cc
|
@ -96,6 +96,37 @@ class Target_i386 : public Sized_target<32, false>
|
|||
elfcpp::Elf_types<32>::Elf_Addr view_address,
|
||||
section_size_type view_size);
|
||||
|
||||
// Scan the relocs during a relocatable link.
|
||||
void
|
||||
scan_relocatable_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_relobj<32, false>* object,
|
||||
unsigned int data_shndx,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
bool needs_special_offset_handling,
|
||||
size_t local_symbol_count,
|
||||
const unsigned char* plocal_symbols,
|
||||
Relocatable_relocs*);
|
||||
|
||||
// Relocate a section during a relocatable link.
|
||||
void
|
||||
relocate_for_relocatable(const Relocate_info<32, false>*,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
off_t offset_in_output_section,
|
||||
const Relocatable_relocs*,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<32>::Elf_Addr view_address,
|
||||
section_size_type view_size,
|
||||
unsigned char* reloc_view,
|
||||
section_size_type reloc_view_size);
|
||||
|
||||
// Return a string used to fill a code section with nops.
|
||||
std::string
|
||||
do_code_fill(section_size_type length);
|
||||
|
@ -240,6 +271,15 @@ class Target_i386 : public Sized_target<32, false>
|
|||
Local_dynamic_type local_dynamic_type_;
|
||||
};
|
||||
|
||||
// A class which returns the size required for a relocation type,
|
||||
// used while scanning relocs during a relocatable link.
|
||||
class Relocatable_size_for_reloc
|
||||
{
|
||||
public:
|
||||
unsigned int
|
||||
get_size_for_reloc(unsigned int, Relobj*);
|
||||
};
|
||||
|
||||
// Adjust TLS relocation type based on the options and whether this
|
||||
// is a local symbol.
|
||||
static tls::Tls_optimization
|
||||
|
@ -2151,6 +2191,148 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
|
|||
view_size);
|
||||
}
|
||||
|
||||
// Return the size of a relocation while scanning during a relocatable
|
||||
// link.
|
||||
|
||||
unsigned int
|
||||
Target_i386::Relocatable_size_for_reloc::get_size_for_reloc(
|
||||
unsigned int r_type,
|
||||
Relobj* object)
|
||||
{
|
||||
switch (r_type)
|
||||
{
|
||||
case elfcpp::R_386_NONE:
|
||||
case elfcpp::R_386_GNU_VTINHERIT:
|
||||
case elfcpp::R_386_GNU_VTENTRY:
|
||||
case elfcpp::R_386_TLS_GD: // Global-dynamic
|
||||
case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url)
|
||||
case elfcpp::R_386_TLS_DESC_CALL:
|
||||
case elfcpp::R_386_TLS_LDM: // Local-dynamic
|
||||
case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic
|
||||
case elfcpp::R_386_TLS_IE: // Initial-exec
|
||||
case elfcpp::R_386_TLS_IE_32:
|
||||
case elfcpp::R_386_TLS_GOTIE:
|
||||
case elfcpp::R_386_TLS_LE: // Local-exec
|
||||
case elfcpp::R_386_TLS_LE_32:
|
||||
return 0;
|
||||
|
||||
case elfcpp::R_386_32:
|
||||
case elfcpp::R_386_PC32:
|
||||
case elfcpp::R_386_GOT32:
|
||||
case elfcpp::R_386_PLT32:
|
||||
case elfcpp::R_386_GOTOFF:
|
||||
case elfcpp::R_386_GOTPC:
|
||||
return 4;
|
||||
|
||||
case elfcpp::R_386_16:
|
||||
case elfcpp::R_386_PC16:
|
||||
return 2;
|
||||
|
||||
case elfcpp::R_386_8:
|
||||
case elfcpp::R_386_PC8:
|
||||
return 1;
|
||||
|
||||
// These are relocations which should only be seen by the
|
||||
// dynamic linker, and should never be seen here.
|
||||
case elfcpp::R_386_COPY:
|
||||
case elfcpp::R_386_GLOB_DAT:
|
||||
case elfcpp::R_386_JUMP_SLOT:
|
||||
case elfcpp::R_386_RELATIVE:
|
||||
case elfcpp::R_386_TLS_TPOFF:
|
||||
case elfcpp::R_386_TLS_DTPMOD32:
|
||||
case elfcpp::R_386_TLS_DTPOFF32:
|
||||
case elfcpp::R_386_TLS_TPOFF32:
|
||||
case elfcpp::R_386_TLS_DESC:
|
||||
object->error(_("unexpected reloc %u in object file"), r_type);
|
||||
return 0;
|
||||
|
||||
case elfcpp::R_386_32PLT:
|
||||
case elfcpp::R_386_TLS_GD_32:
|
||||
case elfcpp::R_386_TLS_GD_PUSH:
|
||||
case elfcpp::R_386_TLS_GD_CALL:
|
||||
case elfcpp::R_386_TLS_GD_POP:
|
||||
case elfcpp::R_386_TLS_LDM_32:
|
||||
case elfcpp::R_386_TLS_LDM_PUSH:
|
||||
case elfcpp::R_386_TLS_LDM_CALL:
|
||||
case elfcpp::R_386_TLS_LDM_POP:
|
||||
case elfcpp::R_386_USED_BY_INTEL_200:
|
||||
default:
|
||||
object->error(_("unsupported reloc %u in object file"), r_type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the relocs during a relocatable link.
|
||||
|
||||
void
|
||||
Target_i386::scan_relocatable_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_relobj<32, false>* object,
|
||||
unsigned int data_shndx,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
bool needs_special_offset_handling,
|
||||
size_t local_symbol_count,
|
||||
const unsigned char* plocal_symbols,
|
||||
Relocatable_relocs* rr)
|
||||
{
|
||||
gold_assert(sh_type == elfcpp::SHT_REL);
|
||||
|
||||
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,
|
||||
Scan_relocatable_relocs>(
|
||||
options,
|
||||
symtab,
|
||||
layout,
|
||||
object,
|
||||
data_shndx,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
output_section,
|
||||
needs_special_offset_handling,
|
||||
local_symbol_count,
|
||||
plocal_symbols,
|
||||
rr);
|
||||
}
|
||||
|
||||
// Relocate a section during a relocatable link.
|
||||
|
||||
void
|
||||
Target_i386::relocate_for_relocatable(
|
||||
const Relocate_info<32, false>* relinfo,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
off_t offset_in_output_section,
|
||||
const Relocatable_relocs* rr,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<32>::Elf_Addr view_address,
|
||||
section_size_type view_size,
|
||||
unsigned char* reloc_view,
|
||||
section_size_type reloc_view_size)
|
||||
{
|
||||
gold_assert(sh_type == elfcpp::SHT_REL);
|
||||
|
||||
gold::relocate_for_relocatable<32, false, Target_i386, elfcpp::SHT_REL>(
|
||||
relinfo,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
output_section,
|
||||
offset_in_output_section,
|
||||
rr,
|
||||
view,
|
||||
view_address,
|
||||
view_size,
|
||||
reloc_view,
|
||||
reloc_view_size);
|
||||
}
|
||||
|
||||
// Return the value to use for a dynamic which requires special
|
||||
// treatment. This is how we support equality comparisons of function
|
||||
// pointers across shared library boundaries, as described in the
|
||||
|
|
295
gold/layout.cc
295
gold/layout.cc
|
@ -36,6 +36,7 @@
|
|||
#include "dynobj.h"
|
||||
#include "ehframe.h"
|
||||
#include "compressed_output.h"
|
||||
#include "reloc.h"
|
||||
#include "layout.h"
|
||||
|
||||
namespace gold
|
||||
|
@ -138,8 +139,6 @@ bool
|
|||
Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr)
|
||||
{
|
||||
// Some section types are never linked. Some are only linked when
|
||||
// doing a relocateable link.
|
||||
switch (shdr.get_sh_type())
|
||||
{
|
||||
case elfcpp::SHT_NULL:
|
||||
|
@ -154,7 +153,9 @@ Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
|
|||
case elfcpp::SHT_RELA:
|
||||
case elfcpp::SHT_REL:
|
||||
case elfcpp::SHT_GROUP:
|
||||
return parameters->output_is_object();
|
||||
// For a relocatable link these should be handled elsewhere.
|
||||
gold_assert(!parameters->output_is_object());
|
||||
return false;
|
||||
|
||||
case elfcpp::SHT_PROGBITS:
|
||||
if (parameters->strip_debug()
|
||||
|
@ -330,13 +331,24 @@ Layout::layout(Sized_relobj<size, big_endian>* object, unsigned int shndx,
|
|||
if (!this->include_section(object, name, shdr))
|
||||
return NULL;
|
||||
|
||||
Output_section* os = this->choose_output_section(object,
|
||||
name,
|
||||
shdr.get_sh_type(),
|
||||
shdr.get_sh_flags(),
|
||||
true);
|
||||
if (os == NULL)
|
||||
return NULL;
|
||||
Output_section* os;
|
||||
|
||||
// In a relocatable link a grouped section must not be combined with
|
||||
// any other sections.
|
||||
if (parameters->output_is_object()
|
||||
&& (shdr.get_sh_flags() & elfcpp::SHF_GROUP) != 0)
|
||||
{
|
||||
name = this->namepool_.add(name, true, NULL);
|
||||
os = this->make_output_section(name, shdr.get_sh_type(),
|
||||
shdr.get_sh_flags());
|
||||
}
|
||||
else
|
||||
{
|
||||
os = this->choose_output_section(object, name, shdr.get_sh_type(),
|
||||
shdr.get_sh_flags(), true);
|
||||
if (os == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// FIXME: Handle SHF_LINK_ORDER somewhere.
|
||||
|
||||
|
@ -346,6 +358,100 @@ Layout::layout(Sized_relobj<size, big_endian>* object, unsigned int shndx,
|
|||
return os;
|
||||
}
|
||||
|
||||
// Handle a relocation section when doing a relocatable link.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Output_section*
|
||||
Layout::layout_reloc(Sized_relobj<size, big_endian>* object,
|
||||
unsigned int,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr,
|
||||
Output_section* data_section,
|
||||
Relocatable_relocs* rr)
|
||||
{
|
||||
gold_assert(parameters->output_is_object());
|
||||
|
||||
int sh_type = shdr.get_sh_type();
|
||||
|
||||
std::string name;
|
||||
if (sh_type == elfcpp::SHT_REL)
|
||||
name = ".rel";
|
||||
else if (sh_type == elfcpp::SHT_RELA)
|
||||
name = ".rela";
|
||||
else
|
||||
gold_unreachable();
|
||||
name += data_section->name();
|
||||
|
||||
Output_section* os = this->choose_output_section(object, name.c_str(),
|
||||
sh_type,
|
||||
shdr.get_sh_flags(),
|
||||
false);
|
||||
|
||||
os->set_should_link_to_symtab();
|
||||
os->set_info_section(data_section);
|
||||
|
||||
Output_section_data* posd;
|
||||
if (sh_type == elfcpp::SHT_REL)
|
||||
{
|
||||
os->set_entsize(elfcpp::Elf_sizes<size>::rel_size);
|
||||
posd = new Output_relocatable_relocs<elfcpp::SHT_REL,
|
||||
size,
|
||||
big_endian>(rr);
|
||||
}
|
||||
else if (sh_type == elfcpp::SHT_RELA)
|
||||
{
|
||||
os->set_entsize(elfcpp::Elf_sizes<size>::rela_size);
|
||||
posd = new Output_relocatable_relocs<elfcpp::SHT_RELA,
|
||||
size,
|
||||
big_endian>(rr);
|
||||
}
|
||||
else
|
||||
gold_unreachable();
|
||||
|
||||
os->add_output_section_data(posd);
|
||||
rr->set_output_data(posd);
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// Handle a group section when doing a relocatable link.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Layout::layout_group(Symbol_table* symtab,
|
||||
Sized_relobj<size, big_endian>* object,
|
||||
unsigned int,
|
||||
const char* group_section_name,
|
||||
const char* signature,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr,
|
||||
const elfcpp::Elf_Word* contents)
|
||||
{
|
||||
gold_assert(parameters->output_is_object());
|
||||
gold_assert(shdr.get_sh_type() == elfcpp::SHT_GROUP);
|
||||
group_section_name = this->namepool_.add(group_section_name, true, NULL);
|
||||
Output_section* os = this->make_output_section(group_section_name,
|
||||
elfcpp::SHT_GROUP,
|
||||
shdr.get_sh_flags());
|
||||
|
||||
// We need to find a symbol with the signature in the symbol table.
|
||||
// This is a hack to force that to happen.
|
||||
Symbol* sym = symtab->lookup(signature, NULL);
|
||||
if (sym == NULL)
|
||||
sym = symtab->define_as_constant(signature, NULL, 0, 0,
|
||||
elfcpp::STT_NOTYPE,
|
||||
elfcpp::STB_WEAK,
|
||||
elfcpp::STV_HIDDEN, 0, false);
|
||||
|
||||
os->set_should_link_to_symtab();
|
||||
os->set_info_symndx(sym);
|
||||
os->set_entsize(4);
|
||||
|
||||
section_size_type entry_count =
|
||||
convert_to_section_size_type(shdr.get_sh_size() / 4);
|
||||
Output_section_data* posd =
|
||||
new Output_data_group<size, big_endian>(object, entry_count, contents);
|
||||
os->add_output_section_data(posd);
|
||||
}
|
||||
|
||||
// Special GNU handling of sections name .eh_frame. They will
|
||||
// normally hold exception frame data as defined by the C++ ABI
|
||||
// (http://codesourcery.com/cxx-abi/).
|
||||
|
@ -496,6 +602,9 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
|
|||
this->unattached_section_list_.push_back(os);
|
||||
else
|
||||
{
|
||||
if (parameters->output_is_object())
|
||||
return os;
|
||||
|
||||
// If we have a SECTIONS clause, we can't handle the attachment
|
||||
// to segments until after we've seen all the sections.
|
||||
if (this->script_options_->saw_sections_clause())
|
||||
|
@ -799,7 +908,9 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
|||
// If there is a SECTIONS clause, put all the input sections into
|
||||
// the required order.
|
||||
Output_segment* load_seg;
|
||||
if (this->script_options_->saw_sections_clause())
|
||||
if (parameters->output_is_object())
|
||||
load_seg = NULL;
|
||||
else if (this->script_options_->saw_sections_clause())
|
||||
load_seg = this->set_section_addresses_from_script(symtab);
|
||||
else
|
||||
load_seg = this->find_first_load_seg();
|
||||
|
@ -808,11 +919,16 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
|||
|
||||
// Lay out the segment headers.
|
||||
Output_segment_headers* segment_headers;
|
||||
segment_headers = new Output_segment_headers(this->segment_list_);
|
||||
if (load_seg != NULL)
|
||||
load_seg->add_initial_output_data(segment_headers);
|
||||
if (phdr_seg != NULL)
|
||||
phdr_seg->add_initial_output_data(segment_headers);
|
||||
if (parameters->output_is_object())
|
||||
segment_headers = NULL;
|
||||
else
|
||||
{
|
||||
segment_headers = new Output_segment_headers(this->segment_list_);
|
||||
if (load_seg != NULL)
|
||||
load_seg->add_initial_output_data(segment_headers);
|
||||
if (phdr_seg != NULL)
|
||||
phdr_seg->add_initial_output_data(segment_headers);
|
||||
}
|
||||
|
||||
// Lay out the file header.
|
||||
Output_file_header* file_header;
|
||||
|
@ -822,9 +938,11 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
|||
load_seg->add_initial_output_data(file_header);
|
||||
|
||||
this->special_output_list_.push_back(file_header);
|
||||
this->special_output_list_.push_back(segment_headers);
|
||||
if (segment_headers != NULL)
|
||||
this->special_output_list_.push_back(segment_headers);
|
||||
|
||||
if (this->script_options_->saw_phdrs_clause())
|
||||
if (this->script_options_->saw_phdrs_clause()
|
||||
&& !parameters->output_is_object())
|
||||
{
|
||||
// Support use of FILEHDRS and PHDRS attachments in a PHDRS
|
||||
// clause in a linker script.
|
||||
|
@ -838,7 +956,11 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
|
|||
|
||||
// Set the file offsets of all the segments, and all the sections
|
||||
// they contain.
|
||||
off_t off = this->set_segment_offsets(target, load_seg, &shndx);
|
||||
off_t off;
|
||||
if (!parameters->output_is_object())
|
||||
off = this->set_segment_offsets(target, load_seg, &shndx);
|
||||
else
|
||||
off = this->set_relocatable_section_offsets(file_header, &shndx);
|
||||
|
||||
// Set the file offsets of all the non-data sections we've seen so
|
||||
// far which don't have to wait for the input sections. We need
|
||||
|
@ -1272,6 +1394,45 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
|
|||
return off;
|
||||
}
|
||||
|
||||
// Set the offsets of all the allocated sections when doing a
|
||||
// relocatable link. This does the same jobs as set_segment_offsets,
|
||||
// only for a relocatable link.
|
||||
|
||||
off_t
|
||||
Layout::set_relocatable_section_offsets(Output_data* file_header,
|
||||
unsigned int *pshndx)
|
||||
{
|
||||
off_t off = 0;
|
||||
|
||||
file_header->set_address_and_file_offset(0, 0);
|
||||
off += file_header->data_size();
|
||||
|
||||
for (Section_list::iterator p = this->section_list_.begin();
|
||||
p != this->section_list_.end();
|
||||
++p)
|
||||
{
|
||||
// We skip unallocated sections here, except that group sections
|
||||
// have to come first.
|
||||
if (((*p)->flags() & elfcpp::SHF_ALLOC) == 0
|
||||
&& (*p)->type() != elfcpp::SHT_GROUP)
|
||||
continue;
|
||||
|
||||
off = align_address(off, (*p)->addralign());
|
||||
|
||||
// The linker script might have set the address.
|
||||
if (!(*p)->is_address_valid())
|
||||
(*p)->set_address(0);
|
||||
(*p)->set_file_offset(off);
|
||||
(*p)->finalize_data_size();
|
||||
off += (*p)->data_size();
|
||||
|
||||
(*p)->set_out_shndx(*pshndx);
|
||||
++*pshndx;
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
// Set the file offset of all the sections not associated with a
|
||||
// segment.
|
||||
|
||||
|
@ -1327,10 +1488,16 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass)
|
|||
unsigned int
|
||||
Layout::set_section_indexes(unsigned int shndx)
|
||||
{
|
||||
const bool output_is_object = parameters->output_is_object();
|
||||
for (Section_list::iterator p = this->unattached_section_list_.begin();
|
||||
p != this->unattached_section_list_.end();
|
||||
++p)
|
||||
{
|
||||
// In a relocatable link, we already did group sections.
|
||||
if (output_is_object
|
||||
&& (*p)->type() == elfcpp::SHT_GROUP)
|
||||
continue;
|
||||
|
||||
(*p)->set_out_shndx(shndx);
|
||||
++shndx;
|
||||
}
|
||||
|
@ -1545,6 +1712,7 @@ Layout::create_shdrs(off_t* poff)
|
|||
Output_section_headers* oshdrs;
|
||||
oshdrs = new Output_section_headers(this,
|
||||
&this->segment_list_,
|
||||
&this->section_list_,
|
||||
&this->unattached_section_list_,
|
||||
&this->namepool_);
|
||||
off_t off = align_address(*poff, oshdrs->addralign());
|
||||
|
@ -2177,6 +2345,7 @@ Layout::get_allocated_sections(Section_list* section_list) const
|
|||
Output_segment*
|
||||
Layout::make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
|
||||
{
|
||||
gold_assert(!parameters->output_is_object());
|
||||
Output_segment* oseg = new Output_segment(type, flags);
|
||||
this->segment_list_.push_back(oseg);
|
||||
return oseg;
|
||||
|
@ -2456,6 +2625,94 @@ Layout::layout<64, true>(Sized_relobj<64, true>* object, unsigned int shndx,
|
|||
unsigned int, unsigned int, off_t*);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout_reloc<32, false>(Sized_relobj<32, false>* object,
|
||||
unsigned int reloc_shndx,
|
||||
const elfcpp::Shdr<32, false>& shdr,
|
||||
Output_section* data_section,
|
||||
Relocatable_relocs* rr);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout_reloc<32, true>(Sized_relobj<32, true>* object,
|
||||
unsigned int reloc_shndx,
|
||||
const elfcpp::Shdr<32, true>& shdr,
|
||||
Output_section* data_section,
|
||||
Relocatable_relocs* rr);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout_reloc<64, false>(Sized_relobj<64, false>* object,
|
||||
unsigned int reloc_shndx,
|
||||
const elfcpp::Shdr<64, false>& shdr,
|
||||
Output_section* data_section,
|
||||
Relocatable_relocs* rr);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
template
|
||||
Output_section*
|
||||
Layout::layout_reloc<64, true>(Sized_relobj<64, true>* object,
|
||||
unsigned int reloc_shndx,
|
||||
const elfcpp::Shdr<64, true>& shdr,
|
||||
Output_section* data_section,
|
||||
Relocatable_relocs* rr);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
void
|
||||
Layout::layout_group<32, false>(Symbol_table* symtab,
|
||||
Sized_relobj<32, false>* object,
|
||||
unsigned int,
|
||||
const char* group_section_name,
|
||||
const char* signature,
|
||||
const elfcpp::Shdr<32, false>& shdr,
|
||||
const elfcpp::Elf_Word* contents);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
template
|
||||
void
|
||||
Layout::layout_group<32, true>(Symbol_table* symtab,
|
||||
Sized_relobj<32, true>* object,
|
||||
unsigned int,
|
||||
const char* group_section_name,
|
||||
const char* signature,
|
||||
const elfcpp::Shdr<32, true>& shdr,
|
||||
const elfcpp::Elf_Word* contents);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
template
|
||||
void
|
||||
Layout::layout_group<64, false>(Symbol_table* symtab,
|
||||
Sized_relobj<64, false>* object,
|
||||
unsigned int,
|
||||
const char* group_section_name,
|
||||
const char* signature,
|
||||
const elfcpp::Shdr<64, false>& shdr,
|
||||
const elfcpp::Elf_Word* contents);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
template
|
||||
void
|
||||
Layout::layout_group<64, true>(Symbol_table* symtab,
|
||||
Sized_relobj<64, true>* object,
|
||||
unsigned int,
|
||||
const char* group_section_name,
|
||||
const char* signature,
|
||||
const elfcpp::Shdr<64, true>& shdr,
|
||||
const elfcpp::Elf_Word* contents);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
Output_section*
|
||||
|
|
|
@ -100,6 +100,29 @@ class Layout
|
|||
const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
|
||||
unsigned int reloc_shndx, unsigned int reloc_type, off_t* offset);
|
||||
|
||||
// Layout an input reloc section when doing a relocatable link. The
|
||||
// section is RELOC_SHNDX in OBJECT, with data in SHDR.
|
||||
// DATA_SECTION is the reloc section to which it refers. RR is the
|
||||
// relocatable information.
|
||||
template<int size, bool big_endian>
|
||||
Output_section*
|
||||
layout_reloc(Sized_relobj<size, big_endian>* object,
|
||||
unsigned int reloc_shndx,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr,
|
||||
Output_section* data_section,
|
||||
Relocatable_relocs* rr);
|
||||
|
||||
// Layout a group section when doing a relocatable link.
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
layout_group(Symbol_table* symtab,
|
||||
Sized_relobj<size, big_endian>* object,
|
||||
unsigned int group_shndx,
|
||||
const char* group_section_name,
|
||||
const char* signature,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr,
|
||||
const elfcpp::Elf_Word* contents);
|
||||
|
||||
// Like layout, only for exception frame sections. OBJECT is an
|
||||
// object file. SYMBOLS is the contents of the symbol table
|
||||
// section, with size SYMBOLS_SIZE. SYMBOL_NAMES is the contents of
|
||||
|
@ -413,6 +436,11 @@ class Layout
|
|||
off_t
|
||||
set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx);
|
||||
|
||||
// Set the file offsets of the sections when doing a relocatable
|
||||
// link.
|
||||
off_t
|
||||
set_relocatable_section_offsets(Output_data*, unsigned int* pshndx);
|
||||
|
||||
// Set the final file offsets of all the sections not associated
|
||||
// with a segment. We set section offsets in three passes: the
|
||||
// first handles all allocated sections, the second sections that
|
||||
|
|
|
@ -378,8 +378,10 @@ Sized_relobj<size, big_endian>::symbol_section_and_value(unsigned int sym,
|
|||
template<int size, bool big_endian>
|
||||
bool
|
||||
Sized_relobj<size, big_endian>::include_section_group(
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
unsigned int index,
|
||||
const char* name,
|
||||
const elfcpp::Shdr<size, big_endian>& shdr,
|
||||
std::vector<bool>* omit)
|
||||
{
|
||||
|
@ -393,13 +395,11 @@ Sized_relobj<size, big_endian>::include_section_group(
|
|||
// groups. Other section groups are always included in the link
|
||||
// just like ordinary sections.
|
||||
elfcpp::Elf_Word flags = elfcpp::Swap<32, big_endian>::readval(pword);
|
||||
if ((flags & elfcpp::GRP_COMDAT) == 0)
|
||||
return true;
|
||||
|
||||
// Look up the group signature, which is the name of a symbol. This
|
||||
// is a lot of effort to go to to read a string. Why didn't they
|
||||
// just use the name of the SHT_GROUP section as the group
|
||||
// signature?
|
||||
// just have the group signature point into the string table, rather
|
||||
// than indirect through a symbol?
|
||||
|
||||
// Get the appropriate symbol table header (this will normally be
|
||||
// the single SHT_SYMTAB section, but in principle it need not be).
|
||||
|
@ -447,8 +447,15 @@ Sized_relobj<size, big_endian>::include_section_group(
|
|||
|
||||
// Record this section group, and see whether we've already seen one
|
||||
// with the same signature.
|
||||
if (layout->add_comdat(signature, true))
|
||||
return true;
|
||||
|
||||
if ((flags & elfcpp::GRP_COMDAT) == 0
|
||||
|| layout->add_comdat(signature, true))
|
||||
{
|
||||
if (parameters->output_is_object())
|
||||
layout->layout_group(symtab, this, index, name, signature, shdr,
|
||||
pword);
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is a duplicate. We want to discard the sections in this
|
||||
// group.
|
||||
|
@ -575,6 +582,10 @@ 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.
|
||||
const bool output_is_object = parameters->output_is_object();
|
||||
std::vector<unsigned int> reloc_sections;
|
||||
|
||||
// Keep track of .eh_frame sections.
|
||||
std::vector<unsigned int> eh_frame_sections;
|
||||
|
||||
|
@ -595,7 +606,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
|
|||
|
||||
if (this->handle_gnu_warning_section(name, i, symtab))
|
||||
{
|
||||
if (!parameters->output_is_object())
|
||||
if (!output_is_object)
|
||||
omit[i] = true;
|
||||
}
|
||||
|
||||
|
@ -614,7 +625,8 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
|
|||
{
|
||||
if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
|
||||
{
|
||||
if (!this->include_section_group(layout, i, shdr, &omit))
|
||||
if (!this->include_section_group(symtab, layout, i, name, shdr,
|
||||
&omit))
|
||||
discard = true;
|
||||
}
|
||||
else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0
|
||||
|
@ -632,13 +644,29 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
|
|||
continue;
|
||||
}
|
||||
|
||||
// When doing a relocatable link we are going to copy input
|
||||
// reloc sections into the output. We only want to copy the
|
||||
// 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
|
||||
&& (shdr.get_sh_type() == elfcpp::SHT_REL
|
||||
|| shdr.get_sh_type() == elfcpp::SHT_RELA))
|
||||
{
|
||||
reloc_sections.push_back(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (output_is_object && shdr.get_sh_type() == elfcpp::SHT_GROUP)
|
||||
continue;
|
||||
|
||||
// The .eh_frame section is special. It holds exception frame
|
||||
// information that we need to read in order to generate the
|
||||
// exception frame header. We process these after all the other
|
||||
// sections so that the exception frame reader can reliably
|
||||
// determine which sections are being discarded, and discard the
|
||||
// corresponding information.
|
||||
if (!parameters->output_is_object()
|
||||
if (!output_is_object
|
||||
&& strcmp(name, ".eh_frame") == 0
|
||||
&& this->check_eh_frame_flags(&shdr))
|
||||
{
|
||||
|
@ -663,6 +691,42 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
|
|||
|
||||
layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags);
|
||||
|
||||
// When doing a relocatable link handle the reloc sections at the
|
||||
// end.
|
||||
if (output_is_object)
|
||||
this->size_relocatable_relocs();
|
||||
for (std::vector<unsigned int>::const_iterator p = reloc_sections.begin();
|
||||
p != reloc_sections.end();
|
||||
++p)
|
||||
{
|
||||
unsigned int i = *p;
|
||||
const unsigned char* pshdr;
|
||||
pshdr = sd->section_headers->data() + i * This::shdr_size;
|
||||
typename This::Shdr shdr(pshdr);
|
||||
|
||||
unsigned int data_shndx = shdr.get_sh_info();
|
||||
if (data_shndx >= shnum)
|
||||
{
|
||||
// We already warned about this above.
|
||||
continue;
|
||||
}
|
||||
|
||||
Output_section* data_section = map_sections[data_shndx].output_section;
|
||||
if (data_section == NULL)
|
||||
{
|
||||
map_sections[i].output_section = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
Relocatable_relocs* rr = new Relocatable_relocs();
|
||||
this->set_relocatable_relocs(i, rr);
|
||||
|
||||
Output_section* os = layout->layout_reloc(this, i, shdr, data_section,
|
||||
rr);
|
||||
map_sections[i].output_section = os;
|
||||
map_sections[i].offset = -1;
|
||||
}
|
||||
|
||||
// Handle the .eh_frame sections at the end.
|
||||
for (std::vector<unsigned int>::const_iterator p = eh_frame_sections.begin();
|
||||
p != eh_frame_sections.end();
|
||||
|
|
|
@ -41,6 +41,7 @@ class Output_section;
|
|||
class Output_file;
|
||||
class Dynobj;
|
||||
class Object_merge_map;
|
||||
class Relocatable_relocs;
|
||||
|
||||
template<typename Stringpool_char>
|
||||
class Stringpool_template;
|
||||
|
@ -456,6 +457,7 @@ class Relobj : public Object
|
|||
Relobj(const std::string& name, Input_file* input_file, off_t offset = 0)
|
||||
: Object(name, input_file, false, offset),
|
||||
map_to_output_(),
|
||||
map_to_relocatable_relocs_(NULL),
|
||||
object_merge_map_(NULL),
|
||||
relocs_must_follow_section_writes_(false)
|
||||
{ }
|
||||
|
@ -562,6 +564,22 @@ class Relobj : public Object
|
|||
this->object_merge_map_ = object_merge_map;
|
||||
}
|
||||
|
||||
// Record the relocatable reloc info for an input reloc section.
|
||||
void
|
||||
set_relocatable_relocs(unsigned int reloc_shndx, Relocatable_relocs* rr)
|
||||
{
|
||||
gold_assert(reloc_shndx < this->shnum());
|
||||
(*this->map_to_relocatable_relocs_)[reloc_shndx] = rr;
|
||||
}
|
||||
|
||||
// Get the relocatable reloc info for an input reloc section.
|
||||
Relocatable_relocs*
|
||||
relocatable_relocs(unsigned int reloc_shndx)
|
||||
{
|
||||
gold_assert(reloc_shndx < this->shnum());
|
||||
return (*this->map_to_relocatable_relocs_)[reloc_shndx];
|
||||
}
|
||||
|
||||
protected:
|
||||
// What we need to know to map an input section to an output
|
||||
// section. We keep an array of these, one for each input section,
|
||||
|
@ -592,10 +610,11 @@ class Relobj : public Object
|
|||
// Count local symbols--implemented by child class.
|
||||
virtual void
|
||||
do_count_local_symbols(Stringpool_template<char>*,
|
||||
Stringpool_template<char>*) = 0;
|
||||
Stringpool_template<char>*) = 0;
|
||||
|
||||
// Finalize the local symbols. Set the output symbol table indexes for the local variables, and set the
|
||||
// offset where local symbol information will be stored.
|
||||
// Finalize the local symbols. Set the output symbol table indexes
|
||||
// for the local variables, and set the offset where local symbol
|
||||
// information will be stored.
|
||||
virtual unsigned int
|
||||
do_finalize_local_symbols(unsigned int, off_t) = 0;
|
||||
|
||||
|
@ -622,6 +641,14 @@ class Relobj : public Object
|
|||
map_to_output() const
|
||||
{ return this->map_to_output_; }
|
||||
|
||||
// Set the size of the relocatable relocs array.
|
||||
void
|
||||
size_relocatable_relocs()
|
||||
{
|
||||
this->map_to_relocatable_relocs_ =
|
||||
new std::vector<Relocatable_relocs*>(this->shnum());
|
||||
}
|
||||
|
||||
// Record that we must wait for the output sections to be written
|
||||
// before applying relocations.
|
||||
void
|
||||
|
@ -631,6 +658,9 @@ class Relobj : public Object
|
|||
private:
|
||||
// Mapping from input sections to output section.
|
||||
std::vector<Map_to_output> map_to_output_;
|
||||
// Mapping from input section index to the information recorded for
|
||||
// the relocations. This is only used for a relocatable link.
|
||||
std::vector<Relocatable_relocs*>* map_to_relocatable_relocs_;
|
||||
// Mappings for merge sections. This is managed by the code in the
|
||||
// Merge_map class.
|
||||
Object_merge_map* object_merge_map_;
|
||||
|
@ -992,6 +1022,14 @@ class Sized_relobj : public Relobj
|
|||
return this->local_values_[sym].output_dynsym_index();
|
||||
}
|
||||
|
||||
// Return the input section index of local symbol SYM.
|
||||
unsigned int
|
||||
local_symbol_input_shndx(unsigned int sym) const
|
||||
{
|
||||
gold_assert(sym < this->local_values_.size());
|
||||
return this->local_values_[sym].input_shndx();
|
||||
}
|
||||
|
||||
// Return the appropriate Sized_target structure.
|
||||
Sized_target<size, big_endian>*
|
||||
sized_target()
|
||||
|
@ -1218,7 +1256,7 @@ class Sized_relobj : public Relobj
|
|||
|
||||
// Whether to include a section group in the link.
|
||||
bool
|
||||
include_section_group(Layout*, unsigned int,
|
||||
include_section_group(Symbol_table*, Layout*, unsigned int, const char*,
|
||||
const elfcpp::Shdr<size, big_endian>&,
|
||||
std::vector<bool>*);
|
||||
|
||||
|
|
|
@ -977,6 +977,9 @@ Command_line::get_special_argument(const char* longname, int argc, char** argv,
|
|||
void
|
||||
Command_line::normalize_options()
|
||||
{
|
||||
if (this->options_.is_shared() && this->options_.is_relocatable())
|
||||
gold_fatal(_("-shared and -r are incompatible"));
|
||||
|
||||
// If the user specifies both -s and -r, convert the -s as -S.
|
||||
// -r requires us to keep externally visible symbols!
|
||||
if (this->options_.strip_all() && this->options_.is_relocatable())
|
||||
|
|
233
gold/output.cc
233
gold/output.cc
|
@ -83,20 +83,33 @@ Output_data::default_alignment_for_size(int size)
|
|||
Output_section_headers::Output_section_headers(
|
||||
const Layout* layout,
|
||||
const Layout::Segment_list* segment_list,
|
||||
const Layout::Section_list* section_list,
|
||||
const Layout::Section_list* unattached_section_list,
|
||||
const Stringpool* secnamepool)
|
||||
: layout_(layout),
|
||||
segment_list_(segment_list),
|
||||
section_list_(section_list),
|
||||
unattached_section_list_(unattached_section_list),
|
||||
secnamepool_(secnamepool)
|
||||
{
|
||||
// Count all the sections. Start with 1 for the null section.
|
||||
off_t count = 1;
|
||||
for (Layout::Segment_list::const_iterator p = segment_list->begin();
|
||||
p != segment_list->end();
|
||||
++p)
|
||||
if ((*p)->type() == elfcpp::PT_LOAD)
|
||||
count += (*p)->output_section_count();
|
||||
if (!parameters->output_is_object())
|
||||
{
|
||||
for (Layout::Segment_list::const_iterator p = segment_list->begin();
|
||||
p != segment_list->end();
|
||||
++p)
|
||||
if ((*p)->type() == elfcpp::PT_LOAD)
|
||||
count += (*p)->output_section_count();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Layout::Section_list::const_iterator p = section_list->begin();
|
||||
p != section_list->end();
|
||||
++p)
|
||||
if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0)
|
||||
++count;
|
||||
}
|
||||
count += unattached_section_list->size();
|
||||
|
||||
const int size = parameters->get_size();
|
||||
|
@ -184,18 +197,48 @@ Output_section_headers::do_sized_write(Output_file* of)
|
|||
|
||||
v += shdr_size;
|
||||
|
||||
unsigned shndx = 1;
|
||||
for (Layout::Segment_list::const_iterator p = this->segment_list_->begin();
|
||||
p != this->segment_list_->end();
|
||||
++p)
|
||||
v = (*p)->write_section_headers SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
|
||||
this->layout_, this->secnamepool_, v, &shndx
|
||||
SELECT_SIZE_ENDIAN(size, big_endian));
|
||||
unsigned int shndx = 1;
|
||||
if (!parameters->output_is_object())
|
||||
{
|
||||
for (Layout::Segment_list::const_iterator p =
|
||||
this->segment_list_->begin();
|
||||
p != this->segment_list_->end();
|
||||
++p)
|
||||
v = (*p)->write_section_headers<size, big_endian>(this->layout_,
|
||||
this->secnamepool_,
|
||||
v,
|
||||
&shndx);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Layout::Section_list::const_iterator p =
|
||||
this->section_list_->begin();
|
||||
p != this->section_list_->end();
|
||||
++p)
|
||||
{
|
||||
// We do unallocated sections below, except that group
|
||||
// sections have to come first.
|
||||
if (((*p)->flags() & elfcpp::SHF_ALLOC) == 0
|
||||
&& (*p)->type() != elfcpp::SHT_GROUP)
|
||||
continue;
|
||||
gold_assert(shndx == (*p)->out_shndx());
|
||||
elfcpp::Shdr_write<size, big_endian> oshdr(v);
|
||||
(*p)->write_header(this->layout_, this->secnamepool_, &oshdr);
|
||||
v += shdr_size;
|
||||
++shndx;
|
||||
}
|
||||
}
|
||||
|
||||
for (Layout::Section_list::const_iterator p =
|
||||
this->unattached_section_list_->begin();
|
||||
p != this->unattached_section_list_->end();
|
||||
++p)
|
||||
{
|
||||
// For a relocatable link, we did unallocated group sections
|
||||
// above, since they have to come first.
|
||||
if ((*p)->type() == elfcpp::SHT_GROUP
|
||||
&& parameters->output_is_object())
|
||||
continue;
|
||||
gold_assert(shndx == (*p)->out_shndx());
|
||||
elfcpp::Shdr_write<size, big_endian> oshdr(v);
|
||||
(*p)->write_header(this->layout_, this->secnamepool_, &oshdr);
|
||||
|
@ -422,16 +465,30 @@ Output_file_header::do_sized_write(Output_file* of)
|
|||
|
||||
oehdr.put_e_entry(this->entry<size>());
|
||||
|
||||
oehdr.put_e_phoff(this->segment_header_->offset());
|
||||
if (this->segment_header_ == NULL)
|
||||
oehdr.put_e_phoff(0);
|
||||
else
|
||||
oehdr.put_e_phoff(this->segment_header_->offset());
|
||||
|
||||
oehdr.put_e_shoff(this->section_header_->offset());
|
||||
|
||||
// FIXME: The target needs to set the flags.
|
||||
oehdr.put_e_flags(0);
|
||||
|
||||
oehdr.put_e_ehsize(elfcpp::Elf_sizes<size>::ehdr_size);
|
||||
oehdr.put_e_phentsize(elfcpp::Elf_sizes<size>::phdr_size);
|
||||
oehdr.put_e_phnum(this->segment_header_->data_size()
|
||||
/ elfcpp::Elf_sizes<size>::phdr_size);
|
||||
|
||||
if (this->segment_header_ == NULL)
|
||||
{
|
||||
oehdr.put_e_phentsize(0);
|
||||
oehdr.put_e_phnum(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
oehdr.put_e_phentsize(elfcpp::Elf_sizes<size>::phdr_size);
|
||||
oehdr.put_e_phnum(this->segment_header_->data_size()
|
||||
/ elfcpp::Elf_sizes<size>::phdr_size);
|
||||
}
|
||||
|
||||
oehdr.put_e_shentsize(elfcpp::Elf_sizes<size>::shdr_size);
|
||||
oehdr.put_e_shnum(this->section_header_->data_size()
|
||||
/ elfcpp::Elf_sizes<size>::shdr_size);
|
||||
|
@ -822,6 +879,80 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
|
|||
this->relocs_.clear();
|
||||
}
|
||||
|
||||
// Class Output_relocatable_relocs.
|
||||
|
||||
template<int sh_type, int size, bool big_endian>
|
||||
void
|
||||
Output_relocatable_relocs<sh_type, size, big_endian>::set_final_data_size()
|
||||
{
|
||||
this->set_data_size(this->rr_->output_reloc_count()
|
||||
* Reloc_types<sh_type, size, big_endian>::reloc_size);
|
||||
}
|
||||
|
||||
// class Output_data_group.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
Output_data_group<size, big_endian>::Output_data_group(
|
||||
Sized_relobj<size, big_endian>* relobj,
|
||||
section_size_type entry_count,
|
||||
const elfcpp::Elf_Word* contents)
|
||||
: Output_section_data(entry_count * 4, 4),
|
||||
relobj_(relobj)
|
||||
{
|
||||
this->flags_ = elfcpp::Swap<32, big_endian>::readval(contents);
|
||||
for (section_size_type i = 1; i < entry_count; ++i)
|
||||
{
|
||||
unsigned int shndx = elfcpp::Swap<32, big_endian>::readval(contents + i);
|
||||
this->input_sections_.push_back(shndx);
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the section group, which means translating the section
|
||||
// indexes to apply to the output file.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
void
|
||||
Output_data_group<size, big_endian>::do_write(Output_file* of)
|
||||
{
|
||||
const off_t off = this->offset();
|
||||
const section_size_type oview_size =
|
||||
convert_to_section_size_type(this->data_size());
|
||||
unsigned char* const oview = of->get_output_view(off, oview_size);
|
||||
|
||||
elfcpp::Elf_Word* contents = reinterpret_cast<elfcpp::Elf_Word*>(oview);
|
||||
elfcpp::Swap<32, big_endian>::writeval(contents, this->flags_);
|
||||
++contents;
|
||||
|
||||
for (std::vector<unsigned int>::const_iterator p =
|
||||
this->input_sections_.begin();
|
||||
p != this->input_sections_.end();
|
||||
++p, ++contents)
|
||||
{
|
||||
section_offset_type dummy;
|
||||
Output_section* os = this->relobj_->output_section(*p, &dummy);
|
||||
|
||||
unsigned int output_shndx;
|
||||
if (os != NULL)
|
||||
output_shndx = os->out_shndx();
|
||||
else
|
||||
{
|
||||
this->relobj_->error(_("section group retained but "
|
||||
"group element discarded"));
|
||||
output_shndx = 0;
|
||||
}
|
||||
|
||||
elfcpp::Swap<32, big_endian>::writeval(contents, output_shndx);
|
||||
}
|
||||
|
||||
size_t wrote = reinterpret_cast<unsigned char*>(contents) - oview;
|
||||
gold_assert(wrote == oview_size);
|
||||
|
||||
of->write_output_view(off, oview_size, oview);
|
||||
|
||||
// We no longer need this information.
|
||||
this->input_sections_.clear();
|
||||
}
|
||||
|
||||
// Output_data_got::Got_entry methods.
|
||||
|
||||
// Write out the entry.
|
||||
|
@ -1460,6 +1591,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
|
|||
link_section_(NULL),
|
||||
link_(0),
|
||||
info_section_(NULL),
|
||||
info_symndx_(NULL),
|
||||
info_(0),
|
||||
type_(type),
|
||||
flags_(flags),
|
||||
|
@ -1871,7 +2003,12 @@ Output_section::write_header(const Layout* layout,
|
|||
{
|
||||
oshdr->put_sh_name(secnamepool->get_offset(this->name_));
|
||||
oshdr->put_sh_type(this->type_);
|
||||
oshdr->put_sh_flags(this->flags_);
|
||||
|
||||
elfcpp::Elf_Xword flags = this->flags_;
|
||||
if (this->info_section_ != NULL)
|
||||
flags |= elfcpp::SHF_INFO_LINK;
|
||||
oshdr->put_sh_flags(flags);
|
||||
|
||||
oshdr->put_sh_addr(this->address());
|
||||
oshdr->put_sh_offset(this->offset());
|
||||
oshdr->put_sh_size(this->data_size());
|
||||
|
@ -1885,6 +2022,8 @@ Output_section::write_header(const Layout* layout,
|
|||
oshdr->put_sh_link(this->link_);
|
||||
if (this->info_section_ != NULL)
|
||||
oshdr->put_sh_info(this->info_section_->out_shndx());
|
||||
else if (this->info_symndx_ != NULL)
|
||||
oshdr->put_sh_info(this->info_symndx_->symtab_index());
|
||||
else
|
||||
oshdr->put_sh_info(this->info_);
|
||||
oshdr->put_sh_addralign(this->addralign_);
|
||||
|
@ -2883,6 +3022,66 @@ template
|
|||
class Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
class Output_relocatable_relocs<elfcpp::SHT_REL, 32, false>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
template
|
||||
class Output_relocatable_relocs<elfcpp::SHT_REL, 32, true>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
template
|
||||
class Output_relocatable_relocs<elfcpp::SHT_REL, 64, false>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
template
|
||||
class Output_relocatable_relocs<elfcpp::SHT_REL, 64, true>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
class Output_relocatable_relocs<elfcpp::SHT_RELA, 32, false>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
template
|
||||
class Output_relocatable_relocs<elfcpp::SHT_RELA, 32, true>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
template
|
||||
class Output_relocatable_relocs<elfcpp::SHT_RELA, 64, false>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
template
|
||||
class Output_relocatable_relocs<elfcpp::SHT_RELA, 64, true>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
class Output_data_group<32, false>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
template
|
||||
class Output_data_group<32, true>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
template
|
||||
class Output_data_group<64, false>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
template
|
||||
class Output_data_group<64, true>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
class Output_data_got<32, false>;
|
||||
|
|
|
@ -38,6 +38,7 @@ class Object;
|
|||
class Symbol;
|
||||
class Output_file;
|
||||
class Output_section;
|
||||
class Relocatable_relocs;
|
||||
class Target;
|
||||
template<int size, bool big_endian>
|
||||
class Sized_target;
|
||||
|
@ -372,6 +373,7 @@ class Output_section_headers : public Output_data
|
|||
Output_section_headers(const Layout*,
|
||||
const Layout::Segment_list*,
|
||||
const Layout::Section_list*,
|
||||
const Layout::Section_list*,
|
||||
const Stringpool*);
|
||||
|
||||
protected:
|
||||
|
@ -392,6 +394,7 @@ class Output_section_headers : public Output_data
|
|||
|
||||
const Layout* layout_;
|
||||
const Layout::Segment_list* segment_list_;
|
||||
const Layout::Section_list* section_list_;
|
||||
const Layout::Section_list* unattached_section_list_;
|
||||
const Stringpool* secnamepool_;
|
||||
};
|
||||
|
@ -1184,6 +1187,54 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
|
|||
addend)); }
|
||||
};
|
||||
|
||||
// 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.
|
||||
|
||||
template<int sh_type, int size, bool big_endian>
|
||||
class Output_relocatable_relocs : public Output_section_data
|
||||
{
|
||||
public:
|
||||
Output_relocatable_relocs(Relocatable_relocs* rr)
|
||||
: Output_section_data(Output_data::default_alignment_for_size(size)),
|
||||
rr_(rr)
|
||||
{ }
|
||||
|
||||
void
|
||||
set_final_data_size();
|
||||
|
||||
// Write out the data. There is nothing to do here.
|
||||
void
|
||||
do_write(Output_file*)
|
||||
{ }
|
||||
|
||||
private:
|
||||
// The relocs associated with this input section.
|
||||
Relocatable_relocs* rr_;
|
||||
};
|
||||
|
||||
// Handle a GROUP section.
|
||||
|
||||
template<int size, bool big_endian>
|
||||
class Output_data_group : public Output_section_data
|
||||
{
|
||||
public:
|
||||
Output_data_group(Sized_relobj<size, big_endian>* relobj,
|
||||
section_size_type entry_count,
|
||||
const elfcpp::Elf_Word* contents);
|
||||
|
||||
void
|
||||
do_write(Output_file*);
|
||||
|
||||
private:
|
||||
// The input object.
|
||||
Sized_relobj<size, big_endian>* relobj_;
|
||||
// The group flag word.
|
||||
elfcpp::Elf_Word flags_;
|
||||
// The section indexes of the input sections in this group.
|
||||
std::vector<unsigned int> input_sections_;
|
||||
};
|
||||
|
||||
// Output_data_got is used to manage a GOT. Each entry in the GOT is
|
||||
// for one symbol--either a global symbol or a local symbol in an
|
||||
// object. The target specific code adds entries to the GOT as
|
||||
|
@ -1626,15 +1677,23 @@ class Output_section : public Output_data
|
|||
void
|
||||
set_info_section(const Output_data* od)
|
||||
{
|
||||
gold_assert(this->info_ == 0);
|
||||
gold_assert(this->info_symndx_ == NULL && this->info_ == 0);
|
||||
this->info_section_ = od;
|
||||
}
|
||||
|
||||
// Set the info field to the symbol table index of a symbol.
|
||||
void
|
||||
set_info_symndx(const Symbol* sym)
|
||||
{
|
||||
gold_assert(this->info_section_ == NULL && this->info_ == 0);
|
||||
this->info_symndx_ = sym;
|
||||
}
|
||||
|
||||
// Set the info field to a constant.
|
||||
void
|
||||
set_info(unsigned int v)
|
||||
{
|
||||
gold_assert(this->info_section_ == NULL);
|
||||
gold_assert(this->info_section_ == NULL && this->info_symndx_ == NULL);
|
||||
this->info_ = v;
|
||||
}
|
||||
|
||||
|
@ -2201,7 +2260,11 @@ class Output_section : public Output_data
|
|||
unsigned int link_;
|
||||
// Set the section info field to the index of this section.
|
||||
const Output_data* info_section_;
|
||||
// If info_section_ is NULL, this is the section info field.
|
||||
// If info_section_ is NULL, set the info field to the symbol table
|
||||
// index of this symbol.
|
||||
const Symbol* info_symndx_;
|
||||
// If info_section_ and info_symndx_ are NULL, this is the section
|
||||
// info field.
|
||||
unsigned int info_;
|
||||
// The section type.
|
||||
const elfcpp::Elf_Word type_;
|
||||
|
|
|
@ -41,14 +41,42 @@ template<int size, bool big_endian>
|
|||
struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
|
||||
{
|
||||
typedef typename elfcpp::Rel<size, big_endian> Reloc;
|
||||
typedef typename elfcpp::Rel_write<size, big_endian> Reloc_write;
|
||||
static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size;
|
||||
|
||||
static inline typename elfcpp::Elf_types<size>::Elf_Swxword
|
||||
get_reloc_addend(const Reloc*)
|
||||
{ gold_unreachable(); }
|
||||
|
||||
static inline void
|
||||
set_reloc_addend(Reloc_write*,
|
||||
typename elfcpp::Elf_types<size>::Elf_Swxword)
|
||||
{ gold_unreachable(); }
|
||||
|
||||
static inline void
|
||||
copy_reloc_addend(Reloc_write*, const Reloc*)
|
||||
{ gold_unreachable(); }
|
||||
};
|
||||
|
||||
template<int size, bool big_endian>
|
||||
struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
|
||||
{
|
||||
typedef typename elfcpp::Rela<size, big_endian> Reloc;
|
||||
typedef typename elfcpp::Rela_write<size, big_endian> Reloc_write;
|
||||
static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
|
||||
|
||||
static inline typename elfcpp::Elf_types<size>::Elf_Swxword
|
||||
get_reloc_addend(const Reloc* p)
|
||||
{ return p->get_r_addend(); }
|
||||
|
||||
static inline void
|
||||
set_reloc_addend(Reloc_write* p,
|
||||
typename elfcpp::Elf_types<size>::Elf_Swxword val)
|
||||
{ p->put_r_addend(val); }
|
||||
|
||||
static inline void
|
||||
copy_reloc_addend(Reloc_write* to, const Reloc* from)
|
||||
{ to->put_r_addend(from->get_r_addend()); }
|
||||
};
|
||||
|
||||
}; // End namespace gold.
|
||||
|
|
100
gold/reloc.cc
100
gold/reloc.cc
|
@ -222,10 +222,14 @@ Sized_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
|
|||
// We are scanning relocations in order to fill out the GOT and
|
||||
// PLT sections. Relocations for sections which are not
|
||||
// allocated (typically debugging sections) should not add new
|
||||
// GOT and PLT entries. So we skip them.
|
||||
typename This::Shdr secshdr(pshdrs + shndx * This::shdr_size);
|
||||
if ((secshdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
|
||||
continue;
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (shdr.get_sh_link() != this->symtab_shndx_)
|
||||
{
|
||||
|
@ -310,11 +314,29 @@ Sized_relobj<size, big_endian>::do_scan_relocs(const General_options& options,
|
|||
p != rd->relocs.end();
|
||||
++p)
|
||||
{
|
||||
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->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);
|
||||
else
|
||||
{
|
||||
Relocatable_relocs* rr = this->relocatable_relocs(p->reloc_shndx);
|
||||
gold_assert(rr != NULL);
|
||||
rr->set_reloc_count(p->reloc_count);
|
||||
target->scan_relocatable_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,
|
||||
rr);
|
||||
}
|
||||
|
||||
delete p->contents;
|
||||
p->contents = NULL;
|
||||
}
|
||||
|
@ -430,6 +452,29 @@ 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()
|
||||
&& (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.
|
||||
Relocatable_relocs* rr = this->relocatable_relocs(i);
|
||||
gold_assert(rr != NULL);
|
||||
Output_data* posd = rr->output_data();
|
||||
gold_assert(posd != NULL);
|
||||
|
||||
pvs->offset = posd->offset();
|
||||
pvs->view_size = posd->data_size();
|
||||
pvs->view = of->get_output_view(pvs->offset, pvs->view_size);
|
||||
pvs->address = posd->address();
|
||||
pvs->is_input_output_view = false;
|
||||
pvs->is_postprocessing_view = false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// In the normal case, this input section is simply mapped to
|
||||
// the output section at offset OUTPUT_OFFSET.
|
||||
|
||||
|
@ -582,6 +627,8 @@ Sized_relobj<size, big_endian>::relocate_sections(
|
|||
off_t output_offset = map_sections[index].offset;
|
||||
|
||||
gold_assert((*pviews)[index].view != NULL);
|
||||
if (parameters->output_is_object())
|
||||
gold_assert((*pviews)[i].view != NULL);
|
||||
|
||||
if (shdr.get_sh_link() != this->symtab_shndx_)
|
||||
{
|
||||
|
@ -622,15 +669,32 @@ Sized_relobj<size, big_endian>::relocate_sections(
|
|||
|
||||
relinfo.reloc_shndx = i;
|
||||
relinfo.data_shndx = index;
|
||||
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->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);
|
||||
else
|
||||
{
|
||||
Relocatable_relocs* rr = this->relocatable_relocs(i);
|
||||
target->relocate_for_relocatable(&relinfo,
|
||||
sh_type,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
os,
|
||||
output_offset,
|
||||
rr,
|
||||
(*pviews)[index].view,
|
||||
(*pviews)[index].address,
|
||||
(*pviews)[index].view_size,
|
||||
(*pviews)[i].view,
|
||||
(*pviews)[i].view_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
95
gold/reloc.h
95
gold/reloc.h
|
@ -38,6 +38,7 @@ class Relobj;
|
|||
class Read_relocs_data;
|
||||
class Symbol;
|
||||
class Layout;
|
||||
class Output_data;
|
||||
class Output_section;
|
||||
|
||||
template<int size>
|
||||
|
@ -170,6 +171,100 @@ class Relocate_task : public Task
|
|||
Task_token* final_blocker_;
|
||||
};
|
||||
|
||||
// During a relocatable link, this class records how relocations
|
||||
// should be handled for a single input reloc section. An instance of
|
||||
// this class is created while scanning relocs, and it is used while
|
||||
// processing relocs.
|
||||
|
||||
class Relocatable_relocs
|
||||
{
|
||||
public:
|
||||
// We use a vector of unsigned char to indicate how the input relocs
|
||||
// should be handled. Each element is one of the following values.
|
||||
// We create this vector when we initially scan the relocations.
|
||||
enum Reloc_strategy
|
||||
{
|
||||
// Copy the input reloc. Don't modify it other than updating the
|
||||
// r_offset field and the r_sym part of the r_info field.
|
||||
RELOC_COPY,
|
||||
// Copy the input reloc which is against an STT_SECTION symbol.
|
||||
// Update the r_offset and r_sym part of the r_info field. Adjust
|
||||
// the addend by subtracting the value of the old local symbol and
|
||||
// adding the value of the new local symbol. The addend is in the
|
||||
// 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 contents of the
|
||||
// section need to be changed. The number indicates the number of
|
||||
// bytes in the addend in the section contents.
|
||||
RELOC_ADJUST_FOR_SECTION_1,
|
||||
RELOC_ADJUST_FOR_SECTION_2,
|
||||
RELOC_ADJUST_FOR_SECTION_4,
|
||||
RELOC_ADJUST_FOR_SECTION_8,
|
||||
// Discard the input reloc--process it completely when relocating
|
||||
// the data section contents.
|
||||
RELOC_DISCARD,
|
||||
// An input reloc which is not discarded, but which requires
|
||||
// target specific processing in order to update it.
|
||||
RELOC_SPECIAL
|
||||
};
|
||||
|
||||
Relocatable_relocs()
|
||||
: reloc_strategies_(), output_reloc_count_(0), posd_(NULL)
|
||||
{ }
|
||||
|
||||
// Record the number of relocs.
|
||||
void
|
||||
set_reloc_count(size_t reloc_count)
|
||||
{ this->reloc_strategies_.reserve(reloc_count); }
|
||||
|
||||
// Record what to do for the next reloc.
|
||||
void
|
||||
set_next_reloc_strategy(Reloc_strategy strategy)
|
||||
{
|
||||
this->reloc_strategies_.push_back(static_cast<unsigned char>(strategy));
|
||||
if (strategy != RELOC_DISCARD)
|
||||
++this->output_reloc_count_;
|
||||
}
|
||||
|
||||
// Record the Output_data associated with this reloc section.
|
||||
void
|
||||
set_output_data(Output_data* posd)
|
||||
{
|
||||
gold_assert(this->posd_ == NULL);
|
||||
this->posd_ = posd;
|
||||
}
|
||||
|
||||
// Return the Output_data associated with this reloc section.
|
||||
Output_data*
|
||||
output_data() const
|
||||
{ return this->posd_; }
|
||||
|
||||
// Return what to do for reloc I.
|
||||
Reloc_strategy
|
||||
strategy(unsigned int i) const
|
||||
{
|
||||
gold_assert(i < this->reloc_strategies_.size());
|
||||
return static_cast<Reloc_strategy>(this->reloc_strategies_[i]);
|
||||
}
|
||||
|
||||
// Return the number of relocations to create in the output file.
|
||||
size_t
|
||||
output_reloc_count() const
|
||||
{ return this->output_reloc_count_; }
|
||||
|
||||
private:
|
||||
typedef std::vector<unsigned char> Reloc_strategies;
|
||||
|
||||
// The strategies for the input reloc. There is one entry in this
|
||||
// vector for each relocation in the input section.
|
||||
Reloc_strategies reloc_strategies_;
|
||||
// The number of relocations to be created in the output file.
|
||||
size_t output_reloc_count_;
|
||||
// The output data structure associated with this relocation.
|
||||
Output_data* posd_;
|
||||
};
|
||||
|
||||
// Standard relocation routines which are used on many targets. Here
|
||||
// SIZE and BIG_ENDIAN refer to the target, not the relocation type.
|
||||
|
||||
|
|
|
@ -25,16 +25,18 @@
|
|||
|
||||
#include "elfcpp.h"
|
||||
#include "symtab.h"
|
||||
#include "reloc.h"
|
||||
#include "reloc-types.h"
|
||||
|
||||
namespace gold
|
||||
{
|
||||
|
||||
// This function implements the generic part of reloc scanning. This
|
||||
// is an inline function which takes a class whose member functions
|
||||
// local() and global() implement the machine specific part of scanning.
|
||||
// We do it this way to avoidmaking a function call for each relocation,
|
||||
// and to avoid repeating the generic code for each target.
|
||||
// This function implements the generic part of reloc scanning. The
|
||||
// template parameter Scan must be a class type which provides two
|
||||
// functions: local() and global(). Those functions implement the
|
||||
// machine specific part of scanning. We do it this way to
|
||||
// avoidmaking a function call for each relocation, and to avoid
|
||||
// repeating the generic code for each target.
|
||||
|
||||
template<int size, bool big_endian, typename Target_type, int sh_type,
|
||||
typename Scan>
|
||||
|
@ -116,11 +118,9 @@ scan_relocs(
|
|||
}
|
||||
|
||||
// This function implements the generic part of relocation processing.
|
||||
// This is an inline function which take a class whose relocate()
|
||||
// implements the machine specific part of relocation. We do it this
|
||||
// way to avoid making a function call for each relocation, and to
|
||||
// avoid repeating the generic relocation handling code for each
|
||||
// target.
|
||||
// The template parameter Relocate must be a class type which provides
|
||||
// a single function, relocate(), which implements the machine
|
||||
// specific part of a relocation.
|
||||
|
||||
// SIZE is the ELF size: 32 or 64. BIG_ENDIAN is the endianness of
|
||||
// the data. SH_TYPE is the section type: SHT_REL or SHT_RELA.
|
||||
|
@ -225,6 +225,316 @@ relocate_section(
|
|||
}
|
||||
}
|
||||
|
||||
// This class may be used as a typical class for the
|
||||
// Scan_relocatable_reloc parameter to scan_relocatable_relocs. The
|
||||
// template parameter Classify_reloc must be a class type which
|
||||
// provides a function get_size_for_reloc which returns the number of
|
||||
// bytes to which a reloc applies. This class is intended to capture
|
||||
// the most typical target behaviour, while still permitting targets
|
||||
// to define their own independent class for Scan_relocatable_reloc.
|
||||
|
||||
template<int sh_type, typename Classify_reloc>
|
||||
class Default_scan_relocatable_relocs
|
||||
{
|
||||
public:
|
||||
// Return the strategy to use for a local symbol which is not a
|
||||
// section symbol, given the relocation type.
|
||||
inline Relocatable_relocs::Reloc_strategy
|
||||
local_non_section_strategy(unsigned int, Relobj*)
|
||||
{ return Relocatable_relocs::RELOC_COPY; }
|
||||
|
||||
// Return the strategy to use for a local symbol which is a section
|
||||
// symbol, given the relocation type.
|
||||
inline Relocatable_relocs::Reloc_strategy
|
||||
local_section_strategy(unsigned int r_type, Relobj* object)
|
||||
{
|
||||
if (sh_type == elfcpp::SHT_RELA)
|
||||
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
|
||||
else
|
||||
{
|
||||
Classify_reloc classify;
|
||||
switch (classify.get_size_for_reloc(r_type, object))
|
||||
{
|
||||
case 0:
|
||||
return Relocatable_relocs::RELOC_COPY;
|
||||
case 1:
|
||||
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1;
|
||||
case 2:
|
||||
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2;
|
||||
case 4:
|
||||
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4;
|
||||
case 8:
|
||||
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_8;
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the strategy to use for a global symbol, given the
|
||||
// relocation type, the object, and the symbol index.
|
||||
inline Relocatable_relocs::Reloc_strategy
|
||||
global_strategy(unsigned int, Relobj*, unsigned int)
|
||||
{ return Relocatable_relocs::RELOC_COPY; }
|
||||
};
|
||||
|
||||
// Scan relocs during a relocatable link. This is a default
|
||||
// definition which should work for most targets.
|
||||
// Scan_relocatable_reloc must name a class type which provides three
|
||||
// functions which return a Relocatable_relocs::Reloc_strategy code:
|
||||
// global_strategy, local_non_section_strategy, and
|
||||
// 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,
|
||||
typename Scan_relocatable_reloc>
|
||||
void
|
||||
scan_relocatable_relocs(
|
||||
const General_options&,
|
||||
Symbol_table*,
|
||||
Layout*,
|
||||
Sized_relobj<size, big_endian>* object,
|
||||
unsigned int data_shndx,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
bool needs_special_offset_handling,
|
||||
size_t local_symbol_count,
|
||||
const unsigned char* plocal_syms,
|
||||
Relocatable_relocs* rr)
|
||||
{
|
||||
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
|
||||
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
|
||||
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
|
||||
Scan_relocatable_reloc scan;
|
||||
|
||||
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
|
||||
{
|
||||
Reltype reloc(prelocs);
|
||||
|
||||
Relocatable_relocs::Reloc_strategy strategy;
|
||||
|
||||
if (needs_special_offset_handling
|
||||
&& !output_section->is_input_address_mapped(object, data_shndx,
|
||||
reloc.get_r_offset()))
|
||||
strategy = Relocatable_relocs::RELOC_DISCARD;
|
||||
else
|
||||
{
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword r_info =
|
||||
reloc.get_r_info();
|
||||
const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
|
||||
const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
|
||||
|
||||
if (r_sym >= local_symbol_count)
|
||||
strategy = scan.global_strategy(r_type, object, r_sym);
|
||||
else
|
||||
{
|
||||
gold_assert(plocal_syms != NULL);
|
||||
typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
|
||||
+ r_sym * sym_size);
|
||||
const unsigned int shndx = lsym.get_st_shndx();
|
||||
if (shndx < elfcpp::SHN_LORESERVE
|
||||
&& shndx != elfcpp::SHN_UNDEF
|
||||
&& !object->is_section_included(lsym.get_st_shndx()))
|
||||
{
|
||||
// RELOC is a relocation against a local symbol
|
||||
// defined in a section we are discarding. Discard
|
||||
// the reloc. FIXME: Should we issue a warning?
|
||||
strategy = Relocatable_relocs::RELOC_DISCARD;
|
||||
}
|
||||
else if (lsym.get_st_type() != elfcpp::STT_SECTION)
|
||||
strategy = scan.local_non_section_strategy(r_type, object);
|
||||
else
|
||||
{
|
||||
strategy = scan.local_section_strategy(r_type, object);
|
||||
if (strategy != Relocatable_relocs::RELOC_DISCARD)
|
||||
{
|
||||
section_offset_type dummy;
|
||||
Output_section* os = object->output_section(shndx,
|
||||
&dummy);
|
||||
os->set_needs_symtab_index();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rr->set_next_reloc_strategy(strategy);
|
||||
}
|
||||
}
|
||||
|
||||
// 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>
|
||||
void
|
||||
relocate_for_relocatable(
|
||||
const Relocate_info<size, big_endian>* relinfo,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
off_t offset_in_output_section,
|
||||
const Relocatable_relocs* rr,
|
||||
unsigned char* view,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr,
|
||||
section_size_type,
|
||||
unsigned char* reloc_view,
|
||||
section_size_type reloc_view_size)
|
||||
{
|
||||
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
|
||||
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc_write
|
||||
Reltype_write;
|
||||
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
|
||||
|
||||
Sized_relobj<size, big_endian>* const object = relinfo->object;
|
||||
const unsigned int local_count = object->local_symbol_count();
|
||||
|
||||
unsigned char* pwrite = reloc_view;
|
||||
|
||||
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
|
||||
{
|
||||
Relocatable_relocs::Reloc_strategy strategy = rr->strategy(i);
|
||||
if (strategy == Relocatable_relocs::RELOC_DISCARD)
|
||||
continue;
|
||||
|
||||
Reltype reloc(prelocs);
|
||||
Reltype_write reloc_write(pwrite);
|
||||
|
||||
typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
|
||||
const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
|
||||
const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
|
||||
|
||||
// Get the new symbol index.
|
||||
|
||||
unsigned int new_symndx;
|
||||
if (r_sym < local_count)
|
||||
{
|
||||
switch (strategy)
|
||||
{
|
||||
case Relocatable_relocs::RELOC_COPY:
|
||||
new_symndx = object->symtab_index(r_sym);
|
||||
gold_assert(new_symndx != -1U);
|
||||
break;
|
||||
|
||||
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA:
|
||||
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1:
|
||||
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2:
|
||||
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4:
|
||||
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_8:
|
||||
{
|
||||
// We are adjusting a section symbol. We need to find
|
||||
// the symbol table index of the section symbol for
|
||||
// the output section corresponding to input section
|
||||
// in which this symbol is defined.
|
||||
gold_assert(r_sym < local_count);
|
||||
unsigned int shndx = object->local_symbol_input_shndx(r_sym);
|
||||
section_offset_type dummy;
|
||||
Output_section* os = object->output_section(shndx, &dummy);
|
||||
gold_assert(os != NULL);
|
||||
gold_assert(os->needs_symtab_index());
|
||||
new_symndx = os->symtab_index();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const Symbol* gsym = object->global_symbol(r_sym);
|
||||
gold_assert(gsym != NULL);
|
||||
if (gsym->is_forwarder())
|
||||
gsym = relinfo->symtab->resolve_forwards(gsym);
|
||||
|
||||
gold_assert(gsym->has_symtab_index());
|
||||
new_symndx = gsym->symtab_index();
|
||||
}
|
||||
|
||||
// Get the new offset--the location in the output section where
|
||||
// this relocation should be applied.
|
||||
|
||||
off_t offset = reloc.get_r_offset();
|
||||
off_t new_offset;
|
||||
if (offset_in_output_section != -1)
|
||||
new_offset = offset + offset_in_output_section;
|
||||
else
|
||||
{
|
||||
new_offset = output_section->output_offset(object,
|
||||
relinfo->data_shndx,
|
||||
offset);
|
||||
gold_assert(new_offset != -1);
|
||||
}
|
||||
|
||||
reloc_write.put_r_offset(new_offset);
|
||||
reloc_write.put_r_info(elfcpp::elf_r_info<size>(new_symndx, r_type));
|
||||
|
||||
// Handle the reloc addend based on the strategy.
|
||||
|
||||
if (strategy == Relocatable_relocs::RELOC_COPY)
|
||||
{
|
||||
if (sh_type == elfcpp::SHT_RELA)
|
||||
Reloc_types<sh_type, size, big_endian>::
|
||||
copy_reloc_addend(&reloc_write,
|
||||
&reloc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The relocation uses a section symbol in the input file.
|
||||
// We are adjusting it to use a section symbol in the output
|
||||
// file. The input section symbol refers to some address in
|
||||
// the input section. We need the relocation in the output
|
||||
// file to refer to that same address. This adjustment to
|
||||
// the addend is the same calculation we use for a simple
|
||||
// absolute relocation for the input section symbol.
|
||||
|
||||
const Symbol_value<size>* psymval = object->local_symbol(r_sym);
|
||||
|
||||
unsigned char* padd = view + offset;
|
||||
switch (strategy)
|
||||
{
|
||||
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA:
|
||||
{
|
||||
typename elfcpp::Elf_types<size>::Elf_Swxword addend;
|
||||
addend = Reloc_types<sh_type, size, big_endian>::
|
||||
get_reloc_addend(&reloc);
|
||||
addend = psymval->value(object, addend);
|
||||
Reloc_types<sh_type, size, big_endian>::
|
||||
set_reloc_addend(&reloc_write, addend);
|
||||
}
|
||||
break;
|
||||
|
||||
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_1:
|
||||
Relocate_functions<size, big_endian>::rel8(padd, object,
|
||||
psymval);
|
||||
break;
|
||||
|
||||
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_2:
|
||||
Relocate_functions<size, big_endian>::rel16(padd, object,
|
||||
psymval);
|
||||
break;
|
||||
|
||||
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4:
|
||||
Relocate_functions<size, big_endian>::rel32(padd, object,
|
||||
psymval);
|
||||
break;
|
||||
|
||||
case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_8:
|
||||
Relocate_functions<size, big_endian>::rel64(padd, object,
|
||||
psymval);
|
||||
break;
|
||||
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
pwrite += reloc_size;
|
||||
}
|
||||
|
||||
gold_assert(static_cast<section_size_type>(pwrite - reloc_view)
|
||||
== reloc_view_size);
|
||||
}
|
||||
|
||||
} // End namespace gold.
|
||||
|
||||
#endif // !defined(GOLD_TARGET_RELOC_H)
|
||||
|
|
|
@ -42,6 +42,7 @@ class General_options;
|
|||
class Object;
|
||||
template<int size, bool big_endian>
|
||||
class Sized_relobj;
|
||||
class Relocatable_relocs;
|
||||
template<int size, bool big_endian>
|
||||
class Relocate_info;
|
||||
class Symbol;
|
||||
|
@ -281,6 +282,42 @@ class Sized_target : public Target
|
|||
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
|
||||
section_size_type view_size) = 0;
|
||||
|
||||
// Scan the relocs during a relocatable link. The parameters are
|
||||
// like scan_relocs, with an additional Relocatable_relocs
|
||||
// parameter, used to record the disposition of the relocs.
|
||||
virtual void
|
||||
scan_relocatable_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_relobj<size, big_endian>* object,
|
||||
unsigned int data_shndx,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
bool needs_special_offset_handling,
|
||||
size_t local_symbol_count,
|
||||
const unsigned char* plocal_symbols,
|
||||
Relocatable_relocs*) = 0;
|
||||
|
||||
// Relocate a section during a relocatable link. The parameters are
|
||||
// like relocate_section, with additional parameters for the view of
|
||||
// the output reloc section.
|
||||
virtual void
|
||||
relocate_for_relocatable(const Relocate_info<size, big_endian>*,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
off_t offset_in_output_section,
|
||||
const Relocatable_relocs*,
|
||||
unsigned char* view,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr
|
||||
view_address,
|
||||
section_size_type view_size,
|
||||
unsigned char* reloc_view,
|
||||
section_size_type reloc_view_size) = 0;
|
||||
|
||||
protected:
|
||||
Sized_target(const Target::Target_info* pti)
|
||||
: Target(pti)
|
||||
|
|
|
@ -197,6 +197,15 @@ two_file_separate_shared_21_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
|
|||
two_file_separate_shared_21_test_LDADD = \
|
||||
two_file_shared_2.so two_file_shared_1.so
|
||||
|
||||
check_PROGRAMS += two_file_relocatable_test
|
||||
two_file_relocatable_test_SOURCES = two_file_test_main.cc
|
||||
two_file_relocatable_test_DEPENDENCIES = \
|
||||
gcctestdir/ld two_file_relocatable.o
|
||||
two_file_relocatable_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
|
||||
two_file_relocatable_test_LDADD = two_file_relocatable.o
|
||||
two_file_relocatable.o: gcctestdir/ld two_file_test_1.o two_file_test_1b.o two_file_test_2.o
|
||||
gcctestdir/ld -r -o $@ two_file_test_1.o two_file_test_1b.o two_file_test_2.o
|
||||
|
||||
# The nonpic tests will fail on platforms which can not put non-PIC
|
||||
# code into shared libraries, so we just don't run them in that case.
|
||||
if FN_PTRS_IN_SO_WITHOUT_PIC
|
||||
|
|
|
@ -60,7 +60,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) $(am__EXEEXT_1) \
|
|||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_pic_1_test \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_test \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_test \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_test
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_test \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test
|
||||
@GCC_FALSE@constructor_test_DEPENDENCIES = libgoldtest.a ../libgold.a \
|
||||
@GCC_FALSE@ ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \
|
||||
@GCC_FALSE@ $(am__DEPENDENCIES_1)
|
||||
|
@ -233,7 +234,8 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
|
|||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_pic_1_test$(EXEEXT) \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_test$(EXEEXT) \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_12_test$(EXEEXT) \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_test$(EXEEXT)
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_separate_shared_21_test$(EXEEXT) \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_relocatable_test$(EXEEXT)
|
||||
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_2 = two_file_shared_1_nonpic_test$(EXEEXT) \
|
||||
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_nonpic_test$(EXEEXT) \
|
||||
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_same_shared_nonpic_test$(EXEEXT) \
|
||||
|
@ -444,6 +446,11 @@ am__two_file_pic_test_SOURCES_DIST = two_file_test_main.cc
|
|||
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_pic_test_OBJECTS = \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
|
||||
two_file_pic_test_OBJECTS = $(am_two_file_pic_test_OBJECTS)
|
||||
am__two_file_relocatable_test_SOURCES_DIST = two_file_test_main.cc
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_relocatable_test_OBJECTS = \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_main.$(OBJEXT)
|
||||
two_file_relocatable_test_OBJECTS = \
|
||||
$(am_two_file_relocatable_test_OBJECTS)
|
||||
am__two_file_same_shared_nonpic_test_SOURCES_DIST = \
|
||||
two_file_test_main.cc
|
||||
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_two_file_same_shared_nonpic_test_OBJECTS = two_file_test_main.$(OBJEXT)
|
||||
|
@ -574,6 +581,7 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
|
|||
$(tls_test_SOURCES) $(two_file_mixed_2_shared_test_SOURCES) \
|
||||
$(two_file_mixed_shared_test_SOURCES) \
|
||||
$(two_file_pic_test_SOURCES) \
|
||||
$(two_file_relocatable_test_SOURCES) \
|
||||
$(two_file_same_shared_nonpic_test_SOURCES) \
|
||||
$(two_file_same_shared_test_SOURCES) \
|
||||
$(two_file_separate_shared_12_nonpic_test_SOURCES) \
|
||||
|
@ -613,6 +621,7 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \
|
|||
$(am__two_file_mixed_2_shared_test_SOURCES_DIST) \
|
||||
$(am__two_file_mixed_shared_test_SOURCES_DIST) \
|
||||
$(am__two_file_pic_test_SOURCES_DIST) \
|
||||
$(am__two_file_relocatable_test_SOURCES_DIST) \
|
||||
$(am__two_file_same_shared_nonpic_test_SOURCES_DIST) \
|
||||
$(am__two_file_same_shared_test_SOURCES_DIST) \
|
||||
$(am__two_file_separate_shared_12_nonpic_test_SOURCES_DIST) \
|
||||
|
@ -866,6 +875,12 @@ object_unittest_SOURCES = object_unittest.cc
|
|||
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_separate_shared_21_test_LDADD = \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2.so two_file_shared_1.so
|
||||
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_SOURCES = two_file_test_main.cc
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_DEPENDENCIES = \
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld two_file_relocatable.o
|
||||
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable_test_LDADD = two_file_relocatable.o
|
||||
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic_test_SOURCES = \
|
||||
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test_2.cc two_file_test_main.cc
|
||||
|
||||
|
@ -1152,6 +1167,9 @@ two_file_mixed_shared_test$(EXEEXT): $(two_file_mixed_shared_test_OBJECTS) $(two
|
|||
two_file_pic_test$(EXEEXT): $(two_file_pic_test_OBJECTS) $(two_file_pic_test_DEPENDENCIES)
|
||||
@rm -f two_file_pic_test$(EXEEXT)
|
||||
$(CXXLINK) $(two_file_pic_test_LDFLAGS) $(two_file_pic_test_OBJECTS) $(two_file_pic_test_LDADD) $(LIBS)
|
||||
two_file_relocatable_test$(EXEEXT): $(two_file_relocatable_test_OBJECTS) $(two_file_relocatable_test_DEPENDENCIES)
|
||||
@rm -f two_file_relocatable_test$(EXEEXT)
|
||||
$(CXXLINK) $(two_file_relocatable_test_LDFLAGS) $(two_file_relocatable_test_OBJECTS) $(two_file_relocatable_test_LDADD) $(LIBS)
|
||||
two_file_same_shared_nonpic_test$(EXEEXT): $(two_file_same_shared_nonpic_test_OBJECTS) $(two_file_same_shared_nonpic_test_DEPENDENCIES)
|
||||
@rm -f two_file_same_shared_nonpic_test$(EXEEXT)
|
||||
$(CXXLINK) $(two_file_same_shared_nonpic_test_LDFLAGS) $(two_file_same_shared_nonpic_test_OBJECTS) $(two_file_same_shared_nonpic_test_LDADD) $(LIBS)
|
||||
|
@ -1557,6 +1575,8 @@ uninstall-am: uninstall-info-am
|
|||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2_pic.o
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared.so: two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o gcctestdir/ld
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_1b_pic.o two_file_test_2_pic.o
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_relocatable.o: gcctestdir/ld two_file_test_1.o two_file_test_1b.o two_file_test_2.o
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -r -o $@ two_file_test_1.o two_file_test_1b.o two_file_test_2.o
|
||||
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic.so: two_file_test_1.o gcctestdir/ld
|
||||
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_1b.o
|
||||
@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic.so: two_file_test_2.o gcctestdir/ld
|
||||
|
|
|
@ -57,6 +57,24 @@ class Target_test : public Sized_target<size, big_endian>
|
|||
section_size_type)
|
||||
{ ERROR("call to Target_test::relocate_section"); }
|
||||
|
||||
void
|
||||
scan_relocatable_relocs(const General_options&, Symbol_table*, Layout*,
|
||||
Sized_relobj<size, big_endian>*, unsigned int,
|
||||
unsigned int, const unsigned char*,
|
||||
size_t, Output_section*, bool, size_t,
|
||||
const unsigned char*, Relocatable_relocs*)
|
||||
{ ERROR("call to Target_test::scan_relocatable_relocs"); }
|
||||
|
||||
void
|
||||
relocate_for_relocatable(const Relocate_info<size, big_endian>*,
|
||||
unsigned int, const unsigned char*, size_t,
|
||||
Output_section*, off_t, const Relocatable_relocs*,
|
||||
unsigned char*,
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr,
|
||||
section_size_type, unsigned char*,
|
||||
section_size_type)
|
||||
{ ERROR("call to Target_test::relocate_for_relocatable"); }
|
||||
|
||||
static const Target::Target_info test_target_info;
|
||||
};
|
||||
|
||||
|
|
180
gold/x86_64.cc
180
gold/x86_64.cc
|
@ -109,6 +109,37 @@ class Target_x86_64 : public Sized_target<64, false>
|
|||
elfcpp::Elf_types<64>::Elf_Addr view_address,
|
||||
section_size_type view_size);
|
||||
|
||||
// Scan the relocs during a relocatable link.
|
||||
void
|
||||
scan_relocatable_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_relobj<64, false>* object,
|
||||
unsigned int data_shndx,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
bool needs_special_offset_handling,
|
||||
size_t local_symbol_count,
|
||||
const unsigned char* plocal_symbols,
|
||||
Relocatable_relocs*);
|
||||
|
||||
// Relocate a section during a relocatable link.
|
||||
void
|
||||
relocate_for_relocatable(const Relocate_info<64, false>*,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
off_t offset_in_output_section,
|
||||
const Relocatable_relocs*,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<64>::Elf_Addr view_address,
|
||||
section_size_type view_size,
|
||||
unsigned char* reloc_view,
|
||||
section_size_type reloc_view_size);
|
||||
|
||||
// Return a string used to fill a code section with nops.
|
||||
std::string
|
||||
do_code_fill(section_size_type length);
|
||||
|
@ -234,6 +265,15 @@ class Target_x86_64 : public Sized_target<64, false>
|
|||
bool skip_call_tls_get_addr_;
|
||||
};
|
||||
|
||||
// A class which returns the size required for a relocation type,
|
||||
// used while scanning relocs during a relocatable link.
|
||||
class Relocatable_size_for_reloc
|
||||
{
|
||||
public:
|
||||
unsigned int
|
||||
get_size_for_reloc(unsigned int, Relobj*);
|
||||
};
|
||||
|
||||
// Adjust TLS relocation type based on the options and whether this
|
||||
// is a local symbol.
|
||||
static tls::Tls_optimization
|
||||
|
@ -1941,6 +1981,146 @@ Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
|
|||
view_size);
|
||||
}
|
||||
|
||||
// Return the size of a relocation while scanning during a relocatable
|
||||
// link.
|
||||
|
||||
unsigned int
|
||||
Target_x86_64::Relocatable_size_for_reloc::get_size_for_reloc(
|
||||
unsigned int r_type,
|
||||
Relobj* object)
|
||||
{
|
||||
switch (r_type)
|
||||
{
|
||||
case elfcpp::R_X86_64_NONE:
|
||||
case elfcpp::R_386_GNU_VTINHERIT:
|
||||
case elfcpp::R_386_GNU_VTENTRY:
|
||||
case elfcpp::R_X86_64_TLSGD: // Global-dynamic
|
||||
case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
|
||||
case elfcpp::R_X86_64_TLSDESC_CALL:
|
||||
case elfcpp::R_X86_64_TLSLD: // Local-dynamic
|
||||
case elfcpp::R_X86_64_DTPOFF32:
|
||||
case elfcpp::R_X86_64_DTPOFF64:
|
||||
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
|
||||
case elfcpp::R_X86_64_TPOFF32: // Local-exec
|
||||
return 0;
|
||||
|
||||
case elfcpp::R_X86_64_64:
|
||||
case elfcpp::R_X86_64_PC64:
|
||||
case elfcpp::R_X86_64_GOTOFF64:
|
||||
case elfcpp::R_X86_64_GOTPC64:
|
||||
case elfcpp::R_X86_64_PLTOFF64:
|
||||
case elfcpp::R_X86_64_GOT64:
|
||||
case elfcpp::R_X86_64_GOTPCREL64:
|
||||
case elfcpp::R_X86_64_GOTPCREL:
|
||||
case elfcpp::R_X86_64_GOTPLT64:
|
||||
return 8;
|
||||
|
||||
case elfcpp::R_X86_64_32:
|
||||
case elfcpp::R_X86_64_32S:
|
||||
case elfcpp::R_X86_64_PC32:
|
||||
case elfcpp::R_X86_64_PLT32:
|
||||
case elfcpp::R_X86_64_GOTPC32:
|
||||
case elfcpp::R_X86_64_GOT32:
|
||||
return 4;
|
||||
|
||||
case elfcpp::R_X86_64_16:
|
||||
case elfcpp::R_X86_64_PC16:
|
||||
return 2;
|
||||
|
||||
case elfcpp::R_X86_64_8:
|
||||
case elfcpp::R_X86_64_PC8:
|
||||
return 1;
|
||||
|
||||
case elfcpp::R_X86_64_COPY:
|
||||
case elfcpp::R_X86_64_GLOB_DAT:
|
||||
case elfcpp::R_X86_64_JUMP_SLOT:
|
||||
case elfcpp::R_X86_64_RELATIVE:
|
||||
// These are outstanding tls relocs, which are unexpected when linking
|
||||
case elfcpp::R_X86_64_TPOFF64:
|
||||
case elfcpp::R_X86_64_DTPMOD64:
|
||||
case elfcpp::R_X86_64_TLSDESC:
|
||||
object->error(_("unexpected reloc %u in object file"), r_type);
|
||||
return 0;
|
||||
|
||||
case elfcpp::R_X86_64_SIZE32:
|
||||
case elfcpp::R_X86_64_SIZE64:
|
||||
default:
|
||||
object->error(_("unsupported reloc %u against local symbol"), r_type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the relocs during a relocatable link.
|
||||
|
||||
void
|
||||
Target_x86_64::scan_relocatable_relocs(const General_options& options,
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_relobj<64, false>* object,
|
||||
unsigned int data_shndx,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
bool needs_special_offset_handling,
|
||||
size_t local_symbol_count,
|
||||
const unsigned char* plocal_symbols,
|
||||
Relocatable_relocs* rr)
|
||||
{
|
||||
gold_assert(sh_type == elfcpp::SHT_RELA);
|
||||
|
||||
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,
|
||||
Scan_relocatable_relocs>(
|
||||
options,
|
||||
symtab,
|
||||
layout,
|
||||
object,
|
||||
data_shndx,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
output_section,
|
||||
needs_special_offset_handling,
|
||||
local_symbol_count,
|
||||
plocal_symbols,
|
||||
rr);
|
||||
}
|
||||
|
||||
// Relocate a section during a relocatable link.
|
||||
|
||||
void
|
||||
Target_x86_64::relocate_for_relocatable(
|
||||
const Relocate_info<64, false>* relinfo,
|
||||
unsigned int sh_type,
|
||||
const unsigned char* prelocs,
|
||||
size_t reloc_count,
|
||||
Output_section* output_section,
|
||||
off_t offset_in_output_section,
|
||||
const Relocatable_relocs* rr,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<64>::Elf_Addr view_address,
|
||||
section_size_type view_size,
|
||||
unsigned char* reloc_view,
|
||||
section_size_type reloc_view_size)
|
||||
{
|
||||
gold_assert(sh_type == elfcpp::SHT_RELA);
|
||||
|
||||
gold::relocate_for_relocatable<64, false, Target_x86_64, elfcpp::SHT_RELA>(
|
||||
relinfo,
|
||||
prelocs,
|
||||
reloc_count,
|
||||
output_section,
|
||||
offset_in_output_section,
|
||||
rr,
|
||||
view,
|
||||
view_address,
|
||||
view_size,
|
||||
reloc_view,
|
||||
reloc_view_size);
|
||||
}
|
||||
|
||||
// Return the value to use for a dynamic which requires special
|
||||
// treatment. This is how we support equality comparisons of function
|
||||
// pointers across shared library boundaries, as described in the
|
||||
|
|
Loading…
Reference in a new issue