public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [gold][aarch64]patch2: link helloworld
@ 2014-07-30  2:05 Jing Yu
  2014-08-04  9:53 ` Jiong Wang
  2014-08-05 17:49 ` Cary Coutant
  0 siblings, 2 replies; 6+ messages in thread
From: Jing Yu @ 2014-07-30  2:05 UTC (permalink / raw)
  To: binutils, Doug Kwan, Cary Coutant; +Cc: Han Shen

[-- Attachment #1: Type: text/plain, Size: 2803 bytes --]

Here is the second patch for aarch64 gold backend, which enables
linking hello_world binary.

On x86:
$ ../binutils-gdb/configure --enable-plugins --disable-multilib
--disable-nls --enable-threads --enable-gold=default
--enable-targets=all
On aarch64:
$ ../binutils-gdb/configure --enable-plugins --disable-multilib
--disable-nls --enable-threads --enable-gold=default
--enable-targets=all

gold/ld-new is able to link hello_world binary dynamically.
Our next patch will support linking hello_world statically and linking
position independent code.

Thanks,
Jing

2014-07-29  Jing Yu <jingyu@google.com>
                  Han Shen <shenhan@google.com>

* elfcpp/aarch64.h(enum): Replace withdrawn with R_AARCH64_withdrawn
* gold/Makefile.am(HFILES): Add aarch64-reloc-property.h
  (DEFFILES): add aarch64-reloc.def
  (TARGETSOURCES): Add aarch64-reloc-property.cc
  (ALL_TARGETOBJS): aarch64-reloc-property.$(OBJEXT)
* gold/Makefile.in: Regenerate
* gold/aarch64-reloc-property.cc: New file
* gold/aarch64-reloc-property.h: New file
* gold/aarch64-reloc.def: New file
* gold/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): Femove 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
  (Target_selector_aarch64): Comment out 32-bit target instantiation.

