public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [gold][aarch64]patch3: static link/shared objects
@ 2014-08-12  0:48 Hán Shěn (沈涵)
  2014-08-29 22:50 ` Cary Coutant
  0 siblings, 1 reply; 5+ messages in thread
From: Hán Shěn (沈涵) @ 2014-08-12  0:48 UTC (permalink / raw)
  To: binutils, Doug Kwan, Cary Coutant, Jing Yu

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

Here is the third patch for aarch64 backend.

This patches enables -
1. static linking hello world
2. limited support for TLSIE and TLSLE
3. limited support for linking shared library, linking executable against shared
   library.

Builds pass -
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

2014-08-11 Han Shen <shenhan@google.com>
                  Jing Yu <jingyu@google.com>

* gold/aarch64-reloc-property.cc(AArch64_reloc_property_table::reloc_name_in_error_message):
  Fix bug in reference reloc property in the table.
* gold/aarch64-reloc.def: Add TLSLE reloc types and fix some errors in
3 other entries.
* gold/aarch64.cc:
  (TARGET_TCB_SIZE): New macro defining how tcb size is computed.
  (Output_data_got_aarch64::add_static_reloc): 2 new methods
(overloaded version).
  (Output_data_got_aarch64::do_write): Add code to write out static relocs.
  (class Output_data_got_aarch64::Static_reloc): New class to wrap
static relocs.
  (Output_data_got_aarch64::static_relocs): New vector to hold static relocs.
  (Target_aarch64::tcb_size): New method.
  (Target_aarch64::Relocate::relocate): Add code handling new reloc types.
  (Target_aarch64::Relocate::relocate_tls): New method.
  (Target_aarch64::Scan::local): Add code handling new reloc types.
  (Target_aarch64::Scan::global): Add code handling new reloc types.




Thanks,
Han

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

diff --git a/configure b/configure
index 26c9886..6a0e527 100755
--- a/configure
+++ b/configure
@@ -2966,17 +2966,18 @@ case "${ENABLE_GOLD}" in
             is_elf=yes
             ;;
         esac
     esac
 
     if test "$is_elf" = "yes"; then
       # Check for target supported by gold.
       case "${target}" in
-        i?86-*-* | x86_64-*-* | sparc*-*-* | powerpc*-*-* | arm*-*-* | tilegx*-*-*)
+        i?86-*-* | x86_64-*-* | sparc*-*-* | powerpc*-*-* | arm*-*-* \
+        | aarch64*-*-* | tilegx*-*-*)
 	  configdirs="$configdirs gold"
 	  if test x${ENABLE_GOLD} = xdefault; then
 	    default_ld=gold
 	  fi
 	  ENABLE_GOLD=yes
           ;;
       esac
     fi
diff --git a/configure.ac b/configure.ac
index 028cbda..8fe1358 100644
--- a/configure.ac
+++ b/configure.ac
@@ -326,17 +326,18 @@ case "${ENABLE_GOLD}" in
             is_elf=yes
             ;;
         esac
     esac
 
     if test "$is_elf" = "yes"; then
       # Check for target supported by gold.
       case "${target}" in
-        i?86-*-* | x86_64-*-* | sparc*-*-* | powerpc*-*-* | arm*-*-* | tilegx*-*-*)
+        i?86-*-* | x86_64-*-* | sparc*-*-* | powerpc*-*-* | arm*-*-* \
+        | aarch64*-*-* | tilegx*-*-*)
 	  configdirs="$configdirs gold"
 	  if test x${ENABLE_GOLD} = xdefault; then
 	    default_ld=gold
 	  fi
 	  ENABLE_GOLD=yes
           ;;
       esac
     fi
diff --git a/gold/aarch64-reloc-property.cc b/gold/aarch64-reloc-property.cc
index beaed10..16f8449 100644
--- a/gold/aarch64-reloc-property.cc
+++ b/gold/aarch64-reloc-property.cc
@@ -125,19 +125,18 @@ AArch64_reloc_property_table::AArch64_reloc_property_table()
 }
 
 // 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];
+  int tidx = code_to_array_index(code);
+  const AArch64_reloc_property* arp = this->table_[tidx];
 
   if (arp == NULL)
     {
       char buffer[100];
       sprintf(buffer, _("invalid reloc %u"), code);
       return std::string(buffer);
     }
 
diff --git a/gold/aarch64-reloc.def b/gold/aarch64-reloc.def
index 4f6710e..4fb1232 100644
--- a/gold/aarch64-reloc.def
+++ b/gold/aarch64-reloc.def
@@ -45,26 +45,31 @@ ARD(ADR_PREL_PG_HI21_NC          , STATIC ,  AARCH64    ,   Y,  -1,    0,0
 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(TSTBR14                      , STATIC ,  CFLOW      ,   N,  -1,   15,15               ,    2,15 , (Symbol::FUNCTION_CALL|Symbol::ABSOLUTE_REF) , TBZNZ )
+ARD(CONDBR19                     , STATIC ,  CFLOW      ,   N,  -1,   20,20               ,    2,20 , (Symbol::FUNCTION_CALL|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_LD64_GOTTPREL_LO12_NC  , STATIC ,  AARCH64    ,   Y,  -1,    0,RL_CHECK_ALIGN8  ,    3,11 , 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.
 
+ARD(TLSLE_ADD_TPREL_HI12         , STATIC ,  AARCH64   ,    Y,  -1,    0,24	          ,   12,23 , Symbol::ABSOLUTE_REF , ADD )
+ARD(TLSLE_ADD_TPREL_LO12         , STATIC ,  AARCH64   ,    Y,  -1,    0,12	          ,    0,11 , Symbol::ABSOLUTE_REF , ADD )
+ARD(TLSLE_ADD_TPREL_LO12_NC      , STATIC ,  AARCH64   ,    Y,  -1,    0,0	          ,    0,11 , Symbol::ABSOLUTE_REF , ADD )
+// Above is from Table 4-18, Local Exec TLS relocations, 544-571.
+
 // 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 7a3fe3b..c3d3410 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -42,16 +42,18 @@
 #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;
 
+#define TARGET_TCB_SIZE ((size / 8) * 2)
+
 namespace
 {
 
 using namespace gold;
 
 template<int size, bool big_endian>
 class Output_data_plt_aarch64;
 
@@ -71,34 +73,236 @@ 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>(),
       symbol_table_(symtab), layout_(layout)
   { }
 
+  // Add a static entry for the GOT entry at OFFSET.  GSYM is a global
+  // symbol and R_TYPE is the code of a dynamic relocation that needs to be
+  // applied in a static link.
+  void
+  add_static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym)
+  { this->static_relocs_.push_back(Static_reloc(got_offset, r_type, gsym)); }
+
+
+  // Add a static reloc for the GOT entry at OFFSET.  RELOBJ is an object
+  // defining a local symbol with INDEX.  R_TYPE is the code of a dynamic
+  // relocation that needs to be applied in a static link.
+  void
+  add_static_reloc(unsigned int got_offset, unsigned int r_type,
+		   Sized_relobj_file<size, big_endian>* relobj,
+		   unsigned int index)
+  {
+    this->static_relocs_.push_back(Static_reloc(got_offset, r_type, relobj,
+						index));
+  }
+
+
  protected:
   // Write out the GOT table.
   void
   do_write(Output_file* of) {
     // The first entry in the GOT is the address of the .dynamic section.
     gold_assert(this->data_size() >= size / 8);
     Output_section* dynamic = this->layout_->dynamic_section();
     Valtype dynamic_addr = dynamic == NULL ? 0 : dynamic->address();
     this->replace_constant(0, dynamic_addr);
     Output_data_got<size, big_endian>::do_write(of);
+
+    // Handling static relocs
+    if (this->static_relocs_.empty())
+      return;
+
+    typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
+
+    gold_assert(parameters->doing_static_link());
+    const off_t offset = this->offset();
+    const section_size_type oview_size =
+      convert_to_section_size_type(this->data_size());
+    unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+    Output_segment* tls_segment = this->layout_->tls_segment();
+    gold_assert(tls_segment != NULL);
+
+    AArch64_address aligned_tcb_address =
+	align_address(TARGET_TCB_SIZE, tls_segment->maximum_alignment());
+
+    for (size_t i = 0; i < this->static_relocs_.size(); ++i)
+      {
+	Static_reloc& reloc(this->static_relocs_[i]);
+	AArch64_address value;
+
+	if (!reloc.symbol_is_global())
+	  {
+	    Sized_relobj_file<size, big_endian>* object = reloc.relobj();
+	    const Symbol_value<size>* psymval =
+	      reloc.relobj()->local_symbol(reloc.index());
+
+	    // We are doing static linking.  Issue an error and skip this
+	    // relocation if the symbol is undefined or in a discarded_section.
+	    bool is_ordinary;
+	    unsigned int shndx = psymval->input_shndx(&is_ordinary);
+	    if ((shndx == elfcpp::SHN_UNDEF)
+		|| (is_ordinary
+		    && shndx != elfcpp::SHN_UNDEF
+		    && !object->is_section_included(shndx)
+		    && !this->symbol_table_->is_section_folded(object, shndx)))
+	      {
+		gold_error(_("undefined or discarded local symbol %u from "
+			     " object %s in GOT"),
+			   reloc.index(), reloc.relobj()->name().c_str());
+		continue;
+	      }
+	    value = psymval->value(object, 0);
+	  }
+	else
+	  {
+	    const Symbol* gsym = reloc.symbol();
+	    gold_assert(gsym != NULL);
+	    if (gsym->is_forwarder())
+	      gsym = this->symbol_table_->resolve_forwards(gsym);
+
+	    // We are doing static linking.  Issue an error and skip this
+	    // relocation if the symbol is undefined or in a discarded_section
+	    // unless it is a weakly_undefined symbol.
+	    if ((gsym->is_defined_in_discarded_section()
+		 || gsym->is_undefined())
+		&& !gsym->is_weak_undefined())
+	      {
+		gold_error(_("undefined or discarded symbol %s in GOT"),
+			   gsym->name());
+		continue;
+	      }
+
+	    if (!gsym->is_weak_undefined())
+	      {
+		const Sized_symbol<size>* sym =
+		  static_cast<const Sized_symbol<size>*>(gsym);
+		value = sym->value();
+	      }
+	    else
+	      value = 0;
+	  }
+
+	unsigned got_offset = reloc.got_offset();
+	gold_assert(got_offset < oview_size);
+
+	typedef typename elfcpp::Swap<size, big_endian>::Valtype Valtype;
+	Valtype* wv = reinterpret_cast<Valtype*>(oview + got_offset);
+	Valtype x;
+	switch (reloc.r_type())
+	  {
+	  case elfcpp::R_AARCH64_TLS_DTPREL64:
+	    x = value;
+	    break;
+	  case elfcpp::R_AARCH64_TLS_TPREL64:
+	    x = value + aligned_tcb_address;
+	    break;
+	  default:
+	    gold_unreachable();
+	  }
+	elfcpp::Swap<size, big_endian>::writeval(wv, x);
+      }
+
+    of->write_output_view(offset, oview_size, oview);
   }
 
  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_;
+
+
+  // This class represent dynamic relocations that need to be applied by
+  // gold because we are using TLS relocations in a static link.
+  class Static_reloc
+  {
+   public:
+    Static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym)
+      : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(true)
+    { this->u_.global.symbol = gsym; }
+
+    Static_reloc(unsigned int got_offset, unsigned int r_type,
+	  Sized_relobj_file<size, big_endian>* relobj, unsigned int index)
+      : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(false)
+    {
+      this->u_.local.relobj = relobj;
+      this->u_.local.index = index;
+    }
+
+    // Return the GOT offset.
+    unsigned int
+    got_offset() const
+    { return this->got_offset_; }
+
+    // Relocation type.
+    unsigned int
+    r_type() const
+    { return this->r_type_; }
+
+    // Whether the symbol is global or not.
+    bool
+    symbol_is_global() const
+    { return this->symbol_is_global_; }
+
+    // For a relocation against a global symbol, the global symbol.
+    Symbol*
+    symbol() const
+    {
+      gold_assert(this->symbol_is_global_);
+      return this->u_.global.symbol;
+    }
+
+    // For a relocation against a local symbol, the defining object.
+    Sized_relobj_file<size, big_endian>*
+    relobj() const
+    {
+      gold_assert(!this->symbol_is_global_);
+      return this->u_.local.relobj;
+    }
+
+    // For a relocation against a local symbol, the local symbol index.
+    unsigned int
+    index() const
+    {
+      gold_assert(!this->symbol_is_global_);
+      return this->u_.local.index;
+    }
+
+   private:
+    // GOT offset of the entry to which this relocation is applied.
+    unsigned int got_offset_;
+    // Type of relocation.
+    unsigned int r_type_;
+    // Whether this relocation is against a global symbol.
+    bool symbol_is_global_;
+    // A global or local symbol.
+    union
+    {
+      struct
+      {
+	// For a global symbol, the symbol itself.
+	Symbol* symbol;
+      } global;
+      struct
+      {
+	// For a local symbol, the object defining object.
+	Sized_relobj_file<size, big_endian>* relobj;
+	// For a local symbol, the symbol index.
+	unsigned int index;
+      } local;
+    } u_;
+  };  // End of inner class Static_reloc
+
+  std::vector<Static_reloc> static_relocs_;
 };
 
 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
 template<int size, bool big_endian>
@@ -108,17 +312,18 @@ class Target_aarch64 : public Sized_target<size, big_endian>
   typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
       Reloc_section;
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
 
   Target_aarch64(const Target::Target_info* info = &aarch64_info)
     : Sized_target<size, big_endian>(info),
       got_(NULL), plt_(NULL), got_plt_(NULL),
       global_offset_table_(NULL), rela_dyn_(NULL),
-      copy_relocs_(elfcpp::R_AARCH64_COPY)
+      copy_relocs_(elfcpp::R_AARCH64_COPY),
+      tcb_size_(TARGET_TCB_SIZE)
   { }
 
   // Scan the relocations to determine unreferenced sections for
   // garbage collection.
   void
   gc_process_relocs(Symbol_table* symtab,
 		    Layout* layout,
 		    Sized_relobj_file<size, big_endian>* object,
@@ -209,16 +414,19 @@ class Target_aarch64 : public Sized_target<size, big_endian>
   //Return the offset of the first non-reserved PLT entry.
   unsigned int
   first_plt_entry_offset() const;
 
   // Return the size of each PLT entry.
   unsigned int
   plt_entry_size() const;
 
+  unsigned int
+  tcb_size() const { return this->tcb_size_; }
+
  protected:
   void
   do_select_as_default_target()
   {
     gold_assert(aarch64_reloc_property_table == NULL);
     aarch64_reloc_property_table = new AArch64_reloc_property_table();
   }
 
@@ -316,17 +524,28 @@ class Target_aarch64 : public Sized_target<size, big_endian>
     relocate(const Relocate_info<size, big_endian>*, Target_aarch64*,
 	     Output_section*,
 	     size_t relnum, const elfcpp::Rela<size, big_endian>&,
 	     unsigned int r_type, const Sized_symbol<size>*,
 	     const Symbol_value<size>*,
 	     unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
 	     section_size_type);
 
-  };
+  private:
+    inline typename AArch64_relocate_functions<size,big_endian>::Status
+    relocate_tls(const Relocate_info<size,big_endian>*,
+		 Target_aarch64<size, big_endian>*,
+		 size_t,
+		 const elfcpp::Rela<size, big_endian>&,
+		 unsigned int r_type, const Sized_symbol<size>*,
+		 const Symbol_value<size>*,
+		 unsigned char*,
+		 typename elfcpp::Elf_types<size>::Elf_Addr);
+
+  };  // End of class Relocate
 
   // A class which returns the size required for a relocation type,
   // used while scanning relocs during a relocatable link.
   class Relocatable_size_for_reloc
   {
    public:
     unsigned int
     get_size_for_reloc(unsigned int, Relobj*);
@@ -405,17 +624,19 @@ class Target_aarch64 : public Sized_target<size, big_endian>
   // The GOT PLT section.
   Output_data_space* got_plt_;
   // The _GLOBAL_OFFSET_TABLE_ symbol.
   Symbol* global_offset_table_;
   // The dynamic reloc section.
   Reloc_section* rela_dyn_;
   // Relocs saved to avoid a COPY reloc.
   Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
-};
+  // Size of TCB
+  const unsigned int tcb_size_;
+};  // End of Target_aarch64
 
 template<>
 const Target::Target_info Target_aarch64<64, false>::aarch64_info =
 {
   64,			// size
   false,		// is_big_endian
   elfcpp::EM_AARCH64,	// machine_code
   false,		// has_make_symbol
@@ -824,17 +1045,17 @@ Output_data_plt_aarch64<size, big_endian>::address_for_local(
 
 // 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>
 class Output_data_plt_aarch64_standard :
   public Output_data_plt_aarch64<size, big_endian>
 {
  public:
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
@@ -1612,57 +1833,123 @@ Target_aarch64<size, big_endian>::Scan::check_non_pic(Relobj* object,
   return;
 }
 
 // Scan a relocation for a local symbol.
 
 template<int size, bool big_endian>
 inline void
 Target_aarch64<size, big_endian>::Scan::local(
-    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 data_shndx,
+    Output_section* output_section,
+    const elfcpp::Rela<size, big_endian>& rela,
     unsigned int r_type,
     const elfcpp::Sym<size, big_endian>& /* lsym */,
     bool is_discarded)
 {
   if (is_discarded)
     return;
 
+  typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
+    Reloc_section;
+
   switch (r_type)
     {
-    case elfcpp::R_AARCH64_ABS64:
     case elfcpp::R_AARCH64_ABS32:
     case elfcpp::R_AARCH64_ABS16:
+      if (parameters->options().output_is_position_independent())
+	{
+	  gold_error(_("%s: unsupported reloc %u in pos independent link."),
+		     object->name().c_str(), r_type);
+	}
+      break;
+
+    case elfcpp::R_AARCH64_ABS64:
       // 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());
+	  Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+	  unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
+	  rela_dyn->add_local_relative(object, r_sym,
+				       elfcpp::R_AARCH64_RELATIVE,
+				       output_section,
+				       data_shndx,
+				       rela.get_r_offset(),
+				       rela.get_r_addend(),
+				       false /* is ifunc */);
 	}
       break;
 
-      // Relocations to generate 19, 21 and 33-bit PC-relative address
+    case elfcpp::R_AARCH64_PREL64:
+    case elfcpp::R_AARCH64_PREL32:
+    case elfcpp::R_AARCH64_PREL16:
+      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_LDST16_ABS_LO12_NC: // 284
+    case elfcpp::R_AARCH64_LDST32_ABS_LO12_NC: // 285
     case elfcpp::R_AARCH64_LDST64_ABS_LO12_NC: // 286
+    case elfcpp::R_AARCH64_LDST128_ABS_LO12_NC: // 299
     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
+    // 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_TSTBR14:
+    case elfcpp::R_AARCH64_CONDBR19:
+    case elfcpp::R_AARCH64_JUMP26:
+    case elfcpp::R_AARCH64_CALL26:
+      break;
+
+    case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+      {
+	layout->set_has_static_tls();
+	// Create a GOT entry for the tp-relative offset.
+	Output_data_got_aarch64<size, big_endian>* got =
+	    target->got_section(symtab, layout);
+	unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+	if (!parameters->doing_static_link())
+	  {
+	    got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
+				    target->rela_dyn_section(layout),
+				    elfcpp::R_AARCH64_TLS_TPREL64);
+	  }
+	else if (!object->local_has_got_offset(r_sym,
+					       GOT_TYPE_TLS_OFFSET))
+	  {
+	    got->add_local(object, r_sym, GOT_TYPE_TLS_OFFSET);
+	    unsigned int got_offset =
+		object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET);
+	    const elfcpp::Elf_Xword addend = rela.get_r_addend();
+	    gold_assert(addend == 0);
+	    got->add_static_reloc(got_offset, elfcpp::R_AARCH64_TLS_TPREL64,
+				  object, r_sym);
+	  }
+      }
+      break;
+
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+      {
+	layout->set_has_static_tls();
+	bool output_is_shared = parameters->options().shared();
+	if (output_is_shared)
+	  gold_error(_("%s: unsupported TLSLEreloc %u in shard code."),
+		     object->name().c_str(), r_type);
+      }
       break;
 
     default:
       unsupported_reloc_local(object, r_type);
     }
 }
 
 
@@ -1680,35 +1967,98 @@ 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,
-    Sized_relobj_file<size, big_endian>* /* object */,
-    unsigned int /* data_shndx */,
-    Output_section* /* output_section */,
-    const elfcpp::Rela<size, big_endian>& /* reloc */,
+    Sized_relobj_file<size, big_endian> * object,
+    unsigned int data_shndx,
+    Output_section* output_section,
+    const elfcpp::Rela<size, big_endian>& rela,
     unsigned int r_type,
     Symbol* gsym)
 {
+  typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
+    Reloc_section;
   switch (r_type)
     {
+    case elfcpp::R_AARCH64_ABS16:
+    case elfcpp::R_AARCH64_ABS32:
     case elfcpp::R_AARCH64_ABS64:
+      {
+	// Make a PLT entry if necessary.
+	if (gsym->needs_plt_entry())
+	  {
+	    target->make_plt_entry(symtab, layout, gsym);
+	    // Since this is not a PC-relative relocation, we may be
+	    // taking the address of a function. In that case we need to
+	    // set the entry in the dynamic symbol table to the address of
+	    // the PLT entry.
+	    if (gsym->is_from_dynobj() && !parameters->options().shared())
+	      gsym->set_needs_dynsym_value();
+	  }
+	// Make a dynamic relocation if necessary.
+	const AArch64_reloc_property* arp =
+	    aarch64_reloc_property_table->get_reloc_property(r_type);
+	gold_assert(arp != NULL);
+	if (gsym->needs_dynamic_reloc(arp->reference_flags()))
+	  {
+	    if (!parameters->options().output_is_position_independent()
+		&& gsym->may_need_copy_reloc())
+	      {
+		gold_error(
+		  _("%s: unsupported reloc %u which may need copyreloc."),
+		  object->name().c_str(), r_type);
+	      }
+	    else if (r_type == elfcpp::R_AARCH64_ABS64
+		     && gsym->can_use_relative_reloc(false))
+	      {
+		Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+		rela_dyn->add_global_relative(gsym,
+					      elfcpp::R_AARCH64_RELATIVE,
+					      output_section,
+					      object,
+					      data_shndx,
+					      rela.get_r_offset(),
+					      rela.get_r_addend(),
+					      false);
+	      }
+	    else
+	      {
+		check_non_pic(object, r_type);
+		Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>*
+		    rela_dyn = target->rela_dyn_section(layout);
+		rela_dyn->add_global(
+		  gsym, r_type, output_section, object,
+		  data_shndx, rela.get_r_offset(),rela.get_r_addend());
+	      }
+	  }
+      }
+      break;
+
+    case elfcpp::R_AARCH64_PREL16:
+    case elfcpp::R_AARCH64_PREL32:
+    case elfcpp::R_AARCH64_PREL64:
       // 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_LDST8_ABS_LO12_NC: // 278
+    case elfcpp::R_AARCH64_LDST16_ABS_LO12_NC: // 284
+    case elfcpp::R_AARCH64_LDST32_ABS_LO12_NC: // 285
+    case elfcpp::R_AARCH64_LDST64_ABS_LO12_NC: // 286
+    case elfcpp::R_AARCH64_LDST128_ABS_LO12_NC: // 299
     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:
@@ -1736,16 +2086,18 @@ Target_aarch64<size, big_endian>::Scan::global(
 	      {
 		// Not implemented yet.
 		gold_assert(false);
 	      }
 	  }
 	break;
       }
 
+    case elfcpp::R_AARCH64_TSTBR14:
+    case elfcpp::R_AARCH64_CONDBR19:
     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() &&
@@ -1755,20 +2107,58 @@ Target_aarch64<size, big_endian>::Scan::global(
 	// 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;
       }
 
+    case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+      {
+	layout->set_has_static_tls();
+	// Create a GOT entry for the tp-relative offset.
+	Output_data_got_aarch64<size, big_endian>* got
+	  = target->got_section(symtab, layout);
+	if (!parameters->doing_static_link())
+	  {
+	    got->add_global_with_rel(
+	      gsym, GOT_TYPE_TLS_OFFSET,
+	      target->rela_dyn_section(layout),
+	      elfcpp::R_AARCH64_TLS_TPREL64);
+	  }
+	if (!gsym->has_got_offset(GOT_TYPE_TLS_OFFSET))
+	  {
+	    got->add_global(gsym, GOT_TYPE_TLS_OFFSET);
+	    unsigned int got_offset =
+	      gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+	    const elfcpp::Elf_Xword addend = rela.get_r_addend();
+	    gold_assert(addend == 0);
+	    got->add_static_reloc(got_offset,
+				  elfcpp::R_AARCH64_TLS_TPREL64, gsym);
+	  }
+      }
+      break;
+
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+      layout->set_has_static_tls();
+      if (parameters->options().shared())
+	gold_error(_("%s: unsupported TLSLE reloc type %u in shared objects."),
+		   object->name().c_str(), r_type);
+      break;
+
     default:
-      gold_error(_("%s: unsupported reloc type"),
-		 aarch64_reloc_property_table->
-		   reloc_name_in_error_message(r_type).c_str());
+      const AArch64_reloc_property* arp =
+	  aarch64_reloc_property_table->get_reloc_property(r_type);
+      gold_assert(arp != NULL);
+      gold_error(_("%s: unsupported reloc type in global scan"),
+		 arp->name().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(
@@ -2051,16 +2441,34 @@ Target_aarch64<size, big_endian>::Relocate::relocate(
 	{
 	  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;
+
+    case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+      if (gsym != NULL)
+	{
+	  gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
+	  got_offset = gsym->got_offset(GOT_TYPE_TLS_OFFSET) - 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_TLS_OFFSET));
+	  got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET)
+			- 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)
     {
@@ -2105,16 +2513,18 @@ Target_aarch64<size, big_endian>::Relocate::relocate(
     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_TSTBR14:
+    case elfcpp::R_AARCH64_CONDBR19:
     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);
@@ -2124,16 +2534,29 @@ Target_aarch64<size, big_endian>::Relocate::relocate(
 
     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;
 
+    case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+      reloc_status = relocate_tls(relinfo, target, relnum, rela, r_type,
+				  gsym, psymval, view, address);
+      break;
+
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+      reloc_status = relocate_tls(relinfo, target, relnum, rela, r_type,
+				  gsym, psymval, view, address);
+      break;
+
     default:
       gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
 			     _("unsupported reloc aaa %u"),
 			     r_type);
       break;
     }
 
   // Report any errors.
@@ -2156,16 +2579,108 @@ Target_aarch64<size, big_endian>::Relocate::relocate(
       break;
     default:
       gold_unreachable();
     }
 
   return true;
 }
 
+template<int size, bool big_endian>
+inline
+typename AArch64_relocate_functions<size,big_endian>::Status
+Target_aarch64<size, big_endian>::Relocate::relocate_tls(
+    const Relocate_info<size,big_endian> * relinfo,
+    Target_aarch64<size, big_endian> * target,
+    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)
+{
+  typedef AArch64_relocate_functions<size,big_endian> aarch64_reloc_funcs;
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_Addr;
+
+  const AArch64_reloc_property * reloc_property =
+    aarch64_reloc_property_table->get_reloc_property(r_type);
+  gold_assert(reloc_property != NULL);
+
+  Sized_relobj_file<size,big_endian> * object = relinfo->object;
+  switch (r_type)
+    {
+    case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+      {
+	// Not implemented - possible IE->LE relaxation opportunity:
+	//   adrp xd, :gottprel:var   =>   movz xd, :tprel_g1:var
+	typename elfcpp::Elf_types<size>::Elf_Addr got_entry_address;
+	if (gsym != NULL)
+	  {
+	    gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
+	    got_entry_address = target->got_->address() +
+	      gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+	  }
+	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_TLS_OFFSET));
+	    got_entry_address = target->got_->address() +
+	      object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET);
+	  }
+	if (r_type == elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21)
+	  {
+	    return aarch64_reloc_funcs::adrp(
+					     view, got_entry_address, address);
+	  }
+	else if (r_type == elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC)
+	  {
+	    return aarch64_reloc_funcs::template rela_general<64>(
+	      view, got_entry_address, 0, reloc_property);
+	  }
+	gold_assert(false);
+      }
+      break;
+
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+      {
+	Output_segment * tls_segment = relinfo->layout->tls_segment();
+	gold_assert(tls_segment != NULL);
+	AArch64_Addr value = psymval->value(object, 0);
+	const elfcpp::Elf_Xword addend = rela.get_r_addend();
+
+	if (!parameters->options().shared())
+	  {
+	    AArch64_Addr aligned_tcb_size =
+	      align_address(target->tcb_size(),
+			    tls_segment->maximum_alignment());
+	    return aarch64_reloc_funcs::template
+		rela_general<32>(view,
+				 value + aligned_tcb_size,
+				 addend,
+				 reloc_property);
+	  }
+	else
+	  gold_error(_("%s: unsupported reloc %u "
+		       "in non-static TLSLE mode."),
+		     object->name().c_str(), r_type);
+      }
+      break;
+
+    default:
+      gold_error(_("%s: unsupported TLS reloc %u."),
+		 object->name().c_str(), r_type);
+    }
+  return aarch64_reloc_funcs::STATUS_BAD_RELOC;
+}
+
+
 // Relocate section data.
 
 template<int size, bool big_endian>
 void
 Target_aarch64<size, big_endian>::relocate_section(
     const Relocate_info<size, big_endian>* relinfo,
     unsigned int sh_type,
     const unsigned char* prelocs,
@@ -2208,53 +2723,81 @@ get_size_for_reloc(
   return 0;
 }
 
 // Scan the relocs during a relocatable link.
 
 template<int size, bool big_endian>
 void
 Target_aarch64<size, big_endian>::scan_relocatable_relocs(
-    Symbol_table* /* symtab */,
-    Layout* /* layout */,
-    Sized_relobj_file<size, big_endian>* /* object */,
-    unsigned int /* data_shndx */,
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* object,
+    unsigned int data_shndx,
     unsigned int sh_type,
-    const unsigned char* /* prelocs */,
-    size_t /* reloc_count */,
-    Output_section* /* output_section */,
-    bool /* needs_special_offset_handling */,
-    size_t /* local_symbol_count */,
-    const unsigned char* /* plocal_symbols */,
-    Relocatable_relocs* /* rr */)
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    size_t local_symbol_count,
+    const unsigned char* plocal_symbols,
+    Relocatable_relocs* rr)
 {
-  //TODO
   gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
+    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
+      Scan_relocatable_relocs>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols,
+    rr);
 }
 
 // Relocate a section during a relocatable link.
 
 template<int size, bool big_endian>
 void
 Target_aarch64<size, big_endian>::relocate_relocs(
-    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 */,
-    typename elfcpp::Elf_types<size>::Elf_Off /* offset_in_output_section */,
-    const Relocatable_relocs* /* rr */,
-    unsigned char* /* view */,
-    typename elfcpp::Elf_types<size>::Elf_Addr /* view_address */,
-    section_size_type /* view_size */,
-    unsigned char* /* reloc_view */,
-    section_size_type /* reloc_view_size */)
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
+    const Relocatable_relocs* rr,
+    unsigned char* view,
+    typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+    section_size_type view_size,
+    unsigned char* reloc_view,
+    section_size_type reloc_view_size)
 {
-  //TODO
   gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::relocate_relocs<size, big_endian, elfcpp::SHT_RELA>(
+    relinfo,
+    prelocs,
+    reloc_count,
+    output_section,
+    offset_in_output_section,
+    rr,
+    view,
+    view_address,
+    view_size,
+    reloc_view,
+    reloc_view_size);
 }
 
 // The selector for aarch64 object files.
 
 template<int size, bool big_endian>
 class Target_selector_aarch64 : public Target_selector
 {
  public:

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

* Re: [gold][aarch64]patch3: static link/shared objects
  2014-08-12  0:48 [gold][aarch64]patch3: static link/shared objects Hán Shěn (沈涵)
@ 2014-08-29 22:50 ` Cary Coutant
  2014-08-29 22:52   ` Andrew Pinski
  0 siblings, 1 reply; 5+ messages in thread
From: Cary Coutant @ 2014-08-29 22:50 UTC (permalink / raw)
  To: Hán Shěn (沈涵); +Cc: binutils, Doug Kwan, Jing Yu

> 2014-08-11 Han Shen <shenhan@google.com>
>                   Jing Yu <jingyu@google.com>
>
> * gold/aarch64-reloc-property.cc(AArch64_reloc_property_table::reloc_name_in_error_message):
>   Fix bug in reference reloc property in the table.
> * gold/aarch64-reloc.def: Add TLSLE reloc types and fix some errors in
> 3 other entries.
> * gold/aarch64.cc:
>   (TARGET_TCB_SIZE): New macro defining how tcb size is computed.
>   (Output_data_got_aarch64::add_static_reloc): 2 new methods
> (overloaded version).
>   (Output_data_got_aarch64::do_write): Add code to write out static relocs.
>   (class Output_data_got_aarch64::Static_reloc): New class to wrap
> static relocs.
>   (Output_data_got_aarch64::static_relocs): New vector to hold static relocs.
>   (Target_aarch64::tcb_size): New method.
>   (Target_aarch64::Relocate::relocate): Add code handling new reloc types.
>   (Target_aarch64::Relocate::relocate_tls): New method.
>   (Target_aarch64::Scan::local): Add code handling new reloc types.
>   (Target_aarch64::Scan::global): Add code handling new reloc types.

Your patch includes the top-level configure patches. Those need to go
to GCC first; I'll take care of adding both aarch64 and mips at the
same time.

The ChangeLog entries shouldn't have "gold/" in the filenames.

+#define TARGET_TCB_SIZE ((size / 8) * 2)

I'm uncomfortable having a file-scope macro that refers to a template
parameter. Can't you just have a static const int TCB_SIZE in
Target_aarch64, and refer to it from the Output_data_got_aarch64 class
as Target_aarch64<size, big_endian::TCB_SIZE?

+  unsigned int
+  tcb_size() const { return this->tcb_size_; }

You can just return This::TCB_SIZE here (with a suitable typedef for This).

+  // Size of TCB
+  const unsigned int tcb_size_;

And this field can go away.

This is OK with the above changes. Thanks!

-cary

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

* Re: [gold][aarch64]patch3: static link/shared objects
  2014-08-29 22:50 ` Cary Coutant
