gold aarch64 patch to enable linking hello_wolrd.
authorJing Yu <jingyu@google.com>
Fri, 8 Aug 2014 21:18:35 +0000 (14:18 -0700)
committerJing Yu <jingyu@google.com>
Fri, 8 Aug 2014 21:18:35 +0000 (14:18 -0700)
elfcpp/ChangeLog:
2014-08-08  Han Shen  <shenhan@google.com>

* aarch64.h (withdrawn): Replaced with R_AARCH64_withdrawn.

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.

elfcpp/ChangeLog
elfcpp/aarch64.h
gold/ChangeLog
gold/Makefile.am
gold/Makefile.in
gold/aarch64-reloc-property.cc [new file with mode: 0644]
gold/aarch64-reloc-property.h [new file with mode: 0644]
gold/aarch64-reloc.def [new file with mode: 0644]
gold/aarch64.cc

index 043fb671defcf97533d7159850f08b33e0d9afb3..eafa25238bb96b1ecfe10aca2b6c903a283868c3 100644 (file)
@@ -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.
index 4d1898f44df36340facd6fd41469298ba1b31749..52ac3eaca9af243c59e76e1843ef86fe2190e567 100644 (file)
@@ -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
index 9e1ef63af59c4f4d9143d7075634c4e266f84e9d..90997bdc8d6a28ad4f2b75fb3658c2af4484ec3a 100644 (file)
@@ -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.
index 17ba4b4f9ceefcd7f61443a9330211763bba4985..df99f23c3a771d3c075f53798f80d9aeea7a6993 100644 (file)
@@ -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)
index a8dd11101338da8f2f4d7c6bacf53599e78d30e2..d4046668f3f0a025b11d7568c6e1f9bf4e01d6a3 100644 (file)
@@ -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 (file)
index 0000000..beaed10
--- /dev/null
@@ -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 (file)
index 0000000..d8d1301
--- /dev/null
@@ -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 (file)
index 0000000..4f6710e
--- /dev/null
@@ -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.
index 17fe03150ca7e87a25e8c4d8bd16402de7eb345c..7a3fe3bd806cc13ac891d59ba24dda7f18dcf3cb 100644 (file)
@@ -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.