1// aarch64-reloc-property.cc -- AArch64 relocation properties   -*- C++ -*-
2
3// Copyright (C) 2014-2017 Free Software Foundation, Inc.
4// Written by Han Shen <shenhan@google.com> and Jing Yu <jingyu@google.com>.
5
6// This file is part of gold.
7
8// This program is free software; you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by
10// the Free Software Foundation; either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16// GNU General Public License for more details.
17
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21// MA 02110-1301, USA.
22
23#include "gold.h"
24
25#include "aarch64-reloc-property.h"
26#include "aarch64.h"
27
28#include "symtab.h"
29
30#include<stdio.h>
31
32namespace gold
33{
34
35template<int L, int U>
36bool
37rvalue_checkup(int64_t x)
38{
39  // We save the extra_alignment_requirement bits on [31:16] of U.
40  // "extra_alignment_requirement" could be 0, 1, 3, 7 and 15.
41  unsigned short extra_alignment_requirement = (U & 0xFFFF0000) >> 16;
42  // [15:0] of U indicates the upper bound check.
43  int64_t u = U & 0x0000FFFF;
44  if (u == 0)
45    {
46      // No requirement to check overflow.
47      gold_assert(L == 0);
48      return (x & extra_alignment_requirement) == 0;
49    }
50
51  // Check both overflow and alignment if needed.
52  int64_t low_bound = -(L == 0 ? 0 : ((int64_t)1 << L));
53  int64_t up_bound = ((int64_t)1 << u);
54  return ((low_bound <= x && x < up_bound)
55	  && ((x & extra_alignment_requirement) == 0));
56}
57
58template<>
59bool
60rvalue_checkup<0, 0>(int64_t) { return true; }
61
62namespace
63{
64
65template<int L, int U>
66class Rvalue_bit_select_impl
67{
68public:
69  static uint64_t
70  calc(uint64_t x)
71  {
72    return (x & ((1ULL << (U+1)) - 1)) >> L;
73  }
74};
75
76template<int L>
77class Rvalue_bit_select_impl<L, 63>
78{
79public:
80  static uint64_t
81  calc(uint64_t x)
82  {
83    return x >> L;
84  }
85};
86
87// By our convention, L=U=0 means that the whole value should be retrieved.
88template<>
89class Rvalue_bit_select_impl<0, 0>
90{
91public:
92  static uint64_t
93  calc(uint64_t x)
94  {
95    return x;
96  }
97};
98
99} // End anonymous namespace.
100
101template<int L, int U>
102uint64_t
103rvalue_bit_select(uint64_t x)
104{
105  return Rvalue_bit_select_impl<L, U>::calc(x);
106}
107
108AArch64_reloc_property::AArch64_reloc_property(
109    unsigned int code,
110    const char* name,
111    Reloc_type rtype,
112    Reloc_class rclass,
113    bool is_implemented,
114    int group_index,
115    int reference_flags,
116    Reloc_inst reloc_inst,
117    rvalue_checkup_func_p rvalue_checkup_func,
118    rvalue_bit_select_func rvalue_bit_select)
119  : code_(code), name_(name), reloc_type_(rtype), reloc_class_(rclass),
120    group_index_(group_index),
121    is_implemented_(is_implemented),
122    reference_flags_(reference_flags),
123    reloc_inst_(reloc_inst),
124    rvalue_checkup_func_(rvalue_checkup_func),
125    rvalue_bit_select_func_(rvalue_bit_select)
126{}
127
128AArch64_reloc_property_table::AArch64_reloc_property_table()
129{
130  const bool Y(true), N(false);
131  for (unsigned int i = 0; i < Property_table_size; ++i)
132    table_[i] = NULL;
133
134#define RL_CHECK_ALIGN2   (1  << 16)
135#define RL_CHECK_ALIGN4   (3  << 16)
136#define RL_CHECK_ALIGN8   (7  << 16)
137#define RL_CHECK_ALIGN16  (15 << 16)
138
139#undef ARD
140#define ARD(rname, type, class, is_implemented, group_index, LB, UB, BSL, BSH, RFLAGS, inst) \
141    do \
142      { \
143	int tidx = code_to_array_index(elfcpp::R_AARCH64_##rname); \
144	AArch64_reloc_property * p = new AArch64_reloc_property( \
145	  elfcpp::R_AARCH64_##rname, "R_AARCH64_" #rname, \
146	  AArch64_reloc_property::RT_##type, \
147	  AArch64_reloc_property::RC_##class, \
148	  is_implemented, \
149	  group_index, \
150	  (RFLAGS), \
151	  AArch64_reloc_property::INST_##inst,	\
152	  rvalue_checkup<LB,UB>,    \
153	  rvalue_bit_select<BSL,BSH>);		\
154	table_[tidx] = p; \
155      } \
156    while (0);
157#include"aarch64-reloc.def"
158#undef ARD
159}
160
161// Return a string describing a relocation code that fails to get a
162// relocation property in get_implemented_static_reloc_property().
163
164std::string
165AArch64_reloc_property_table::reloc_name_in_error_message(unsigned int code)
166{
167  int tidx = code_to_array_index(code);
168  const AArch64_reloc_property* arp = this->table_[tidx];
169
170  if (arp == NULL)
171    {
172      char buffer[100];
173      sprintf(buffer, _("invalid reloc %u"), code);
174      return std::string(buffer);
175    }
176
177  // gold only implements static relocation codes.
178  AArch64_reloc_property::Reloc_type reloc_type = arp->reloc_type();
179  gold_assert(reloc_type == AArch64_reloc_property::RT_STATIC
180	      || !arp->is_implemented());
181
182  const char* prefix = NULL;
183  switch (reloc_type)
184    {
185    case AArch64_reloc_property::RT_STATIC:
186      prefix = arp->is_implemented() ? _("reloc ") : _("unimplemented reloc ");
187      break;
188    case AArch64_reloc_property::RT_DYNAMIC:
189      prefix = _("dynamic reloc ");
190      break;
191    default:
192      gold_unreachable();
193    }
194  return std::string(prefix) + arp->name();
195}
196
197}
198