binutils-gdb/gold/target-reloc.h
Ian Lance Taylor d491d34e93 * object.cc (Xindex::initialize_symtab_xindex): New function.
(Xindex::read_symtab_xindex): New function.
	(Xindex::sym_xindex_to_shndx): New function.
	(Sized_relobj::find_symtab): Pick up SHT_SYMTAB_SHNDX section if
	available.
	(Sized_relobj::do_initialize_xindex): New function.
	(Sized_relobj::do_read_symbols): Adjust section links.
	(Sized_relobj::symbol_section_and_value): Add is_ordinary
	parameter.  Change all callers.
	(Sized_relobj::include_section_group): Adjust section links and
	symbol section indexes.
	(Sized_relobj::do_layout): Adjust section links.
	(Sized_relobj::do_count_local_symbols): Adjust section links and
	symbol section indexes.
	(Sized_relobj::do_finalize_local_symbols): Distinguish between
	ordinary and special symbols.
	(Sized_relobj::write_local_symbols): Add symtab_xindex and
	dynsym_xindex parameters.  Change all callers.  Adjust section
	links.  Use SHN_XINDEX when needed.
	(Sized_relobj::get_symbol_location_info): Adjust section links.
	Don't get fooled by special symbols.
	* object.h (class Xindex): Define.
	(class Object): Add xindex_ parameter.  Declare virtual functoin
	do_initialize_xindex.
	(Object::adjust_sym_shndx): New function.
	(Object::set_xindex): New protected function.
	(class Symbol_value): Add is_ordinary_shndx_ field.
	(Symbol_value::Symbol_value): Initialize is_ordinary_shndx_.
	(Symbol_value::value): Assert ordinary section.
	(Symbol_value::initialize_input_to_output_map): Likewise.
	(Symbol_value::set_input_shndx): Add is_ordinary parameter.
	Change all callers.
	(Symbol_value::input_shndx): Add is_ordinary parameter.  Change
	all callers.
	(class Sized_relobj): Update declarations.
	(Sized_relobj::local_symbol_input_shndx): Add is_ordinary
	parameter.  Change all callers.
	(Sized_relobj::adjust_shndx): New function.
	* dynobj.cc (Sized_dynobj::Sized_dynobj): Initialize dynsym_shndx_
	field.
	(Sized_dynobj::find_dynsym_sections): Remove pdynsym_shndx
	parameter.  Change all callers.  Pick up SHT_DYNSYM_SHNDX section
	for SHT_DYNSYM section if available.  Set dynsym_shndx_ field.
	(Sized_dynobj::read_dynsym_section): Adjust section links.
	(Sized_dynobj::read_dynamic): Likewise.
	(Sized_dynobj::do_read_symbols): Use dynsym_shndx_ field.  Adjust
	section links.
	(Sized_dynobj::do_initialize_xindex): New function.
	* dynobj.h (class Sized_dynobj): Add dynsym_shndx_ field.  Declare
	do_initialize_xindex.
	(Sized_dynobj::adjust_shndx): New function.
	* layout.cc (Layout::Layout): Initialize symtab_xindex_ and
	dynsym_xindex_ fields.
	(Layout::finalize): Add a call to set_section_indexes before
	creating the symtab sections.
	(Layout::set_section_indexes): Don't do anything if the section
	already has a section index.
	(Layout::create_symtab_sections): Add shnum parameter.  Change
	caller.  Create .symtab_shndx section if needed.
	(Layout::create_shdrs): Add shstrtab_section parameter.  Change
	caller.
	(Layout::allocated_output_section_count): New function.
	(Layout::create_dynamic_symtab): Create .dynsym_shndx section if
	needed.
	* layout.h (class Layout): Add symtab_xindex_ and dynsym_xindex_
	fields.  Update declarations.
	(Layout::symtab_xindex): New function.
	(Layout::dynsym_xindex): New function.
	(class Write_symbols_task): Add layout_ field.
	(Write_symbols_task::Write_symbols_task): Add layout parameter.
	Change caller.
	* output.cc (Output_section_headers::Output_section_headers): Add
	shstrtab_section parameter.  Change all callers.
	(Output_section_headers::do_sized_write): Store overflow values
	for section count and section string table section index in
	section header zero.
	(Output_file_header::do_sized_write): Check for overflow of
	section count and section string table section index.
	(Output_symtab_xindex::do_write): New function.
	(Output_symtab_xindex::endian_do_write): New function.
	* output.h (class Output_section_headers): Add shstrtab_section_.
	Update declarations.
	(class Output_symtab_xindex): Define.
	(Output_section::has_out_shndx): New function.
	* symtab.cc (Symbol::init_fields): Initialize is_ordinary_shndx_
	field.
	(Symbol::init_base): Add st_shndx and is_ordinary parameters.
	Change all callers.
	(Sized_symbol::init): Likewise.
	(Symbol::output_section): Check for ordinary symbol.
	(Symbol_table::add_from_object): Remove orig_sym parameter.  Add
	st_shndx, is_ordinary, and orig_st_shndx parameters.  Change all
	callers.
	(Symbol_table::add_from_relobj): Add symndx_offset parameter.
	Change all callers.  Simplify handling of symbols from sections
	not included in the link.
	(Symbol_table::add_from_dynobj): Handle ordinary symbol
	distinction.
	(Weak_alias_sorter::operator()): Assert that symbols are
	ordinary.
	(Symbol_table::sized_finalize_symbol): Handle ordinary symbol
	distinction.
	(Symbol_table::write_globals): Add symtab_xindex and dynsym_xindex
	parameters.  Change all callers.
	(Symbol_table::sized_write_globals): Likewise.  Handle ordinary
	symbol distinction.  Use SHN_XINDEX when needed.
	(Symbol_table::write_section_symbol): Add symtab_xindex
	parameter.  Change all callers.
	(Symbol_table::sized_write_section_symbol): Likewise.  Use
	SHN_XINDEX when needed.
	* symtab.h (class Symbol): Add is_ordinary_shndx_ field.  Update
	declarations.
	(Symbol::shndx): Add is_ordinary parameter.  Change all callers.
	(Symbol::is_defined): Check is_ordinary.
	(Symbol::is_undefined, Symbol::is_weak_undefined): Likewise.
	(Symbol::is_absolute, Symbol::is_common): Likewise.
	(class Sized_symbol): Update declarations.
	(class Symbol_table): Update declarations.
	* resolve.cc (Symbol::override_base): Add st_shndx and is_ordinary
	parameters.  Change all callers.
	(Sized_symbol::override): Likewise.
	(Symbol_table::override): Likewise.
	(symbol_to_bits): Add is_ordinary parameter.  Change all callers.
	(Symbol_table::resolve): Remove orig_sym parameter.  Add st_shndx,
	is_ordinary, and orig_st_shndx parameters.  Change all callers.
	* copy-relocs.cc (Copy_relocs::emit_copy_reloc): Require symbol
	to be in an ordinary section.
	* dwarf_reader.cc (Sized_dwarf_line_info::symbol_section): Add
	object and is_ordinary parameters.  Change all callers.
	(Sized_dwarf_line_info::read_relocs): Add object parameter.
	Change all callers.  Don't add undefined or non-ordinary symbols
	to reloc_map_.
	(Sized_dwarf_line_info::read_line_mappings): Add object parameter.
	Change all callers.
	* dwarf_reader.h (class Sized_dwarf_line_info): Update
	declarations.
	* ehframe.cc (Eh_frame::read_fde): Check for ordinary symbol.
	* reloc.cc (Sized_relobj::do_read_relocs): Adjust section links.
	(Sized_relobj::relocate_sections): Likewise.
	* target-reloc.h (scan_relocs): Adjust section symbol index.
	(scan_relocatable_relocs): Likewise.
	* i386.cc (Scan::local): Check for ordinary symbols.
	* sparc.cc (Scan::local): Likewise.
	* x86_64.cc (Scan::local): Likewise.
	* testsuite/binary_unittest.cc (Sized_binary_test): Update calls
	to symbol_section_and_value.
	* testsuite/many_sections_test.cc: New file.
	* testsuite/Makefile.am (BUILT_SOURCES): Define.
	(check_PROGRAMS): Add many_sections_test.
	(many_sections_test_SOURCES): Define.
	(many_sections_test_DEPENDENCIES): Define.
	(many_sections_test_LDFLAGS): Define.
	(BUILT_SOURCES): Add many_sections_define.h.
	(many_sections_define.h): New target.
	(BUILT_SOURCES): Add many_sections_check.h.
	(many_sections_check.h): New target.
	(check_PROGRAMS): Add many_sections_r_test.
	(many_sections_r_test_SOURCES): Define.
	(many_sections_r_test_DEPENDENCIES): Define.
	(many_sections_r_test_LDFLAGS): Define.
	(many_sections_r_test_LDADD): Define.
	(many_sections_r_test.o): New target.
	* testsuite/Makefile.in: Rebuild.
