binutils-gdb/gold/reloc.h
Cary Coutant b7a4e9d8e6 Fix compile errors about shift counts too large.
In order to get around the optimizer and newer compiler warnings
about shift counts, the overflow checking code had resorted to
some messy shifting, and with the never-before-seen instantiations
of the template functions, we were still running afoul of the
compiler checks.

This patch replaces those messy shift sequences with a simple
class template that provides the min and max limits for any
bit size up to 64, with a specialization for 64 that prevents
the compiler from complaining.

gold/
	PR gold/19577
	* reloc.h (Limits): New class.
	(Bits::has_overflow32): Use min/max values from Limits.
	(Bits::has_unsigned_overflow32): Likewise.
	(Bits::has_signed_unsigned_overflow32): Likewise.
	(Bits::has_overflow): Likewise.
	(Bits::has_unsigned_overflow): Likewise.
	(Bits::has_signed_unsigned_overflow64): Likewise.
2016-02-06 18:19:13 -08:00

1202 lines
38 KiB
C++

// reloc.h -- relocate input files for gold -*- C++ -*-
// Copyright (C) 2006-2016 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_RELOC_H
#define GOLD_RELOC_H
#include <vector>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#endif
#include "elfcpp.h"
#include "workqueue.h"
namespace gold
{
class General_options;
class Object;
class Relobj;
struct Read_relocs_data;
class Symbol;
class Layout;
class Output_data;
class Output_section;
template<int size>
class Sized_symbol;
template<int size, bool big_endian>
class Sized_relobj_file;
template<int size>
class Symbol_value;
template<int sh_type, bool dynamic, int size, bool big_endian>
class Output_data_reloc;
// A class to read the relocations for an object file, and then queue
// up a task to see if they require any GOT/PLT/COPY relocations in
// the symbol table.
class Read_relocs : public Task
{
public:
// THIS_BLOCKER and NEXT_BLOCKER are passed along to a Scan_relocs
// or Gc_process_relocs task, so that they run in a deterministic
// order.
Read_relocs(Symbol_table* symtab, Layout* layout, Relobj* object,
Task_token* this_blocker, Task_token* next_blocker)
: symtab_(symtab), layout_(layout), object_(object),
this_blocker_(this_blocker), next_blocker_(next_blocker)
{ }
// The standard Task methods.
Task_token*
is_runnable();
void
locks(Task_locker*);
void
run(Workqueue*);
std::string
get_name() const;
private:
Symbol_table* symtab_;
Layout* layout_;
Relobj* object_;
Task_token* this_blocker_;
Task_token* next_blocker_;
};
// Process the relocs to figure out which sections are garbage.
// Very similar to scan relocs.
class Gc_process_relocs : public Task
{
public:
// THIS_BLOCKER prevents this task from running until the previous
// one is finished. NEXT_BLOCKER prevents the next task from
// running.
Gc_process_relocs(Symbol_table* symtab, Layout* layout, Relobj* object,
Read_relocs_data* rd, Task_token* this_blocker,
Task_token* next_blocker)
: symtab_(symtab), layout_(layout), object_(object), rd_(rd),
this_blocker_(this_blocker), next_blocker_(next_blocker)
{ }
~Gc_process_relocs();
// The standard Task methods.
Task_token*
is_runnable();
void
locks(Task_locker*);
void
run(Workqueue*);
std::string
get_name() const;
private:
Symbol_table* symtab_;
Layout* layout_;
Relobj* object_;
Read_relocs_data* rd_;
Task_token* this_blocker_;
Task_token* next_blocker_;
};
// Scan the relocations for an object to see if they require any
// GOT/PLT/COPY relocations.
class Scan_relocs : public Task
{
public:
// THIS_BLOCKER prevents this task from running until the previous
// one is finished. NEXT_BLOCKER prevents the next task from
// running.
Scan_relocs(Symbol_table* symtab, Layout* layout, Relobj* object,
Read_relocs_data* rd, Task_token* this_blocker,
Task_token* next_blocker)
: symtab_(symtab), layout_(layout), object_(object), rd_(rd),
this_blocker_(this_blocker), next_blocker_(next_blocker)
{ }
~Scan_relocs();
// The standard Task methods.
Task_token*
is_runnable();
void
locks(Task_locker*);
void
run(Workqueue*);
std::string
get_name() const;
private:
Symbol_table* symtab_;
Layout* layout_;
Relobj* object_;
Read_relocs_data* rd_;
Task_token* this_blocker_;
Task_token* next_blocker_;
};
// A class to perform all the relocations for an object file.
class Relocate_task : public Task
{
public:
Relocate_task(const Symbol_table* symtab, const Layout* layout,
Relobj* object, Output_file* of,
Task_token* input_sections_blocker,
Task_token* output_sections_blocker, Task_token* final_blocker)
: symtab_(symtab), layout_(layout), object_(object), of_(of),
input_sections_blocker_(input_sections_blocker),
output_sections_blocker_(output_sections_blocker),
final_blocker_(final_blocker)
{ }
// The standard Task methods.
Task_token*
is_runnable();
void
locks(Task_locker*);
void
run(Workqueue*);
std::string
get_name() const;
private:
const Symbol_table* symtab_;
const Layout* layout_;
Relobj* object_;
Output_file* of_;
Task_token* input_sections_blocker_;
Task_token* output_sections_blocker_;
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 addend should not be
// adjusted.
RELOC_ADJUST_FOR_SECTION_0,
// Like RELOC_ADJUST_FOR_SECTION_RELA but the contents of the
// section need to be changed. The number indicates the number of
// bytes in the addend in the section contents.
RELOC_ADJUST_FOR_SECTION_1,
RELOC_ADJUST_FOR_SECTION_2,
RELOC_ADJUST_FOR_SECTION_4,
RELOC_ADJUST_FOR_SECTION_8,
// Like RELOC_ADJUST_FOR_SECTION_4 but for unaligned relocs.
RELOC_ADJUST_FOR_SECTION_4_UNALIGNED,
// 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]);
}
// Set the strategy for reloc I.
void
set_strategy(unsigned int i, Reloc_strategy strategy)
{
gold_assert(i < this->reloc_strategies_.size());
this->reloc_strategies_[i] = strategy;
}
// 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_;
};
template<int valsize>
class Bits;
// Standard relocation routines which are used on many targets. Here
// SIZE and BIG_ENDIAN refer to the target, not the relocation type.
template<int size, bool big_endian>
class Relocate_functions
{
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
typedef typename elfcpp::Elf_types<size>::Elf_Swxword Addendtype;
enum Overflow_check
{
// No overflow checking.
CHECK_NONE,
// Check for overflow of a signed value.
CHECK_SIGNED,
// Check for overflow of an unsigned value.
CHECK_UNSIGNED,
// Check for overflow of a signed or unsigned value.
// (i.e., no error if either signed or unsigned fits.)
CHECK_SIGNED_OR_UNSIGNED
};
enum Reloc_status
{
RELOC_OK,
RELOC_OVERFLOW
};
private:
// Check for overflow.
template<int valsize>
static inline Reloc_status
check_overflow(Address value, Overflow_check check)
{
switch (check)
{
case CHECK_SIGNED:
if (size == 32)
return (Bits<valsize>::has_overflow32(value)
? RELOC_OVERFLOW
: RELOC_OK);
else
return (Bits<valsize>::has_overflow(value)
? RELOC_OVERFLOW
: RELOC_OK);
case CHECK_UNSIGNED:
if (size == 32)
return (Bits<valsize>::has_unsigned_overflow32(value)
? RELOC_OVERFLOW
: RELOC_OK);
else
return (Bits<valsize>::has_unsigned_overflow(value)
? RELOC_OVERFLOW
: RELOC_OK);
case CHECK_SIGNED_OR_UNSIGNED:
if (size == 32)
return (Bits<valsize>::has_signed_unsigned_overflow32(value)
? RELOC_OVERFLOW
: RELOC_OK);
else
return (Bits<valsize>::has_signed_unsigned_overflow64(value)
? RELOC_OVERFLOW
: RELOC_OK);
case CHECK_NONE:
default:
return RELOC_OK;
}
}
// Do a simple relocation with the addend in the section contents.
// VALSIZE is the size of the value.
template<int valsize>
static inline Reloc_status
rel(unsigned char* view, Address value, Overflow_check check)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype addend = elfcpp::Swap<valsize, big_endian>::readval(wv);
value += addend;
elfcpp::Swap<valsize, big_endian>::
writeval(wv, static_cast<Valtype>(value));
return check_overflow<valsize>(value, check);
}
// Like the above but for relocs at unaligned addresses.
template<int valsize>
static inline Reloc_status
rel_unaligned(unsigned char* view, Address value, Overflow_check check)
{
typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
Valtype;
Valtype addend = elfcpp::Swap_unaligned<valsize, big_endian>::readval(view);
value += addend;
elfcpp::Swap_unaligned<valsize, big_endian>::
writeval(view, static_cast<Valtype>(value));
return check_overflow<valsize>(value, check);
}
// Do a simple relocation using a Symbol_value with the addend in
// the section contents. VALSIZE is the size of the value to
// relocate.
template<int valsize>
static inline Reloc_status
rel(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Overflow_check check)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype addend = elfcpp::Swap<valsize, big_endian>::readval(wv);
Address value = psymval->value(object, addend);
elfcpp::Swap<valsize, big_endian>::
writeval(wv, static_cast<Valtype>(value));
return check_overflow<valsize>(value, check);
}
// Like the above but for relocs at unaligned addresses.
template<int valsize>
static inline Reloc_status
rel_unaligned(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Overflow_check check)
{
typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
Valtype;
Valtype addend = elfcpp::Swap_unaligned<valsize, big_endian>::readval(view);
Address value = psymval->value(object, addend);
elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, value);
return check_overflow<valsize>(value, check);
}
// Do a simple relocation with the addend in the relocation.
// VALSIZE is the size of the value.
template<int valsize>
static inline Reloc_status
rela(unsigned char* view, Address value, Addendtype addend,
Overflow_check check)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
value += addend;
elfcpp::Swap<valsize, big_endian>::writeval(wv, value);
return check_overflow<valsize>(value, check);
}
// Do a simple relocation using a symbol value with the addend in
// the relocation. VALSIZE is the size of the value.
template<int valsize>
static inline Reloc_status
rela(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Overflow_check check)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Address value = psymval->value(object, addend);
elfcpp::Swap<valsize, big_endian>::writeval(wv, value);
return check_overflow<valsize>(value, check);
}
// Do a simple PC relative relocation with the addend in the section
// contents. VALSIZE is the size of the value.
template<int valsize>
static inline Reloc_status
pcrel(unsigned char* view, Address value, Address address,
Overflow_check check)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype addend = elfcpp::Swap<valsize, big_endian>::readval(wv);
value = value + addend - address;
elfcpp::Swap<valsize, big_endian>::writeval(wv, value);
return check_overflow<valsize>(value, check);
}
// Like the above but for relocs at unaligned addresses.
template<int valsize>
static inline Reloc_status
pcrel_unaligned(unsigned char* view, Address value, Address address,
Overflow_check check)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype addend = elfcpp::Swap_unaligned<valsize, big_endian>::readval(view);
value = value + addend - address;
elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, value);
return check_overflow<valsize>(value, check);
}
// Do a simple PC relative relocation with a Symbol_value with the
// addend in the section contents. VALSIZE is the size of the
// value.
template<int valsize>
static inline Reloc_status
pcrel(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Address address,
Overflow_check check)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype addend = elfcpp::Swap<valsize, big_endian>::readval(wv);
Address value = psymval->value(object, addend) - address;
elfcpp::Swap<valsize, big_endian>::writeval(wv, value);
return check_overflow<valsize>(value, check);
}
// Do a simple PC relative relocation with the addend in the
// relocation. VALSIZE is the size of the value.
template<int valsize>
static inline Reloc_status
pcrela(unsigned char* view, Address value, Addendtype addend, Address address,
Overflow_check check)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
value = value + addend - address;
elfcpp::Swap<valsize, big_endian>::writeval(wv, value);
return check_overflow<valsize>(value, check);
}
// Do a simple PC relative relocation with a Symbol_value with the
// addend in the relocation. VALSIZE is the size of the value.
template<int valsize>
static inline Reloc_status
pcrela(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Address address,
Overflow_check check)
{
typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Address value = psymval->value(object, addend) - address;
elfcpp::Swap<valsize, big_endian>::writeval(wv, value);
return check_overflow<valsize>(value, check);
}
typedef Relocate_functions<size, big_endian> This;
public:
// Do a simple 8-bit REL relocation with the addend in the section
// contents.
static inline void
rel8(unsigned char* view, Address value)
{ This::template rel<8>(view, value, CHECK_NONE); }
static inline Reloc_status
rel8_check(unsigned char* view, Address value, Overflow_check check)
{ return This::template rel<8>(view, value, check); }
static inline void
rel8(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval)
{ This::template rel<8>(view, object, psymval, CHECK_NONE); }
static inline Reloc_status
rel8_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Overflow_check check)
{ return This::template rel<8>(view, object, psymval, check); }
// Do an 8-bit RELA relocation with the addend in the relocation.
static inline void
rela8(unsigned char* view, Address value, Addendtype addend)
{ This::template rela<8>(view, value, addend, CHECK_NONE); }
static inline Reloc_status
rela8_check(unsigned char* view, Address value, Addendtype addend,
Overflow_check check)
{ return This::template rela<8>(view, value, addend, check); }
static inline void
rela8(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend)
{ This::template rela<8>(view, object, psymval, addend, CHECK_NONE); }
static inline Reloc_status
rela8_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Overflow_check check)
{ return This::template rela<8>(view, object, psymval, addend, check); }
// Do a simple 8-bit PC relative relocation with the addend in the
// section contents.
static inline void
pcrel8(unsigned char* view, unsigned char value, Address address)
{ This::template pcrel<8>(view, value, address, CHECK_NONE); }
static inline Reloc_status
pcrel8_check(unsigned char* view, unsigned char value, Address address,
Overflow_check check)
{ return This::template pcrel<8>(view, value, address, check); }
static inline void
pcrel8(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Address address)
{ This::template pcrel<8>(view, object, psymval, address, CHECK_NONE); }
static inline Reloc_status
pcrel8_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Address address,
Overflow_check check)
{ return This::template pcrel<8>(view, object, psymval, address, check); }
// Do a simple 8-bit PC relative RELA relocation with the addend in
// the reloc.
static inline void
pcrela8(unsigned char* view, Address value, Addendtype addend,
Address address)
{ This::template pcrela<8>(view, value, addend, address, CHECK_NONE); }
static inline Reloc_status
pcrela8_check(unsigned char* view, Address value, Addendtype addend,
Address address, Overflow_check check)
{ return This::template pcrela<8>(view, value, addend, address, check); }
static inline void
pcrela8(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Address address)
{ This::template pcrela<8>(view, object, psymval, addend, address,
CHECK_NONE); }
static inline Reloc_status
pcrela8_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Address address,
Overflow_check check)
{ return This::template pcrela<8>(view, object, psymval, addend, address,
check); }
// Do a simple 16-bit REL relocation with the addend in the section
// contents.
static inline void
rel16(unsigned char* view, Address value)
{ This::template rel<16>(view, value, CHECK_NONE); }
static inline Reloc_status
rel16_check(unsigned char* view, Address value, Overflow_check check)
{ return This::template rel<16>(view, value, check); }
static inline void
rel16(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval)
{ This::template rel<16>(view, object, psymval, CHECK_NONE); }
static inline Reloc_status
rel16_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Overflow_check check)
{ return This::template rel<16>(view, object, psymval, check); }
// Do an 16-bit RELA relocation with the addend in the relocation.
static inline void
rela16(unsigned char* view, Address value, Addendtype addend)
{ This::template rela<16>(view, value, addend, CHECK_NONE); }
static inline Reloc_status
rela16_check(unsigned char* view, Address value, Addendtype addend,
Overflow_check check)
{ return This::template rela<16>(view, value, addend, check); }
static inline void
rela16(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend)
{ This::template rela<16>(view, object, psymval, addend, CHECK_NONE); }
static inline Reloc_status
rela16_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Overflow_check check)
{ return This::template rela<16>(view, object, psymval, addend, check); }
// Do a simple 16-bit PC relative REL relocation with the addend in
// the section contents.
static inline void
pcrel16(unsigned char* view, Address value, Address address)
{ This::template pcrel<16>(view, value, address, CHECK_NONE); }
static inline Reloc_status
pcrel16_check(unsigned char* view, Address value, Address address,
Overflow_check check)
{ return This::template pcrel<16>(view, value, address, check); }
static inline void
pcrel16(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Address address)
{ This::template pcrel<16>(view, object, psymval, address, CHECK_NONE); }
static inline Reloc_status
pcrel16_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Address address,
Overflow_check check)
{ return This::template pcrel<16>(view, object, psymval, address, check); }
// Do a simple 16-bit PC relative RELA relocation with the addend in
// the reloc.
static inline void
pcrela16(unsigned char* view, Address value, Addendtype addend,
Address address)
{ This::template pcrela<16>(view, value, addend, address, CHECK_NONE); }
static inline Reloc_status
pcrela16_check(unsigned char* view, Address value, Addendtype addend,
Address address, Overflow_check check)
{ return This::template pcrela<16>(view, value, addend, address, check); }
static inline void
pcrela16(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Address address)
{ This::template pcrela<16>(view, object, psymval, addend, address,
CHECK_NONE); }
static inline Reloc_status
pcrela16_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Address address,
Overflow_check check)
{ return This::template pcrela<16>(view, object, psymval, addend, address,
check); }
// Do a simple 32-bit REL relocation with the addend in the section
// contents.
static inline void
rel32(unsigned char* view, Address value)
{ This::template rel<32>(view, value, CHECK_NONE); }
static inline Reloc_status
rel32_check(unsigned char* view, Address value, Overflow_check check)
{ return This::template rel<32>(view, value, check); }
// Like above but for relocs at unaligned addresses.
static inline void
rel32_unaligned(unsigned char* view, Address value)
{ This::template rel_unaligned<32>(view, value, CHECK_NONE); }
static inline Reloc_status
rel32_unaligned_check(unsigned char* view, Address value,
Overflow_check check)
{ return This::template rel_unaligned<32>(view, value, check); }
static inline void
rel32(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval)
{ This::template rel<32>(view, object, psymval, CHECK_NONE); }
static inline Reloc_status
rel32_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Overflow_check check)
{ return This::template rel<32>(view, object, psymval, check); }
// Like above but for relocs at unaligned addresses.
static inline void
rel32_unaligned(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval)
{ This::template rel_unaligned<32>(view, object, psymval, CHECK_NONE); }
static inline Reloc_status
rel32_unaligned_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Overflow_check check)
{ return This::template rel_unaligned<32>(view, object, psymval, check); }
// Do a 32-bit RELA relocation with the addend in the relocation.
static inline void
rela32(unsigned char* view, Address value, Addendtype addend)
{ This::template rela<32>(view, value, addend, CHECK_NONE); }
static inline Reloc_status
rela32(unsigned char* view, Address value, Addendtype addend,
Overflow_check check)
{ return This::template rela<32>(view, value, addend, check); }
static inline void
rela32(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend)
{ This::template rela<32>(view, object, psymval, addend, CHECK_NONE); }
static inline Reloc_status
rela32_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Overflow_check check)
{ return This::template rela<32>(view, object, psymval, addend, check); }
// Do a simple 32-bit PC relative REL relocation with the addend in
// the section contents.
static inline void
pcrel32(unsigned char* view, Address value, Address address)
{ This::template pcrel<32>(view, value, address, CHECK_NONE); }
static inline Reloc_status
pcrel32_check(unsigned char* view, Address value, Address address,
Overflow_check check)
{ return This::template pcrel<32>(view, value, address, check); }
// Unaligned version of the above.
static inline void
pcrel32_unaligned(unsigned char* view, Address value, Address address)
{ This::template pcrel_unaligned<32>(view, value, address, CHECK_NONE); }
static inline Reloc_status
pcrel32_unaligned_check(unsigned char* view, Address value, Address address,
Overflow_check check)
{ return This::template pcrel_unaligned<32>(view, value, address, check); }
static inline void
pcrel32(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Address address)
{ This::template pcrel<32>(view, object, psymval, address, CHECK_NONE); }
static inline Reloc_status
pcrel32_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Address address,
Overflow_check check)
{ return This::template pcrel<32>(view, object, psymval, address, check); }
// Do a simple 32-bit PC relative RELA relocation with the addend in
// the relocation.
static inline void
pcrela32(unsigned char* view, Address value, Addendtype addend,
Address address)
{ This::template pcrela<32>(view, value, addend, address, CHECK_NONE); }
static inline Reloc_status
pcrela32_check(unsigned char* view, Address value, Addendtype addend,
Address address, Overflow_check check)
{ return This::template pcrela<32>(view, value, addend, address, check); }
static inline void
pcrela32(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Address address)
{ This::template pcrela<32>(view, object, psymval, addend, address,
CHECK_NONE); }
static inline Reloc_status
pcrela32_check(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Address address,
Overflow_check check)
{ return This::template pcrela<32>(view, object, psymval, addend, address,
check); }
// Do a simple 64-bit REL relocation with the addend in the section
// contents.
static inline void
rel64(unsigned char* view, Address value)
{ This::template rel<64>(view, value, CHECK_NONE); }
static inline void
rel64(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval)
{ This::template rel<64>(view, object, psymval, CHECK_NONE); }
// Do a 64-bit RELA relocation with the addend in the relocation.
static inline void
rela64(unsigned char* view, Address value, Addendtype addend)
{ This::template rela<64>(view, value, addend, CHECK_NONE); }
static inline void
rela64(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend)
{ This::template rela<64>(view, object, psymval, addend, CHECK_NONE); }
// Do a simple 64-bit PC relative REL relocation with the addend in
// the section contents.
static inline void
pcrel64(unsigned char* view, Address value, Address address)
{ This::template pcrel<64>(view, value, address, CHECK_NONE); }
static inline void
pcrel64(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Address address)
{ This::template pcrel<64>(view, object, psymval, address, CHECK_NONE); }
// Do a simple 64-bit PC relative RELA relocation with the addend in
// the relocation.
static inline void
pcrela64(unsigned char* view, Address value, Addendtype addend,
Address address)
{ This::template pcrela<64>(view, value, addend, address, CHECK_NONE); }
static inline void
pcrela64(unsigned char* view,
const Sized_relobj_file<size, big_endian>* object,
const Symbol_value<size>* psymval,
Addendtype addend,
Address address)
{ This::template pcrela<64>(view, object, psymval, addend, address,
CHECK_NONE); }
};
// Convenience class for min and max values of a given BITS length.
template<int bits>
class Limits
{
public:
static const uint64_t MAX_UNSIGNED = (1ULL << bits) - 1;
static const int64_t MAX_SIGNED = MAX_UNSIGNED >> 1;
static const int64_t MIN_SIGNED = -MAX_SIGNED - 1;
};
template<>
class Limits<64>
{
public:
static const uint64_t MAX_UNSIGNED = ~0ULL;
static const int64_t MAX_SIGNED = MAX_UNSIGNED >> 1;
static const int64_t MIN_SIGNED = -MAX_SIGNED - 1;
};
// Integer manipulation functions used by various targets when
// performing relocations.
template<int bits>
class Bits
{
public:
// Sign extend an n-bit unsigned integer stored in a uint32_t into
// an int32_t. BITS must be between 1 and 32.
static inline int32_t
sign_extend32(uint32_t val)
{
gold_assert(bits > 0 && bits <= 32);
if (bits == 32)
return static_cast<int32_t>(val);
uint32_t mask = (~static_cast<uint32_t>(0)) >> (32 - bits);
val &= mask;
uint32_t top_bit = 1U << (bits - 1);
int32_t as_signed = static_cast<int32_t>(val);
if ((val & top_bit) != 0)
as_signed -= static_cast<int32_t>(top_bit * 2);
return as_signed;
}
// Return true if VAL (stored in a uint32_t) has overflowed a signed
// value with BITS bits.
static inline bool
has_overflow32(uint32_t val)
{
gold_assert(bits > 0 && bits <= 32);
if (bits == 32)
return false;
const int32_t max = static_cast<int32_t>(Limits<bits>::MAX_SIGNED);
const int32_t min = static_cast<int32_t>(Limits<bits>::MIN_SIGNED);
int32_t as_signed = static_cast<int32_t>(val);
return as_signed > max || as_signed < min;
}
// Return true if VAL (stored in a uint32_t) has overflowed an unsigned
// value with BITS bits.
static inline bool
has_unsigned_overflow32(uint32_t val)
{
gold_assert(bits > 0 && bits <= 32);
if (bits == 32)
return false;
const uint32_t max = static_cast<uint32_t>(Limits<bits>::MAX_UNSIGNED);
return val > max;
}
// Return true if VAL (stored in a uint32_t) has overflowed both a
// signed and an unsigned value. E.g.,
// Bits<8>::has_signed_unsigned_overflow32 would check -128 <= VAL <
// 255.
static inline bool
has_signed_unsigned_overflow32(uint32_t val)
{
gold_assert(bits > 0 && bits <= 32);
if (bits == 32)
return false;
const int32_t max = static_cast<int32_t>(Limits<bits>::MAX_UNSIGNED);
const int32_t min = static_cast<int32_t>(Limits<bits>::MIN_SIGNED);
int32_t as_signed = static_cast<int32_t>(val);
return as_signed > max || as_signed < min;
}
// Select bits from A and B using bits in MASK. For each n in
// [0..31], the n-th bit in the result is chosen from the n-th bits
// of A and B. A zero selects A and a one selects B.
static inline uint32_t
bit_select32(uint32_t a, uint32_t b, uint32_t mask)
{ return (a & ~mask) | (b & mask); }
// Sign extend an n-bit unsigned integer stored in a uint64_t into
// an int64_t. BITS must be between 1 and 64.
static inline int64_t
sign_extend(uint64_t val)
{
gold_assert(bits > 0 && bits <= 64);
if (bits == 64)
return static_cast<int64_t>(val);
uint64_t mask = (~static_cast<uint64_t>(0)) >> (64 - bits);
val &= mask;
uint64_t top_bit = static_cast<uint64_t>(1) << (bits - 1);
int64_t as_signed = static_cast<int64_t>(val);
if ((val & top_bit) != 0)
as_signed -= static_cast<int64_t>(top_bit * 2);
return as_signed;
}
// Return true if VAL (stored in a uint64_t) has overflowed a signed
// value with BITS bits.
static inline bool
has_overflow(uint64_t val)
{
gold_assert(bits > 0 && bits <= 64);
if (bits == 64)
return false;
const int64_t max = Limits<bits>::MAX_SIGNED;
const int64_t min = Limits<bits>::MIN_SIGNED;
int64_t as_signed = static_cast<int64_t>(val);
return as_signed > max || as_signed < min;
}
// Return true if VAL (stored in a uint64_t) has overflowed an unsigned
// value with BITS bits.
static inline bool
has_unsigned_overflow(uint64_t val)
{
gold_assert(bits > 0 && bits <= 64);
if (bits == 64)
return false;
const uint64_t max = Limits<bits>::MAX_UNSIGNED;
return val > max;
}
// Return true if VAL (stored in a uint64_t) has overflowed both a
// signed and an unsigned value. E.g.,
// Bits<8>::has_signed_unsigned_overflow would check -128 <= VAL <
// 255.
static inline bool
has_signed_unsigned_overflow64(uint64_t val)
{
gold_assert(bits > 0 && bits <= 64);
if (bits == 64)
return false;
const int64_t max = static_cast<int64_t>(Limits<bits>::MAX_UNSIGNED);
const int64_t min = Limits<bits>::MIN_SIGNED;
int64_t as_signed = static_cast<int64_t>(val);
return as_signed > max || as_signed < min;
}
// Select bits from A and B using bits in MASK. For each n in
// [0..31], the n-th bit in the result is chosen from the n-th bits
// of A and B. A zero selects A and a one selects B.
static inline uint64_t
bit_select64(uint64_t a, uint64_t b, uint64_t mask)
{ return (a & ~mask) | (b & mask); }
};
// Track relocations while reading a section. This lets you ask for
// the relocation at a certain offset, and see how relocs occur
// between points of interest.
template<int size, bool big_endian>
class Track_relocs
{
public:
Track_relocs()
: prelocs_(NULL), len_(0), pos_(0), reloc_size_(0)
{ }
// Initialize the Track_relocs object. OBJECT is the object holding
// the reloc section, RELOC_SHNDX is the section index of the reloc
// section, and RELOC_TYPE is the type of the reloc section
// (elfcpp::SHT_REL or elfcpp::SHT_RELA). This returns false if
// something went wrong.
bool
initialize(Object* object, unsigned int reloc_shndx,
unsigned int reloc_type);
// Return the offset in the data section to which the next reloc
// applies. This returns -1 if there is no next reloc.
off_t
next_offset() const;
// Return the symbol index of the next reloc. This returns -1U if
// there is no next reloc.
unsigned int
next_symndx() const;
// Return the addend of the next reloc. This returns 0 if there is
// no next reloc.
uint64_t
next_addend() const;
// Advance to OFFSET within the data section, and return the number
// of relocs which would be skipped.
int
advance(off_t offset);
// Checkpoint the current position in the reloc section.
section_size_type
checkpoint() const
{ return this->pos_; }
// Reset the position to CHECKPOINT.
void
reset(section_size_type checkpoint)
{ this->pos_ = checkpoint; }
private:
// The contents of the input object's reloc section.
const unsigned char* prelocs_;
// The length of the reloc section.
section_size_type len_;
// Our current position in the reloc section.
section_size_type pos_;
// The size of the relocs in the section.
int reloc_size_;
};
} // End namespace gold.
#endif // !defined(GOLD_RELOC_H)