|  | // aarch64-reloc-property.cc -- AArch64 relocation properties   -*- C++ -*- | 
|  |  | 
|  | // Copyright (C) 2014-2025 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(); | 
|  | } | 
|  |  | 
|  | } |