[-- Attachment #2: gold.patch2 --]
[-- Type: application/octet-stream, Size: 78460 bytes --]

diff --git a/elfcpp/aarch64.h b/elfcpp/aarch64.h
index 4d1898f..52ac3ea 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/Makefile.am b/gold/Makefile.am
index 17ba4b4..df99f23 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 a8dd111..d404666 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 0000000..99372dc
--- /dev/null
+++ b/gold/aarch64-reloc-property.cc
@@ -0,0 +1,173 @@
+// 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,
+    const std::string& operation,
+    bool is_implemented,
+    int group_index,
+    int reference_flags,
+    Reloc_inst reloc_inst,
+    rvalue_checkup_func_p rvalue_checkup_func,
+    rvalue_bit_select_func_p rvalue_bit_select_func)
+  : code_(code), name_(name), reloc_type_(rtype), reloc_class_(rclass),
+    operation_(operation), 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_func)
+{
+  if(code == elfcpp::R_AARCH64_ABS64)
+    {
+      this->size_ = 8;
+    }
+  this->size_ = 4;
+}
+
+AArch64_reloc_property_table::AArch64_reloc_property_table()
+{
+  Parse_expression A("A"), P("P"), S("S"), GOT("GOT");
+  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, roperation, 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, \
+	  (roperation).s_expression(), \
+	  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 0000000..2d507d7
--- /dev/null
+++ b/gold/aarch64-reloc-property.h
@@ -0,0 +1,395 @@
+// 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>
+
+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_p)(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_; }
+
+  const std::string&
+  operation() const
+  { return this->operation_; }
+
+  // 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 size of relocation.
+  size_t
+  size() const
+  { return this->size_; }
+
+  // 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, const std::string& operation,
+			 bool is_implemented, int group_index,
+			 int reference_flags,
+			 Reloc_inst reloc_inst,
+			 rvalue_checkup_func_p rvalue_checkup_func,
+			 rvalue_bit_select_func_p rvalue_bit_select_func);
+
+  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&);
+
+  // The Tree_node class is used to represent parsed relocation operations.
+  // We look at Trees to extract information about relocation operations.
+  class Tree_node
+  {
+   public:
+    typedef std::vector<Tree_node*> Tree_node_vector;
+
+    // Construct a leaf node.
+    Tree_node(const char* name)
+      : is_leaf_(true), name_(name), children_()
+    { }
+
+    // Construct an internal node.  A node owns all its children and is
+    // responsible for releasing them at its own destruction.
+    Tree_node(Tree_node_vector::const_iterator begin,
+	      Tree_node_vector::const_iterator end)
+      : is_leaf_(false), name_(), children_()
+    {
+      for (Tree_node_vector::const_iterator p = begin; p != end; ++p)
+	this->children_.push_back(*p);
+    }
+
+    ~Tree_node()
+    {
+      for(size_t i = 0; i <this->children_.size(); ++i)
+	delete this->children_[i];
+    }
+
+    // Whether this is a leaf node.
+    bool
+    is_leaf() const
+    { return this->is_leaf_; }
+
+    // Return name of this.  This is only valid for a leaf node.
+    const std::string&
+    name() const
+    {
+      gold_assert(this->is_leaf_);
+      return this->name_;
+    }
+
+    // Return the number of children.  This is only valid for a non-leaf node.
+    size_t
+    number_of_children() const
+    {
+      gold_assert(!this->is_leaf_);
+      return this->children_.size();
+    }
+
+    // Return the i-th child of this.  This is only valid for a non-leaf node.
+    Tree_node*
+    child(size_t i) const
+    {
+      gold_assert(!this->is_leaf_ && i < this->children_.size());
+      return this->children_[i];
+    }
+
+    // Parse an S-expression string and build a tree and return the root node.
+    // Caller is responsible for releasing tree after use.
+    static Tree_node*
+    make_tree(const std::string&);
+
+    // Convert a tree back to an S-expression string.
+    std::string
+    s_expression() const
+    {
+      if (this->is_leaf_)
+	return this->name_;
+
+      // Concatenate S-expressions of children. Enclose them with
+      // a pair of parentheses and use space as token delimiters.
+      std::string s("(");
+      for(size_t i = 0; i <this->children_.size(); ++i)
+	s = s + " " + this->children_[i]->s_expression();
+      return s + " )";
+    }
+
+   private:
+    // Whether this is a leaf node.
+    bool is_leaf_;
+    // Name of this if this is a leaf node.
+    std::string name_;
+    // Children of this if this a non-leaf node.
+    Tree_node_vector children_;
+  };
+
+  // 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_;
+  // Relocation operation
+  const std::string operation_;
+  // 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_p 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);
+    gold_assert(idx < Property_table_size);
+    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);
+    gold_assert(idx < Property_table_size);
+    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&);
+
+  // The Parse_expression class is used to convert relocation operations in
+  // aarch64-reloc.def into S-expression strings, which are parsed again to
+  // build actual expression trees.  We do not build the expression trees
+  // directly because the parser for operations in arm-reloc.def is simpler
+  // this way.  Conversion from S-expressions to trees is simple.
+  class Parse_expression
+  {
+   public:
+    // Construction a Parse_expression with an S-expression string.
+    Parse_expression(const std::string& s_expression)
+      : s_expression_(s_expression)
+    { }
+
+    // Value of this expression as an S-expression string.
+    const std::string&
+    s_expression() const
+    { return this->s_expression_; }
+
+    // We want to overload operators used in relocation operations so
+    // that we can execute operations in arm-reloc.def to generate
+    // S-expressions directly.
+#define DEF_OPERATOR_OVERLOAD(op) \
+    Parse_expression \
+    operator op (const Parse_expression& e) \
+    { \
+      return Parse_expression("( " #op " " + this->s_expression_ + " " + \
+			      e.s_expression_ + " )"); \
+    }
+
+    // Operator appearing in relocation operations in arm-reloc.def.
+    DEF_OPERATOR_OVERLOAD(+)
+    DEF_OPERATOR_OVERLOAD(-)
+
+   private:
+    // This represented as an S-expression string.
+    std::string s_expression_;
+  };  // End of inner class Parse_expression
+
+#define DEF_RELOC_FUNC(name) \
+  static Parse_expression \
+  (name)(const Parse_expression& arg) \
+  { return Parse_expression("( " #name " " + arg.s_expression() + " )"); }
+
+  // Functions appearing in relocation operations in arm-reloc.def.
+  DEF_RELOC_FUNC(Page)
+  DEF_RELOC_FUNC(G)
+  DEF_RELOC_FUNC(GDAT)
+  DEF_RELOC_FUNC(GTPREL)
+
+  // Map aarch64 rtypes into range(0,300) as following
+  //   256 ~ 313 -> 0 ~ 57
+  //   512 ~ 573 -> 128 ~ 189
+  //   1024 ~ 1032 -> 256 ~ 264
+  int
+  code_to_array_index(unsigned int code) const
+  {
+    if (code == 0) return 0;
+    gold_assert(code >= 256 && code <= 1200);
+    unsigned int rv;
+    if (code & (1 << 10))
+      {
+	rv = 256 + code - 1024;
+	gold_assert(rv < Property_table_size);
+      }
+    else if (code & (1 << 9))
+      {
+	rv = 128 + code - 512;
+	gold_assert(rv < 256);
+      }
+    else
+      {
+	rv = code - 256;
+	gold_assert(rv < 128);
+      }
+    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 0000000..5da4794
--- /dev/null
+++ b/gold/aarch64-reloc.def
@@ -0,0 +1,69 @@
+// 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------------------------------------------------------------------------------+   |      |                       |     |			    |
+// Operation---------------------------------------------+                                  |   |      |                       |     |			    |
+// Class-------------------------------------+           |                                  |   |      |                       |     |			    |
+// Type----------------------------+         |           |                                  |   |      |                       |     |			    |
+// Name                            |         |           |                                  |   |      |                       |     |			    |
+//  |                              |         |           |                                  |   |      |                       |     |			    |
+ARD(ABS64                        , STATIC ,  DATA      , S + A                          ,   Y,  -1,   0,0                ,    0,0  , Symbol::ABSOLUTE_REF , DATA )
+ARD(ABS32                        , STATIC ,  DATA      , S + A                          ,   Y,  -1,  31,32               ,    0,0  , Symbol::ABSOLUTE_REF , DATA )
+ARD(ABS16                        , STATIC ,  DATA      , S + A                          ,   Y,  -1,  15,16               ,    0,0  , Symbol::ABSOLUTE_REF , DATA )
+ARD(PREL64                       , STATIC ,  DATA      , S + A - P                      ,   Y,  -1,   0,0                ,    0,0  , Symbol::RELATIVE_REF , DATA )
+ARD(PREL32                       , STATIC ,  DATA      , S + A - P                      ,   Y,  -1,  31,32               ,    0,0  , Symbol::RELATIVE_REF , DATA )
+ARD(PREL16                       , STATIC ,  DATA      , S + A - P                      ,   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   , Page(S + A) - Page(P)          ,   Y, -1,   32,32               ,   12,32 , Symbol::RELATIVE_REF , ADRP )
+ARD(ADR_PREL_PG_HI21_NC          , STATIC ,  AARCH64   , Page(S + A) - Page(P)          ,   Y, -1,    0,0                ,   12,32 , Symbol::RELATIVE_REF , ADRP )
+ARD(LDST8_ABS_LO12_NC            , STATIC ,  AARCH64   , S + A                          ,   Y, -1,    0,0                ,    0,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(LDST16_ABS_LO12_NC           , STATIC ,  AARCH64   , S + A                          ,   Y, -1,    0,RL_CHECK_ALIGN2  ,    1,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(LDST32_ABS_LO12_NC           , STATIC ,  AARCH64   , S + A                          ,   Y, -1,    0,RL_CHECK_ALIGN4  ,    2,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(LDST64_ABS_LO12_NC           , STATIC ,  AARCH64   , S + A                          ,   Y, -1,    0,RL_CHECK_ALIGN8  ,    3,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(LDST128_ABS_LO12_NC          , STATIC ,  AARCH64   , S + A                          ,   Y, -1,    0,RL_CHECK_ALIGN16 ,    4,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(ADD_ABS_LO12_NC              , STATIC ,  AARCH64   , S + A                          ,   Y, -1,    0,0                ,    0,11 , Symbol::ABSOLUTE_REF , ADD )
+ARD(ADR_GOT_PAGE                 , STATIC ,  AARCH64   , Page(G(GDAT(S + A))) - Page(P) ,   Y, -1,   32,32               ,   12,32 , Symbol::RELATIVE_REF , ADRP )
+ARD(LD64_GOT_LO12_NC             , STATIC ,  AARCH64   , G(GDAT(S + A))                 ,   Y, -1,    0,RL_CHECK_ALIGN8  ,    3,11 , Symbol::ABSOLUTE_REF , LDST )
+ARD(TSTBR14                      , STATIC ,  CFLOW     , S + A - P                      ,   N, -1,   15,15               ,    2,15 , Symbol::ABSOLUTE_REF , TBZNZ )
+ARD(CONDBR19                     , STATIC ,  CFLOW     , S + A - P                      ,   N, -1,   20,20               ,    2,20 , Symbol::ABSOLUTE_REF , CONDB )
+ARD(CALL26                       , STATIC ,  CFLOW     , S + A - P                      ,   Y, -1,   27,27               ,    2,27 , (Symbol::FUNCTION_CALL|Symbol::RELATIVE_REF) , CALL )
+ARD(JUMP26                       , STATIC ,  CFLOW     , S + A - P                      ,   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   , G(GTPREL(S+A)) - GOT           ,   N, -1,    0,0                ,   16,31 , Symbol::ABSOLUTE_REF , MOVW )
+ARD(TLSIE_MOVW_GOTTPREL_G0_NC    , STATIC ,  AARCH64   , G(GTPREL(S+A)) - GOT           ,   N, -1,    0,0                ,    0,15 , Symbol::ABSOLUTE_REF , MOVW )
+ARD(TLSIE_ADR_GOTTPREL_PAGE21    , STATIC ,  AARCH64   , Page(G(GTPREL(S+A))) - Page(P) ,   Y, -1,   32,32               ,   12,32 , Symbol::ABSOLUTE_REF , ADRP )
+ARD(TLSIE_LD64_GOTTPREL_LO12_NC  , STATIC ,  AARCH64   , G(GTPREL(S+A))                 ,   N, -1,   32,32               ,   12,32 , Symbol::ABSOLUTE_REF , LDST )
+ARD(TLSIE_LD_GOTTPREL_PREL19     , STATIC ,  AARCH64   , G(GTPREL(S+A)) - P             ,   N, -1,   20,20               ,    2,20 , Symbol::ABSOLUTE_REF , LD )
+// Above is from Table 4-17, Initial Exec TLS relocatios, 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 17fe031..16396cb 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));
+	(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,335 @@ 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},	// ADR   [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;
+
+  // Page(expr) = expr & ~0xFFF
+
+  static inline typename elfcpp::Swap<size, big_endian>::Valtype
+  Page(typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    return (address >> 12) << 12;
+  }
+
+  // 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,
+      (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,
+      (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, (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,
+	    typename elfcpp::Elf_types<size>::Elf_Addr address,
+	    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) - address;
+    elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, (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);
+    typename elfcpp::Elf_types<size>::Elf_Addr x =
+      psymval->value(object, addend);
+    elfcpp::Swap<valsize, big_endian>::writeval(wv, (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.
+    typename elfcpp::Elf_types<size>::Elf_Addr x =
+      psymval->value(object, addend);
+
+    // Select bits from X.
+    typename elfcpp::Elf_types<size>::Elf_Addr 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.
+    typename elfcpp::Elf_types<size>::Elf_Addr x = s + addend;
+
+    // Select bits from X.
+    typename elfcpp::Elf_types<size>::Elf_Addr 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,
+    typename elfcpp::Elf_types<size>::Elf_Addr address,
+    const AArch64_reloc_property* reloc_property)
+  {
+    // Calculate relocation.
+    typename elfcpp::Elf_types<size>::Elf_Addr x =
+      psymval->value(object, addend) - address;
+
+    // Select bits from X.
+    typename elfcpp::Elf_types<size>::Elf_Addr 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,
+    typename elfcpp::Elf_types<size>::Elf_Addr sa,
+    typename elfcpp::Elf_types<size>::Elf_Addr 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,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr address,
+       const AArch64_reloc_property* reloc_property)
+  {
+    typename elfcpp::Elf_types<size>::Elf_Addr 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 +1485,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 +1503,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 +1530,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 +1553,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 +1577,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 +1609,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 +1622,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 +1635,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;
+
+      // 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;
 
-      //TODO
+    default:
+      unsupported_reloc_local(object, r_type);
     }
 }
 
@@ -1207,20 +1684,135 @@ 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:
+      const AArch64_reloc_property* arp =
+	aarch64_reloc_property_table->get_reloc_property(r_type);
+      gold_assert(arp != NULL);
+      gold_error(_("%s: unsupported reloc type"), arp->name().c_str());
+    }
   return;
 }
 
+// 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>
 void
 Target_aarch64<size, big_endian>::gc_process_relocs(
@@ -1241,11 +1833,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 +1875,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 +1894,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 +1969,197 @@ 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 +2168,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<64, big_endian>::Relocate AArch64_relocate;
+  gold::relocate_section<64, 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,7 +2254,6 @@ 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>
@@ -1421,16 +2262,16 @@ 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")))
+		      (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")))
   { }
 
   virtual Target*
@@ -1438,10 +2279,9 @@ class Target_selector_aarch64 : public Target_selector
   { return new Target_aarch64<size, big_endian>(); }
 };
 
-Target_selector_aarch64<32, true> target_selector_aarch64elf32b;
-Target_selector_aarch64<32, false> target_selector_aarch64elf32;
+// 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.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [gold][aarch64]patch2: link helloworld
  2014-07-30  2:05 [gold][aarch64]patch2: link helloworld Jing Yu
@ 2014-08-04  9:53 ` Jiong Wang
  2014-08-05 17:49 ` Cary Coutant
  1 sibling, 0 replies; 6+ messages in thread
From: Jiong Wang @ 2014-08-04  9:53 UTC (permalink / raw)
  To: Jing Yu, binutils, Doug Kwan, Cary Coutant; +Cc: Han Shen

Hi Jing,

  this hello world milestone patch generally looks good to me.

  looking forward to your following patches.

-- Jiong

On 30/07/14 03:03, Jing Yu wrote:
> Here is the second patch for aarch64 gold backend, which enables
> linking hello_world binary.
>
> On x86:
> $ ../binutils-gdb/configure --enable-plugins --disable-multilib
> --disable-nls --enable-threads --enable-gold=default
> --enable-targets=all
> On aarch64:
> $ ../binutils-gdb/configure --enable-plugins --disable-multilib
> --disable-nls --enable-threads --enable-gold=default
> --enable-targets=all
>
> gold/ld-new is able to link hello_world binary dynamically.
> Our next patch will support linking hello_world statically and linking
> position independent code.
>
> Thanks,
> Jing
>
> 2014-07-29  Jing Yu <jingyu@google.com>
>                    Han Shen <shenhan@google.com>
>
> * elfcpp/aarch64.h(enum): Replace withdrawn with R_AARCH64_withdrawn
> * gold/Makefile.am(HFILES): Add aarch64-reloc-property.h
>    (DEFFILES): add aarch64-reloc.def
>    (TARGETSOURCES): Add aarch64-reloc-property.cc
>    (ALL_TARGETOBJS): aarch64-reloc-property.$(OBJEXT)
> * gold/Makefile.in: Regenerate
> * gold/aarch64-reloc-property.cc: New file
> * gold/aarch64-reloc-property.h: New file
> * gold/aarch64-reloc.def: New file
> * gold/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): Femove 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
>    (Target_selector_aarch64): Comment out 32-bit target instantiation.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [gold][aarch64]patch2: link helloworld
  2014-07-30  2:05 [gold][aarch64]patch2: link helloworld Jing Yu
  2014-08-04  9:53 ` Jiong Wang
@ 2014-08-05 17:49 ` Cary Coutant
  2014-08-07 23:52   ` Jing Yu
  1 sibling, 1 reply; 6+ messages in thread
From: Cary Coutant @ 2014-08-05 17:49 UTC (permalink / raw)
  To: Jing Yu; +Cc: binutils, Doug Kwan, Han Shen

> 2014-07-29  Jing Yu <jingyu@google.com>
>                   Han Shen <shenhan@google.com>
>
> * elfcpp/aarch64.h(enum): Replace withdrawn with R_AARCH64_withdrawn
> * gold/Makefile.am(HFILES): Add aarch64-reloc-property.h

The ChangeLog entry needs to be split into two, one for
elfcpp/ChangeLog, and one for gold/ChangeLog. Remove the "elfcpp/" and
"gold/" from the file names on each line. Please put periods at the
end of each entry.

>   (Output_data_plt_aarch64::do_write): Femove useless got_base. Set
> the got_pov entry to plt0.

"Remove"

> diff --git a/gold/Makefile.in b/gold/Makefile.in

No need to include generated files in the patch.

+  return (low_bound <= x && x < up_bound)
+    && ((x & extra_alignment_requirement) == 0);

Put another set of parens around the entire expression, and indent the
second line so the "&&" is aligned properly.

+template<>
+bool
+rvalue_checkup<0,0>(int64_t) {return true;}

Spaces after the comma, and inside the braces.

+template<>
+uint64_t
+rvalue_bit_select<0,0>(uint64_t x) { return x; }

Likewise.

+  if(code == elfcpp::R_AARCH64_ABS64)

Space between "if" and "(".

+  typedef uint64_t (*rvalue_bit_select_func_p)(uint64_t);

This typedef uses the "_p" convention for predicate functions, but the
function doesn't return bool.

+ const AArch64_reloc_property*
+  get_reloc_property(unsigned int code) const

Bad indentation here.

+    unsigned int idx = code_to_array_index(code);
+    gold_assert(idx < Property_table_size);

The assert here seems overcautious -- code_to_array_index() already
does the same assert.

What happens if you receive an object file with a bad relocation type?
It would be preferable to issue a regular error on bad input, rather
than an internal error. You should assert only when a logic error in
gold's own code could lead to a false condition.

+  // The Parse_expression class is used to convert relocation operations in
+  // aarch64-reloc.def into S-expression strings, which are parsed again to
+  // build actual expression trees.  We do not build the expression trees
+  // directly because the parser for operations in arm-reloc.def is simpler
+  // this way.  Conversion from S-expressions to trees is simple.

So you parse the "S + A" forms from aarch64-reloc.def into a tree form
(letting the compiler do the actual parsing), then convert that back
to a different string-based "( + S A )" form during initialization.
Then, when it's time to apply the relocation, you plan to parse the "(
+ S A )" form into a tree form again, right?

Don't take this as an objection, but why not just put the S-expression
form directly into the .def file, and save a bit of initialization
time? Alternatively, parsing the two forms doesn't seem appreciably
different, so why not just parse the original form when it's time to
apply relocations? Or, why not just save the tree form after the first
parse?

In Relocate::relocate(), none of the relocations implemented so far
use these expressions -- are you planning to take advantage of these
expressions to simplify the logic later, or will they continue to go
unused?

+  // Map aarch64 rtypes into range(0,300) as following
+  //   256 ~ 313 -> 0 ~ 57
+  //   512 ~ 573 -> 128 ~ 189
+  //   1024 ~ 1032 -> 256 ~ 264

Why bother to reserve space in your array for the dynamic relocations?

+protected:
+  void
+  do_select_as_default_target()

"protected" should be indented one space.

+    offset = this->first_plt_entry_offset() +
+      this->count_ * this->get_plt_entry_size();

Parenthesize the expression and indent the second line under the open paren.

+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}, // ADR   [30:29]-immlo  [23:5]-immhi

Should this be ADRP?

+  {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
+};

+  // Page(expr) = expr & ~0xFFF
+
+  static inline typename elfcpp::Swap<size, big_endian>::Valtype
+  Page(typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    return (address >> 12) << 12;
+  }

Why write it as a mask operation in the comment, but use shifting in
the implementation? I'd prefer the mask operation, and the comment
ought to be in English.

+    elfcpp::Swap<valsize, big_endian>::writeval(wv,
+      (Valtype)(val | (immed << doffset)));

+    elfcpp::Swap<valsize, big_endian>::writeval(wv,
+      (Valtype)(val | (immed1 << doffset1) | (immed2 << doffset2)));

+    elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, (Valtype)x);

(... and several more places ...)

Use static_cast<Valtype>(...).

+    typename elfcpp::Elf_types<size>::Elf_Addr x =
+      psymval->value(object, addend);

It's customary to indent lines by four spaces in cases like this
(e.g., when you begin the entire rhs of an assignment on a new line).

+  int got_base = target->got_ != NULL
+       ? target->got_->current_data_size() >= 0x8000 ? 0x8000 : 0
+       : 0;

Parenthesize the expression and indent subsequent lines under the open paren.

+      (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")))

I think this would be much easier to read if you specialized each of
the four constructors, like this:

template<int size, bool big_endian>
class Target_selector_aarch64 : public Target_selector
{
 public:
  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")
{ }

-cary

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [gold][aarch64]patch2: link helloworld
  2014-08-05 17:49 ` Cary Coutant
@ 2014-08-07 23:52   ` Jing Yu
  2014-08-08 16:33     ` Cary Coutant
  0 siblings, 1 reply; 6+ messages in thread
From: Jing Yu @ 2014-08-07 23:52 UTC (permalink / raw)
  To: Cary Coutant; +Cc: binutils, Doug Kwan, Han Shen

[-- Attachment #1: Type: text/plain, Size: 10001 bytes --]

On Tue, Aug 5, 2014 at 10:49 AM, Cary Coutant <ccoutant@google.com> wrote:
>> 2014-07-29  Jing Yu <jingyu@google.com>
>>                   Han Shen <shenhan@google.com>
>>
>> * elfcpp/aarch64.h(enum): Replace withdrawn with R_AARCH64_withdrawn
>> * gold/Makefile.am(HFILES): Add aarch64-reloc-property.h
>
> The ChangeLog entry needs to be split into two, one for
> elfcpp/ChangeLog, and one for gold/ChangeLog. Remove the "elfcpp/" and
> "gold/" from the file names on each line. Please put periods at the
> end of each entry.
Done.
>
>>   (Output_data_plt_aarch64::do_write): Femove useless got_base. Set
>> the got_pov entry to plt0.
>
> "Remove"
Done.
>
>> diff --git a/gold/Makefile.in b/gold/Makefile.in
>
> No need to include generated files in the patch.
>
> +  return (low_bound <= x && x < up_bound)
> +    && ((x & extra_alignment_requirement) == 0);
>
> Put another set of parens around the entire expression, and indent the
> second line so the "&&" is aligned properly.
Done.
>
> +template<>
> +bool
> +rvalue_checkup<0,0>(int64_t) {return true;}
>
> Spaces after the comma, and inside the braces.
Done.
>
> +template<>
> +uint64_t
> +rvalue_bit_select<0,0>(uint64_t x) { return x; }
>
> Likewise.
Done.
>
> +  if(code == elfcpp::R_AARCH64_ABS64)
>
> Space between "if" and "(".
Done.
>
> +  typedef uint64_t (*rvalue_bit_select_func_p)(uint64_t);
>
> This typedef uses the "_p" convention for predicate functions, but the
> function doesn't return bool.
Done.
>
> + const AArch64_reloc_property*
> +  get_reloc_property(unsigned int code) const
>
> Bad indentation here.
Done.
>
> +    unsigned int idx = code_to_array_index(code);
> +    gold_assert(idx < Property_table_size);
>
> The assert here seems overcautious -- code_to_array_index() already
> does the same assert.
Done.

>
> What happens if you receive an object file with a bad relocation type?
> It would be preferable to issue a regular error on bad input, rather
> than an internal error. You should assert only when a logic error in
> gold's own code could lead to a false condition.
Yes, added gold_error when encountering an unexpected reloc type.

>
> +  // The Parse_expression class is used to convert relocation operations in
> +  // aarch64-reloc.def into S-expression strings, which are parsed again to
> +  // build actual expression trees.  We do not build the expression trees
> +  // directly because the parser for operations in arm-reloc.def is simpler
> +  // this way.  Conversion from S-expressions to trees is simple.
>
> So you parse the "S + A" forms from aarch64-reloc.def into a tree form
> (letting the compiler do the actual parsing), then convert that back
> to a different string-based "( + S A )" form during initialization.
> Then, when it's time to apply the relocation, you plan to parse the "(
> + S A )" form into a tree form again, right?
>
> Don't take this as an objection, but why not just put the S-expression
> form directly into the .def file, and save a bit of initialization
> time? Alternatively, parsing the two forms doesn't seem appreciably
> different, so why not just parse the original form when it's time to
> apply relocations? Or, why not just save the tree form after the first
> parse?
>
> In Relocate::relocate(), none of the relocations implemented so far
> use these expressions -- are you planning to take advantage of these
> expressions to simplify the logic later, or will they continue to go
> unused?

Ok, removed this part totally, including string s_expression member
variable, since we probably won't use this approach.

>
> +  // Map aarch64 rtypes into range(0,300) as following
> +  //   256 ~ 313 -> 0 ~ 57
> +  //   512 ~ 573 -> 128 ~ 189
> +  //   1024 ~ 1032 -> 256 ~ 264
>
> Why bother to reserve space in your array for the dynamic relocations?
Yeah, that's correct. Removed mapping from 1024-1032.

>
> +protected:
> +  void
> +  do_select_as_default_target()
>
> "protected" should be indented one space.
Done.

>
> +    offset = this->first_plt_entry_offset() +
> +      this->count_ * this->get_plt_entry_size();
>
> Parenthesize the expression and indent the second line under the open paren.
Done.

>
> +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}, // ADR   [30:29]-immlo  [23:5]-immhi
>
> Should this be ADRP?
Yes. Done.
>
> +  {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
> +};
>
> +  // Page(expr) = expr & ~0xFFF
> +
> +  static inline typename elfcpp::Swap<size, big_endian>::Valtype
> +  Page(typename elfcpp::Elf_types<size>::Elf_Addr address)
> +  {
> +    return (address >> 12) << 12;
> +  }
>
> Why write it as a mask operation in the comment, but use shifting in
> the implementation? I'd prefer the mask operation, and the comment
> ought to be in English.
Changed the implementation and comment.

>
> +    elfcpp::Swap<valsize, big_endian>::writeval(wv,
> +      (Valtype)(val | (immed << doffset)));
>
> +    elfcpp::Swap<valsize, big_endian>::writeval(wv,
> +      (Valtype)(val | (immed1 << doffset1) | (immed2 << doffset2)));
>
> +    elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view, (Valtype)x);
>
> (... and several more places ...)
>
> Use static_cast<Valtype>(...).
Done.

>
> +    typename elfcpp::Elf_types<size>::Elf_Addr x =
> +      psymval->value(object, addend);
>
> It's customary to indent lines by four spaces in cases like this
> (e.g., when you begin the entire rhs of an assignment on a new line).
Done.

>
> +  int got_base = target->got_ != NULL
> +       ? target->got_->current_data_size() >= 0x8000 ? 0x8000 : 0
> +       : 0;
>
> Parenthesize the expression and indent subsequent lines under the open paren.

Done.
>
> +      (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")))
>
> I think this would be much easier to read if you specialized each of
> the four constructors, like this:
>
Done.

> template<int size, bool big_endian>
> class Target_selector_aarch64 : public Target_selector
> {
>  public:
>   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")
> { }
>
> -cary

Thanks for the review!
Attached the updated patch.

elfcpp/Changelog:
2014-08-07  Jing Yu <jingyu@google.com>
                       Han Shen <shenhan@google.com>

* aarch64.h(enum): Replace withdrawn with R_AARCH64_withdrawn.


gold/Changelog:
2014-08-07  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.

[-- Attachment #2: gold.patch2 --]
[-- Type: application/octet-stream, Size: 71877 bytes --]

diff --git a/elfcpp/aarch64.h b/elfcpp/aarch64.h
index 4d1898f..52ac3ea 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/Makefile.am b/gold/Makefile.am
index 17ba4b4..df99f23 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/aarch64-reloc-property.cc b/gold/aarch64-reloc-property.cc
new file mode 100644
index 0000000..beaed10
--- /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 0000000..d8d1301
--- /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 0000000..b279c69
--- /dev/null
+++ b/gold/aarch64-reloc.def
@@ -0,0 +1,68 @@
+// 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-fl
+
+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 relocatios, 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 17fe031..7d4baaf 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,341 @@ 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;
+
+  // Return the page address of the address.
+  // Page(address) = address & ~0xFFF
+
+  static inline typename elfcpp::Swap<size, big_endian>::Valtype
+  Page(typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    return (address &
+	    (~(typename elfcpp::Elf_types<size>::Elf_Addr)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,
+	    typename elfcpp::Elf_types<size>::Elf_Addr address,
+	    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) - 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);
+    typename elfcpp::Elf_types<size>::Elf_Addr 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.
+    typename elfcpp::Elf_types<size>::Elf_Addr x =
+	psymval->value(object, addend);
+
+    // Select bits from X.
+    typename elfcpp::Elf_types<size>::Elf_Addr 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.
+    typename elfcpp::Elf_types<size>::Elf_Addr x = s + addend;
+
+    // Select bits from X.
+    typename elfcpp::Elf_types<size>::Elf_Addr 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,
+    typename elfcpp::Elf_types<size>::Elf_Addr address,
+    const AArch64_reloc_property* reloc_property)
+  {
+    // Calculate relocation.
+    typename elfcpp::Elf_types<size>::Elf_Addr x =
+	psymval->value(object, addend) - address;
+
+    // Select bits from X.
+    typename elfcpp::Elf_types<size>::Elf_Addr 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,
+    typename elfcpp::Elf_types<size>::Elf_Addr sa,
+    typename elfcpp::Elf_types<size>::Elf_Addr 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,
+       typename elfcpp::Elf_types<size>::Elf_Addr addend,
+       typename elfcpp::Elf_types<size>::Elf_Addr address,
+       const AArch64_reloc_property* reloc_property)
+  {
+    typename elfcpp::Elf_types<size>::Elf_Addr 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 +1491,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 +1509,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 +1536,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 +1559,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 +1583,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 +1615,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 +1628,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 +1641,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 +1690,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 +1838,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 +1880,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 +1899,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 +1974,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 +2174,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 +2260,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.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [gold][aarch64]patch2: link helloworld
  2014-08-07 23:52   ` Jing Yu
@ 2014-08-08 16:33     ` Cary Coutant
  2014-08-08 21:44       ` Jing Yu
  0 siblings, 1 reply; 6+ messages in thread
From: Cary Coutant @ 2014-08-08 16:33 UTC (permalink / raw)
  To: Jing Yu; +Cc: binutils, Doug Kwan, Han Shen

> elfcpp/Changelog:
> 2014-08-07  Jing Yu <jingyu@google.com>
>                        Han Shen <shenhan@google.com>
>
> * aarch64.h(enum): Replace withdrawn with R_AARCH64_withdrawn.
>
>
> gold/Changelog:
> 2014-08-07  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.

+// Above is from Table 4-10, Relocations for control-fl

Looks like this comment got truncated.

+// Above is from Table 4-17, Initial Exec TLS relocatios, 539-543.

"relocations"

+  Page(typename elfcpp::Elf_types<size>::Elf_Addr address)

It might be worth making a class-local typedef for this type.

+    return (address &
+    (~(typename elfcpp::Elf_types<size>::Elf_Addr)0xFFF));

Please use static_cast (which will be more manageable with the local typedef).

OK with these changes (please post the patch as committed for
reference). Thanks!

-cary

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [gold][aarch64]patch2: link helloworld
  2014-08-08 16:33     ` Cary Coutant
@ 2014-08-08 21:44       ` Jing Yu
  0 siblings, 0 replies; 6+ messages in thread
From: Jing Yu @ 2014-08-08 21:44 UTC (permalink / raw)
  To: Cary Coutant; +Cc: binutils, Doug Kwan, Han Shen

[-- Attachment #1: Type: text/plain, Size: 3175 bytes --]

Thanks!
Patch attached (including  gold/Makefile.in) was committed.


On Fri, Aug 8, 2014 at 9:33 AM, Cary Coutant <ccoutant@google.com> wrote:
>> elfcpp/Changelog:
>> 2014-08-07  Jing Yu <jingyu@google.com>
>>                        Han Shen <shenhan@google.com>
>>
>> * aarch64.h(enum): Replace withdrawn with R_AARCH64_withdrawn.
>>
>>
>> gold/Changelog:
>> 2014-08-07  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.
>
> +// Above is from Table 4-10, Relocations for control-fl
>
> Looks like this comment got truncated.
>
> +// Above is from Table 4-17, Initial Exec TLS relocatios, 539-543.
>
> "relocations"
>
> +  Page(typename elfcpp::Elf_types<size>::Elf_Addr address)
>
> It might be worth making a class-local typedef for this type.
>
> +    return (address &
> +    (~(typename elfcpp::Elf_types<size>::Elf_Addr)0xFFF));
>
> Please use static_cast (which will be more manageable with the local typedef).
>
> OK with these changes (please post the patch as committed for
> reference). Thanks!
>
> -cary

[-- Attachment #2: gold.patch2 --]
[-- Type: application/octet-stream, Size: 75046 bytes --]

diff --git a/elfcpp/ChangeLog b/elfcpp/ChangeLog
index 043fb67..eafa252 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 4d1898f..52ac3ea 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 9e1ef63..90997bd 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 17ba4b4..df99f23 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 a8dd111..d404666 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 0000000..beaed10
--- /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 0000000..d8d1301
--- /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 0000000..4f6710e
--- /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 17fe031..7a3fe3b 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.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-08-08 21:44 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-30  2:05 [gold][aarch64]patch2: link helloworld Jing Yu
2014-08-04  9:53 ` Jiong Wang
2014-08-05 17:49 ` Cary Coutant
2014-08-07 23:52   ` Jing Yu
2014-08-08 16:33     ` Cary Coutant
2014-08-08 21:44       ` Jing Yu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).