aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog22
-rw-r--r--gold/Makefile.am9
-rw-r--r--gold/Makefile.in11
-rw-r--r--gold/arm-reloc-property.cc287
-rw-r--r--gold/arm-reloc-property.h360
-rw-r--r--gold/arm-reloc.def194
-rw-r--r--gold/arm.cc47
-rw-r--r--gold/configure.tgt2
-rw-r--r--gold/parameters.cc5
-rw-r--r--gold/target.h11
10 files changed, 920 insertions, 28 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 2a811db..94dfe4b 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,25 @@
+2010-02-02 Doug Kwan <dougkwan@google.com>
+
+ * Makefile.am (HFILES): Add arm-reloc-property.h.
+ (DEFFILES): New.
+ (TARGETSOURCES): Add arm-reloc-property.cc
+ (ALL_TARGETOBJS): Add arm-reloc-property.$(OBJEXT)
+ (libgold_a_SOURCES): $(DEFFILES)
+ * Makefile.in: Regenerate.
+ * arm-reloc-property.cc: New file.
+ * arm-reloc-property.h: New file.
+ * arm-reloc.def: New file.
+ * arm.cc: Update comments.
+ (arm-reloc-property.h): New included header.
+ (arm_reloc_property_table): New global variable.
+ (Target_arm::do_select_as_default_target): New method definition.
+ * configure.tgt (armeb*-*-*,armbe*-*-*,arm*-*-*): Add
+ arm-reloc-property to targ_extra_obj.
+ * parameters.cc (set_parameters_target): Call
+ Target::select_as_default_target().
+ * target.h (Target::select_as_default_target): New method definition.
+ (Target::do_select_as_default_target): Same.
+
2010-02-01 Doug Kwan <dougkwan@google.com>
* arm.cc (Arm_exidx_fixup::Arm_exidx_fixup): Initialize
diff --git a/gold/Makefile.am b/gold/Makefile.am
index 784f821..e0665e0 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -84,6 +84,7 @@ CCFILES = \
workqueue-threads.cc
HFILES = \
+ arm-reloc-property.h \
archive.h \
attributes.h \
binary.h \
@@ -134,16 +135,18 @@ HFILES = \
YFILES = \
yyscript.y
+DEFFILES = arm-reloc.def
+
EXTRA_DIST = yyscript.c yyscript.h
TARGETSOURCES = \
- i386.cc x86_64.cc sparc.cc powerpc.cc arm.cc
+ i386.cc x86_64.cc sparc.cc powerpc.cc arm.cc arm-reloc-property.cc
ALL_TARGETOBJS = \
i386.$(OBJEXT) x86_64.$(OBJEXT) sparc.$(OBJEXT) powerpc.$(OBJEXT) \
- arm.$(OBJEXT)
+ arm.$(OBJEXT) arm-reloc-property.$(OBJEXT)
-libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES)
+libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES) $(DEFFILES)
libgold_a_LIBADD = $(LIBOBJS)
sources_var = main.cc
diff --git a/gold/Makefile.in b/gold/Makefile.in
index e118a51..29e1d1a 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -92,7 +92,7 @@ am__objects_1 = archive.$(OBJEXT) attributes.$(OBJEXT) \
am__objects_2 =
am__objects_3 = yyscript.$(OBJEXT)
am_libgold_a_OBJECTS = $(am__objects_1) $(am__objects_2) \
- $(am__objects_3)
+ $(am__objects_3) $(am__objects_2)
libgold_a_OBJECTS = $(am_libgold_a_OBJECTS)
PROGRAMS = $(noinst_PROGRAMS)
am_incremental_dump_OBJECTS = incremental-dump.$(OBJEXT)
@@ -398,6 +398,7 @@ CCFILES = \
workqueue-threads.cc
HFILES = \
+ arm-reloc-property.h \
archive.h \
attributes.h \
binary.h \
@@ -448,15 +449,16 @@ HFILES = \
YFILES = \
yyscript.y
+DEFFILES = arm-reloc.def
EXTRA_DIST = yyscript.c yyscript.h
TARGETSOURCES = \
- i386.cc x86_64.cc sparc.cc powerpc.cc arm.cc
+ i386.cc x86_64.cc sparc.cc powerpc.cc arm.cc arm-reloc-property.cc
ALL_TARGETOBJS = \
i386.$(OBJEXT) x86_64.$(OBJEXT) sparc.$(OBJEXT) powerpc.$(OBJEXT) \
- arm.$(OBJEXT)
+ arm.$(OBJEXT) arm-reloc-property.$(OBJEXT)
-libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES)
+libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES) $(DEFFILES)
libgold_a_LIBADD = $(LIBOBJS)
sources_var = main.cc
deps_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL_DEP)
@@ -598,6 +600,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/mremap.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm-reloc-property.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attributes.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary.Po@am__quote@
diff --git a/gold/arm-reloc-property.cc b/gold/arm-reloc-property.cc
new file mode 100644
index 0000000..ae93c47
--- /dev/null
+++ b/gold/arm-reloc-property.cc
@@ -0,0 +1,287 @@
+// arm-reloc-property.cc -- ARM relocation property.
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@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 <cstring>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "elfcpp.h"
+#include "arm.h"
+#include "arm-reloc-property.h"
+
+namespace gold
+{
+
+// Arm_reloc_property::Tree_node methods.
+
+// Parse an S-expression S and build a tree and return the root node.
+// Caller is responsible for releasing tree after use.
+
+Arm_reloc_property::Tree_node*
+Arm_reloc_property::Tree_node::make_tree(const std::string& s)
+{
+ std::stack<size_t> size_stack;
+ Tree_node_vector node_stack;
+
+ // strtok needs a non-const string pointer.
+ char* buffer = new char[s.size() + 1];
+ memcpy(buffer, s.data(), s.size());
+ buffer[s.size()] = '\0';
+ char* token = strtok(buffer, " ");
+
+ while (token != NULL)
+ {
+ if (strcmp(token, "(") == 0)
+ // Remember the node stack position for start of a new internal node.
+ size_stack.push(node_stack.size());
+ else if (strcmp(token, ")") == 0)
+ {
+ // Pop all tree nodes after the previous '(' and use them as
+ // children to build a new internal node. Push internal node back.
+ size_t current_size = node_stack.size();
+ size_t prev_size = size_stack.top();
+ size_stack.pop();
+ Tree_node* node =
+ new Tree_node(node_stack.begin() + prev_size,
+ node_stack.begin() + current_size);
+ node_stack.resize(prev_size);
+ node_stack.push_back(node);
+ }
+ else
+ // Just push a leaf node to node_stack.
+ node_stack.push_back(new Tree_node(token));
+
+ token = strtok(NULL, " ");
+ }
+
+ delete[] buffer;
+
+ // At this point, size_stack should be empty and node_stack should only
+ // contain the root node.
+ gold_assert(size_stack.empty() && node_stack.size() == 1);
+ return node_stack[0];
+}
+
+// Arm_reloc_property methods.
+
+// Constructor.
+
+Arm_reloc_property::Arm_reloc_property(
+ unsigned int code,
+ const char* name,
+ Reloc_type rtype,
+ bool is_deprecated,
+ Reloc_class rclass,
+ const std::string& operation,
+ bool is_implemented,
+ int group_index,
+ bool checks_overflow)
+ : code_(code), name_(name), reloc_type_(rtype), reloc_class_(rclass),
+ group_index_(group_index), size_(0), align_(1),
+ relative_address_base_(RAB_NONE), is_deprecated_(is_deprecated),
+ is_implemented_(is_implemented), checks_overflow_(checks_overflow),
+ uses_got_entry_(false), uses_got_origin_(false), uses_plt_entry_(false),
+ uses_thumb_bit_(false), uses_symbol_base_(false), uses_addend_(false)
+{
+ // Set size and alignment of static and dynamic relocations.
+ if (rtype == RT_STATIC)
+ {
+ switch (rclass)
+ {
+ case RC_DATA:
+ // Except for R_ARM_ABS16 and R_ARM_ABS8, all static data relocations
+ // have size 4. All static data relocations have alignment of 1.
+ if (code == elfcpp::R_ARM_ABS8)
+ this->size_ = 1;
+ else if (code == elfcpp::R_ARM_ABS16)
+ this->size_ = 2;
+ else
+ this->size_ = 4;
+ this->align_ = 1;
+ break;
+ case RC_MISC:
+ // R_ARM_V4BX should be treated as an ARM relocation. For all
+ // others, just use defaults.
+ if (code != elfcpp::R_ARM_V4BX)
+ break;
+ // Fall through.
+ case RC_ARM:
+ this->size_ = 4;
+ this->align_ = 4;
+ break;
+ case RC_THM16:
+ this->size_ = 2;
+ this->align_ = 2;
+ break;
+ case RC_THM32:
+ this->size_ = 4;
+ this->align_ = 2;
+ break;
+ default:
+ gold_unreachable();
+ }
+ }
+ else if (rtype == RT_DYNAMIC)
+ {
+ // With the exception of R_ARM_COPY, all dynamic relocations requires
+ // that the place being relocated is a word-aligned 32-bit object.
+ if (code != elfcpp::R_ARM_COPY)
+ {
+ this->size_ = 4;
+ this->align_ = 4;
+ }
+ }
+
+ // If no relocation operation is specified, we are done.
+ if (operation == "NONE")
+ return;
+
+ // Extract information from relocation operation.
+ Tree_node* root_node = Tree_node::make_tree(operation);
+ Tree_node* node = root_node;
+
+ // Check for an expression of the form XXX - YYY.
+ if (!node->is_leaf()
+ && node->child(0)->is_leaf()
+ && node->child(0)->name() == "-")
+ {
+ struct RAB_table_entry
+ {
+ Relative_address_base rab;
+ const char* name;
+ };
+
+ static const RAB_table_entry rab_table[] =
+ {
+ { RAB_B_S, "( B S )" },
+ { RAB_DELTA_B_S, "( DELTA_B ( S ) )" },
+ { RAB_GOT_ORG, "GOT_ORG" },
+ { RAB_P, "P" },
+ { RAB_Pa, "Pa" },
+ { RAB_TLS, "TLS" },
+ { RAB_tp, "tp" }
+ };
+
+ static size_t rab_table_size = sizeof(rab_table) / sizeof(rab_table[0]);
+ const std::string rhs(node->child(2)->s_expression());
+ for (size_t i = 0; i < rab_table_size; ++i)
+ if (rhs == rab_table[i].name)
+ {
+ this->relative_address_base_ = rab_table[i].rab;
+ break;
+ }
+
+ gold_assert(this->relative_address_base_ != RAB_NONE);
+ if (this->relative_address_base_ == RAB_B_S)
+ this->uses_symbol_base_ = true;
+ node = node->child(1);
+ }
+
+ // Check for an expression of the form XXX | T.
+ if (!node->is_leaf()
+ && node->child(0)->is_leaf()
+ && node->child(0)->name() == "|")
+ {
+ gold_assert(node->number_of_children() == 3
+ && node->child(2)->is_leaf()
+ && node->child(2)->name() == "T");
+ this->uses_thumb_bit_ = true;
+ node = node->child(1);
+ }
+
+ // Check for an expression of the form XXX + A.
+ if (!node->is_leaf()
+ && node->child(0)->is_leaf()
+ && node->child(0)->name() == "+")
+ {
+ gold_assert(node->number_of_children() == 3
+ && node->child(2)->is_leaf()
+ && node->child(2)->name() == "A");
+ this->uses_addend_ = true;
+ node = node->child(1);
+ }
+
+ // Check for an expression of the form XXX(S).
+ if (!node->is_leaf() && node->child(0)->is_leaf())
+ {
+ gold_assert(node->number_of_children() == 2
+ && node->child(1)->is_leaf()
+ && node->child(1)->name() == "S");
+ const std::string func(node->child(0)->name());
+ if (func == "B")
+ this->uses_symbol_base_ = true;
+ else if (func == "GOT")
+ this->uses_got_entry_ = true;
+ else if (func == "PLT")
+ this->uses_plt_entry_ = true;
+ else if (func == "Module" || func == "DELTA_B")
+ // These are used in dynamic relocations.
+ ;
+ else
+ gold_unreachable();
+ node = node->child(1);
+ }
+
+ gold_assert(node->is_leaf() && node->name() == "S");
+
+ delete root_node;
+}
+
+// Arm_reloc_property_table methods.
+
+// Constructor. This processing informations in arm-reloc.def to
+// initialize the table.
+
+Arm_reloc_property_table::Arm_reloc_property_table()
+{
+ // These appers in arm-reloc.def. Do not rename them.
+ Parse_expression A("A"), GOT_ORG("GOT_ORG"), NONE("NONE"), P("P"),
+ Pa("Pa"), S("S"), T("T"), TLS("TLS"), tp("tp");
+ const bool Y(true), N(false);
+
+ for (unsigned int i = 0; i < Property_table_size; ++i)
+ this->table_[i] = NULL;
+
+#undef RD
+#define RD(name, type, deprecated, class, operation, is_implemented, \
+ group_index, checks_oveflow) \
+ do \
+ { \
+ unsigned int code = elfcpp::R_ARM_##name; \
+ gold_assert(code < Property_table_size); \
+ this->table_[code] = \
+ new Arm_reloc_property(elfcpp::R_ARM_##name, "R_ARM_" #name, \
+ Arm_reloc_property::RT_##type, deprecated, \
+ Arm_reloc_property::RC_##class, \
+ (operation).s_expression(), is_implemented, \
+ group_index, checks_oveflow); \
+ } \
+ while(0);
+
+#include "arm-reloc.def"
+#undef RD
+}
+
+} // End namespace gold.
diff --git a/gold/arm-reloc-property.h b/gold/arm-reloc-property.h
new file mode 100644
index 0000000..2d88211
--- /dev/null
+++ b/gold/arm-reloc-property.h
@@ -0,0 +1,360 @@
+// arm-reloc-property.h -- ARM relocation properties -*- C++ -*-
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@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_ARM_RELOC_PROPERTY_H
+#define GOLD_ARM_RELOC_PROPERTY_H
+
+namespace gold
+{
+// The Arm_reloc_property class is to store information about a paticular
+// relocation code.
+
+class Arm_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.
+ RT_PRIVATE, // Private relocations, not supported by gold.
+ RT_OBSOLETE // Obsolete relocations that should not be used.
+ };
+
+ // Classes of relocation codes.
+ enum Reloc_class {
+ RC_NONE, // No relocation class.
+ RC_DATA, // Data relocation.
+ RC_ARM, // ARM instruction relocation.
+ RC_THM16, // 16-bit THUMB instruction relocation.
+ RC_THM32, // 32-bit THUMB instruction relocation.
+ RC_MISC // Miscellaneous class.
+ };
+
+ // Types of bases of relative addressing relocation codes.
+ enum Relative_address_base {
+ RAB_NONE, // Relocation is not relative addressing
+ RAB_B_S, // Address origin of output segment of defining symbol.
+ RAB_DELTA_B_S, // Change of address origin.
+ RAB_GOT_ORG, // Origin of GOT.
+ RAB_P, // Address of the place being relocated.
+ RAB_Pa, // Adjusted address (P & 0xfffffffc).
+ RAB_TLS, // Thread local storage.
+ RAB_tp // Thread pointer.
+ };
+
+ // 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_; }
+
+ // Whether this code is deprecated.
+ bool
+ is_deprecated() const
+ { return this->is_deprecated_; }
+
+ // 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_; }
+
+ // Whether relocation checks for overflow.
+ bool
+ checks_overflow() const
+ { return this->checks_overflow_; }
+
+ // Return size of relocation.
+ size_t
+ size() const
+ { return this->size_; }
+
+ // Return alignment of relocation.
+ size_t
+ align() const
+ { return this->align_; }
+
+ // Whether relocation use a GOT entry.
+ bool
+ uses_got_entry() const
+ { return this->uses_got_entry_; }
+
+ // Whether relocation use a GOT origin.
+ bool
+ uses_got_origin() const
+ { return this->uses_got_origin_; }
+
+ // Whether relocation uses the Thumb-bit in a symbol address.
+ bool
+ uses_thumb_bit() const
+ { return this->uses_thumb_bit_; }
+
+ // Whether relocation uses the symbol base.
+ bool
+ uses_symbol_base() const
+ { return this->uses_symbol_base_; }
+
+ // Return the type of relative address base or RAB_NONE if this
+ // is not a relative addressing relocation.
+ Relative_address_base
+ relative_address_base() const
+ { return this->relative_address_base_; }
+
+ protected:
+ // These are protected. We only allow Arm_reloc_property_table to
+ // manage Arm_reloc_property.
+ Arm_reloc_property(unsigned int code, const char* name, Reloc_type rtype,
+ bool is_deprecated, Reloc_class rclass,
+ const std::string& operation, bool is_implemented,
+ int group_index, bool checks_overflow);
+
+ friend class Arm_reloc_property_table;
+
+ private:
+ // Copying is not allowed.
+ Arm_reloc_property(const Arm_reloc_property&);
+ Arm_reloc_property& operator=(const Arm_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.
+ unsigned int code_;
+ // Relocation name.
+ 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;
+ // Whether this uses a GOT entry.
+ bool uses_got_entry_ : 1;
+ // Whether this uses a GOT origin.
+ bool uses_got_origin_ : 1;
+ // Whether this uses a PLT entry.
+ bool uses_plt_entry_ : 1;
+ // Whether this uses the THUMB bit in symbol address.
+ bool uses_thumb_bit_ : 1;
+ // Whether this uses the symbol base.
+ bool uses_symbol_base_ : 1;
+ // Whether this uses an addend.
+ bool uses_addend_ : 1;
+};
+
+// Arm_reloc_property_table. This table is used for looking up propeties
+// of relocationt types. The table entries are initialized using information
+// from arm-reloc.def.
+
+class Arm_reloc_property_table
+{
+ public:
+ Arm_reloc_property_table();
+
+ // Return an Arm_reloc_property object for CODE if it is a valid relocation
+ // code or NULL otherwise.
+ const Arm_reloc_property*
+ get_reloc_property(unsigned int code) const
+ {
+ gold_assert(code < Property_table_size);
+ return this->table_[code];
+ }
+
+ private:
+ // Copying is not allowed.
+ Arm_reloc_property_table(const Arm_reloc_property_table&);
+ Arm_reloc_property_table& operator=(const Arm_reloc_property_table&);
+
+ // The Parse_expression class is used to convert relocation operations in
+ // arm-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. Coversion 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(-)
+ DEF_OPERATOR_OVERLOAD(|)
+
+ private:
+ // This represented as an S-expression string.
+ std::string s_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(B)
+ DEF_RELOC_FUNC(DELTA_B)
+ DEF_RELOC_FUNC(GOT)
+ DEF_RELOC_FUNC(Module)
+ DEF_RELOC_FUNC(PLT)
+
+ static const unsigned int Property_table_size = 256;
+
+ // The property table.
+ Arm_reloc_property* table_[Property_table_size];
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_ARM_RELOC_PROPERTY_H)
diff --git a/gold/arm-reloc.def b/gold/arm-reloc.def
new file mode 100644
index 0000000..6228839
--- /dev/null
+++ b/gold/arm-reloc.def
@@ -0,0 +1,194 @@
+// arm-reloc.def -- ARM relocation definitions.
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Doug Kwan <dougkwan@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.
+
+// The information here is based on the official ARM document "ELF for ARM
+// Architecture" (Document number ARM IHI 0044C). The first five columns of
+// the table below are derived from Table 4-8 in the ARM ELF document. Each
+// relocation from Table 4-8 corresponds to one relocation definition in the
+// table below. A relocation defintion has the following information:
+//
+// Name: This is the name of the relocation without the "R_ARM_" prefix.
+//
+// Type: Relocation type. There are four.
+// - STATIC for static relocations processed by a static linker.
+// - DYNAMIC for dynamic relocations processed by a dynamic linker.
+// - PRIVATE for R_ARM_PRIVATE_<n> private relocation type.
+// - OBSOLETE for old relocation types no longer used.
+// We do not use DEPRECATED as a distinct type since we still have to
+// handle deprecated relocations so we one of the types above.
+//
+// Deprecated: Whether this is a deprecated relocation type. The linker
+// is expected to handle these though they should not be generated by fully
+// conforming tool-chains.
+//
+// Operation: An expression specifying how the linker should performace a
+// relocation. If there is no operation or the operation cannot be
+// specified, it is "NONE".
+//
+// Implemented: Whether this is implemented by the gold.
+//
+// Group_index: For a group relocation type, it is one of 0, 1 or 2. For
+// a non-group relocation type, it is -1.
+//
+// Overflow: Whether gold should check for overflow. This is "No" by default
+// for relocation types DYNAMIC, PRIVATE and OBSOLETE.
+//
+// Overflow-----------------------------------------------------------------+
+// Group index----------------------------------------------------------+ |
+// Implemented-------------------------------------------------------+ | |
+// Operation-------------------------------+ | | |
+// Class----------------------------+ | | | |
+// Deprecated--------------------+ | | | | |
+// Type----------------+ | | | | | |
+// Name | | | | | | |
+// | | | | | | | |
+RD(NONE , STATIC , N, MISC , NONE , Y, -1, N)
+RD(PC24 , STATIC , Y, ARM , ((S + A) | T) - P , Y, -1, Y)
+RD(ABS32 , STATIC , N, DATA , (S + A) | T , Y, -1, N)
+RD(REL32 , STATIC , N, DATA , ((S + A) | T) - P , Y, -1, N)
+RD(LDR_PC_G0 , STATIC , N, ARM , S + A - P , Y, 0, Y)
+RD(ABS16 , STATIC , N, DATA , S + A , Y, -1, Y)
+RD(ABS12 , STATIC , N, ARM , S + A , Y, -1, Y)
+RD(THM_ABS5 , STATIC , N, THM16, S + A , Y, -1, Y)
+RD(ABS8 , STATIC , N, DATA , S + A , Y, -1, Y)
+RD(SBREL32 , STATIC , N, DATA , ((S + A) | T) - B(S) , N, -1, N)
+RD(THM_CALL , STATIC , N, THM32, ((S + A) | T) - P , Y, -1, Y)
+RD(THM_PC8 , STATIC , N, THM16, S + A - Pa , Y, -1, Y)
+RD(BREL_ADJ , DYNAMIC , N, DATA , DELTA_B(S) + A , Y, -1, N)
+RD(TLS_DESC , DYNAMIC , N, DATA , NONE , Y, -1, N)
+RD(THM_SWI8 , OBSOLETE, N, NONE , NONE , N, -1, N)
+RD(XPC25 , OBSOLETE, N, NONE , NONE , N, -1, N)
+RD(THM_XPC22 , OBSOLETE, N, NONE , NONE , N, -1, N)
+RD(TLS_DTPMOD32 , DYNAMIC , N, DATA , Module(S) , Y, -1, N)
+RD(TLS_DTPOFF32 , DYNAMIC , N, DATA , S + A - TLS , Y, -1, N)
+RD(TLS_TPOFF32 , DYNAMIC , N, DATA , S + A - tp , Y, -1, N)
+RD(COPY , DYNAMIC , N, MISC , NONE , Y, -1, N)
+RD(GLOB_DAT , DYNAMIC , N, DATA , (S + A) | T , Y, -1, N)
+RD(JUMP_SLOT , DYNAMIC , N, DATA , (S + A) | T , Y, -1, N)
+RD(RELATIVE , DYNAMIC , N, DATA , B(S) + A , Y, -1, N)
+RD(GOTOFF32 , STATIC , N, DATA , ((S + A) | T) - GOT_ORG, Y, -1, N)
+RD(BASE_PREL , STATIC , N, DATA , B(S) + A - P , Y, -1, N)
+RD(GOT_BREL , STATIC , N, DATA , GOT(S) + A - GOT_ORG , Y, -1, N)
+RD(PLT32 , STATIC , Y, ARM , ((S + A) | T) - P , Y, -1, Y)
+RD(CALL , STATIC , N, ARM , ((S + A) | T) - P , Y, -1, Y)
+RD(JUMP24 , STATIC , N, ARM , ((S + A) | T) - P , Y, -1, Y)
+RD(THM_JUMP24 , STATIC , N, THM32, ((S + A) | T) - P , Y, -1, Y)
+RD(BASE_ABS , STATIC , N, DATA , B(S) + A , Y, -1, N)
+RD(ALU_PCREL_7_0 , OBSOLETE, N, NONE , NONE , N, -1, N)
+RD(ALU_PCREL_15_8 , OBSOLETE, N, NONE , NONE , N, -1, N)
+RD(ALU_PCREL_23_15 , OBSOLETE, N, NONE , NONE , N, -1, N)
+RD(LDR_SBREL_11_0_NC , STATIC , Y, ARM , S + A - B(S) , N, -1, N)
+RD(ALU_SBREL_19_12_NC, STATIC , Y, ARM , S + A - B(S) , N, -1, N)
+RD(ALU_SBREL_27_20_CK, STATIC , Y, ARM , S + A - B(S) , N, -1, Y)
+RD(TARGET1 , STATIC , N, MISC , NONE , Y, -1, N)
+RD(SBREL31 , STATIC , Y, DATA , ((S + A) | T) - B(S) , N, -1, N)
+RD(V4BX , STATIC , N, MISC , NONE , Y, -1, N)
+RD(TARGET2 , STATIC , N, MISC , NONE , Y, -1, N)
+RD(PREL31 , STATIC , N, DATA , ((S + A) | T) - P , Y, -1, Y)
+RD(MOVW_ABS_NC , STATIC , N, ARM , (S + A) | T , Y, -1, N)
+RD(MOVT_ABS , STATIC , N, ARM , S + A , Y, -1, Y)
+RD(MOVW_PREL_NC , STATIC , N, ARM , ((S + A) | T) - P , Y, -1, N)
+RD(MOVT_PREL , STATIC , N, ARM , (S + A) - P , Y, -1, Y)
+RD(THM_MOVW_ABS_NC , STATIC , N, THM32, (S + A) | T , Y, -1, N)
+RD(THM_MOVT_ABS , STATIC , N, THM32, S + A , Y, -1, Y)
+RD(THM_MOVW_PREL_NC , STATIC , N, THM32, ((S + A) | T) - P , Y, -1, N)
+RD(THM_MOVT_PREL , STATIC , N, THM32, S + A - P , Y, -1, Y)
+RD(THM_JUMP19 , STATIC , N, THM32, ((S + A) | T) - P , Y, -1, Y)
+RD(THM_JUMP6 , STATIC , N, THM16, S + A - P , Y, -1, Y)
+RD(THM_ALU_PREL_11_0 , STATIC , N, THM32, ((S + A) | T) - Pa , Y, -1, Y)
+RD(THM_PC12 , STATIC , N, THM32, S + A - Pa , Y, -1, Y)
+RD(ABS32_NOI , STATIC , N, DATA , S + A , Y, -1, N)
+RD(REL32_NOI , STATIC , N, DATA , S + A - P , N, -1, N)
+RD(ALU_PC_G0_NC , STATIC , N, ARM , ((S + A) | T) - P , Y, 0, N)
+RD(ALU_PC_G0 , STATIC , N, ARM , ((S + A) | T) - P , Y, 0, Y)
+RD(ALU_PC_G1_NC , STATIC , N, ARM , ((S + A) | T) - P , Y, 1, N)
+RD(ALU_PC_G1 , STATIC , N, ARM , ((S + A) | T) - P , Y, 1, Y)
+RD(ALU_PC_G2 , STATIC , N, ARM , ((S + A) | T) - P , Y, 2, Y)
+RD(LDR_PC_G1 , STATIC , N, ARM , S + A - P , Y, 1, Y)
+RD(LDR_PC_G2 , STATIC , N, ARM , S + A - P , Y, 2, Y)
+RD(LDRS_PC_G0 , STATIC , N, ARM , S + A - P , Y, 0, Y)
+RD(LDRS_PC_G1 , STATIC , N, ARM , S + A - P , Y, 1, Y)
+RD(LDRS_PC_G2 , STATIC , N, ARM , S + A - P , Y, 2, Y)
+RD(LDC_PC_G0 , STATIC , N, ARM , S + A - P , Y, 0, Y)
+RD(LDC_PC_G1 , STATIC , N, ARM , S + A - P , Y, 1, Y)
+RD(LDC_PC_G2 , STATIC , N, ARM , S + A - P , Y, 2, Y)
+RD(ALU_SB_G0_NC , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, 0, N)
+RD(ALU_SB_G0 , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, 0, Y)
+RD(ALU_SB_G1_NC , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, 1, N)
+RD(ALU_SB_G1 , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, 1, Y)
+RD(ALU_SB_G2 , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, 2, Y)
+RD(LDR_SB_G0 , STATIC , N, ARM , S + A - B(S) , Y, 0, Y)
+RD(LDR_SB_G1 , STATIC , N, ARM , S + A - B(S) , Y, 1, Y)
+RD(LDR_SB_G2 , STATIC , N, ARM , S + A - B(S) , Y, 2, Y)
+RD(LDRS_SB_G0 , STATIC , N, ARM , S + A - B(S) , Y, 0, Y)
+RD(LDRS_SB_G1 , STATIC , N, ARM , S + A - B(S) , Y, 1, Y)
+RD(LDRS_SB_G2 , STATIC , N, ARM , S + A - B(S) , Y, 2, Y)
+RD(LDC_SB_G0 , STATIC , N, ARM , S + A - B(S) , Y, 0, Y)
+RD(LDC_SB_G1 , STATIC , N, ARM , S + A - B(S) , Y, 1, Y)
+RD(LDC_SB_G2 , STATIC , N, ARM , S + A - B(S) , Y, 2, Y)
+RD(MOVW_BREL_NC , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, -1, N)
+RD(MOVT_BREL , STATIC , N, ARM , S + A - B(S) , Y, -1, Y)
+RD(MOVW_BREL , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, -1, Y)
+RD(THM_MOVW_BREL_NC , STATIC , N, THM32, ((S + A) | T) - B(S) , Y, -1, N)
+RD(THM_MOVT_BREL , STATIC , N, THM32, S + A - B(S) , Y, -1, Y)
+RD(THM_MOVW_BREL , STATIC , N, THM32, ((S + A) | T) - B(S) , Y, -1, Y)
+RD(TLS_GOTDESC , STATIC , N, DATA , NONE , Y, -1, N)
+RD(TLS_CALL , STATIC , N, ARM , NONE , N, -1, Y)
+RD(TLS_DESCSEQ , STATIC , N, ARM , NONE , N, -1, Y)
+RD(THM_TLS_CALL , STATIC , N, THM32, NONE , N, -1, Y)
+RD(PLT32_ABS , STATIC , N, DATA , PLT(S) + A , N, -1, N)
+RD(GOT_ABS , STATIC , N, DATA , GOT(S) + A , N, -1, N)
+RD(GOT_PREL , STATIC , N, DATA , GOT(S) + A - P , N, -1, N)
+RD(GOT_BREL12 , STATIC , N, ARM , GOT(S) + A - GOT_ORG , N, -1, Y)
+RD(GOTOFF12 , STATIC , N, ARM , S + A - GOT_ORG , N, -1, Y)
+RD(GOTRELAX , STATIC , N, MISC , NONE , N, -1, N)
+RD(GNU_VTENTRY , STATIC , Y, DATA , NONE , Y, -1, N)
+RD(GNU_VTINHERIT , STATIC , Y, DATA , NONE , Y, -1, N)
+RD(THM_JUMP11 , STATIC , N, THM16, S + A - P , Y, -1, Y)
+RD(THM_JUMP8 , STATIC , N, THM16, S + A - P , Y, -1, Y)
+RD(TLS_GD32 , STATIC , N, DATA , GOT(S) + A - P , N, -1, N)
+RD(TLS_LDM32 , STATIC , N, DATA , GOT(S) + A - P , N, -1, N)
+RD(TLS_LDO32 , STATIC , N, DATA , S + A - TLS , N, -1, N)
+RD(TLS_IE32 , STATIC , N, DATA , GOT(S) + A - P , N, -1, N)
+RD(TLS_LE32 , STATIC , N, DATA , S + A - tp , N, -1, N)
+RD(TLS_LDO12 , STATIC , N, ARM , S + A - TLS , N, -1, Y)
+RD(TLS_LE12 , STATIC , N, ARM , S + A - tp , N, -1, Y)
+RD(TLS_IE12GP , STATIC , N, ARM , GOT(S) + A - GOT_ORG , N, -1, Y)
+RD(PRIVATE_0 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_1 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_2 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_3 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_4 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_5 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_6 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_7 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_8 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_9 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_10 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_11 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_12 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_13 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_14 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(PRIVATE_15 , PRIVATE , N, NONE , NONE , N, -1, N)
+RD(ME_TOO , OBSOLETE, N, NONE , NONE , N, -1, N)
+RD(THM_TLS_DESCSEQ16 , STATIC , N, THM16, NONE , N, -1, Y)
+RD(THM_TLS_DESCSEQ32 , STATIC , N, THM32, NONE , N, -1, Y)
diff --git a/gold/arm.cc b/gold/arm.cc
index 89a4149..b421a7f 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -50,6 +50,7 @@
#include "defstd.h"
#include "gc.h"
#include "attributes.h"
+#include "arm-reloc-property.h"
namespace
{
@@ -99,30 +100,25 @@ const int32_t THM2_MAX_BWD_BRANCH_OFFSET = (-(1 << 24) + 4);
// supporting Android only for the time being.
//
// TODOs:
-// - Support the following relocation types as needed:
-// R_ARM_SBREL32
-// R_ARM_LDR_SBREL_11_0_NC
-// R_ARM_ALU_SBREL_19_12_NC
-// R_ARM_ALU_SBREL_27_20_CK
-// R_ARM_SBREL31
-// R_ARM_REL32_NOI
-// R_ARM_PLT32_ABS
-// R_ARM_GOT_ABS
-// R_ARM_GOT_BREL12
-// R_ARM_GOTOFF12
-// R_ARM_TLS_GD32
-// R_ARM_TLS_LDM32
-// R_ARM_TLS_LDO32
-// R_ARM_TLS_IE32
-// R_ARM_TLS_LE32
-// R_ARM_TLS_LDO12
-// R_ARM_TLS_LE12
-// R_ARM_TLS_IE12GP
-//
+// - Implement all static relocation types documented in arm-reloc.def.
// - Make PLTs more flexible for different architecture features like
// Thumb-2 and BE8.
// There are probably a lot more.
+// Ideally we would like to avoid using global variables but this is used
+// very in many places and sometimes in loops. If we use a function
+// returning a static instance of Arm_reloc_property_table, it will very
+// slow in an threaded environment since the static instance needs to be
+// locked. The pointer is below initialized in the
+// Target::do_select_as_default_target() hook so that we do not spend time
+// building the table if we are not linking ARM objects.
+//
+// An alternative is to to process the information in arm-reloc.def in
+// compilation time and generate a representation of it in PODs only. That
+// way we can avoid initialization when the linker starts.
+
+Arm_reloc_property_table *arm_reloc_property_table = NULL;
+
// Instruction template class. This class is similar to the insn_sequence
// struct in bfd/elf32-arm.c.
@@ -2133,6 +2129,17 @@ class Target_arm : public Sized_target<32, big_endian>
int
do_attributes_order(int num) const;
+ // This is called when the target is selected as the default.
+ void
+ do_select_as_default_target()
+ {
+ // No locking is required since there should only be one default target.
+ // We cannot have both the big-endian and little-endian ARM targets
+ // as the default.
+ gold_assert(arm_reloc_property_table == NULL);
+ arm_reloc_property_table = new Arm_reloc_property_table();
+ }
+
private:
// The class which scans relocations.
class Scan
diff --git a/gold/configure.tgt b/gold/configure.tgt
index de6d4f9..0f3b1c3 100644
--- a/gold/configure.tgt
+++ b/gold/configure.tgt
@@ -106,6 +106,7 @@ powerpc64-*)
;;
armeb*-*-*|armbe*-*-*)
targ_obj=arm
+ targ_extra_obj=arm-reloc-property
targ_machine=EM_ARM
targ_size=32
targ_big_endian=true
@@ -113,6 +114,7 @@ armeb*-*-*|armbe*-*-*)
;;
arm*-*-*)
targ_obj=arm
+ targ_extra_obj=arm-reloc-property
targ_machine=EM_ARM
targ_size=32
targ_big_endian=false
diff --git a/gold/parameters.cc b/gold/parameters.cc
index 2a53998..9cf7808 100644
--- a/gold/parameters.cc
+++ b/gold/parameters.cc
@@ -141,7 +141,10 @@ set_parameters_options(const General_options* options)
void
set_parameters_target(Target* target)
-{ static_parameters.set_target(target); }
+{
+ static_parameters.set_target(target);
+ target->select_as_default_target();
+}
void
set_parameters_doing_static_link(bool doing_static_link)
diff --git a/gold/target.h b/gold/target.h
index 88cc973..20de7a4 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -325,6 +325,12 @@ class Target
attributes_order(int num) const
{ return this->do_attributes_order(num); }
+ // When a target is selected as the default target, we call this method,
+ // which may be used for expensive, target-specific initialization.
+ void
+ select_as_default_target()
+ { this->do_select_as_default_target(); }
+
protected:
// This struct holds the constant information for a child class. We
// use a struct to avoid the overhead of virtual function calls for
@@ -510,6 +516,11 @@ class Target
do_attributes_order(int num) const
{ return num; }
+ // This may be overridden by the child class.
+ virtual void
+ do_select_as_default_target()
+ { }
+
private:
// The implementations of the four do_make_elf_object virtual functions are
// almost identical except for their sizes and endianity. We use a template.