diff options
-rw-r--r-- | gold/ChangeLog | 22 | ||||
-rw-r--r-- | gold/Makefile.am | 9 | ||||
-rw-r--r-- | gold/Makefile.in | 11 | ||||
-rw-r--r-- | gold/arm-reloc-property.cc | 287 | ||||
-rw-r--r-- | gold/arm-reloc-property.h | 360 | ||||
-rw-r--r-- | gold/arm-reloc.def | 194 | ||||
-rw-r--r-- | gold/arm.cc | 47 | ||||
-rw-r--r-- | gold/configure.tgt | 2 | ||||
-rw-r--r-- | gold/parameters.cc | 5 | ||||
-rw-r--r-- | gold/target.h | 11 |
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. |