2008-04-19 18:30:58 +00:00

558 lines
18 KiB
C++

// target-reloc.h -- target specific relocation support -*- C++ -*-
// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.
#ifndef GOLD_TARGET_RELOC_H
#define GOLD_TARGET_RELOC_H
#include "elfcpp.h"
#include "symtab.h"
#include "reloc.h"
#include "reloc-types.h"
namespace gold
{
// 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>
inline void
scan_relocs(
const General_options& options,
Symbol_table* symtab,
Layout* layout,
Target_type* target,
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_count,
const unsigned char* plocal_syms)
{
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 scan;
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
{
Reltype reloc(prelocs);
if (needs_special_offset_handling
&& !output_section->is_input_address_mapped(object, data_shndx,
reloc.get_r_offset()))
continue;
typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
if (r_sym < local_count)
{
gold_assert(plocal_syms != NULL);
typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
+ r_sym * sym_size);
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
if (is_ordinary
&& shndx != elfcpp::SHN_UNDEF
&& !object->is_section_included(shndx))
{
// RELOC is a relocation against a local symbol in a
// section we are discarding. We can ignore this
// relocation. It will eventually become a reloc
// against the value zero.
//
// FIXME: We should issue a warning if this is an
// allocated section; is this the best place to do it?
//
// FIXME: The old GNU linker would in some cases look
// for the linkonce section which caused this section to
// be discarded, and, if the other section was the same
// size, change the reloc to refer to the other section.
// That seems risky and weird to me, and I don't know of
// any case where it is actually required.
continue;
}
scan.local(options, symtab, layout, target, object, data_shndx,
output_section, reloc, r_type, lsym);
}
else
{
Symbol* gsym = object->global_symbol(r_sym);
gold_assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = symtab->resolve_forwards(gsym);
scan.global(options, symtab, layout, target, object, data_shndx,
output_section, reloc, r_type, gsym);
}
}
}
// This function implements the generic part of relocation processing.
// 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.
// RELOCATE implements operator() to do a relocation.
// PRELOCS points to the relocation data. RELOC_COUNT is the number
// of relocs. OUTPUT_SECTION is the output section.
// NEEDS_SPECIAL_OFFSET_HANDLING is true if input offsets need to be
// mapped to output offsets.
// VIEW is the section data, VIEW_ADDRESS is its memory address, and
// VIEW_SIZE is the size. These refer to the input section, unless
// NEEDS_SPECIAL_OFFSET_HANDLING is true, in which case they refer to
// the output section.
template<int size, bool big_endian, typename Target_type, int sh_type,
typename Relocate>
inline void
relocate_section(
const Relocate_info<size, big_endian>* relinfo,
Target_type* target,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
bool needs_special_offset_handling,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
section_size_type view_size)
{
typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
Relocate relocate;
Sized_relobj<size, big_endian>* object = relinfo->object;
unsigned int local_count = object->local_symbol_count();
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
{
Reltype reloc(prelocs);
section_offset_type offset =
convert_to_section_size_type(reloc.get_r_offset());
if (needs_special_offset_handling)
{
offset = output_section->output_offset(relinfo->object,
relinfo->data_shndx,
offset);
if (offset == -1)
continue;
}
typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
const Sized_symbol<size>* sym;
Symbol_value<size> symval;
const Symbol_value<size> *psymval;
if (r_sym < local_count)
{
sym = NULL;
psymval = object->local_symbol(r_sym);
}
else
{
const Symbol* gsym = object->global_symbol(r_sym);
gold_assert(gsym != NULL);
if (gsym->is_forwarder())
gsym = relinfo->symtab->resolve_forwards(gsym);
sym = static_cast<const Sized_symbol<size>*>(gsym);
if (sym->has_symtab_index())
symval.set_output_symtab_index(sym->symtab_index());
else
symval.set_no_output_symtab_entry();
symval.set_output_value(sym->value());
psymval = &symval;
}
if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, psymval,
view + offset, view_address + offset, view_size))
continue;
if (offset < 0 || static_cast<section_size_type>(offset) >= view_size)
{
gold_error_at_location(relinfo, i, offset,
_("reloc has bad offset %zu"),
static_cast<size_t>(offset));
continue;
}
if (sym != NULL
&& sym->is_undefined()
&& sym->binding() != elfcpp::STB_WEAK
&& (!parameters->options().shared() // -shared
|| parameters->options().defs())) // -z defs
gold_undefined_symbol(sym, relinfo, i, offset);
if (sym != NULL && sym->has_warning())
relinfo->symtab->issue_warning(sym, relinfo, i, offset);
}
}
// 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_ADJUST_FOR_SECTION_0;
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, 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);
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
if (is_ordinary
&& shndx != elfcpp::SHN_UNDEF
&& !object->is_section_included(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, 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 view_address,
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_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:
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);
bool is_ordinary;
unsigned int shndx =
object->local_symbol_input_shndx(r_sym, &is_ordinary);
gold_assert(is_ordinary);
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);
}
// In an object file, r_offset is an offset within the section.
// In an executable or dynamic object, generated by
// --emit-relocs, r_offset is an absolute address.
if (!parameters->options().relocatable())
new_offset += view_address;
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_0:
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)