@ 2014-08-29 22:52   ` Andrew Pinski
  2014-08-29 23:02     ` Cary Coutant
  0 siblings, 1 reply; 5+ messages in thread
From: Andrew Pinski @ 2014-08-29 22:52 UTC (permalink / raw)
  To: Cary Coutant
  Cc: Hán Shěn (沈涵), binutils, Doug Kwan, Jing Yu

On Fri, Aug 29, 2014 at 3:50 PM, Cary Coutant <ccoutant@google.com> wrote:
>> 2014-08-11 Han Shen <shenhan@google.com>
>>                   Jing Yu <jingyu@google.com>
>>
>> * gold/aarch64-reloc-property.cc(AArch64_reloc_property_table::reloc_name_in_error_message):
>>   Fix bug in reference reloc property in the table.
>> * gold/aarch64-reloc.def: Add TLSLE reloc types and fix some errors in
>> 3 other entries.
>> * gold/aarch64.cc:
>>   (TARGET_TCB_SIZE): New macro defining how tcb size is computed.
>>   (Output_data_got_aarch64::add_static_reloc): 2 new methods
>> (overloaded version).
>>   (Output_data_got_aarch64::do_write): Add code to write out static relocs.
>>   (class Output_data_got_aarch64::Static_reloc): New class to wrap
>> static relocs.
>>   (Output_data_got_aarch64::static_relocs): New vector to hold static relocs.
>>   (Target_aarch64::tcb_size): New method.
>>   (Target_aarch64::Relocate::relocate): Add code handling new reloc types.
>>   (Target_aarch64::Relocate::relocate_tls): New method.
>>   (Target_aarch64::Scan::local): Add code handling new reloc types.
>>   (Target_aarch64::Scan::global): Add code handling new reloc types.
>
> Your patch includes the top-level configure patches. Those need to go
> to GCC first; I'll take care of adding both aarch64 and mips at the
> same time.
>
> The ChangeLog entries shouldn't have "gold/" in the filenames.
>
> +#define TARGET_TCB_SIZE ((size / 8) * 2)
>
> I'm uncomfortable having a file-scope macro that refers to a template
> parameter. Can't you just have a static const int TCB_SIZE in
> Target_aarch64, and refer to it from the Output_data_got_aarch64 class
> as Target_aarch64<size, big_endian::TCB_SIZE?
>
> +  unsigned int
> +  tcb_size() const { return this->tcb_size_; }
>
> You can just return This::TCB_SIZE here (with a suitable typedef for This).
>
> +  // Size of TCB
> +  const unsigned int tcb_size_;
>
> And this field can go away.
>
> This is OK with the above changes. Thanks!

