198 lines
5.1 KiB
C++
198 lines
5.1 KiB
C++
// aarch64-reloc-property.cc -- AArch64 relocation properties -*- C++ -*-
|
|
|
|
// Copyright (C) 2014-2019 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.
|
|
|
|
#include "gold.h"
|
|
|
|
#include "aarch64-reloc-property.h"
|
|
#include "aarch64.h"
|
|
|
|
#include "symtab.h"
|
|
|
|
#include<stdio.h>
|
|
|
|
namespace gold
|
|
{
|
|
|
|
template<int L, int U>
|
|
bool
|
|
rvalue_checkup(int64_t x)
|
|
{
|
|
// We save the extra_alignment_requirement bits on [31:16] of U.
|
|
// "extra_alignment_requirement" could be 0, 1, 3, 7 and 15.
|
|
unsigned short extra_alignment_requirement = (U & 0xFFFF0000) >> 16;
|
|
// [15:0] of U indicates the upper bound check.
|
|
int64_t u = U & 0x0000FFFF;
|
|
if (u == 0)
|
|
{
|
|
// No requirement to check overflow.
|
|
gold_assert(L == 0);
|
|
return (x & extra_alignment_requirement) == 0;
|
|
}
|
|
|
|
// Check both overflow and alignment if needed.
|
|
int64_t low_bound = -(L == 0 ? 0 : ((int64_t)1 << L));
|
|
int64_t up_bound = ((int64_t)1 << u);
|
|
return ((low_bound <= x && x < up_bound)
|
|
&& ((x & extra_alignment_requirement) == 0));
|
|
}
|
|
|
|
template<>
|
|
bool
|
|
rvalue_checkup<0, 0>(int64_t) { return true; }
|
|
|
|
namespace
|
|
{
|
|
|
|
template<int L, int U>
|
|
class Rvalue_bit_select_impl
|
|
{
|
|
public:
|
|
static uint64_t
|
|
calc(uint64_t x)
|
|
{
|
|
return (x & ((1ULL << (U+1)) - 1)) >> L;
|
|
}
|
|
};
|
|
|
|
template<int L>
|
|
class Rvalue_bit_select_impl<L, 63>
|
|
{
|
|
public:
|
|
static uint64_t
|
|
calc(uint64_t x)
|
|
{
|
|
return x >> L;
|
|
}
|
|
};
|
|
|
|
// By our convention, L=U=0 means that the whole value should be retrieved.
|
|
template<>
|
|
class Rvalue_bit_select_impl<0, 0>
|
|
{
|
|
public:
|
|
static uint64_t
|
|
calc(uint64_t x)
|
|
{
|
|
return x;
|
|
}
|
|
};
|
|
|
|
} // End anonymous namespace.
|
|
|
|
template<int L, int U>
|
|
uint64_t
|
|
rvalue_bit_select(uint64_t x)
|
|
{
|
|
return Rvalue_bit_select_impl<L, U>::calc(x);
|
|
}
|
|
|
|
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)
|
|
: code_(code), name_(name), reloc_type_(rtype), reloc_class_(rclass),
|
|
group_index_(group_index),
|
|
is_implemented_(is_implemented),
|
|
reference_flags_(reference_flags),
|
|
reloc_inst_(reloc_inst),
|
|
rvalue_checkup_func_(rvalue_checkup_func),
|
|
rvalue_bit_select_func_(rvalue_bit_select)
|
|
{}
|
|
|
|
AArch64_reloc_property_table::AArch64_reloc_property_table()
|
|
{
|
|
const bool Y(true), N(false);
|
|
for (unsigned int i = 0; i < Property_table_size; ++i)
|
|
table_[i] = NULL;
|
|
|
|
#define RL_CHECK_ALIGN2 (1 << 16)
|
|
#define RL_CHECK_ALIGN4 (3 << 16)
|
|
#define RL_CHECK_ALIGN8 (7 << 16)
|
|
#define RL_CHECK_ALIGN16 (15 << 16)
|
|
|
|
#undef ARD
|
|
#define ARD(rname, type, class, is_implemented, group_index, LB, UB, BSL, BSH, RFLAGS, inst) \
|
|
do \
|
|
{ \
|
|
int tidx = code_to_array_index(elfcpp::R_AARCH64_##rname); \
|
|
AArch64_reloc_property * p = new AArch64_reloc_property( \
|
|
elfcpp::R_AARCH64_##rname, "R_AARCH64_" #rname, \
|
|
AArch64_reloc_property::RT_##type, \
|
|
AArch64_reloc_property::RC_##class, \
|
|
is_implemented, \
|
|
group_index, \
|
|
(RFLAGS), \
|
|
AArch64_reloc_property::INST_##inst, \
|
|
rvalue_checkup<LB,UB>, \
|
|
rvalue_bit_select<BSL,BSH>); \
|
|
table_[tidx] = p; \
|
|
} \
|
|
while (0);
|
|
#include"aarch64-reloc.def"
|
|
#undef ARD
|
|
}
|
|
|
|
// Return a string describing a relocation code that fails to get a
|
|
// relocation property in get_implemented_static_reloc_property().
|
|
|
|
std::string
|
|
AArch64_reloc_property_table::reloc_name_in_error_message(unsigned int code)
|
|
{
|
|
int tidx = code_to_array_index(code);
|
|
const AArch64_reloc_property* arp = this->table_[tidx];
|
|
|
|
if (arp == NULL)
|
|
{
|
|
char buffer[100];
|
|
sprintf(buffer, _("invalid reloc %u"), code);
|
|
return std::string(buffer);
|
|
}
|
|
|
|
// gold only implements static relocation codes.
|
|
AArch64_reloc_property::Reloc_type reloc_type = arp->reloc_type();
|
|
gold_assert(reloc_type == AArch64_reloc_property::RT_STATIC
|
|
|| !arp->is_implemented());
|
|
|
|
const char* prefix = NULL;
|
|
switch (reloc_type)
|
|
{
|
|
case AArch64_reloc_property::RT_STATIC:
|
|
prefix = arp->is_implemented() ? _("reloc ") : _("unimplemented reloc ");
|
|
break;
|
|
case AArch64_reloc_property::RT_DYNAMIC:
|
|
prefix = _("dynamic reloc ");
|
|
break;
|
|
default:
|
|
gold_unreachable();
|
|
}
|
|
return std::string(prefix) + arp->name();
|
|
}
|
|
|
|
}
|