binutils-gdb/gold/aarch64-reloc-property.h
2016-01-01 23:00:01 +10:30

246 lines
7.0 KiB
C++

// aarch64-reloc-property.h -- AArch64 relocation properties -*- C++ -*-
// Copyright (C) 2014-2016 Free Software Foundation, Inc.
// Written by Han Shen <shenhan@google.com> and Jing Yu <jingyu@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_AARCH64_RELOC_PROPERTY_H
#define GOLD_AARCH64_RELOC_PROPERTY_H
#include<vector>
#include<string>
#include"aarch64.h"
namespace gold
{
// The AArch64_reloc_property class is to store information about a particular
// relocation code.
class AArch64_reloc_property
{
public:
// Types of relocation codes.
enum Reloc_type {
RT_NONE, // No relocation type.
RT_STATIC, // Relocations processed by static linkers.
RT_DYNAMIC, // Relocations processed by dynamic linkers.
};
// Classes of relocation codes.
enum Reloc_class {
RC_NONE, // No relocation class.
RC_DATA, // Data relocation.
RC_AARCH64, // Static AArch64 relocations
RC_CFLOW, // Control flow
RC_TLS, // Thread local storage
RC_DYNAMIC, // Dynamic relocation
};
// Instructions that are associated with relocations.
enum Reloc_inst {
INST_DATA = 0,
INST_MOVW = 1, // movz, movk, movn
INST_LD = 2, // ld literal
INST_ADR = 3, // adr
INST_ADRP = 4, // adrp
INST_ADD = 5, // add
INST_LDST = 6, // ld/st
INST_TBZNZ = 7, // tbz/tbnz
INST_CONDB = 8, // B.cond
INST_B = 9, // b [25:0]
INST_CALL = 10, // bl [25:0]
INST_NUM = 11, // total number of entries in the table
};
// Types of bases of relative addressing relocation codes.
// enum Relative_address_base {
// RAB_NONE, // Relocation is not relative addressing
// };
typedef bool (*rvalue_checkup_func_p)(int64_t);
typedef uint64_t (*rvalue_bit_select_func)(uint64_t);
// Relocation code represented by this.
unsigned int
code() const
{ return this->code_; }
// Name of the relocation code.
const std::string&
name() const
{ return this->name_; }
// Type of relocation code.
Reloc_type
reloc_type() const
{ return this->reloc_type_; }
// Class of relocation code.
Reloc_class
reloc_class() const
{ return this->reloc_class_; }
// Whether this code is implemented in gold.
bool
is_implemented() const
{ return this->is_implemented_; }
// If code is a group relocation code, return the group number, otherwise -1.
int
group_index() const
{ return this->group_index_; }
// Return alignment of relocation.
size_t
align() const
{ return this->align_; }
int
reference_flags() const
{ return this->reference_flags_; }
// Instruction associated with this relocation.
Reloc_inst
reloc_inst() const
{ return this->reloc_inst_; }
// Check overflow of x
bool checkup_x_value(int64_t x) const
{ return this->rvalue_checkup_func_(x); }
// Return portions of x as is defined in aarch64-reloc.def.
uint64_t select_x_value(uint64_t x) const
{ return this->rvalue_bit_select_func_(x); }
protected:
// These are protected. We only allow AArch64_reloc_property_table to
// manage AArch64_reloc_property.
AArch64_reloc_property(unsigned int code, const char* name, Reloc_type rtype,
Reloc_class rclass,
bool is_implemented,
int group_index,
int reference_flags,
Reloc_inst reloc_inst,
rvalue_checkup_func_p rvalue_checkup_func,
rvalue_bit_select_func rvalue_bit_select);
friend class AArch64_reloc_property_table;
private:
// Copying is not allowed.
AArch64_reloc_property(const AArch64_reloc_property&);
AArch64_reloc_property& operator=(const AArch64_reloc_property&);
// Relocation code.
const unsigned int code_;
// Relocation name.
const std::string name_;
// Type of relocation.
Reloc_type reloc_type_;
// Class of relocation.
Reloc_class reloc_class_;
// Group index (0, 1, or 2) if this is a group relocation or -1 otherwise.
int group_index_;
// Size of relocation.
size_t size_;
// Alignment of relocation.
size_t align_;
// Relative address base.
// Relative_address_base relative_address_base_;
// Whether this is deprecated.
bool is_deprecated_ : 1;
// Whether this is implemented in gold.
bool is_implemented_ : 1;
// Whether this checks overflow.
bool checks_overflow_ : 1;
const int reference_flags_;
// Instruction associated with relocation.
Reloc_inst reloc_inst_;
rvalue_checkup_func_p rvalue_checkup_func_;
rvalue_bit_select_func rvalue_bit_select_func_;
};
class AArch64_reloc_property_table
{
public:
AArch64_reloc_property_table();
const AArch64_reloc_property*
get_reloc_property(unsigned int code) const
{
unsigned int idx = code_to_array_index(code);
return this->table_[idx];
}
// Like get_reloc_property but only return non-NULL if relocation code is
// static and implemented.
const AArch64_reloc_property*
get_implemented_static_reloc_property(unsigned int code) const
{
unsigned int idx = code_to_array_index(code);
const AArch64_reloc_property* arp = this->table_[idx];
return ((arp != NULL
&& (arp->reloc_type() == AArch64_reloc_property::RT_STATIC)
&& arp->is_implemented())
? arp
: NULL);
}
// Return a string describing the relocation code that is not
// an implemented static reloc code.
std::string
reloc_name_in_error_message(unsigned int code);
private:
// Copying is not allowed.
AArch64_reloc_property_table(const AArch64_reloc_property_table&);
AArch64_reloc_property_table& operator=(const AArch64_reloc_property_table&);
// Map aarch64 rtypes into range(0,300) as following
// 256 ~ 313 -> 0 ~ 57
// 512 ~ 573 -> 128 ~ 189
int
code_to_array_index(unsigned int code) const
{
if (code == 0) return 0;
if (!((code >= elfcpp::R_AARCH64_ABS64 &&
code <= elfcpp::R_AARCH64_LD64_GOTPAGE_LO15)
|| (code >= elfcpp::R_AARCH64_TLSGD_ADR_PREL21 &&
code <= elfcpp::R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC)))
{
gold_error(_("Invalid/unrecognized reloc reloc %d."), code);
}
unsigned int rv = -1;
if (code & (1 << 9))
rv = 128 + code - 512; // 512 - 573
else if (code & (1 << 8))
rv = code - 256; // 256 - 313
gold_assert(rv <= Property_table_size);
return rv;
}
static const unsigned int Property_table_size = 300;
AArch64_reloc_property* table_[Property_table_size];
}; // End of class AArch64_reloc_property_table
} // End namespace gold.
#endif // !defined(GOLD_AARCH64_RELOC_PROPERTY_H)