The TCB changes size for ILP32.

Thanks,
Andrew

>
> -cary

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

* Re: [gold][aarch64]patch3: static link/shared objects
  2014-08-29 22:52   ` Andrew Pinski
@ 2014-08-29 23:02     ` Cary Coutant
  2014-08-30  1:00       ` Hán Shěn (沈涵)
  0 siblings, 1 reply; 5+ messages in thread
From: Cary Coutant @ 2014-08-29 23:02 UTC (permalink / raw)
  To: Andrew Pinski
  Cc: Hán Shěn (沈涵), binutils, Doug Kwan, Jing Yu

> The TCB changes size for ILP32.

Yes, but that will be Target_aarch64<32, ...>::TCB_SIZE, as distinct
from Target_aarch64<64, ...>::TCB_SIZE. And target->tcb_size() will
return whichever one is appropriate.

-cary

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

* Re: [gold][aarch64]patch3: static link/shared objects
  2014-08-29 23:02     ` Cary Coutant
@ 2014-08-30  1:00       ` Hán Shěn (沈涵)
  0 siblings, 0 replies; 5+ messages in thread
From: Hán Shěn (沈涵) @ 2014-08-30  1:00 UTC (permalink / raw)
  To: Cary Coutant; +Cc: Andrew Pinski, binutils, Doug Kwan, Jing Yu

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

Hi Cary and Andrew, thanks for the review.
Modified per your review feedback (TCB_SIZE macro replaced with const
static member, configure* removed from patch and removed 'gold/' in
ChangeLog entries.)

CL submitted as attached patch.

Thanks,
Han

On Fri, Aug 29, 2014 at 4:02 PM, Cary Coutant <ccoutant@google.com> wrote:
>
> > The TCB changes size for ILP32.
>
> Yes, but that will be Target_aarch64<32, ...>::TCB_SIZE, as distinct
> from Target_aarch64<64, ...>::TCB_SIZE. And target->tcb_size() will
> return whichever one is appropriate.
>
> -cary

[-- Attachment #2: patched --]
[-- Type: application/octet-stream, Size: 32600 bytes --]

diff --git a/gold/ChangeLog b/gold/ChangeLog
index e915c6f..4fce2cb 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,26 @@
+2014-08-29 Han Shen <shenhan@google.com>
+	   Jing Yu <jingyu@google.com>
+
+	* aarch64-reloc-property.cc
+	(AArch64_reloc_property_table::reloc_name_in_error_message): Fix bug in
+	reference reloc property in the table.
+	* aarch64-reloc.def: Add TLSLE reloc types and fix some errors in
+	3 other entries.
+	* aarch64.cc: (Output_data_got_aarch64::add_static_reloc):
+	2 new overloaded methods.
+	(Output_data_got_aarch64::do_write): Add code to write out
+	static relocs.
+	(class Output_data_got_aarch64::Static_reloc): New class to wrap
+	static relocs.
+	(Output_data_got_aarch64::static_relocs): New vector to
+	hold static relocs.
+	(Target_aarch64::TCB_SIZE): New const static memeber.
+	(Target_aarch64::tcb_size): New method.
+	(Target_aarch64::Relocate::relocate): Add code handling new reloc types.
+	(Target_aarch64::Relocate::relocate_tls): New method.
+	(Target_aarch64::Scan::local): Add code handling new reloc types.
+	(Target_aarch64::Scan::global): Add code handling new reloc types.
+
 2014-08-13  Sriraman Tallam  <tmsriram@google.com>
 
 	* options.h (-no-pie): Add option.
diff --git a/gold/aarch64-reloc-property.cc b/gold/aarch64-reloc-property.cc
index beaed10..16f8449 100644
--- a/gold/aarch64-reloc-property.cc
+++ b/gold/aarch64-reloc-property.cc
@@ -130,9 +130,8 @@ AArch64_reloc_property_table::AArch64_reloc_property_table()
 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];
+  int tidx = code_to_array_index(code);
+  const AArch64_reloc_property* arp = this->table_[tidx];
 
   if (arp == NULL)
     {
diff --git a/gold/aarch64-reloc.def b/gold/aarch64-reloc.def
index 4f6710e..4fb1232 100644
--- a/gold/aarch64-reloc.def
+++ b/gold/aarch64-reloc.def
@@ -50,8 +50,8 @@ ARD(LDST128_ABS_LO12_NC          , STATIC ,  AARCH64    ,   Y,  -1,    0,RL_CHEC
 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(TSTBR14                      , STATIC ,  CFLOW      ,   N,  -1,   15,15               ,    2,15 , (Symbol::FUNCTION_CALL|Symbol::ABSOLUTE_REF) , TBZNZ )
+ARD(CONDBR19                     , STATIC ,  CFLOW      ,   N,  -1,   20,20               ,    2,20 , (Symbol::FUNCTION_CALL|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,
@@ -60,10 +60,15 @@ ARD(JUMP26                       , STATIC ,  CFLOW      ,   Y,  -1,   27,27
 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_LD64_GOTTPREL_LO12_NC  , STATIC ,  AARCH64    ,   Y,  -1,    0,RL_CHECK_ALIGN8  ,    3,11 , 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.
 
+ARD(TLSLE_ADD_TPREL_HI12         , STATIC ,  AARCH64   ,    Y,  -1,    0,24	          ,   12,23 , Symbol::ABSOLUTE_REF , ADD )
+ARD(TLSLE_ADD_TPREL_LO12         , STATIC ,  AARCH64   ,    Y,  -1,    0,12	          ,    0,11 , Symbol::ABSOLUTE_REF , ADD )
+ARD(TLSLE_ADD_TPREL_LO12_NC      , STATIC ,  AARCH64   ,    Y,  -1,    0,0	          ,    0,11 , Symbol::ABSOLUTE_REF , ADD )
+// Above is from Table 4-18, Local Exec TLS relocations, 544-571.
+
 // 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
diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index 7a3fe3b..2a6340a 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -76,6 +76,27 @@ class Output_data_got_aarch64 : public Output_data_got<size, big_endian>
       symbol_table_(symtab), layout_(layout)
   { }
 
+  // Add a static entry for the GOT entry at OFFSET.  GSYM is a global
+  // symbol and R_TYPE is the code of a dynamic relocation that needs to be
+  // applied in a static link.
+  void
+  add_static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym)
+  { this->static_relocs_.push_back(Static_reloc(got_offset, r_type, gsym)); }
+
+
+  // Add a static reloc for the GOT entry at OFFSET.  RELOBJ is an object
+  // defining a local symbol with INDEX.  R_TYPE is the code of a dynamic
+  // relocation that needs to be applied in a static link.
+  void
+  add_static_reloc(unsigned int got_offset, unsigned int r_type,
+		   Sized_relobj_file<size, big_endian>* relobj,
+		   unsigned int index)
+  {
+    this->static_relocs_.push_back(Static_reloc(got_offset, r_type, relobj,
+						index));
+  }
+
+
  protected:
   // Write out the GOT table.
   void
@@ -86,6 +107,104 @@ class Output_data_got_aarch64 : public Output_data_got<size, big_endian>
     Valtype dynamic_addr = dynamic == NULL ? 0 : dynamic->address();
     this->replace_constant(0, dynamic_addr);
     Output_data_got<size, big_endian>::do_write(of);
+
+    // Handling static relocs
+    if (this->static_relocs_.empty())
+      return;
+
+    typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
+
+    gold_assert(parameters->doing_static_link());
+    const off_t offset = this->offset();
+    const section_size_type oview_size =
+      convert_to_section_size_type(this->data_size());
+    unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+    Output_segment* tls_segment = this->layout_->tls_segment();
+    gold_assert(tls_segment != NULL);
+
+    AArch64_address aligned_tcb_address =
+      align_address(Target_aarch64<size,big_endian>::TCB_SIZE,
+		    tls_segment->maximum_alignment());
+
+    for (size_t i = 0; i < this->static_relocs_.size(); ++i)
+      {
+	Static_reloc& reloc(this->static_relocs_[i]);
+	AArch64_address value;
+
+	if (!reloc.symbol_is_global())
+	  {
+	    Sized_relobj_file<size, big_endian>* object = reloc.relobj();
+	    const Symbol_value<size>* psymval =
+	      reloc.relobj()->local_symbol(reloc.index());
+
+	    // We are doing static linking.  Issue an error and skip this
+	    // relocation if the symbol is undefined or in a discarded_section.
+	    bool is_ordinary;
+	    unsigned int shndx = psymval->input_shndx(&is_ordinary);
+	    if ((shndx == elfcpp::SHN_UNDEF)
+		|| (is_ordinary
+		    && shndx != elfcpp::SHN_UNDEF
+		    && !object->is_section_included(shndx)
+		    && !this->symbol_table_->is_section_folded(object, shndx)))
+	      {
+		gold_error(_("undefined or discarded local symbol %u from "
+			     " object %s in GOT"),
+			   reloc.index(), reloc.relobj()->name().c_str());
+		continue;
+	      }
+	    value = psymval->value(object, 0);
+	  }
+	else
+	  {
+	    const Symbol* gsym = reloc.symbol();
+	    gold_assert(gsym != NULL);
+	    if (gsym->is_forwarder())
+	      gsym = this->symbol_table_->resolve_forwards(gsym);
+
+	    // We are doing static linking.  Issue an error and skip this
+	    // relocation if the symbol is undefined or in a discarded_section
+	    // unless it is a weakly_undefined symbol.
+	    if ((gsym->is_defined_in_discarded_section()
+		 || gsym->is_undefined())
+		&& !gsym->is_weak_undefined())
+	      {
+		gold_error(_("undefined or discarded symbol %s in GOT"),
+			   gsym->name());
+		continue;
+	      }
+
+	    if (!gsym->is_weak_undefined())
+	      {
+		const Sized_symbol<size>* sym =
+		  static_cast<const Sized_symbol<size>*>(gsym);
+		value = sym->value();
+	      }
+	    else
+	      value = 0;
+	  }
+
+	unsigned got_offset = reloc.got_offset();
+	gold_assert(got_offset < oview_size);
+
+	typedef typename elfcpp::Swap<size, big_endian>::Valtype Valtype;
+	Valtype* wv = reinterpret_cast<Valtype*>(oview + got_offset);
+	Valtype x;
+	switch (reloc.r_type())
+	  {
+	  case elfcpp::R_AARCH64_TLS_DTPREL64:
+	    x = value;
+	    break;
+	  case elfcpp::R_AARCH64_TLS_TPREL64:
+	    x = value + aligned_tcb_address;
+	    break;
+	  default:
+	    gold_unreachable();
+	  }
+	elfcpp::Swap<size, big_endian>::writeval(wv, x);
+      }
+
+    of->write_output_view(offset, oview_size, oview);
   }
 
  private:
@@ -94,6 +213,90 @@ class Output_data_got_aarch64 : public Output_data_got<size, big_endian>
   // A pointer to the Layout class, so that we can find the .dynamic
   // section when we write out the GOT section.
   Layout* layout_;
+
+
+  // This class represent dynamic relocations that need to be applied by
+  // gold because we are using TLS relocations in a static link.
+  class Static_reloc
+  {
+   public:
+    Static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym)
+      : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(true)
+    { this->u_.global.symbol = gsym; }
+
+    Static_reloc(unsigned int got_offset, unsigned int r_type,
+	  Sized_relobj_file<size, big_endian>* relobj, unsigned int index)
+      : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(false)
+    {
+      this->u_.local.relobj = relobj;
+      this->u_.local.index = index;
+    }
+
+    // Return the GOT offset.
+    unsigned int
+    got_offset() const
+    { return this->got_offset_; }
+
+    // Relocation type.
+    unsigned int
+    r_type() const
+    { return this->r_type_; }
+
+    // Whether the symbol is global or not.
+    bool
+    symbol_is_global() const
+    { return this->symbol_is_global_; }
+
+    // For a relocation against a global symbol, the global symbol.
+    Symbol*
+    symbol() const
+    {
+      gold_assert(this->symbol_is_global_);
+      return this->u_.global.symbol;
+    }
+
+    // For a relocation against a local symbol, the defining object.
+    Sized_relobj_file<size, big_endian>*
+    relobj() const
+    {
+      gold_assert(!this->symbol_is_global_);
+      return this->u_.local.relobj;
+    }
+
+    // For a relocation against a local symbol, the local symbol index.
+    unsigned int
+    index() const
+    {
+      gold_assert(!this->symbol_is_global_);
+      return this->u_.local.index;
+    }
+
+   private:
+    // GOT offset of the entry to which this relocation is applied.
+    unsigned int got_offset_;
+    // Type of relocation.
+    unsigned int r_type_;
+    // Whether this relocation is against a global symbol.
+    bool symbol_is_global_;
+    // A global or local symbol.
+    union
+    {
+      struct
+      {
+	// For a global symbol, the symbol itself.
+	Symbol* symbol;
+      } global;
+      struct
+      {
+	// For a local symbol, the object defining object.
+	Sized_relobj_file<size, big_endian>* relobj;
+	// For a local symbol, the symbol index.
+	unsigned int index;
+      } local;
+    } u_;
+  };  // End of inner class Static_reloc
+
+  std::vector<Static_reloc> static_relocs_;
 };
 
 AArch64_reloc_property_table* aarch64_reloc_property_table = NULL;
@@ -105,9 +308,11 @@ template<int size, bool big_endian>
 class Target_aarch64 : public Sized_target<size, big_endian>
 {
  public:
+  typedef Target_aarch64<size,big_endian> This;
   typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
       Reloc_section;
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+  const static int TCB_SIZE = size / 8 * 2;
 
   Target_aarch64(const Target::Target_info* info = &aarch64_info)
     : Sized_target<size, big_endian>(info),
@@ -214,6 +419,9 @@ class Target_aarch64 : public Sized_target<size, big_endian>
   unsigned int
   plt_entry_size() const;
 
+  unsigned int
+  tcb_size() const { return This::TCB_SIZE; }
+
  protected:
   void
   do_select_as_default_target()
@@ -321,7 +529,18 @@ class Target_aarch64 : public Sized_target<size, big_endian>
 	     unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
 	     section_size_type);
 
-  };
+  private:
+    inline typename AArch64_relocate_functions<size,big_endian>::Status
+    relocate_tls(const Relocate_info<size,big_endian>*,
+		 Target_aarch64<size, big_endian>*,
+		 size_t,
+		 const elfcpp::Rela<size, big_endian>&,
+		 unsigned int r_type, const Sized_symbol<size>*,
+		 const Symbol_value<size>*,
+		 unsigned char*,
+		 typename elfcpp::Elf_types<size>::Elf_Addr);
+
+  };  // End of class Relocate
 
   // A class which returns the size required for a relocation type,
   // used while scanning relocs during a relocatable link.
@@ -410,7 +629,7 @@ class Target_aarch64 : public Sized_target<size, big_endian>
   Reloc_section* rela_dyn_;
   // Relocs saved to avoid a COPY reloc.
   Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
-};
+};  // End of Target_aarch64
 
 template<>
 const Target::Target_info Target_aarch64<64, false>::aarch64_info =
@@ -829,7 +1048,7 @@ 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>
@@ -1617,13 +1836,13 @@ Target_aarch64<size, big_endian>::Scan::check_non_pic(Relobj* object,
 template<int size, bool big_endian>
 inline void
 Target_aarch64<size, big_endian>::Scan::local(
-    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 data_shndx,
+    Output_section* output_section,
+    const elfcpp::Rela<size, big_endian>& rela,
     unsigned int r_type,
     const elfcpp::Sym<size, big_endian>& /* lsym */,
     bool is_discarded)
@@ -1631,33 +1850,99 @@ Target_aarch64<size, big_endian>::Scan::local(
   if (is_discarded)
     return;
 
+  typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
+    Reloc_section;
+
   switch (r_type)
     {
-    case elfcpp::R_AARCH64_ABS64:
     case elfcpp::R_AARCH64_ABS32:
     case elfcpp::R_AARCH64_ABS16:
+      if (parameters->options().output_is_position_independent())
+	{
+	  gold_error(_("%s: unsupported reloc %u in pos independent link."),
+		     object->name().c_str(), r_type);
+	}
+      break;
+
+    case elfcpp::R_AARCH64_ABS64:
       // 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());
+	  Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+	  unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
+	  rela_dyn->add_local_relative(object, r_sym,
+				       elfcpp::R_AARCH64_RELATIVE,
+				       output_section,
+				       data_shndx,
+				       rela.get_r_offset(),
+				       rela.get_r_addend(),
+				       false /* is ifunc */);
 	}
       break;
 
-      // Relocations to generate 19, 21 and 33-bit PC-relative address
+    case elfcpp::R_AARCH64_PREL64:
+    case elfcpp::R_AARCH64_PREL32:
+    case elfcpp::R_AARCH64_PREL16:
+      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_LDST16_ABS_LO12_NC: // 284
+    case elfcpp::R_AARCH64_LDST32_ABS_LO12_NC: // 285
     case elfcpp::R_AARCH64_LDST64_ABS_LO12_NC: // 286
+    case elfcpp::R_AARCH64_LDST128_ABS_LO12_NC: // 299
     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
+    // 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_TSTBR14:
+    case elfcpp::R_AARCH64_CONDBR19:
+    case elfcpp::R_AARCH64_JUMP26:
+    case elfcpp::R_AARCH64_CALL26:
+      break;
+
+    case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+      {
+	layout->set_has_static_tls();
+	// Create a GOT entry for the tp-relative offset.
+	Output_data_got_aarch64<size, big_endian>* got =
+	    target->got_section(symtab, layout);
+	unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+	if (!parameters->doing_static_link())
+	  {
+	    got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
+				    target->rela_dyn_section(layout),
+				    elfcpp::R_AARCH64_TLS_TPREL64);
+	  }
+	else if (!object->local_has_got_offset(r_sym,
+					       GOT_TYPE_TLS_OFFSET))
+	  {
+	    got->add_local(object, r_sym, GOT_TYPE_TLS_OFFSET);
+	    unsigned int got_offset =
+		object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET);
+	    const elfcpp::Elf_Xword addend = rela.get_r_addend();
+	    gold_assert(addend == 0);
+	    got->add_static_reloc(got_offset, elfcpp::R_AARCH64_TLS_TPREL64,
+				  object, r_sym);
+	  }
+      }
+      break;
+
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+      {
+	layout->set_has_static_tls();
+	bool output_is_shared = parameters->options().shared();
+	if (output_is_shared)
+	  gold_error(_("%s: unsupported TLSLEreloc %u in shard code."),
+		     object->name().c_str(), r_type);
+      }
       break;
 
     default:
@@ -1685,16 +1970,74 @@ Target_aarch64<size, big_endian>::Scan::global(
     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 */,
+    Sized_relobj_file<size, big_endian> * object,
+    unsigned int data_shndx,
+    Output_section* output_section,
+    const elfcpp::Rela<size, big_endian>& rela,
     unsigned int r_type,
     Symbol* gsym)
 {
+  typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
+    Reloc_section;
   switch (r_type)
     {
+    case elfcpp::R_AARCH64_ABS16:
+    case elfcpp::R_AARCH64_ABS32:
     case elfcpp::R_AARCH64_ABS64:
+      {
+	// Make a PLT entry if necessary.
+	if (gsym->needs_plt_entry())
+	  {
+	    target->make_plt_entry(symtab, layout, gsym);
+	    // Since this is not a PC-relative relocation, we may be
+	    // taking the address of a function. In that case we need to
+	    // set the entry in the dynamic symbol table to the address of
+	    // the PLT entry.
+	    if (gsym->is_from_dynobj() && !parameters->options().shared())
+	      gsym->set_needs_dynsym_value();
+	  }
+	// Make a dynamic relocation if necessary.
+	const AArch64_reloc_property* arp =
+	    aarch64_reloc_property_table->get_reloc_property(r_type);
+	gold_assert(arp != NULL);
+	if (gsym->needs_dynamic_reloc(arp->reference_flags()))
+	  {
+	    if (!parameters->options().output_is_position_independent()
+		&& gsym->may_need_copy_reloc())
+	      {
+		gold_error(
+		  _("%s: unsupported reloc %u which may need copyreloc."),
+		  object->name().c_str(), r_type);
+	      }
+	    else if (r_type == elfcpp::R_AARCH64_ABS64
+		     && gsym->can_use_relative_reloc(false))
+	      {
+		Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+		rela_dyn->add_global_relative(gsym,
+					      elfcpp::R_AARCH64_RELATIVE,
+					      output_section,
+					      object,
+					      data_shndx,
+					      rela.get_r_offset(),
+					      rela.get_r_addend(),
+					      false);
+	      }
+	    else
+	      {
+		check_non_pic(object, r_type);
+		Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>*
+		    rela_dyn = target->rela_dyn_section(layout);
+		rela_dyn->add_global(
+		  gsym, r_type, output_section, object,
+		  data_shndx, rela.get_r_offset(),rela.get_r_addend());
+	      }
+	  }
+      }
+      break;
+
+    case elfcpp::R_AARCH64_PREL16:
+    case elfcpp::R_AARCH64_PREL32:
+    case elfcpp::R_AARCH64_PREL64:
       // This is used to fill the GOT absolute address.
       if (gsym->needs_plt_entry())
 	{
@@ -1704,6 +2047,11 @@ Target_aarch64<size, big_endian>::Scan::global(
 
     case elfcpp::R_AARCH64_ADR_PREL_PG_HI21:
     case elfcpp::R_AARCH64_ADR_PREL_PG_HI21_NC:
+    case elfcpp::R_AARCH64_LDST8_ABS_LO12_NC: // 278
+    case elfcpp::R_AARCH64_LDST16_ABS_LO12_NC: // 284
+    case elfcpp::R_AARCH64_LDST32_ABS_LO12_NC: // 285
+    case elfcpp::R_AARCH64_LDST64_ABS_LO12_NC: // 286
+    case elfcpp::R_AARCH64_LDST128_ABS_LO12_NC: // 299
     case elfcpp::R_AARCH64_ADD_ABS_LO12_NC:
       {
 	// Do nothing here.
@@ -1741,6 +2089,8 @@ Target_aarch64<size, big_endian>::Scan::global(
 	break;
       }
 
+    case elfcpp::R_AARCH64_TSTBR14:
+    case elfcpp::R_AARCH64_CONDBR19:
     case elfcpp::R_AARCH64_JUMP26:
     case elfcpp::R_AARCH64_CALL26:
       {
@@ -1760,10 +2110,48 @@ Target_aarch64<size, big_endian>::Scan::global(
 	break;
       }
 
+    case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+      {
+	layout->set_has_static_tls();
+	// Create a GOT entry for the tp-relative offset.
+	Output_data_got_aarch64<size, big_endian>* got
+	  = target->got_section(symtab, layout);
+	if (!parameters->doing_static_link())
+	  {
+	    got->add_global_with_rel(
+	      gsym, GOT_TYPE_TLS_OFFSET,
+	      target->rela_dyn_section(layout),
+	      elfcpp::R_AARCH64_TLS_TPREL64);
+	  }
+	if (!gsym->has_got_offset(GOT_TYPE_TLS_OFFSET))
+	  {
+	    got->add_global(gsym, GOT_TYPE_TLS_OFFSET);
+	    unsigned int got_offset =
+	      gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+	    const elfcpp::Elf_Xword addend = rela.get_r_addend();
+	    gold_assert(addend == 0);
+	    got->add_static_reloc(got_offset,
+				  elfcpp::R_AARCH64_TLS_TPREL64, gsym);
+	  }
+      }
+      break;
+
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+      layout->set_has_static_tls();
+      if (parameters->options().shared())
+	gold_error(_("%s: unsupported TLSLE reloc type %u in shared objects."),
+		   object->name().c_str(), r_type);
+      break;
+
     default:
-      gold_error(_("%s: unsupported reloc type"),
-		 aarch64_reloc_property_table->
-		   reloc_name_in_error_message(r_type).c_str());
+      const AArch64_reloc_property* arp =
+	  aarch64_reloc_property_table->get_reloc_property(r_type);
+      gold_assert(arp != NULL);
+      gold_error(_("%s: unsupported reloc type in global scan"),
+		 arp->name().c_str());
     }
   return;
 }  // End of Scan::global
@@ -2056,6 +2444,24 @@ Target_aarch64<size, big_endian>::Relocate::relocate(
 	}
       have_got_offset = true;
       break;
+
+    case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+      if (gsym != NULL)
+	{
+	  gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
+	  got_offset = gsym->got_offset(GOT_TYPE_TLS_OFFSET) - 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_TLS_OFFSET));
+	  got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET)
+			- got_base);
+	}
+      have_got_offset = true;
+      break;
+
     default:
       break;
     }
@@ -2110,6 +2516,8 @@ Target_aarch64<size, big_endian>::Relocate::relocate(
 	view, object, psymval, addend, reloc_property);
       break;
 
+    case elfcpp::R_AARCH64_TSTBR14:
+    case elfcpp::R_AARCH64_CONDBR19:
     case elfcpp::R_AARCH64_CALL26:
     case elfcpp::R_AARCH64_JUMP26:
       reloc_status = Reloc::template pcrela_general<32>(
@@ -2129,6 +2537,19 @@ Target_aarch64<size, big_endian>::Relocate::relocate(
 	view, value, addend, reloc_property);
       break;
 
+    case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+      reloc_status = relocate_tls(relinfo, target, relnum, rela, r_type,
+				  gsym, psymval, view, address);
+      break;
+
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+      reloc_status = relocate_tls(relinfo, target, relnum, rela, r_type,
+				  gsym, psymval, view, address);
+      break;
+
     default:
       gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
 			     _("unsupported reloc aaa %u"),
@@ -2161,6 +2582,98 @@ Target_aarch64<size, big_endian>::Relocate::relocate(
   return true;
 }
 
+template<int size, bool big_endian>
+inline
+typename AArch64_relocate_functions<size,big_endian>::Status
+Target_aarch64<size, big_endian>::Relocate::relocate_tls(
+    const Relocate_info<size,big_endian> * relinfo,
+    Target_aarch64<size, big_endian> * target,
+    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)
+{
+  typedef AArch64_relocate_functions<size,big_endian> aarch64_reloc_funcs;
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_Addr;
+
+  const AArch64_reloc_property * reloc_property =
+    aarch64_reloc_property_table->get_reloc_property(r_type);
+  gold_assert(reloc_property != NULL);
+
+  Sized_relobj_file<size,big_endian> * object = relinfo->object;
+  switch (r_type)
+    {
+    case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+    case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+      {
+	// Not implemented - possible IE->LE relaxation opportunity:
+	//   adrp xd, :gottprel:var   =>   movz xd, :tprel_g1:var
+	typename elfcpp::Elf_types<size>::Elf_Addr got_entry_address;
+	if (gsym != NULL)
+	  {
+	    gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
+	    got_entry_address = target->got_->address() +
+	      gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+	  }
+	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_TLS_OFFSET));
+	    got_entry_address = target->got_->address() +
+	      object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET);
+	  }
+	if (r_type == elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21)
+	  {
+	    return aarch64_reloc_funcs::adrp(
+					     view, got_entry_address, address);
+	  }
+	else if (r_type == elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC)
+	  {
+	    return aarch64_reloc_funcs::template rela_general<64>(
+	      view, got_entry_address, 0, reloc_property);
+	  }
+	gold_assert(false);
+      }
+      break;
+
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
+    case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+      {
+	Output_segment * tls_segment = relinfo->layout->tls_segment();
+	gold_assert(tls_segment != NULL);
+	AArch64_Addr value = psymval->value(object, 0);
+	const elfcpp::Elf_Xword addend = rela.get_r_addend();
+
+	if (!parameters->options().shared())
+	  {
+	    AArch64_Addr aligned_tcb_size =
+	      align_address(target->tcb_size(),
+			    tls_segment->maximum_alignment());
+	    return aarch64_reloc_funcs::template
+		rela_general<32>(view,
+				 value + aligned_tcb_size,
+				 addend,
+				 reloc_property);
+	  }
+	else
+	  gold_error(_("%s: unsupported reloc %u "
+		       "in non-static TLSLE mode."),
+		     object->name().c_str(), r_type);
+      }
+      break;
+
+    default:
+      gold_error(_("%s: unsupported TLS reloc %u."),
+		 object->name().c_str(), r_type);
+    }
+  return aarch64_reloc_funcs::STATUS_BAD_RELOC;
+}
+
+
 // Relocate section data.
 
 template<int size, bool big_endian>
@@ -2213,21 +2726,37 @@ get_size_for_reloc(
 template<int size, bool big_endian>
 void
 Target_aarch64<size, big_endian>::scan_relocatable_relocs(
-    Symbol_table* /* symtab */,
-    Layout* /* layout */,
-    Sized_relobj_file<size, big_endian>* /* object */,
-    unsigned int /* data_shndx */,
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* object,
+    unsigned int data_shndx,
     unsigned int sh_type,
-    const unsigned char* /* prelocs */,
-    size_t /* reloc_count */,
-    Output_section* /* output_section */,
-    bool /* needs_special_offset_handling */,
-    size_t /* local_symbol_count */,
-    const unsigned char* /* plocal_symbols */,
-    Relocatable_relocs* /* rr */)
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    size_t local_symbol_count,
+    const unsigned char* plocal_symbols,
+    Relocatable_relocs* rr)
 {
-  //TODO
   gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
+    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
+      Scan_relocatable_relocs>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols,
+    rr);
 }
 
 // Relocate a section during a relocatable link.
@@ -2235,21 +2764,33 @@ Target_aarch64<size, big_endian>::scan_relocatable_relocs(
 template<int size, bool big_endian>
 void
 Target_aarch64<size, big_endian>::relocate_relocs(
-    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 */,
-    typename elfcpp::Elf_types<size>::Elf_Off /* offset_in_output_section */,
-    const Relocatable_relocs* /* rr */,
-    unsigned char* /* view */,
-    typename elfcpp::Elf_types<size>::Elf_Addr /* view_address */,
-    section_size_type /* view_size */,
-    unsigned char* /* reloc_view */,
-    section_size_type /* reloc_view_size */)
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
+    const Relocatable_relocs* rr,
+    unsigned char* view,
+    typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+    section_size_type view_size,
+    unsigned char* reloc_view,
+    section_size_type reloc_view_size)
 {
-  //TODO
   gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::relocate_relocs<size, big_endian, elfcpp::SHT_RELA>(
+    relinfo,
+    prelocs,
+    reloc_count,
+    output_section,
+    offset_in_output_section,
+    rr,
+    view,
+    view_address,
+    view_size,
+    reloc_view,
+    reloc_view_size);
 }
 
 // The selector for aarch64 object files.

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

end of thread, other threads:[~2014-08-30  1:00 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-12  0:48 [gold][aarch64]patch3: static link/shared objects Hán Shěn (沈涵)
2014-08-29 22:50 ` Cary Coutant
2014-08-29 22:52   ` Andrew Pinski
2014-08-29 23:02     ` Cary Coutant
2014-08-30  1:00       ` Hán Shěn (沈涵)

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).