summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--elfcpp/ChangeLog4
-rw-r--r--elfcpp/aarch64.h2
-rw-r--r--gold/ChangeLog42
-rw-r--r--gold/Makefile.am7
-rw-r--r--gold/Makefile.in7
-rw-r--r--gold/aarch64-reloc-property.cc164
-rw-r--r--gold/aarch64-reloc-property.h245
-rw-r--r--gold/aarch64-reloc.def70
-rw-r--r--gold/aarch64.cc1148
9 files changed, 1533 insertions, 156 deletions
diff --git a/elfcpp/ChangeLog b/elfcpp/ChangeLog
index 043fb671def..eafa25238bb 100644
--- a/elfcpp/ChangeLog
+++ b/elfcpp/ChangeLog
@@ -1,3 +1,7 @@
+2014-08-08 Han Shen <shenhan@google.com>
+
+ * aarch64.h (withdrawn): Replaced with R_AARCH64_withdrawn.
+
2014-07-29 Matthew Fortune <matthew.fortune@imgtec.com>
* elfcpp.h (PT_MIPS_ABIFLAGS): New program header type.
diff --git a/elfcpp/aarch64.h b/elfcpp/aarch64.h
index 4d1898f44df..52ac3eaca9a 100644
--- a/elfcpp/aarch64.h
+++ b/elfcpp/aarch64.h
@@ -46,7 +46,7 @@ enum
{
// Null relocation codes
R_AARCH64_NONE = 0, // None
- withdrawn = 256, // Treat as R_AARCH64_NONE
+ R_AARCH64_withdrawn = 256, // Treat as R_AARCH64_NONE
// Static relocations
R_AARCH64_ABS64 = 257, // S + A
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 9e1ef63af59..90997bdc8d6 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,45 @@
+2014-08-08 Jing Yu <jingyu@google.com>
+ Han Shen <shenhan@google.com>
+
+ * Makefile.am (HFILES): Add aarch64-reloc-property.h.
+ (DEFFILES): add aarch64-reloc.def.
+ (TARGETSOURCES): Add aarch64-reloc-property.cc.
+ (ALL_TARGETOBJS): Add aarch64-reloc-property.$(OBJEXT).
+ * Makefile.in: Regenerate.
+ * aarch64-reloc-property.cc: New file.
+ * aarch64-reloc-property.h: New file.
+ * aarch64-reloc.def: New file.
+ * aarch64.cc: Include aarch64-reloc-property.h. Replace spaces
+ with tab to make the format consistent.
+ (Output_data_got_aarch64::symbol_table_): New method.
+ (Target_aarch64::do_plt_address_for_global): New method.
+ (Target_aarch64::do_plt_address_for_local): New method.
+ (Target_aarch64::do_select_as_default_target): New method.
+ (Target_aarch64::do_make_data_plt): New method.
+ (Target_aarch64::make_data_plt): New method.
+ (Output_data_plt_aarch64::has_irelative_section): New method.
+ (Output_data_plt_aarch64::address_for_global): New method.
+ (Output_data_plt_aarch64::address_for_local): New method.
+ (Output_data_plt_aarch64::irelative_rel_): New parameter.
+ (Output_data_plt_aarch64::add_entry): Implement contents.
+ (Output_data_plt_aarch64::set_final_data_size): Fix typo.
+ (Output_data_plt_aarch64::do_write): Remove useless got_base. Set
+ the got_pov entry to plt0.
+ (Output_data_plt_aarch64_standard::do_fill_first_plt_entry):
+ Implement contents.
+ (Output_data_plt_aarch64_standard::do_fill_plt_entry): Implement.
+ (AArch64_howto): New struct.
+ (aarch64_howto[]): New static const array.
+ (AArch64_relocate_functions): New class.
+ (Target_aarch64::Scan::get_reference_flags): Remove method.
+ (Target_aarch64::Scan::local): Implement to support a few relocations.
+ (Target_aarch64::Scan::global): Implement to support a few relocations.
+ (Target_aarch64::make_plt_section): Implement contents.
+ (Target_aarch64::make_plt_entry): Implement contents.
+ (Target_aarch64::do_finalize_sections): Implement contents.
+ (Target_aarch64::Relocate::relocate): Implement a few relocations.
+ (Target_aarch64::relocate_section): Implement contents.
+
2014-08-06 Alan Modra <amodra@gmail.com>
* testsuite/defsym_test.sh: Allow ppc64le localentry annotation.
diff --git a/gold/Makefile.am b/gold/Makefile.am
index 17ba4b4f9ce..df99f23c3a7 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -106,6 +106,7 @@ CCFILES = \
HFILES = \
arm-reloc-property.h \
+ aarch64-reloc-property.h \
archive.h \
attributes.h \
binary.h \
@@ -158,18 +159,18 @@ HFILES = \
YFILES = \
yyscript.y
-DEFFILES = arm-reloc.def
+DEFFILES = arm-reloc.def aarch64-reloc.def
EXTRA_DIST = yyscript.c yyscript.h
TARGETSOURCES = \
i386.cc x86_64.cc sparc.cc powerpc.cc arm.cc arm-reloc-property.cc tilegx.cc \
- mips.cc aarch64.cc
+ mips.cc aarch64.cc aarch64-reloc-property.cc
ALL_TARGETOBJS = \
i386.$(OBJEXT) x86_64.$(OBJEXT) sparc.$(OBJEXT) powerpc.$(OBJEXT) \
arm.$(OBJEXT) arm-reloc-property.$(OBJEXT) tilegx.$(OBJEXT) \
- mips.$(OBJEXT) aarch64.$(OBJEXT)
+ mips.$(OBJEXT) aarch64.$(OBJEXT) aarch64-reloc-property.$(OBJEXT)
libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES) $(DEFFILES)
libgold_a_LIBADD = $(LIBOBJS)
diff --git a/gold/Makefile.in b/gold/Makefile.in
index a8dd1110133..d4046668f3f 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -477,6 +477,7 @@ CCFILES = \
HFILES = \
arm-reloc-property.h \
+ aarch64-reloc-property.h \
archive.h \
attributes.h \
binary.h \
@@ -529,16 +530,16 @@ HFILES = \
YFILES = \
yyscript.y
-DEFFILES = arm-reloc.def
+DEFFILES = arm-reloc.def aarch64-reloc.def
EXTRA_DIST = yyscript.c yyscript.h
TARGETSOURCES = \
i386.cc x86_64.cc sparc.cc powerpc.cc arm.cc arm-reloc-property.cc tilegx.cc \
- mips.cc aarch64.cc
+ mips.cc aarch64.cc aarch64-reloc-property.cc
ALL_TARGETOBJS = \
i386.$(OBJEXT) x86_64.$(OBJEXT) sparc.$(OBJEXT) powerpc.$(OBJEXT) \
arm.$(OBJEXT) arm-reloc-property.$(OBJEXT) tilegx.$(OBJEXT) \
- mips.$(OBJEXT) aarch64.$(OBJEXT)
+ mips.$(OBJEXT) aarch64.$(OBJEXT) aarch64-reloc-property.$(OBJEXT)
libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES) $(DEFFILES)
libgold_a_LIBADD = $(LIBOBJS)
diff --git a/gold/aarch64-reloc-property.cc b/gold/aarch64-reloc-property.cc
new file mode 100644
index 00000000000..beaed10f872
--- /dev/null
+++ b/gold/aarch64-reloc-property.cc
@@ -0,0 +1,164 @@
+// aarch64-reloc-property.cc -- AArch64 relocation properties -*- C++ -*-
+
+// Copyright (C) 2014 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; }
+
+template<int L, int U>
+uint64_t
+rvalue_bit_select(uint64_t x)
+{
+ if (U == 63) return x >> L;
+ return (x & (((uint64_t)1 << (U+1)) - 1)) >> L;
+}
+
+template<>
+uint64_t
+rvalue_bit_select<0, 0>(uint64_t x) { return 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)
+{
+ gold_assert(code < Property_table_size);
+
+ const AArch64_reloc_property* arp = this->table_[code];
+
+ 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();
+}
+
+}
diff --git a/gold/aarch64-reloc-property.h b/gold/aarch64-reloc-property.h
new file mode 100644
index 00000000000..d8d13017efe
--- /dev/null
+++ b/gold/aarch64-reloc-property.h
@@ -0,0 +1,245 @@
+// aarch64-reloc-property.h -- AArch64 relocation properties -*- C++ -*-
+
+// Copyright (C) 2014 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)
diff --git a/gold/aarch64-reloc.def b/gold/aarch64-reloc.def
new file mode 100644
index 00000000000..4f6710e79c4
--- /dev/null
+++ b/gold/aarch64-reloc.def
@@ -0,0 +1,70 @@
+// aarch64-reloc.def -- AArch64 relocation definitions.
+
+// Copyright (C) 2014 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.
+//
+//
+//
+// Insn modified by relocation, see enum Reloc_inst -------------------------------------------------------------------------+
+// Symbol reference type -----------------------------------------------------------------------------+ |
+// Portion off X to retrieve -------------------------------------------------------------------+ | |
+// Checking function, see Note(A)---------------------------------------+ | | |
+// Group index---------------------------------------------------+ | | | |
+// Implemented----------------------------------------------+ | | | | |
+// Class-------------------------------------+ | | | | | |
+// Type----------------------------+ | | | | | | |
+// Name | | | | | | | |
+// | | | | | | | | |
+ARD(ABS64 , STATIC , DATA , Y, -1, 0,0 , 0,0 , Symbol::ABSOLUTE_REF , DATA )
+ARD(ABS32 , STATIC , DATA , Y, -1, 31,32 , 0,0 , Symbol::ABSOLUTE_REF , DATA )
+ARD(ABS16 , STATIC , DATA , Y, -1, 15,16 , 0,0 , Symbol::ABSOLUTE_REF , DATA )
+ARD(PREL64 , STATIC , DATA , Y, -1, 0,0 , 0,0 , Symbol::RELATIVE_REF , DATA )
+ARD(PREL32 , STATIC , DATA , Y, -1, 31,32 , 0,0 , Symbol::RELATIVE_REF , DATA )
+ARD(PREL16 , STATIC , DATA , Y, -1, 15,16 , 0,0 , Symbol::RELATIVE_REF , DATA )
+// Above is from Table 4-6, Data relocations, 257-262.
+
+ARD(ADR_PREL_PG_HI21 , STATIC , AARCH64 , Y, -1, 32,32 , 12,32 , Symbol::RELATIVE_REF , ADRP )
+ARD(ADR_PREL_PG_HI21_NC , STATIC , AARCH64 , Y, -1, 0,0 , 12,32 , Symbol::RELATIVE_REF , ADRP )
+ARD(LDST8_ABS_LO12_NC , STATIC , AARCH64 , Y, -1, 0,0 , 0,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(LDST16_ABS_LO12_NC , STATIC , AARCH64 , Y, -1, 0,RL_CHECK_ALIGN2 , 1,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(LDST32_ABS_LO12_NC , STATIC , AARCH64 , Y, -1, 0,RL_CHECK_ALIGN4 , 2,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(LDST64_ABS_LO12_NC , STATIC , AARCH64 , Y, -1, 0,RL_CHECK_ALIGN8 , 3,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(LDST128_ABS_LO12_NC , STATIC , AARCH64 , Y, -1, 0,RL_CHECK_ALIGN16 , 4,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(ADD_ABS_LO12_NC , STATIC , AARCH64 , Y, -1, 0,0 , 0,11 , Symbol::ABSOLUTE_REF , ADD )
+ARD(ADR_GOT_PAGE , STATIC , AARCH64 , Y, -1, 32,32 , 12,32 , Symbol::RELATIVE_REF , ADRP )
+ARD(LD64_GOT_LO12_NC , STATIC , AARCH64 , Y, -1, 0,RL_CHECK_ALIGN8 , 3,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(TSTBR14 , STATIC , CFLOW , N, -1, 15,15 , 2,15 , Symbol::ABSOLUTE_REF , TBZNZ )
+ARD(CONDBR19 , STATIC , CFLOW , N, -1, 20,20 , 2,20 , Symbol::ABSOLUTE_REF , CONDB )
+ARD(CALL26 , STATIC , CFLOW , Y, -1, 27,27 , 2,27 , (Symbol::FUNCTION_CALL|Symbol::RELATIVE_REF) , CALL )
+ARD(JUMP26 , STATIC , CFLOW , Y, -1, 27,27 , 2,27 , (Symbol::FUNCTION_CALL|Symbol::RELATIVE_REF) , B )
+// Above is from Table 4-10, Relocations for control-flow instructions,
+// 279-283.
+
+ARD(TLSIE_MOVW_GOTTPREL_G1 , STATIC , AARCH64 , N, -1, 0,0 , 16,31 , Symbol::ABSOLUTE_REF , MOVW )
+ARD(TLSIE_MOVW_GOTTPREL_G0_NC , STATIC , AARCH64 , N, -1, 0,0 , 0,15 , Symbol::ABSOLUTE_REF , MOVW )
+ARD(TLSIE_ADR_GOTTPREL_PAGE21 , STATIC , AARCH64 , Y, -1, 32,32 , 12,32 , Symbol::ABSOLUTE_REF , ADRP )
+ARD(TLSIE_LD64_GOTTPREL_LO12_NC , STATIC , AARCH64 , N, -1, 32,32 , 12,32 , Symbol::ABSOLUTE_REF , LDST )
+ARD(TLSIE_LD_GOTTPREL_PREL19 , STATIC , AARCH64 , N, -1, 20,20 , 2,20 , Symbol::ABSOLUTE_REF , LD )
+// Above is from Table 4-17, Initial Exec TLS relocations, 539-543.
+
+// Note -
+// A - Checking X, (L,U), if L == 0 && U == 0, no check. Otherwise, L!=0,
+// check that -2^L<=X<2^U. Also an extra alignment check could be embeded
+// into U.
diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index 17fe03150ca..7a3fe3bd806 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -1,7 +1,7 @@
// aarch64.cc -- aarch64 target support for gold.
// Copyright (C) 2014 Free Software Foundation, Inc.
-// Written by Jing Yu <jingyu@google.com>.
+// Written by Jing Yu <jingyu@google.com> and Han Shen <shenhan@google.com>.
// This file is part of gold.
@@ -42,6 +42,7 @@
#include "nacl.h"
#include "gc.h"
#include "icf.h"
+#include "aarch64-reloc-property.h"
// The first three .got.plt entries are reserved.
const int32_t AARCH64_GOTPLT_RESERVE_COUNT = 3;
@@ -60,6 +61,9 @@ class Output_data_plt_aarch64_standard;
template<int size, bool big_endian>
class Target_aarch64;
+template<int size, bool big_endian>
+class AArch64_relocate_functions;
+
// Output_data_got_aarch64 class.
template<int size, bool big_endian>
@@ -68,7 +72,8 @@ class Output_data_got_aarch64 : public Output_data_got<size, big_endian>
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
Output_data_got_aarch64(Symbol_table* symtab, Layout* layout)
- : Output_data_got<size, big_endian>(), layout_(layout)
+ : Output_data_got<size, big_endian>(),
+ symbol_table_(symtab), layout_(layout)
{ }
protected:
@@ -84,11 +89,15 @@ class Output_data_got_aarch64 : public Output_data_got<size, big_endian>
}
private:
+ // Symbol table of the output object.
+ Symbol_table* symbol_table_;
// A pointer to the Layout class, so that we can find the .dynamic
// section when we write out the GOT section.
Layout* layout_;
};
+AArch64_reloc_property_table* aarch64_reloc_property_table = NULL;
+
// The aarch64 target class.
// See the ABI at
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
@@ -184,6 +193,15 @@ class Target_aarch64 : public Sized_target<size, big_endian>
unsigned char* reloc_view,
section_size_type reloc_view_size);
+ // Return the PLT section.
+ uint64_t
+ do_plt_address_for_global(const Symbol* gsym) const
+ { return this->plt_section()->address_for_global(gsym); }
+
+ uint64_t
+ do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const
+ { return this->plt_section()->address_for_local(relobj, symndx); }
+
// Return the number of entries in the PLT.
unsigned int
plt_entry_count() const;
@@ -196,6 +214,27 @@ class Target_aarch64 : public Sized_target<size, big_endian>
unsigned int
plt_entry_size() const;
+ protected:
+ void
+ do_select_as_default_target()
+ {
+ gold_assert(aarch64_reloc_property_table == NULL);
+ aarch64_reloc_property_table = new AArch64_reloc_property_table();
+ }
+
+ virtual Output_data_plt_aarch64<size, big_endian>*
+ do_make_data_plt(Layout* layout, Output_data_space* got_plt)
+ {
+ return new Output_data_plt_aarch64_standard<size, big_endian>(layout,
+ got_plt);
+ }
+
+ Output_data_plt_aarch64<size, big_endian>*
+ make_data_plt(Layout* layout, Output_data_space* got_plt)
+ {
+ return this->do_make_data_plt(layout, got_plt);
+ }
+
private:
// The class which scans relocations.
class Scan
@@ -205,9 +244,6 @@ class Target_aarch64 : public Sized_target<size, big_endian>
: issued_non_pic_error_(false)
{ }
- static inline int
- get_reference_flags(unsigned int r_type);
-
inline void
local(Symbol_table* symtab, Layout* layout, Target_aarch64* target,
Sized_relobj_file<size, big_endian>* object,
@@ -227,23 +263,23 @@ class Target_aarch64 : public Sized_target<size, big_endian>
inline bool
local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
- Target_aarch64<size, big_endian>* ,
- Sized_relobj_file<size, big_endian>* ,
- unsigned int ,
- Output_section* ,
- const elfcpp::Rela<size, big_endian>& ,
- unsigned int r_type,
- const elfcpp::Sym<size, big_endian>&);
+ Target_aarch64<size, big_endian>* ,
+ Sized_relobj_file<size, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size, big_endian>& ,
+ unsigned int r_type,
+ const elfcpp::Sym<size, big_endian>&);
inline bool
global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
- Target_aarch64<size, big_endian>* ,
- Sized_relobj_file<size, big_endian>* ,
- unsigned int ,
- Output_section* ,
- const elfcpp::Rela<size, big_endian>& ,
- unsigned int r_type,
- Symbol* gsym);
+ Target_aarch64<size, big_endian>* ,
+ Sized_relobj_file<size, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size, big_endian>& ,
+ unsigned int r_type,
+ Symbol* gsym);
private:
static void
@@ -489,7 +525,7 @@ const Target::Target_info Target_aarch64<32, true>::aarch64_info =
template<int size, bool big_endian>
Output_data_got_aarch64<size, big_endian>*
Target_aarch64<size, big_endian>::got_section(Symbol_table* symtab,
- Layout* layout)
+ Layout* layout)
{
if (this->got_ == NULL)
{
@@ -515,10 +551,10 @@ Target_aarch64<size, big_endian>::got_section(Symbol_table* symtab,
// Generate .got section.
this->got_ = new Output_data_got_aarch64<size, big_endian>(symtab,
- layout);
+ layout);
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
- (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
- this->got_, got_order, true);
+ (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
+ this->got_, got_order, true);
// The first word of GOT is reserved for the address of .dynamic.
// We put 0 here now. The value will be replaced later in
// Output_data_got_aarch64::do_write.
@@ -528,32 +564,32 @@ Target_aarch64<size, big_endian>::got_section(Symbol_table* symtab,
// _GLOBAL_OFFSET_TABLE_ value points to the start of the .got section,
// even if there is a .got.plt section.
this->global_offset_table_ =
- symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
- Symbol_table::PREDEFINED,
- this->got_,
- 0, 0, elfcpp::STT_OBJECT,
- elfcpp::STB_LOCAL,
- elfcpp::STV_HIDDEN, 0,
- false, false);
+ symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+ Symbol_table::PREDEFINED,
+ this->got_,
+ 0, 0, elfcpp::STT_OBJECT,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ false, false);
// Generate .got.plt section.
this->got_plt_ = new Output_data_space(size / 8, "** GOT PLT");
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
- (elfcpp::SHF_ALLOC
- | elfcpp::SHF_WRITE),
- this->got_plt_, got_plt_order,
- is_got_plt_relro);
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_plt_, got_plt_order,
+ is_got_plt_relro);
// The first three entries are reserved.
- this->got_plt_->set_current_data_size
- (AARCH64_GOTPLT_RESERVE_COUNT * (size / 8));
+ this->got_plt_->set_current_data_size(
+ AARCH64_GOTPLT_RESERVE_COUNT * (size / 8));
if (!is_got_plt_relro)
- {
- // Those bytes can go into the relro segment.
- layout->increase_relro
- (AARCH64_GOTPLT_RESERVE_COUNT * (size / 8));
- }
+ {
+ // Those bytes can go into the relro segment.
+ layout->increase_relro(
+ AARCH64_GOTPLT_RESERVE_COUNT * (size / 8));
+ }
}
return this->got_;
@@ -590,8 +626,8 @@ class Output_data_plt_aarch64 : public Output_section_data
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
Output_data_plt_aarch64(Layout* layout,
- uint64_t addralign,
- Output_data_space* got_plt)
+ uint64_t addralign,
+ Output_data_space* got_plt)
: Output_section_data(addralign),
got_plt_(got_plt),
count_(0)
@@ -610,6 +646,11 @@ class Output_data_plt_aarch64 : public Output_section_data
rela_plt()
{ return this->rel_; }
+ // Return whether we created a section for IRELATIVE relocations.
+ bool
+ has_irelative_section() const
+ { return this->irelative_rel_ != NULL; }
+
// Return the number of PLT entries.
unsigned int
entry_count() const
@@ -625,6 +666,14 @@ class Output_data_plt_aarch64 : public Output_section_data
get_plt_entry_size() const
{ return this->do_get_plt_entry_size(); }
+ // Return the PLT address to use for a global symbol.
+ uint64_t
+ address_for_global(const Symbol*);
+
+ // Return the PLT address to use for a local symbol.
+ uint64_t
+ address_for_local(const Relobj*, unsigned int symndx);
+
protected:
// Fill in the first PLT entry.
void
@@ -682,6 +731,9 @@ class Output_data_plt_aarch64 : public Output_section_data
// The reloc section.
Reloc_section* rel_;
+ // The IRELATIVE relocs, if necessary. These must follow the
+ // regular PLT relocations.
+ Reloc_section* irelative_rel_;
// The .got section.
Output_data_got_aarch64<size, big_endian>* got_;
// The .got.plt section.
@@ -717,16 +769,67 @@ void
Output_data_plt_aarch64<size, big_endian>::add_entry(Symbol* gsym)
{
gold_assert(!gsym->has_plt_offset());
- //TODO
+
+ gsym->set_plt_offset((this->count_) * this->get_plt_entry_size()
+ + this->first_plt_entry_offset());
+
+ ++this->count_;
+
+ section_offset_type got_offset = this->got_plt_->current_data_size();
+
+ // Every PLT entry needs a GOT entry which points back to the PLT
+ // entry (this will be changed by the dynamic linker, normally
+ // lazily when the function is called).
+ this->got_plt_->set_current_data_size(got_offset + size / 8);
+
+ // Every PLT entry needs a reloc.
+ gsym->set_needs_dynsym_entry();
+ this->rel_->add_global(gsym, elfcpp::R_AARCH64_JUMP_SLOT,
+ this->got_plt_, got_offset, 0);
+
+ // Note that we don't need to save the symbol. The contents of the
+ // PLT are independent of which symbols are used. The symbols only
+ // appear in the relocations.
+}
+
+// Return the PLT address to use for a global symbol.
+
+template<int size, bool big_endian>
+uint64_t
+Output_data_plt_aarch64<size, big_endian>::address_for_global(
+ const Symbol* gsym)
+{
+ uint64_t offset = 0;
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false))
+ offset = (this->first_plt_entry_offset() +
+ this->count_ * this->get_plt_entry_size());
+ return this->address() + offset + gsym->plt_offset();
+}
+
+// Return the PLT address to use for a local symbol. These are always
+// IRELATIVE relocs.
+
+template<int size, bool big_endian>
+uint64_t
+Output_data_plt_aarch64<size, big_endian>::address_for_local(
+ const Relobj* object,
+ unsigned int r_sym)
+{
+ return (this->address()
+ + this->first_plt_entry_offset()
+ + this->count_ * this->get_plt_entry_size()
+ + object->local_plt_offset(r_sym));
}
// Set the final size.
+
template<int size, bool big_endian>
void
Output_data_plt_aarch64<size, big_endian>::set_final_data_size()
{
this->set_data_size(this->first_plt_entry_offset()
- + this->count * this->get_plt_entry_size());
+ + this->count_ * this->get_plt_entry_size());
}
template<int size, bool big_endian>
@@ -737,8 +840,8 @@ class Output_data_plt_aarch64_standard :
typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
Output_data_plt_aarch64_standard(Layout* layout, Output_data_space* got_plt)
: Output_data_plt_aarch64<size, big_endian>(layout,
- size == 32 ? 4 : 8,
- got_plt)
+ size == 32 ? 4 : 8,
+ got_plt)
{ }
protected:
@@ -754,15 +857,15 @@ class Output_data_plt_aarch64_standard :
virtual void
do_fill_first_plt_entry(unsigned char* pov,
- Address got_address,
- Address plt_address);
+ Address got_address,
+ Address plt_address);
virtual void
do_fill_plt_entry(unsigned char* pov,
- Address got_address,
- Address plt_address,
- unsigned int got_offset,
- unsigned int plt_offset);
+ Address got_address,
+ Address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset);
private:
// The size of the first plt entry size.
@@ -885,8 +988,8 @@ template<int size, bool big_endian>
void
Output_data_plt_aarch64_standard<size, big_endian>::do_fill_first_plt_entry(
unsigned char* pov,
- Address /* got_address */,
- Address /* plt_address */)
+ Address got_address,
+ Address plt_address)
{
// PLT0 of the small PLT looks like this in ELF64 -
// stp x16, x30, [sp, #-16]! Save the reloc and lr on stack.
@@ -899,22 +1002,62 @@ Output_data_plt_aarch64_standard<size, big_endian>::do_fill_first_plt_entry(
// PLT0 will be slightly different in ELF32 due to different got entry
// size.
memcpy(pov, this->first_plt_entry, this->first_plt_entry_size);
- // TODO
+ Address gotplt_2nd_ent = got_address + (size / 8) * 2;
+
+ // Fill in the top 21 bits for this: ADRP x16, PLT_GOT + 8 * 2.
+ // ADRP: (PG(S+A)-PG(P)) >> 12) & 0x1fffff.
+ // FIXME: This only works for 64bit
+ AArch64_relocate_functions<size, big_endian>::adrp(pov + 4,
+ gotplt_2nd_ent, plt_address + 4);
+
+ // Fill in R_AARCH64_LDST8_LO12
+ elfcpp::Swap<32, big_endian>::writeval(
+ pov + 8,
+ ((this->first_plt_entry[2] & 0xffc003ff)
+ | ((gotplt_2nd_ent & 0xff8) << 7)));
+
+ // Fill in R_AARCH64_ADD_ABS_LO12
+ elfcpp::Swap<32, big_endian>::writeval(
+ pov + 12,
+ ((this->first_plt_entry[3] & 0xffc003ff)
+ | ((gotplt_2nd_ent & 0xfff) << 10)));
}
// Subsequent entries in the PLT for an executable.
+// FIXME: This only works for 64bit
template<int size, bool big_endian>
void
Output_data_plt_aarch64_standard<size, big_endian>::do_fill_plt_entry(
unsigned char* pov,
- Address /* got_address*/,
- Address /* plt_address */,
- unsigned int /* got_offset */,
- unsigned int /* plt_offset */)
+ Address got_address,
+ Address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset)
{
memcpy(pov, this->plt_entry, this->plt_entry_size);
- //TODO
+
+ Address gotplt_entry_address = got_address + got_offset;
+ Address plt_entry_address = plt_address + plt_offset;
+
+ // Fill in R_AARCH64_PCREL_ADR_HI21
+ AArch64_relocate_functions<size, big_endian>::adrp(
+ pov,
+ gotplt_entry_address,
+ plt_entry_address);
+
+ // Fill in R_AARCH64_LDST64_ABS_LO12
+ elfcpp::Swap<32, big_endian>::writeval(
+ pov + 4,
+ ((this->plt_entry[1] & 0xffc003ff)
+ | ((gotplt_entry_address & 0xff8) << 7)));
+
+ // Fill in R_AARCH64_ADD_ABS_LO12
+ elfcpp::Swap<32, big_endian>::writeval(
+ pov + 8,
+ ((this->plt_entry[2] & 0xffc003ff)
+ | ((gotplt_entry_address & 0xfff) <<10)));
+
}
// Write out the PLT. This uses the hand-coded instructions above,
@@ -939,8 +1082,6 @@ Output_data_plt_aarch64<size, big_endian>::do_write(Output_file* of)
// The base address of the .plt section.
typename elfcpp::Elf_types<size>::Elf_Addr plt_address = this->address();
- // The base address of the .got section.
- typename elfcpp::Elf_types<size>::Elf_Addr got_base = this->got_->address();
// The base address of the PLT portion of the .got section.
typename elfcpp::Elf_types<size>::Elf_Addr got_address
= this->got_plt_->address();
@@ -966,11 +1107,10 @@ Output_data_plt_aarch64<size, big_endian>::do_write(Output_file* of)
{
// Set and adjust the PLT entry itself.
this->fill_plt_entry(pov, got_address, plt_address,
- got_offset, plt_offset);
+ got_offset, plt_offset);
- // Set the entry in the GOT.
- elfcpp::Swap<size, big_endian>::writeval(got_pov,
- plt_address + plt_offset);
+ // Set the entry in the GOT, which points to plt0.
+ elfcpp::Swap<size, big_endian>::writeval(got_pov, plt_address);
}
gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
@@ -980,6 +1120,333 @@ Output_data_plt_aarch64<size, big_endian>::do_write(Output_file* of)
of->write_output_view(got_file_offset, got_size, got_view);
}
+// Telling how to update the immediate field of an instruction.
+struct AArch64_howto
+{
+ // The immediate field mask.
+ elfcpp::Elf_Xword dst_mask;
+
+ // The offset to apply relocation immediate
+ int doffset;
+
+ // The second part offset, if the immediate field has two parts.
+ // -1 if the immediate field has only one part.
+ int doffset2;
+};
+
+static const AArch64_howto aarch64_howto[AArch64_reloc_property::INST_NUM] =
+{
+ {0, -1, -1}, // DATA
+ {0x1fffe0, 5, -1}, // MOVW [20:5]-imm16
+ {0xffffe0, 5, -1}, // LD [23:5]-imm19
+ {0x60ffffe0, 29, 5}, // ADR [30:29]-immlo [23:5]-immhi
+ {0x60ffffe0, 29, 5}, // ADRP [30:29]-immlo [23:5]-immhi
+ {0x3ffc00, 10, -1}, // ADD [21:10]-imm12
+ {0x3ffc00, 10, -1}, // LDST [21:10]-imm12
+ {0x7ffe0, 5, -1}, // TBZNZ [18:5]-imm14
+ {0xffffe0, 5, -1}, // CONDB [23:5]-imm19
+ {0x3ffffff, 0, -1}, // B [25:0]-imm26
+ {0x3ffffff, 0, -1}, // CALL [25:0]-imm26
+};
+
+// AArch64 relocate function class
+
+template<int size, bool big_endian>
+class AArch64_relocate_functions
+{
+ public:
+ typedef enum
+ {
+ STATUS_OKAY, // No error during relocation.
+ STATUS_OVERFLOW, // Relocation overflow.
+ STATUS_BAD_RELOC, // Relocation cannot be applied.
+ } Status;
+
+ private:
+ typedef AArch64_relocate_functions<size, big_endian> This;
+ typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
+ // Return the page address of the address.
+ // Page(address) = address & ~0xFFF
+
+ static inline typename elfcpp::Swap<size, big_endian>::Valtype
+ Page(Address address)
+ {
+ return (address & (~static_cast<Address>(0xFFF)));
+ }
+
+ // Update instruction (pointed by view) with selected bits (immed).
+ // val = (val & ~dst_mask) | (immed << doffset)
+
+ template<int valsize>
+ static inline void
+ update_view(unsigned char* view,
+ typename elfcpp::Swap<size, big_endian>::Valtype immed,
+ elfcpp::Elf_Xword doffset,
+ elfcpp::Elf_Xword dst_mask)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+
+ // Clear immediate fields.
+ val &= ~dst_mask;
+ elfcpp::Swap<valsize, big_endian>::writeval(wv,
+ static_cast<Valtype>(val | (immed << doffset)));
+ }
+
+ // Update two parts of an instruction (pointed by view) with selected
+ // bits (immed1 and immed2).
+ // val = (val & ~dst_mask) | (immed1 << doffset1) | (immed2 << doffset2)
+
+ template<int valsize>
+ static inline void
+ update_view_two_parts(
+ unsigned char* view,
+ typename elfcpp::Swap<size, big_endian>::Valtype immed1,
+ typename elfcpp::Swap<size, big_endian>::Valtype immed2,
+ elfcpp::Elf_Xword doffset1,
+ elfcpp::Elf_Xword doffset2,
+ elfcpp::Elf_Xword dst_mask)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
+ val &= ~dst_mask;
+ elfcpp::Swap<valsize, big_endian>::writeval(wv,
+ static_cast<Valtype>(val | (immed1 << doffset1) |
+ (immed2 << doffset2)));
+ }
+
+ // Update adr or adrp instruction with [32:12] of X.
+ // In adr and adrp: [30:29] immlo [23:5] immhi
+
+ static inline void
+ update_adr(unsigned char* view,
+ typename elfcpp::Swap<size, big_endian>::Valtype x,
+ const AArch64_reloc_property* /* reloc_property */)
+ {
+ elfcpp::Elf_Xword dst_mask = (0x3 << 29) | (0x7ffff << 5);
+ typename elfcpp::Swap<32, big_endian>::Valtype immed =
+ (x >> 12) & 0x1fffff;
+ This::template update_view_two_parts<32>(
+ view,
+ immed & 0x3,
+ (immed & 0x1ffffc) >> 2,
+ 29,
+ 5,
+ dst_mask);
+ }
+
+ public:
+
+ // Do a simple rela relocation at unaligned addresses.
+
+ template<int valsize>
+ static inline typename This::Status
+ rela_ua(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ const AArch64_reloc_property* reloc_property)
+ {
+ typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
+ Valtype;
+ typename elfcpp::Elf_types<size>::Elf_Addr x =
+ psymval->value(object, addend);
+ elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view,
+ static_cast<Valtype>(x));
+ return (reloc_property->checkup_x_value(x)
+ ? This::STATUS_OKAY
+ : This::STATUS_OVERFLOW);
+ }
+
+ // Do a simple pc-relative relocation at unaligned addresses.
+
+ template<int valsize>
+ static inline typename This::Status
+ pcrela_ua(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ Address address,
+ const AArch64_reloc_property* reloc_property)
+ {
+ typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
+ Valtype;
+ Address x = psymval->value(object, addend) - address;
+ elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view,
+ static_cast<Valtype>(x));
+ return (reloc_property->checkup_x_value(x)
+ ? This::STATUS_OKAY
+ : This::STATUS_OVERFLOW);
+ }
+
+ // Do a simple rela relocation at aligned addresses.
+
+ template<int valsize>
+ static inline typename This::Status
+ rela(
+ unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ const AArch64_reloc_property* reloc_property)
+ {
+ typedef typename elfcpp::Swap<valsize, big_endian>::Valtype
+ Valtype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Address x = psymval->value(object, addend);
+ elfcpp::Swap<valsize, big_endian>::writeval(wv,
+ static_cast<Valtype>(x));
+ return (reloc_property->checkup_x_value(x)
+ ? This::STATUS_OKAY
+ : This::STATUS_OVERFLOW);
+ }
+
+ // Do relocate. Update selected bits in text.
+ // new_val = (val & ~dst_mask) | (immed << doffset)
+
+ template<int valsize>
+ static inline typename This::Status
+ rela_general(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ const AArch64_reloc_property* reloc_property)
+ {
+ // Calculate relocation.
+ Address x = psymval->value(object, addend);
+
+ // Select bits from X.
+ Address immed = reloc_property->select_x_value(x);
+
+ // Update view.
+ const AArch64_reloc_property::Reloc_inst inst =
+ reloc_property->reloc_inst();
+ // If it is a data relocation or instruction has 2 parts of immediate
+ // fields, you should not call rela_general.
+ gold_assert(aarch64_howto[inst].doffset2 == -1 &&
+ aarch64_howto[inst].doffset != -1);
+ This::template update_view<valsize>(view, immed,
+ aarch64_howto[inst].doffset,
+ aarch64_howto[inst].dst_mask);
+
+ // Do check overflow or alignment if needed.
+ return (reloc_property->checkup_x_value(x)
+ ? This::STATUS_OKAY
+ : This::STATUS_OVERFLOW);
+ }
+
+ // Do relocate. Update selected bits in text.
+ // new val = (val & ~dst_mask) | (immed << doffset)
+
+ template<int valsize>
+ static inline typename This::Status
+ rela_general(
+ unsigned char* view,
+ typename elfcpp::Swap<size, big_endian>::Valtype s,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ const AArch64_reloc_property* reloc_property)
+ {
+ // Calculate relocation.
+ Address x = s + addend;
+
+ // Select bits from X.
+ Address immed = reloc_property->select_x_value(x);
+
+ // Update view.
+ const AArch64_reloc_property::Reloc_inst inst =
+ reloc_property->reloc_inst();
+ // If it is a data relocation or instruction has 2 parts of immediate
+ // fields, you should not call rela_general.
+ gold_assert(aarch64_howto[inst].doffset2 == -1 &&
+ aarch64_howto[inst].doffset != -1);
+ This::template update_view<valsize>(view, immed,
+ aarch64_howto[inst].doffset,
+ aarch64_howto[inst].dst_mask);
+
+ // Do check overflow or alignment if needed.
+ return (reloc_property->checkup_x_value(x)
+ ? This::STATUS_OKAY
+ : This::STATUS_OVERFLOW);
+ }
+
+ // Do address relative relocate. Update selected bits in text.
+ // new val = (val & ~dst_mask) | (immed << doffset)
+
+ template<int valsize>
+ static inline typename This::Status
+ pcrela_general(
+ unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ typename elfcpp::Swap<size, big_endian>::Valtype addend,
+ Address address,
+ const AArch64_reloc_property* reloc_property)
+ {
+ // Calculate relocation.
+ Address x = psymval->value(object, addend) - address;
+
+ // Select bits from X.
+ Address immed = reloc_property->select_x_value(x);
+
+ // Update view.
+ const AArch64_reloc_property::Reloc_inst inst =
+ reloc_property->reloc_inst();
+ // If it is a data relocation or instruction has 2 parts of immediate
+ // fields, you should not call pcrela_general.
+ gold_assert(aarch64_howto[inst].doffset2 == -1 &&
+ aarch64_howto[inst].doffset != -1);
+ This::template update_view<valsize>(view, immed,
+ aarch64_howto[inst].doffset,
+ aarch64_howto[inst].dst_mask);
+
+ // Do check overflow or alignment if needed.
+ return (reloc_property->checkup_x_value(x)
+ ? This::STATUS_OKAY
+ : This::STATUS_OVERFLOW);
+ }
+
+ // Calculate PG(S+A) - PG(address), update adrp instruction.
+ // R_AARCH64_ADR_PREL_PG_HI21
+
+ static inline typename This::Status
+ adrp(
+ unsigned char* view,
+ Address sa,
+ Address address)
+ {
+ typename elfcpp::Swap<size, big_endian>::Valtype x =
+ This::Page(sa) - This::Page(address);
+ update_adr(view, x, NULL);
+ return (size == 64 && Bits<32>::has_overflow(x)
+ ? This::STATUS_OVERFLOW
+ : This::STATUS_OKAY);
+ }
+
+ // Calculate PG(S+A) - PG(address), update adrp instruction.
+ // R_AARCH64_ADR_PREL_PG_HI21
+
+ static inline typename This::Status
+ adrp(unsigned char* view,
+ const Sized_relobj_file<size, big_endian>* object,
+ const Symbol_value<size>* psymval,
+ Address addend,
+ Address address,
+ const AArch64_reloc_property* reloc_property)
+ {
+ Address sa = psymval->value(object, addend);
+ typename elfcpp::Swap<size, big_endian>::Valtype x =
+ This::Page(sa) - This::Page(address);
+ update_adr(view, x, reloc_property);
+ return (reloc_property->checkup_x_value(x)
+ ? This::STATUS_OKAY
+ : This::STATUS_OVERFLOW);
+ }
+
+};
+
// Return the number of entries in the PLT.
template<int size, bool big_endian>
@@ -1016,29 +1483,12 @@ Target_aarch64<size, big_endian>::plt_entry_size() const
template<int size, bool big_endian>
tls::Tls_optimization
Target_aarch64<size, big_endian>::optimize_tls_reloc(bool /* is_final */,
- int /* r_type */)
+ int /* r_type */)
{
//TODO
return tls::TLSOPT_NONE;
}
-// Get the Reference_flags for a particular relocation.
-template<int size, bool big_endian>
-int
-Target_aarch64<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
-{
- switch (r_type)
- {
- case elfcpp::R_AARCH64_NONE:
- // No symbol reference.
- return 0;
- //TODO
- default:
- // Not expected. We will give an error later.
- return 0;
- }
-}
-
// Returns true if this relocation type could be that of a function pointer.
template<int size, bool big_endian>
@@ -1051,7 +1501,7 @@ Target_aarch64<size, big_endian>::Scan::possible_function_pointer_reloc(
case elfcpp::R_AARCH64_ABS64:
//TODO
{
- return true;
+ return true;
}
}
return false;
@@ -1078,7 +1528,7 @@ Target_aarch64<size, big_endian>::Scan::local_reloc_may_be_function_pointer(
// not possible to distinguish pointer taken versus a call by looking at
// the relocation types.
return (parameters->options().shared()
- || possible_function_pointer_reloc(r_type));
+ || possible_function_pointer_reloc(r_type));
}
// For safe ICF, scan a relocation for a global symbol to check if it
@@ -1101,10 +1551,10 @@ Target_aarch64<size, big_endian>::Scan::global_reloc_may_be_function_pointer(
// When building a shared library, do not fold symbols whose visibility
// is hidden, internal or protected.
return ((parameters->options().shared()
- && (gsym->visibility() == elfcpp::STV_INTERNAL
- || gsym->visibility() == elfcpp::STV_PROTECTED
- || gsym->visibility() == elfcpp::STV_HIDDEN))
- || possible_function_pointer_reloc(r_type));
+ && (gsym->visibility() == elfcpp::STV_INTERNAL
+ || gsym->visibility() == elfcpp::STV_PROTECTED
+ || gsym->visibility() == elfcpp::STV_HIDDEN))
+ || possible_function_pointer_reloc(r_type));
}
// Report an unsupported relocation against a local symbol.
@@ -1125,7 +1575,7 @@ Target_aarch64<size, big_endian>::Scan::unsupported_reloc_local(
template<int size, bool big_endian>
void
Target_aarch64<size, big_endian>::Scan::check_non_pic(Relobj* object,
- unsigned int r_type)
+ unsigned int r_type)
{
gold_assert(r_type != elfcpp::R_AARCH64_NONE);
@@ -1157,7 +1607,7 @@ Target_aarch64<size, big_endian>::Scan::check_non_pic(Relobj* object,
return;
gold_assert(parameters->options().output_is_position_independent());
object->error(_("requires unsupported dynamic reloc; "
- "recompile with -fPIC"));
+ "recompile with -fPIC"));
this->issued_non_pic_error_ = true;
return;
}
@@ -1170,7 +1620,7 @@ Target_aarch64<size, big_endian>::Scan::local(
Symbol_table* /* symtab */,
Layout* /* layout */,
Target_aarch64<size, big_endian>* /* target */,
- Sized_relobj_file<size, big_endian>* /* object */,
+ Sized_relobj_file<size, big_endian>* object,
unsigned int /* data_shndx */,
Output_section* /* output_section */,
const elfcpp::Rela<size, big_endian>& /* reloc */,
@@ -1183,10 +1633,35 @@ Target_aarch64<size, big_endian>::Scan::local(
switch (r_type)
{
- case elfcpp::R_AARCH64_NONE:
+ case elfcpp::R_AARCH64_ABS64:
+ case elfcpp::R_AARCH64_ABS32:
+ case elfcpp::R_AARCH64_ABS16:
+ // If building a shared library or pie, we need to mark this as a dynmic
+ // reloction, so that the dynamic loader can relocate it.
+ // Not supported yet.
+ if (parameters->options().output_is_position_independent())
+ {
+ gold_error(_("%s: unsupported ABS64 relocation type for pie or "
+ "shared library.\n"),
+ object->name().c_str());
+ }
+ break;
+
+ // Relocations to generate 19, 21 and 33-bit PC-relative address
+ case elfcpp::R_AARCH64_ADR_PREL_PG_HI21: // 275
+ case elfcpp::R_AARCH64_LDST8_ABS_LO12_NC: // 278
+ case elfcpp::R_AARCH64_LDST64_ABS_LO12_NC: // 286
+ case elfcpp::R_AARCH64_ADD_ABS_LO12_NC: // 277
break;
- //TODO
+ // Control flow, pc-relative. We don't need to do anything for a relative
+ // addressing relocation against a local symbol if it does not reference
+ // the GOT.
+ case elfcpp::R_AARCH64_CALL26: // 283
+ break;
+
+ default:
+ unsupported_reloc_local(object, r_type);
}
}
@@ -1207,18 +1682,132 @@ Target_aarch64<size, big_endian>::Scan::unsupported_reloc_global(
template<int size, bool big_endian>
inline void
Target_aarch64<size, big_endian>::Scan::global(
- Symbol_table* /* symtab */,
- Layout* /* layout */,
- Target_aarch64<size, big_endian>* /* target */,
+ Symbol_table* symtab,
+ Layout* layout,
+ Target_aarch64<size, big_endian>* target,
Sized_relobj_file<size, big_endian>* /* object */,
unsigned int /* data_shndx */,
Output_section* /* output_section */,
const elfcpp::Rela<size, big_endian>& /* reloc */,
- unsigned int /* r_type */,
- Symbol* /* gsym */)
+ unsigned int r_type,
+ Symbol* gsym)
{
- //TODO
+ switch (r_type)
+ {
+ case elfcpp::R_AARCH64_ABS64:
+ // This is used to fill the GOT absolute address.
+ if (gsym->needs_plt_entry())
+ {
+ target->make_plt_entry(symtab, layout, gsym);
+ }
+ break;
+
+ case elfcpp::R_AARCH64_ADR_PREL_PG_HI21:
+ case elfcpp::R_AARCH64_ADR_PREL_PG_HI21_NC:
+ case elfcpp::R_AARCH64_ADD_ABS_LO12_NC:
+ {
+ // Do nothing here.
+ break;
+ }
+
+ case elfcpp::R_AARCH64_ADR_GOT_PAGE:
+ case elfcpp::R_AARCH64_LD64_GOT_LO12_NC:
+ {
+ // This pair of relocations is used to access a specific GOT entry.
+ // Note a GOT entry is an *address* to a symbol.
+ // The symbol requires a GOT entry
+ Output_data_got_aarch64<size, big_endian>* got =
+ target->got_section(symtab, layout);
+ if (gsym->final_value_is_known())
+ {
+ got->add_global(gsym, GOT_TYPE_STANDARD);
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ if (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible()
+ || (gsym->visibility() == elfcpp::STV_PROTECTED
+ && parameters->options().shared()))
+ got->add_global_with_rel(gsym, GOT_TYPE_STANDARD,
+ rela_dyn, elfcpp::R_AARCH64_GLOB_DAT);
+ else
+ {
+ // Not implemented yet.
+ gold_assert(false);
+ }
+ }
+ break;
+ }
+
+ case elfcpp::R_AARCH64_JUMP26:
+ case elfcpp::R_AARCH64_CALL26:
+ {
+ if (gsym->final_value_is_known())
+ break;
+
+ if (gsym->is_defined() &&
+ !gsym->is_from_dynobj() &&
+ !gsym->is_preemptible())
+ break;
+
+ // Make plt entry for function call.
+ const AArch64_reloc_property* arp =
+ aarch64_reloc_property_table->get_reloc_property(r_type);
+ gold_assert(arp != NULL);
+ target->make_plt_entry(symtab, layout, gsym);
+ break;
+ }
+
+ default:
+ gold_error(_("%s: unsupported reloc type"),
+ aarch64_reloc_property_table->
+ reloc_name_in_error_message(r_type).c_str());
+ }
return;
+} // End of Scan::global
+
+// Create the PLT section.
+template<int size, bool big_endian>
+void
+Target_aarch64<size, big_endian>::make_plt_section(
+ Symbol_table* symtab, Layout* layout)
+{
+ if (this->plt_ == NULL)
+ {
+ // Create the GOT section first.
+ this->got_section(symtab, layout);
+
+ this->plt_ = this->make_data_plt(layout, this->got_plt_);
+
+ layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_EXECINSTR),
+ this->plt_, ORDER_PLT, false);
+
+ // Make the sh_info field of .rela.plt point to .plt.
+ Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
+ rela_plt_os->set_info_section(this->plt_->output_section());
+ }
+}
+
+// Create a PLT entry for a global symbol.
+
+template<int size, bool big_endian>
+void
+Target_aarch64<size, big_endian>::make_plt_entry(
+ Symbol_table* symtab,
+ Layout* layout,
+ Symbol* gsym)
+{
+ if (gsym->has_plt_offset())
+ return;
+
+ if (this->plt_ == NULL)
+ this->make_plt_section(symtab, layout);
+
+ this->plt_->add_entry(gsym);
}
template<int size, bool big_endian>
@@ -1241,11 +1830,12 @@ Target_aarch64<size, big_endian>::gc_process_relocs(
return;
}
- gold::gc_process_relocs<size, big_endian,
- Target_aarch64<size, big_endian>,
- elfcpp::SHT_RELA,
- typename Target_aarch64<size, big_endian>::Scan,
- typename Target_aarch64<size, big_endian>::Relocatable_size_for_reloc>(
+ gold::gc_process_relocs<
+ size, big_endian,
+ Target_aarch64<size, big_endian>,
+ elfcpp::SHT_RELA,
+ typename Target_aarch64<size, big_endian>::Scan,
+ typename Target_aarch64<size, big_endian>::Relocatable_size_for_reloc>(
symtab,
layout,
this,
@@ -1282,10 +1872,7 @@ Target_aarch64<size, big_endian>::scan_relocs(
object->name().c_str());
return;
}
-
- gold::scan_relocs<size, big_endian, Target_aarch64<size, big_endian>,
- elfcpp::SHT_RELA,
- typename Target_aarch64<size, big_endian>::Scan>(
+ gold::scan_relocs<size, big_endian, Target_aarch64, elfcpp::SHT_RELA, Scan>(
symtab,
layout,
this,
@@ -1304,11 +1891,73 @@ Target_aarch64<size, big_endian>::scan_relocs(
template<int size, bool big_endian>
void
Target_aarch64<size, big_endian>::do_finalize_sections(
- Layout* /* layout */,
+ Layout* layout,
const Input_objects*,
- Symbol_table* /* symtab */)
+ Symbol_table* symtab)
{
- //TODO
+ const Reloc_section* rel_plt = (this->plt_ == NULL
+ ? NULL
+ : this->plt_->rela_plt());
+ layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt,
+ this->rela_dyn_, true, false);
+
+ // Set the size of the _GLOBAL_OFFSET_TABLE_ symbol to the size of
+ // the .got.plt section.
+ Symbol* sym = this->global_offset_table_;
+ if (sym != NULL)
+ {
+ uint64_t data_size = this->got_plt_->current_data_size();
+ symtab->get_sized_symbol<size>(sym)->set_symsize(data_size);
+
+ // If the .got section is more than 0x8000 bytes, we add
+ // 0x8000 to the value of _GLOBAL_OFFSET_TABLE_, so that 16
+ // bit relocations have a greater chance of working.
+ if (data_size >= 0x8000)
+ symtab->get_sized_symbol<size>(sym)->set_value(
+ symtab->get_sized_symbol<size>(sym)->value() + 0x8000);
+ }
+
+ if (parameters->doing_static_link()
+ && (this->plt_ == NULL || !this->plt_->has_irelative_section()))
+ {
+ // If linking statically, make sure that the __rela_iplt symbols
+ // were defined if necessary, even if we didn't create a PLT.
+ static const Define_symbol_in_segment syms[] =
+ {
+ {
+ "__rela_iplt_start", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF_W, // segment_flags_set
+ elfcpp::PF(0), // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_HIDDEN, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_START, // offset_from_base
+ true // only_if_ref
+ },
+ {
+ "__rela_iplt_end", // name
+ elfcpp::PT_LOAD, // segment_type
+ elfcpp::PF_W, // segment_flags_set
+ elfcpp::PF(0), // segment_flags_clear
+ 0, // value
+ 0, // size
+ elfcpp::STT_NOTYPE, // type
+ elfcpp::STB_GLOBAL, // binding
+ elfcpp::STV_HIDDEN, // visibility
+ 0, // nonvis
+ Symbol::SEGMENT_START, // offset_from_base
+ true // only_if_ref
+ }
+ };
+
+ symtab->define_symbols(layout, 2, syms,
+ layout->script_options()->saw_sections_clause());
+ }
+
return;
}
@@ -1317,19 +1966,198 @@ Target_aarch64<size, big_endian>::do_finalize_sections(
template<int size, bool big_endian>
inline bool
Target_aarch64<size, big_endian>::Relocate::relocate(
- const Relocate_info<size, big_endian>* /* relinfo */,
- Target_aarch64<size, big_endian>* /* target */,
+ const Relocate_info<size, big_endian>* relinfo,
+ Target_aarch64<size, big_endian>* target,
Output_section* ,
- size_t /* relnum */,
- const elfcpp::Rela<size, big_endian>& /* rela */,
- unsigned int /* r_type */,
- const Sized_symbol<size>* /* gsym */,
- const Symbol_value<size>* /* psymval */,
- unsigned char* /* view */,
- typename elfcpp::Elf_types<size>::Elf_Addr /* address */,
+ size_t relnum,
+ const elfcpp::Rela<size, big_endian>& rela,
+ unsigned int r_type,
+ const Sized_symbol<size>* gsym,
+ const Symbol_value<size>* psymval,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
section_size_type /* view_size */)
{
- //TODO
+ if (view == NULL)
+ return true;
+
+ typedef AArch64_relocate_functions<size, big_endian> Reloc;
+
+ const AArch64_reloc_property* reloc_property =
+ aarch64_reloc_property_table->get_reloc_property(r_type);
+
+ if (reloc_property == NULL)
+ {
+ std::string reloc_name =
+ aarch64_reloc_property_table->reloc_name_in_error_message(r_type);
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("cannot relocate %s in object file"),
+ reloc_name.c_str());
+ return true;
+ }
+
+ const Sized_relobj_file<size, big_endian>* object = relinfo->object;
+
+ // Pick the value to use for symbols defined in the PLT.
+ Symbol_value<size> symval;
+ if (gsym != NULL
+ && gsym->use_plt_offset(reloc_property->reference_flags()))
+ {
+ symval.set_output_value(target->plt_address_for_global(gsym));
+ psymval = &symval;
+ }
+ else if (gsym == NULL && psymval->is_ifunc_symbol())
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ if (object->local_has_plt_offset(r_sym))
+ {
+ symval.set_output_value(target->plt_address_for_local(object, r_sym));
+ psymval = &symval;
+ }
+ }
+
+ const elfcpp::Elf_Xword addend = rela.get_r_addend();
+
+ // Get the GOT offset if needed.
+ // For aarch64, the GOT pointer points to the start of the GOT section.
+ bool have_got_offset = false;
+ int got_offset = 0;
+ int got_base = (target->got_ != NULL
+ ? (target->got_->current_data_size() >= 0x8000
+ ? 0x8000 : 0)
+ : 0);
+ switch (r_type)
+ {
+ case elfcpp::R_AARCH64_MOVW_GOTOFF_G0:
+ case elfcpp::R_AARCH64_MOVW_GOTOFF_G0_NC:
+ case elfcpp::R_AARCH64_MOVW_GOTOFF_G1:
+ case elfcpp::R_AARCH64_MOVW_GOTOFF_G1_NC:
+ case elfcpp::R_AARCH64_MOVW_GOTOFF_G2:
+ case elfcpp::R_AARCH64_MOVW_GOTOFF_G2_NC:
+ case elfcpp::R_AARCH64_MOVW_GOTOFF_G3:
+ case elfcpp::R_AARCH64_GOTREL64:
+ case elfcpp::R_AARCH64_GOTREL32:
+ case elfcpp::R_AARCH64_GOT_LD_PREL19:
+ case elfcpp::R_AARCH64_LD64_GOTOFF_LO15:
+ case elfcpp::R_AARCH64_ADR_GOT_PAGE:
+ case elfcpp::R_AARCH64_LD64_GOT_LO12_NC:
+ case elfcpp::R_AARCH64_LD64_GOTPAGE_LO15:
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+ got_offset = gsym->got_offset(GOT_TYPE_STANDARD) - got_base;
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+ got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
+ - got_base);
+ }
+ have_got_offset = true;
+ break;
+ default:
+ break;
+ }
+
+ typename Reloc::Status reloc_status = Reloc::STATUS_OKAY;
+ typename elfcpp::Elf_types<size>::Elf_Addr value;
+ switch (r_type)
+ {
+ case elfcpp::R_AARCH64_NONE:
+ break;
+
+ case elfcpp::R_AARCH64_ABS64:
+ reloc_status = Reloc::template rela_ua<64>(
+ view, object, psymval, addend, reloc_property);
+ break;
+
+ case elfcpp::R_AARCH64_ABS32:
+ reloc_status = Reloc::template rela_ua<32>(
+ view, object, psymval, addend, reloc_property);
+ break;
+
+ case elfcpp::R_AARCH64_ABS16:
+ reloc_status = Reloc::template rela_ua<16>(
+ view, object, psymval, addend, reloc_property);
+ break;
+
+ case elfcpp::R_AARCH64_PREL64:
+ reloc_status = Reloc::template pcrela_ua<64>(
+ view, object, psymval, addend, address, reloc_property);
+
+ case elfcpp::R_AARCH64_PREL32:
+ reloc_status = Reloc::template pcrela_ua<32>(
+ view, object, psymval, addend, address, reloc_property);
+
+ case elfcpp::R_AARCH64_PREL16:
+ reloc_status = Reloc::template pcrela_ua<16>(
+ view, object, psymval, addend, address, reloc_property);
+
+ case elfcpp::R_AARCH64_ADR_PREL_PG_HI21_NC:
+ case elfcpp::R_AARCH64_ADR_PREL_PG_HI21:
+ reloc_status = Reloc::adrp(view, object, psymval, addend, address,
+ reloc_property);
+ break;
+
+ case elfcpp::R_AARCH64_LDST8_ABS_LO12_NC:
+ case elfcpp::R_AARCH64_LDST16_ABS_LO12_NC:
+ case elfcpp::R_AARCH64_LDST32_ABS_LO12_NC:
+ case elfcpp::R_AARCH64_LDST64_ABS_LO12_NC:
+ case elfcpp::R_AARCH64_LDST128_ABS_LO12_NC:
+ case elfcpp::R_AARCH64_ADD_ABS_LO12_NC:
+ reloc_status = Reloc::template rela_general<32>(
+ view, object, psymval, addend, reloc_property);
+ break;
+
+ case elfcpp::R_AARCH64_CALL26:
+ case elfcpp::R_AARCH64_JUMP26:
+ reloc_status = Reloc::template pcrela_general<32>(
+ view, object, psymval, addend, address, reloc_property);
+ break;
+
+ case elfcpp::R_AARCH64_ADR_GOT_PAGE:
+ gold_assert(have_got_offset);
+ value = target->got_->address() + got_base + got_offset;
+ reloc_status = Reloc::adrp(view, value + addend, address);
+ break;
+
+ case elfcpp::R_AARCH64_LD64_GOT_LO12_NC:
+ gold_assert(have_got_offset);
+ value = target->got_->address() + got_base + got_offset;
+ reloc_status = Reloc::template rela_general<32>(
+ view, value, addend, reloc_property);
+ break;
+
+ default:
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("unsupported reloc aaa %u"),
+ r_type);
+ break;
+ }
+
+ // Report any errors.
+ switch (reloc_status)
+ {
+ case Reloc::STATUS_OKAY:
+ break;
+ case Reloc::STATUS_OVERFLOW:
+ gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+ _("relocation overflow in %s"),
+ reloc_property->name().c_str());
+ break;
+ case Reloc::STATUS_BAD_RELOC:
+ gold_error_at_location(
+ relinfo,
+ relnum,
+ rela.get_r_offset(),
+ _("unexpected opcode while processing relocation %s"),
+ reloc_property->name().c_str());
+ break;
+ default:
+ gold_unreachable();
+ }
+
return true;
}
@@ -1338,19 +2166,31 @@ Target_aarch64<size, big_endian>::Relocate::relocate(
template<int size, bool big_endian>
void
Target_aarch64<size, big_endian>::relocate_section(
- const Relocate_info<size, big_endian>* /* relinfo */,
+ const Relocate_info<size, big_endian>* relinfo,
unsigned int sh_type,
- const unsigned char* /* prelocs */,
- size_t /* reloc_count */,
- Output_section* /* output_section */,
- bool /*needs_special_offset_handling */,
- unsigned char* /* view */,
- typename elfcpp::Elf_types<size>::Elf_Addr /* address */,
- section_size_type /* view_size */,
- const Reloc_symbol_changes* /* reloc_symbol_changes */)
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size,
+ const Reloc_symbol_changes* reloc_symbol_changes)
{
- //TODO
gold_assert(sh_type == elfcpp::SHT_RELA);
+ typedef typename Target_aarch64<size, big_endian>::Relocate AArch64_relocate;
+ gold::relocate_section<size, big_endian, Target_aarch64, elfcpp::SHT_RELA,
+ AArch64_relocate, gold::Default_comdat_behavior>(
+ relinfo,
+ this,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ view,
+ address,
+ view_size,
+ reloc_symbol_changes);
}
// Return the size of a relocation while scanning during a relocatable
@@ -1412,36 +2252,46 @@ Target_aarch64<size, big_endian>::relocate_relocs(
gold_assert(sh_type == elfcpp::SHT_RELA);
}
-
// The selector for aarch64 object files.
template<int size, bool big_endian>
class Target_selector_aarch64 : public Target_selector
{
public:
- Target_selector_aarch64()
- : Target_selector(elfcpp::EM_AARCH64, size, big_endian,
- (size == 64
- ? (big_endian ? "elf64-bigaarch64"
- : "elf64-littleaarch64")
- : (big_endian ? "elf32-bigaarch64"
- : "elf32-littleaarch64")),
- (size == 64
- ? (big_endian ? "aarch64_elf64_be_vec"
- : "aarch64_elf64_le_vec")
- : (big_endian ? "aarch64_elf32_be_vec"
- : "aarch64_elf32_le_vec")))
- { }
+ Target_selector_aarch64();
virtual Target*
do_instantiate_target()
{ return new Target_aarch64<size, big_endian>(); }
};
+template<>
+Target_selector_aarch64<32, true>::Target_selector_aarch64()
+ : Target_selector(elfcpp::EM_AARCH64, 32, true,
+ "elf32-bigaarch64", "aarch64_elf32_be_vec")
+{ }
+
+template<>
+Target_selector_aarch64<32, false>::Target_selector_aarch64()
+ : Target_selector(elfcpp::EM_AARCH64, 32, false,
+ "elf32-littleaarch64", "aarch64_elf32_le_vec")
+{ }
+
+template<>
+Target_selector_aarch64<64, true>::Target_selector_aarch64()
+ : Target_selector(elfcpp::EM_AARCH64, 64, true,
+ "elf64-bigaarch64", "aarch64_elf64_be_vec")
+{ }
+
+template<>
+Target_selector_aarch64<64, false>::Target_selector_aarch64()
+ : Target_selector(elfcpp::EM_AARCH64, 64, false,
+ "elf64-littleaarch64", "aarch64_elf64_le_vec")
+{ }
+
Target_selector_aarch64<32, true> target_selector_aarch64elf32b;
Target_selector_aarch64<32, false> target_selector_aarch64elf32;
Target_selector_aarch64<64, true> target_selector_aarch64elfb;
Target_selector_aarch64<64, false> target_selector_aarch64elf;
-
} // End anonymous namespace.