X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Farm.cc;h=70e27892df4778736121901d99de9284c4c0954a;hb=5da151d470a6c99ae6cbd5efa01f2a3b97261e59;hp=123f896e9d33c7451fe6c15088a1a669264d7090;hpb=0e70b9111a696f5b70cade541df55de14c31f9f1;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/arm.cc b/gold/arm.cc index 123f896e9d..70e27892df 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -1,6 +1,6 @@ // arm.cc -- arm target support for gold. -// Copyright 2009, 2010 Free Software Foundation, Inc. +// Copyright (C) 2009-2014 Free Software Foundation, Inc. // Written by Doug Kwan based on the i386 code // by Ian Lance Taylor . // This file also contains borrowed and adapted code from @@ -51,6 +51,7 @@ #include "gc.h" #include "attributes.h" #include "arm-reloc-property.h" +#include "nacl.h" namespace { @@ -60,6 +61,9 @@ using namespace gold; template class Output_data_plt_arm; +template +class Output_data_plt_arm_standard; + template class Stub_table; @@ -107,7 +111,7 @@ const size_t ARM_TCB_SIZE = 8; // // This is a very simple port of gold for ARM-EABI. It is intended for // supporting Android only for the time being. -// +// // TODOs: // - Implement all static relocation types documented in arm-reloc.def. // - Make PLTs more flexible for different architecture features like @@ -116,7 +120,7 @@ const size_t ARM_TCB_SIZE = 8; // 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 +// returning a static instance of Arm_reloc_property_table, it will be 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 @@ -126,7 +130,7 @@ const size_t ARM_TCB_SIZE = 8; // 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; +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. @@ -138,7 +142,7 @@ class Insn_template enum Type { THUMB16_TYPE = 1, - // THUMB16_SPECIAL_TYPE is used by sub-classes of Stub for instruction + // THUMB16_SPECIAL_TYPE is used by sub-classes of Stub for instruction // templates with class-specific semantics. Currently this is used // only by the Cortex_a8_stub class for handling condition codes in // conditional branches. @@ -152,24 +156,24 @@ class Insn_template static const Insn_template thumb16_insn(uint32_t data) - { return Insn_template(data, THUMB16_TYPE, elfcpp::R_ARM_NONE, 0); } + { return Insn_template(data, THUMB16_TYPE, elfcpp::R_ARM_NONE, 0); } // A Thumb conditional branch, in which the proper condition is inserted // when we build the stub. static const Insn_template thumb16_bcond_insn(uint32_t data) - { return Insn_template(data, THUMB16_SPECIAL_TYPE, elfcpp::R_ARM_NONE, 1); } + { return Insn_template(data, THUMB16_SPECIAL_TYPE, elfcpp::R_ARM_NONE, 1); } static const Insn_template thumb32_insn(uint32_t data) - { return Insn_template(data, THUMB32_TYPE, elfcpp::R_ARM_NONE, 0); } + { return Insn_template(data, THUMB32_TYPE, elfcpp::R_ARM_NONE, 0); } static const Insn_template thumb32_b_insn(uint32_t data, int reloc_addend) { return Insn_template(data, THUMB32_TYPE, elfcpp::R_ARM_THM_JUMP24, reloc_addend); - } + } static const Insn_template arm_insn(uint32_t data) @@ -181,7 +185,7 @@ class Insn_template static const Insn_template data_word(unsigned data, unsigned int r_type, int reloc_addend) - { return Insn_template(data, DATA_TYPE, r_type, reloc_addend); } + { return Insn_template(data, DATA_TYPE, r_type, reloc_addend); } // Accessors. This class is used for read-only objects so no modifiers // are provided. @@ -270,7 +274,7 @@ typedef enum arm_stub_cortex_a8_first = arm_stub_a8_veneer_b_cond, // Last Cortex-A8 stub type. arm_stub_cortex_a8_last = arm_stub_a8_veneer_blx, - + // Last stub type. arm_stub_type_last = arm_stub_v4_veneer_bx } Stub_type; @@ -312,7 +316,7 @@ class Stub_template unsigned alignment() const { return this->alignment_; } - + // Return whether entry point is in thumb mode. bool entry_in_thumb_mode() const @@ -349,7 +353,7 @@ class Stub_template // as possible. Stub_template(const Stub_template&); Stub_template& operator=(const Stub_template&); - + // Stub type. Stub_type type_; // Points to an array of Insn_templates. @@ -364,7 +368,7 @@ class Stub_template bool entry_in_thumb_mode_; // A table of reloc instruction indices and offsets. We can find these by // looking at the instruction templates but we pre-compute and then stash - // them here for speed. + // them here for speed. std::vector relocs_; }; @@ -405,7 +409,7 @@ class Stub void set_offset(section_offset_type offset) { this->offset_ = offset; } - + // Return the relocation target address of the i-th relocation in the // stub. This must be defined in a child class. Arm_address @@ -437,7 +441,7 @@ class Stub else this->do_fixed_endian_write(view, view_size); } - + // This must be overridden if a child class uses the THUMB16_SPECIAL_TYPE // instruction template. virtual uint16_t @@ -550,7 +554,7 @@ class Reloc_stub : public Stub // Whether this equals to another key k. bool - eq(const Key& k) const + eq(const Key& k) const { return ((this->stub_type_ == k.stub_type_) && (this->r_sym_ == k.r_sym_) @@ -598,10 +602,10 @@ class Reloc_stub : public Stub // If this is a local symbol, this is the index in the defining object. // Otherwise, it is invalid_index for a global symbol. unsigned int r_sym_; - // If r_sym_ is invalid index. This points to a global symbol. - // Otherwise, this points a relobj. We used the unsized and target - // independent Symbol and Relobj classes instead of Sized_symbol<32> and - // Arm_relobj. This is done to avoid making the stub class a template + // If r_sym_ is an invalid index, this points to a global symbol. + // Otherwise, it points to a relobj. We used the unsized and target + // independent Symbol and Relobj classes instead of Sized_symbol<32> and + // Arm_relobj, in order to avoid making the stub class a template // as most of the stub machinery is endianness-neutral. However, it // may require a bit of casting done by users of this class. union @@ -641,7 +645,7 @@ class Reloc_stub : public Stub // Cortex-A8 stub class. We need a Cortex-A8 stub to redirect any 32-bit // THUMB branch that meets the following conditions: -// +// // 1. The branch straddles across a page boundary. i.e. lower 12-bit of // branch address is 0xffe. // 2. The branch target address is in the same page as the first word of the @@ -715,15 +719,15 @@ class Cortex_a8_stub : public Stub { if (this->stub_template()->type() == arm_stub_a8_veneer_b_cond) { - // The conditional branch veneer has two relocations. - gold_assert(i < 2); + // The conditional branch veneer has two relocations. + gold_assert(i < 2); return i == 0 ? this->source_address_ + 4 : this->destination_address_; } else { - // All other Cortex-A8 stubs have only one relocation. - gold_assert(i == 0); - return this->destination_address_; + // All other Cortex-A8 stubs have only one relocation. + gold_assert(i == 0); + return this->destination_address_; } } @@ -850,13 +854,13 @@ class Stub_factory private: // Constructor and destructor are protected since we only return a single // instance created in Stub_factory::get_instance(). - + Stub_factory(); // A Stub_factory may not be copied since it is a singleton. Stub_factory(const Stub_factory&); Stub_factory& operator=(Stub_factory&); - + // Stub templates. These are initialized in the constructor. const Stub_template* stub_templates_[arm_stub_type_last+1]; }; @@ -895,8 +899,8 @@ class Stub_table : public Output_data current_data_size() const { return this->current_data_size_for_child(); } - // Add a STUB with using KEY. Caller is reponsible for avoid adding - // if already a STUB with the same key has been added. + // Add a STUB using KEY. The caller is responsible for avoiding addition + // if a STUB with the same key has already been added. void add_reloc_stub(Reloc_stub* stub, const Reloc_stub::Key& key) { @@ -915,8 +919,8 @@ class Stub_table : public Output_data } // Add a Cortex-A8 STUB that fixes up a THUMB branch at ADDRESS. - // Caller is reponsible for avoid adding if already a STUB with the same - // address has been added. + // The caller is responsible for avoiding addition if a STUB with the same + // address has already been added. void add_cortex_a8_stub(Arm_address address, Cortex_a8_stub* stub) { @@ -970,7 +974,7 @@ class Stub_table : public Output_data // needing the Cortex-A8 workaround. void finalize_stubs(); - + // Apply Cortex-A8 workaround to an address range. void apply_cortex_a8_workaround_to_address_range(Target_arm*, @@ -981,7 +985,7 @@ class Stub_table : public Output_data // Write out section contents. void do_write(Output_file*); - + // Return the required alignment. uint64_t do_addralign() const @@ -996,7 +1000,7 @@ class Stub_table : public Output_data void set_final_data_size() { this->set_data_size(this->current_data_size()); } - + private: // Relocate one stub. void @@ -1064,12 +1068,17 @@ class Arm_exidx_cantunwind : public Output_section_data this->do_fixed_endian_write(of); } + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** ARM cantunwind")); } + private: // Implement do_write for a given endianness. template void inline do_fixed_endian_write(Output_file*); - + // The object containing the section pointed by this. Relobj* relobj_; // The section index of the section pointed by this. @@ -1078,7 +1087,7 @@ class Arm_exidx_cantunwind : public Output_section_data // During EXIDX coverage fix-up, we compact an EXIDX section. The // Offset map is used to map input section offset within the EXIDX section -// to the output offset from the start of this EXIDX section. +// to the output offset from the start of this EXIDX section. typedef std::map Arm_exidx_section_offset_map; @@ -1099,6 +1108,10 @@ class Arm_exidx_merged_section : public Output_relaxed_input_section const Arm_exidx_section_offset_map& section_offset_map, uint32_t deleted_bytes); + // Build output contents. + void + build_contents(const unsigned char*, section_size_type); + // Return the original EXIDX input section. const Arm_exidx_input_section& exidx_input_section() const @@ -1123,6 +1136,10 @@ class Arm_exidx_merged_section : public Output_relaxed_input_section const Arm_exidx_input_section& exidx_input_section_; // Section offset map. const Arm_exidx_section_offset_map& section_offset_map_; + // Merged section contents. We need to keep build the merged section + // and save it here to avoid accessing the original EXIDX section when + // we cannot lock the sections' object. + unsigned char* section_contents_; }; // A class to wrap an ordinary input section containing executable code. @@ -1133,16 +1150,17 @@ class Arm_input_section : public Output_relaxed_input_section public: Arm_input_section(Relobj* relobj, unsigned int shndx) : Output_relaxed_input_section(relobj, shndx, 1), - original_addralign_(1), original_size_(0), stub_table_(NULL) + original_addralign_(1), original_size_(0), stub_table_(NULL), + original_contents_(NULL) { } ~Arm_input_section() - { } + { delete[] this->original_contents_; } // Initialize. void init(); - + // Whether this is a stub table owner. bool is_stub_table_owner() const @@ -1197,7 +1215,7 @@ class Arm_input_section : public Output_relaxed_input_section bool do_output_offset(const Relobj* object, unsigned int shndx, section_offset_type offset, - section_offset_type* poutput) const + section_offset_type* poutput) const { if ((object == this->relobj()) && (shndx == this->shndx()) @@ -1223,6 +1241,10 @@ class Arm_input_section : public Output_relaxed_input_section uint32_t original_size_; // Stub table. Stub_table* stub_table_; + // Original section contents. We have to make a copy here since the file + // containing the original section may not be locked when we need to access + // the contents. + unsigned char* original_contents_; }; // Arm_exidx_fixup class. This is used to define a number of methods @@ -1242,16 +1264,19 @@ class Arm_exidx_fixup ~Arm_exidx_fixup() { delete this->section_offset_map_; } - // Process an EXIDX section for entry merging. Return number of bytes to - // be deleted in output. If parts of the input EXIDX section are merged - // a heap allocated Arm_exidx_section_offset_map is store in the located - // PSECTION_OFFSET_MAP. The caller owns the map and is reponsible for - // releasing it. + // Process an EXIDX section for entry merging. SECTION_CONTENTS points + // to the EXIDX contents and SECTION_SIZE is the size of the contents. Return + // number of bytes to be deleted in output. If parts of the input EXIDX + // section are merged a heap allocated Arm_exidx_section_offset_map is store + // in the located PSECTION_OFFSET_MAP. The caller owns the map and is + // responsible for releasing it. template uint32_t process_exidx_section(const Arm_exidx_input_section* exidx_input_section, + const unsigned char* section_contents, + section_size_type section_size, Arm_exidx_section_offset_map** psection_offset_map); - + // Append an EXIDX_CANTUNWIND entry pointing at the end of the last // input section, if there is not one already. void @@ -1321,9 +1346,13 @@ class Arm_output_section : public Output_section public: typedef std::vector > Text_section_list; + // We need to force SHF_LINK_ORDER in a SHT_ARM_EXIDX section. Arm_output_section(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags) - : Output_section(name, type, flags) + : Output_section(name, type, + (type == elfcpp::SHT_ARM_EXIDX + ? flags | elfcpp::SHF_LINK_ORDER + : flags)) { if (type == elfcpp::SHT_ARM_EXIDX) this->set_always_keeps_input_sections(); @@ -1331,10 +1360,10 @@ class Arm_output_section : public Output_section ~Arm_output_section() { } - + // Group input sections for stub generation. void - group_sections(section_size_type, bool, Target_arm*); + group_sections(section_size_type, bool, Target_arm*, const Task*); // Downcast a base pointer to an Arm_output_section pointer. This is // not type-safe but we only use Arm_output_section not the base class. @@ -1353,7 +1382,8 @@ class Arm_output_section : public Output_section fix_exidx_coverage(Layout* layout, const Text_section_list& sorted_text_section, Symbol_table* symtab, - bool merge_exidx_entries); + bool merge_exidx_entries, + const Task* task); // Link an EXIDX section into its corresponding text section. void @@ -1369,7 +1399,8 @@ class Arm_output_section : public Output_section Input_section_list::const_iterator, Input_section_list::const_iterator, Target_arm*, - std::vector*); + std::vector*, + const Task* task); }; // Arm_exidx_input_section class. This represents an EXIDX input section. @@ -1381,14 +1412,15 @@ class Arm_exidx_input_section static_cast(-1); Arm_exidx_input_section(Relobj* relobj, unsigned int shndx, - unsigned int link, uint32_t size, uint32_t addralign) + unsigned int link, uint32_t size, + uint32_t addralign, uint32_t text_size) : relobj_(relobj), shndx_(shndx), link_(link), size_(size), - addralign_(addralign), has_errors_(false) + addralign_(addralign), text_size_(text_size), has_errors_(false) { } ~Arm_exidx_input_section() { } - + // Accessors: This is a read-only class. // Return the object containing this EXIDX input section. @@ -1411,11 +1443,16 @@ class Arm_exidx_input_section size() const { return this->size_; } - // Reutnr address alignment of EXIDX input section. + // Return address alignment of EXIDX input section. uint32_t addralign() const { return this->addralign_; } + // Return size of the associated text input section. + uint32_t + text_size() const + { return this->text_size_; } + // Whether there are any errors in the EXIDX input section. bool has_errors() const @@ -1437,6 +1474,8 @@ class Arm_exidx_input_section uint32_t size_; // Address alignment of this. For ARM 32-bit is sufficient. uint32_t addralign_; + // Size of associated text section. + uint32_t text_size_; // Whether this has any errors. bool has_errors_; }; @@ -1444,14 +1483,14 @@ class Arm_exidx_input_section // Arm_relobj class. template -class Arm_relobj : public Sized_relobj<32, big_endian> +class Arm_relobj : public Sized_relobj_file<32, big_endian> { public: static const Arm_address invalid_address = static_cast(-1); Arm_relobj(const std::string& name, Input_file* input_file, off_t offset, - const typename elfcpp::Ehdr<32, big_endian>& ehdr) - : Sized_relobj<32, big_endian>(name, input_file, offset, ehdr), + const typename elfcpp::Ehdr<32, big_endian>& ehdr) + : Sized_relobj_file<32, big_endian>(name, input_file, offset, ehdr), stub_tables_(), local_symbol_is_thumb_function_(), attributes_section_data_(NULL), mapping_symbols_info_(), section_has_cortex_a8_workaround_(NULL), exidx_section_map_(), @@ -1461,7 +1500,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian> ~Arm_relobj() { delete this->attributes_section_data_; } - + // Return the stub table of the SHNDX-th section if there is one. Stub_table* stub_table(unsigned int shndx) const @@ -1486,7 +1525,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian> gold_assert(r_sym < this->local_symbol_is_thumb_function_.size()); return this->local_symbol_is_thumb_function_[r_sym]; } - + // Scan all relocation sections for stub generation. void scan_sections_for_stubs(Target_arm*, const Symbol_table*, @@ -1534,7 +1573,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian> || (p1.first == p2.first && p1.second < p2.second)); } }; - + // We only care about the first character of a mapping symbol, so // we only store that instead of the whole symbol name. typedef std::map // Whether a section contains any Cortex-A8 workaround. bool section_has_cortex_a8_workaround(unsigned int shndx) const - { + { return (this->section_has_cortex_a8_workaround_ != NULL && (*this->section_has_cortex_a8_workaround_)[shndx]); } - + // Mark a section that has Cortex-A8 workaround. void mark_section_for_cortex_a8_workaround(unsigned int shndx) @@ -1590,7 +1629,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian> void set_output_local_symbol_count_needs_update() { this->output_local_symbol_count_needs_update_ = true; } - + // Update output local symbol count at the end of relaxation. void update_output_local_symbol_count(); @@ -1599,7 +1638,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian> bool merge_flags_and_attributes() const { return this->merge_flags_and_attributes_; } - + // Export list of EXIDX section indices. void get_exidx_shndx_list(std::vector* list) const @@ -1612,7 +1651,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian> if (p->second->shndx() == p->first) list->push_back(p->first); } - // Sort list to make result independent of implementation of map. + // Sort list to make result independent of implementation of map. std::sort(list->begin(), list->end()); } @@ -1622,7 +1661,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian> do_setup() { // Call parent's setup method. - Sized_relobj<32, big_endian>::do_setup(); + Sized_relobj_file<32, big_endian>::do_setup(); // Initialize look-up tables. Stub_table_list empty_stub_table_list(this->shnum(), NULL); @@ -1632,12 +1671,13 @@ class Arm_relobj : public Sized_relobj<32, big_endian> // Count the local symbols. void do_count_local_symbols(Stringpool_template*, - Stringpool_template*); + Stringpool_template*); void - do_relocate_sections(const Symbol_table* symtab, const Layout* layout, - const unsigned char* pshdrs, - typename Sized_relobj<32, big_endian>::Views* pivews); + do_relocate_sections( + const Symbol_table* symtab, const Layout* layout, + const unsigned char* pshdrs, Output_file* of, + typename Sized_relobj_file<32, big_endian>::Views* pivews); // Read the symbol information. void @@ -1653,18 +1693,18 @@ class Arm_relobj : public Sized_relobj<32, big_endian> bool section_needs_reloc_stub_scanning(const elfcpp::Shdr<32, big_endian>&, const Relobj::Output_sections&, - const Symbol_table *, const unsigned char*); + const Symbol_table*, const unsigned char*); // Whether a section is a scannable text section. bool section_is_scannable(const elfcpp::Shdr<32, big_endian>&, unsigned int, - const Output_section*, const Symbol_table *); + const Output_section*, const Symbol_table*); // Whether a section needs to be scanned for the Cortex-A8 erratum. bool section_needs_cortex_a8_stub_scanning(const elfcpp::Shdr<32, big_endian>&, unsigned int, Output_section*, - const Symbol_table *); + const Symbol_table*); // Scan a section for the Cortex-A8 erratum. void @@ -1673,7 +1713,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian> Target_arm*); // Find the linked text section of an EXIDX section by looking at the - // first reloction of the EXIDX section. PSHDR points to the section + // first relocation of the EXIDX section. PSHDR points to the section // headers of a relocation section and PSYMS points to the local symbols. // PSHNDX points to a location storing the text section index if found. // Return whether we can find the linked section. @@ -1733,7 +1773,7 @@ class Arm_dynobj : public Sized_dynobj<32, big_endian> : Sized_dynobj<32, big_endian>(name, input_file, offset, ehdr), processor_specific_flags_(0), attributes_section_data_(NULL) { } - + ~Arm_dynobj() { delete this->attributes_section_data_; } @@ -1826,13 +1866,13 @@ class Cortex_a8_reloc { } // Accessors: This is a read-only class. - + // Return the relocation stub associated with this relocation if there is // one. const Reloc_stub* reloc_stub() const - { return this->reloc_stub_; } - + { return this->reloc_stub_; } + // Return the relocation type. unsigned int r_type() const @@ -1877,7 +1917,8 @@ class Arm_output_data_got : public Output_data_got<32, big_endian> // relocation that needs to be applied in a static link. void add_static_reloc(unsigned int got_offset, unsigned int r_type, - Sized_relobj<32, big_endian>* relobj, unsigned int index) + Sized_relobj_file<32, big_endian>* relobj, + unsigned int index) { this->static_relocs_.push_back(Static_reloc(got_offset, r_type, relobj, index)); @@ -1894,7 +1935,7 @@ class Arm_output_data_got : public Output_data_got<32, big_endian> // Same as the above but for a local symbol in OBJECT with INDEX. void add_tls_gd32_with_static_reloc(unsigned int got_type, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int index); protected: @@ -1913,7 +1954,7 @@ class Arm_output_data_got : public Output_data_got<32, big_endian> { this->u_.global.symbol = gsym; } Static_reloc(unsigned int got_offset, unsigned int r_type, - Sized_relobj<32, big_endian>* relobj, unsigned int index) + Sized_relobj_file<32, big_endian>* relobj, unsigned int index) : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(false) { this->u_.local.relobj = relobj; @@ -1944,7 +1985,7 @@ class Arm_output_data_got : public Output_data_got<32, big_endian> } // For a relocation against a local symbol, the defining object. - Sized_relobj<32, big_endian>* + Sized_relobj_file<32, big_endian>* relobj() const { gold_assert(!this->symbol_is_global_); @@ -1977,7 +2018,7 @@ class Arm_output_data_got : public Output_data_got<32, big_endian> struct { // For a local symbol, the object defining object. - Sized_relobj<32, big_endian>* relobj; + Sized_relobj_file<32, big_endian>* relobj; // For a local symbol, the symbol index. unsigned int index; } local; @@ -1992,7 +2033,7 @@ class Arm_output_data_got : public Output_data_got<32, big_endian> std::vector static_relocs_; }; -// The ARM target has many relocation types with odd-sizes or incontigious +// The ARM target has many relocation types with odd-sizes or noncontiguous // bits. The default handling of relocatable relocation cannot process these // relocations. So we have to extend the default code. @@ -2038,7 +2079,8 @@ class Arm_scan_relocatable_relocs : case elfcpp::R_ARM_TARGET1: case elfcpp::R_ARM_TARGET2: gold_unreachable(); - // Relocations that write full 32 bits. + // Relocations that write full 32 bits and + // have alignment of 1. case elfcpp::R_ARM_ABS32: case elfcpp::R_ARM_REL32: case elfcpp::R_ARM_SBREL32: @@ -2056,7 +2098,7 @@ class Arm_scan_relocatable_relocs : case elfcpp::R_ARM_TLS_LDO32: case elfcpp::R_ARM_TLS_IE32: case elfcpp::R_ARM_TLS_LE32: - return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4; + return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4_UNALIGNED; default: // For all other static relocations, return RELOC_SPECIAL. return Relocatable_relocs::RELOC_SPECIAL; @@ -2065,65 +2107,6 @@ class Arm_scan_relocatable_relocs : } }; -// Utilities for manipulating integers of up to 32-bits - -namespace utils -{ - // Sign extend an n-bit unsigned integer stored in an uint32_t into - // an int32_t. NO_BITS must be between 1 to 32. - template - static inline int32_t - sign_extend(uint32_t bits) - { - gold_assert(no_bits >= 0 && no_bits <= 32); - if (no_bits == 32) - return static_cast(bits); - uint32_t mask = (~((uint32_t) 0)) >> (32 - no_bits); - bits &= mask; - uint32_t top_bit = 1U << (no_bits - 1); - int32_t as_signed = static_cast(bits); - return (bits & top_bit) ? as_signed + (-top_bit * 2) : as_signed; - } - - // Detects overflow of an NO_BITS integer stored in a uint32_t. - template - static inline bool - has_overflow(uint32_t bits) - { - gold_assert(no_bits >= 0 && no_bits <= 32); - if (no_bits == 32) - return false; - int32_t max = (1 << (no_bits - 1)) - 1; - int32_t min = -(1 << (no_bits - 1)); - int32_t as_signed = static_cast(bits); - return as_signed > max || as_signed < min; - } - - // Detects overflow of an NO_BITS integer stored in a uint32_t when it - // fits in the given number of bits as either a signed or unsigned value. - // For example, has_signed_unsigned_overflow<8> would check - // -128 <= bits <= 255 - template - static inline bool - has_signed_unsigned_overflow(uint32_t bits) - { - gold_assert(no_bits >= 2 && no_bits <= 32); - if (no_bits == 32) - return false; - int32_t max = static_cast((1U << no_bits) - 1); - int32_t min = -(1 << (no_bits - 1)); - int32_t as_signed = static_cast(bits); - return as_signed > max || as_signed < min; - } - - // Select bits from A and B using bits in MASK. For each n in [0..31], - // the n-th bit in the result is chosen from the n-th bits of A and B. - // A zero selects A and a one selects B. - static inline uint32_t - bit_select(uint32_t a, uint32_t b, uint32_t mask) - { return (a & ~mask) | (b & mask); } -}; - template class Target_arm : public Sized_target<32, big_endian> { @@ -2134,44 +2117,17 @@ class Target_arm : public Sized_target<32, big_endian> // When were are relocating a stub, we pass this as the relocation number. static const size_t fake_relnum_for_stubs = static_cast(-1); - Target_arm() - : Sized_target<32, big_endian>(&arm_info), + Target_arm(const Target::Target_info* info = &arm_info) + : Sized_target<32, big_endian>(info), got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL), - copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL), + copy_relocs_(elfcpp::R_ARM_COPY), got_mod_index_offset_(-1U), tls_base_symbol_defined_(false), stub_tables_(), stub_factory_(Stub_factory::get_instance()), - may_use_blx_(false), should_force_pic_veneer_(false), + should_force_pic_veneer_(false), arm_input_section_map_(), attributes_section_data_(NULL), fix_cortex_a8_(false), cortex_a8_relocs_info_() { } - // Virtual function which is set to return true by a target if - // it can use relocation types to determine if a function's - // pointer is taken. - virtual bool - can_check_for_function_pointers() const - { return true; } - - // Whether a section called SECTION_NAME may have function pointers to - // sections not eligible for safe ICF folding. - virtual bool - section_may_have_icf_unsafe_pointers(const char* section_name) const - { - return (!is_prefix_of(".ARM.exidx", section_name) - && !is_prefix_of(".ARM.extab", section_name) - && Target::section_may_have_icf_unsafe_pointers(section_name)); - } - - // Whether we can use BLX. - bool - may_use_blx() const - { return this->may_use_blx_; } - - // Set use-BLX flag. - void - set_may_use_blx(bool value) - { this->may_use_blx_ = value; } - // Whether we force PCI branch veneers. bool should_force_pic_veneer() const @@ -2181,7 +2137,7 @@ class Target_arm : public Sized_target<32, big_endian> void set_should_force_pic_veneer(bool value) { this->should_force_pic_veneer_ = value; } - + // Whether we use THUMB-2 instructions. bool using_thumb2() const @@ -2233,13 +2189,43 @@ class Target_arm : public Sized_target<32, big_endian> || arch == elfcpp::TAG_CPU_ARCH_V7 || arch == elfcpp::TAG_CPU_ARCH_V7E_M); } - - // Process the relocations to determine unreferenced sections for + + // Whether we have v4T interworking instructions available. + bool + may_use_v4t_interworking() const + { + Object_attribute* attr = + this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch); + int arch = attr->int_value(); + return (arch != elfcpp::TAG_CPU_ARCH_PRE_V4 + && arch != elfcpp::TAG_CPU_ARCH_V4); + } + + // Whether we have v5T interworking instructions available. + bool + may_use_v5t_interworking() const + { + Object_attribute* attr = + this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch); + int arch = attr->int_value(); + if (parameters->options().fix_arm1176()) + return (arch == elfcpp::TAG_CPU_ARCH_V6T2 + || arch == elfcpp::TAG_CPU_ARCH_V7 + || arch == elfcpp::TAG_CPU_ARCH_V6_M + || arch == elfcpp::TAG_CPU_ARCH_V6S_M + || arch == elfcpp::TAG_CPU_ARCH_V7E_M); + else + return (arch != elfcpp::TAG_CPU_ARCH_PRE_V4 + && arch != elfcpp::TAG_CPU_ARCH_V4 + && arch != elfcpp::TAG_CPU_ARCH_V4T); + } + + // Process the relocations to determine unreferenced sections for // garbage collection. void gc_process_relocs(Symbol_table* symtab, Layout* layout, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int data_shndx, unsigned int sh_type, const unsigned char* prelocs, @@ -2253,7 +2239,7 @@ class Target_arm : public Sized_target<32, big_endian> void scan_relocs(Symbol_table* symtab, Layout* layout, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int data_shndx, unsigned int sh_type, const unsigned char* prelocs, @@ -2289,7 +2275,7 @@ class Target_arm : public Sized_target<32, big_endian> void scan_relocatable_relocs(Symbol_table* symtab, Layout* layout, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int data_shndx, unsigned int sh_type, const unsigned char* prelocs, @@ -2300,20 +2286,21 @@ class Target_arm : public Sized_target<32, big_endian> const unsigned char* plocal_symbols, Relocatable_relocs*); - // Relocate a section during a relocatable link. + // Emit relocations for a section. void - relocate_for_relocatable(const Relocate_info<32, big_endian>*, - unsigned int sh_type, - const unsigned char* prelocs, - size_t reloc_count, - Output_section* output_section, - off_t offset_in_output_section, - const Relocatable_relocs*, - unsigned char* view, - Arm_address view_address, - section_size_type view_size, - unsigned char* reloc_view, - section_size_type reloc_view_size); + relocate_relocs(const Relocate_info<32, big_endian>*, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + typename elfcpp::Elf_types<32>::Elf_Off + offset_in_output_section, + const Relocatable_relocs*, + unsigned char* view, + Arm_address view_address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size); // Perform target-specific processing in a relocatable link. This is // only used if we use the relocation strategy RELOC_SPECIAL. @@ -2323,16 +2310,17 @@ class Target_arm : public Sized_target<32, big_endian> const unsigned char* preloc_in, size_t relnum, Output_section* output_section, - off_t offset_in_output_section, + typename elfcpp::Elf_types<32>::Elf_Off + offset_in_output_section, unsigned char* view, typename elfcpp::Elf_types<32>::Elf_Addr view_address, section_size_type view_size, unsigned char* preloc_out); - + // Return whether SYM is defined by the ABI. bool - do_is_defined_by_abi(Symbol* sym) const + do_is_defined_by_abi(const Symbol* sym) const { return strcmp(sym->name(), "__tls_get_addr") == 0; } // Return whether there is a GOT section. @@ -2371,12 +2359,12 @@ class Target_arm : public Sized_target<32, big_endian> // Map platform-specific reloc types static unsigned int - get_real_reloc_type (unsigned int r_type); + get_real_reloc_type(unsigned int r_type); // // Methods to support stub-generations. // - + // Return the stub factory const Stub_factory& stub_factory() const @@ -2402,12 +2390,12 @@ class Target_arm : public Sized_target<32, big_endian> bool, const unsigned char*, Arm_address, section_size_type); - // Relocate a stub. + // Relocate a stub. void relocate_stub(Stub*, const Relocate_info<32, big_endian>*, Output_section*, unsigned char*, Arm_address, section_size_type); - + // Get the default ARM target. static Target_arm* default_target() @@ -2458,6 +2446,11 @@ class Target_arm : public Sized_target<32, big_endian> unsigned char*, Arm_address); protected: + // Make the PLT-generator object. + Output_data_plt_arm* + make_data_plt(Layout* layout, Output_data_space* got_plt) + { return this->do_make_data_plt(layout, got_plt); } + // Make an ELF object. Object* do_make_elf_object(const std::string&, Input_file*, off_t, @@ -2485,7 +2478,7 @@ class Target_arm : public Sized_target<32, big_endian> { return new Arm_output_section(name, type, flags); } void - do_adjust_elf_header(unsigned char* view, int len) const; + do_adjust_elf_header(unsigned char* view, int len); // We only need to generate stubs, and hence perform relaxation if we are // not doing relocatable linking. @@ -2494,7 +2487,7 @@ class Target_arm : public Sized_target<32, big_endian> { return !parameters->options().relocatable(); } bool - do_relax(int, const Input_objects*, Symbol_table*, Layout*); + do_relax(int, const Input_objects*, Symbol_table*, Layout*, const Task*); // Determine whether an object attribute tag takes an integer, a // string or both. @@ -2516,6 +2509,32 @@ class Target_arm : public Sized_target<32, big_endian> arm_reloc_property_table = new Arm_reloc_property_table(); } + // Virtual function which is set to return true by a target if + // it can use relocation types to determine if a function's + // pointer is taken. + virtual bool + do_can_check_for_function_pointers() const + { return true; } + + // Whether a section called SECTION_NAME may have function pointers to + // sections not eligible for safe ICF folding. + virtual bool + do_section_may_have_icf_unsafe_pointers(const char* section_name) const + { + return (!is_prefix_of(".ARM.exidx", section_name) + && !is_prefix_of(".ARM.extab", section_name) + && Target::do_section_may_have_icf_unsafe_pointers(section_name)); + } + + virtual void + do_define_standard_symbols(Symbol_table*, Layout*); + + virtual Output_data_plt_arm* + do_make_data_plt(Layout* layout, Output_data_space* got_plt) + { + return new Output_data_plt_arm_standard(layout, got_plt); + } + private: // The class which scans relocations. class Scan @@ -2525,17 +2544,21 @@ class Target_arm : public Sized_target<32, big_endian> : issued_non_pic_error_(false) { } + static inline int + get_reference_flags(unsigned int r_type); + inline void local(Symbol_table* symtab, Layout* layout, Target_arm* target, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int data_shndx, Output_section* output_section, const elfcpp::Rel<32, big_endian>& reloc, unsigned int r_type, - const elfcpp::Sym<32, big_endian>& lsym); + const elfcpp::Sym<32, big_endian>& lsym, + bool is_discarded); inline void global(Symbol_table* symtab, Layout* layout, Target_arm* target, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int data_shndx, Output_section* output_section, const elfcpp::Rel<32, big_endian>& reloc, unsigned int r_type, @@ -2543,28 +2566,28 @@ class Target_arm : public Sized_target<32, big_endian> inline bool local_reloc_may_be_function_pointer(Symbol_table* , Layout* , Target_arm* , - Sized_relobj<32, big_endian>* , - unsigned int , - Output_section* , - const elfcpp::Rel<32, big_endian>& , + Sized_relobj_file<32, big_endian>* , unsigned int , - const elfcpp::Sym<32, big_endian>&); + Output_section* , + const elfcpp::Rel<32, big_endian>& , + unsigned int , + const elfcpp::Sym<32, big_endian>&); inline bool global_reloc_may_be_function_pointer(Symbol_table* , Layout* , Target_arm* , - Sized_relobj<32, big_endian>* , - unsigned int , - Output_section* , - const elfcpp::Rel<32, big_endian>& , + Sized_relobj_file<32, big_endian>* , + unsigned int , + Output_section* , + const elfcpp::Rel<32, big_endian>& , unsigned int , Symbol*); private: static void - unsupported_reloc_local(Sized_relobj<32, big_endian>*, + unsupported_reloc_local(Sized_relobj_file<32, big_endian>*, unsigned int r_type); static void - unsupported_reloc_global(Sized_relobj<32, big_endian>*, + unsupported_reloc_global(Sized_relobj_file<32, big_endian>*, unsigned int r_type, Symbol*); void @@ -2607,7 +2630,7 @@ class Target_arm : public Sized_target<32, big_endian> // Return whether the static relocation needs to be applied. inline bool should_apply_static_reloc(const Sized_symbol<32>* gsym, - int ref_flags, + unsigned int r_type, bool is_32bit, Output_section* output_section); @@ -2626,7 +2649,7 @@ class Target_arm : public Sized_target<32, big_endian> // reloc. This means the relocation type accesses a symbol not via // GOT or PLT. static inline bool - reloc_is_non_pic (unsigned int r_type) + reloc_is_non_pic(unsigned int r_type) { switch (r_type) { @@ -2662,7 +2685,7 @@ class Target_arm : public Sized_target<32, big_endian> // Do a TLS relocation. inline typename Arm_relocate_functions::Status relocate_tls(const Relocate_info<32, big_endian>*, Target_arm*, - size_t, const elfcpp::Rel<32, big_endian>&, unsigned int, + size_t, const elfcpp::Rel<32, big_endian>&, unsigned int, const Sized_symbol<32>*, const Symbol_value<32>*, unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, section_size_type); @@ -2706,7 +2729,7 @@ class Target_arm : public Sized_target<32, big_endian> // Create a GOT entry for the TLS module index. unsigned int got_mod_index_entry(Symbol_table* symtab, Layout* layout, - Sized_relobj<32, big_endian>* object); + Sized_relobj_file<32, big_endian>* object); // Get the PLT section. const Output_data_plt_arm* @@ -2737,7 +2760,7 @@ class Target_arm : public Sized_target<32, big_endian> // Add a potential copy relocation. void copy_reloc(Symbol_table* symtab, Layout* layout, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int shndx, Output_section* output_section, Symbol* sym, const elfcpp::Rel<32, big_endian>& reloc) { @@ -2775,6 +2798,18 @@ class Target_arm : public Sized_target<32, big_endian> static std::string tag_cpu_name_value(unsigned int); + // Query attributes object to see if integer divide instructions may be + // present in an object. + static bool + attributes_accept_div(int arch, int profile, + const Object_attribute* div_attr); + + // Query attributes object to see if integer divide instructions are + // forbidden to be in the object. This is not the inverse of + // attributes_accept_div. + static bool + attributes_forbid_div(const Object_attribute* div_attr); + // Merge object attributes from input object and those in the output. void merge_object_attributes(const char*, const Attributes_section_data*); @@ -2797,7 +2832,7 @@ class Target_arm : public Sized_target<32, big_endian> // Group input sections for stub generation. void - group_sections(Layout*, section_size_type, bool); + group_sections(Layout*, section_size_type, bool, const Task*); // Scan a relocation for stub generation. void @@ -2822,7 +2857,8 @@ class Target_arm : public Sized_target<32, big_endian> // Fix .ARM.exidx section coverage. void fix_exidx_coverage(Layout*, const Input_objects*, - Arm_output_section*, Symbol_table*); + Arm_output_section*, Symbol_table*, + const Task*); // Functors for STL set. struct output_section_address_less_than @@ -2856,7 +2892,7 @@ class Target_arm : public Sized_target<32, big_endian> Arm_input_section*, Section_id_hash> Arm_input_section_map; - + // Map output addresses to relocs for Cortex-A8 erratum. typedef Unordered_map Cortex_a8_relocs_info; @@ -2871,8 +2907,6 @@ class Target_arm : public Sized_target<32, big_endian> Reloc_section* rel_dyn_; // Relocs saved to avoid a COPY reloc. Copy_relocs copy_relocs_; - // Space for variables copied with a COPY reloc. - Output_data_space* dynbss_; // Offset of the GOT entry for the TLS module index. unsigned int got_mod_index_offset_; // True if the _TLS_MODULE_BASE_ symbol has been defined. @@ -2881,8 +2915,6 @@ class Target_arm : public Sized_target<32, big_endian> Stub_table_list stub_tables_; // Stub factory. const Stub_factory &stub_factory_; - // Whether we can use BLX. - bool may_use_blx_; // Whether we force PIC branch veneers. bool should_force_pic_veneer_; // Map for locating Arm_input_sections. @@ -2905,17 +2937,21 @@ const Target::Target_info Target_arm::arm_info = false, // has_resolve false, // has_code_fill true, // is_default_stack_executable + false, // can_icf_inline_merge_sections '\0', // wrap_char "/usr/lib/libc.so.1", // dynamic_linker 0x8000, // default_text_segment_address 0x1000, // abi_pagesize (overridable by -z max-page-size) 0x1000, // common_pagesize (overridable by -z common-page-size) + false, // isolate_execinstr + 0, // rosegment_gap elfcpp::SHN_UNDEF, // small_common_shndx elfcpp::SHN_UNDEF, // large_common_shndx 0, // small_common_section_flags 0, // large_common_section_flags ".ARM.attributes", // attributes_section - "aeabi" // attributes_vendor + "aeabi", // attributes_vendor + "_start" // entry_symbol_name }; // Arm relocate functions class @@ -2928,7 +2964,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> typedef enum { STATUS_OKAY, // No error during relocation. - STATUS_OVERFLOW, // Relocation oveflow. + STATUS_OVERFLOW, // Relocation overflow. STATUS_BAD_RELOC // Relocation cannot be applied. } Status; @@ -2938,10 +2974,10 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // Encoding of imm16 argument for movt and movw ARM instructions // from ARM ARM: - // + // // imm16 := imm4 | imm12 // - // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0 + // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0 // +-------+---------------+-------+-------+-----------------------+ // | | |imm4 | |imm12 | // +-------+---------------+-------+-------+-----------------------+ @@ -2954,7 +2990,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> { // According to the Elf ABI for ARM Architecture the immediate // field is sign-extended to form the addend. - return utils::sign_extend<16>(((val >> 4) & 0xf000) | (val & 0xfff)); + return Bits<16>::sign_extend32(((val >> 4) & 0xf000) | (val & 0xfff)); } // Insert X into VAL based on the ARM instruction encoding described @@ -2972,10 +3008,10 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // Encoding of imm16 argument for movt and movw Thumb2 instructions // from ARM ARM: - // + // // imm16 := imm4 | i | imm3 | imm8 // - // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0 + // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0 // +---------+-+-----------+-------++-+-----+-------+---------------+ // | |i| |imm4 || |imm3 | |imm8 | // +---------+-+-----------+-------++-+-----+-------+---------------+ @@ -2988,10 +3024,10 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> { // According to the Elf ABI for ARM Architecture the immediate // field is sign-extended to form the addend. - return utils::sign_extend<16>(((val >> 4) & 0xf000) - | ((val >> 15) & 0x0800) - | ((val >> 4) & 0x0700) - | (val & 0x00ff)); + return Bits<16>::sign_extend32(((val >> 4) & 0xf000) + | ((val >> 15) & 0x0800) + | ((val >> 4) & 0x0700) + | (val & 0x00ff)); } // Insert X into VAL based on the Thumb2 instruction encoding @@ -3073,14 +3109,14 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // Handle ARM long branches. static typename This::Status arm_branch_common(unsigned int, const Relocate_info<32, big_endian>*, - unsigned char *, const Sized_symbol<32>*, + unsigned char*, const Sized_symbol<32>*, const Arm_relobj*, unsigned int, const Symbol_value<32>*, Arm_address, Arm_address, bool); // Handle THUMB long branches. static typename This::Status thumb_branch_common(unsigned int, const Relocate_info<32, big_endian>*, - unsigned char *, const Sized_symbol<32>*, + unsigned char*, const Sized_symbol<32>*, const Arm_relobj*, unsigned int, const Symbol_value<32>*, Arm_address, Arm_address, bool); @@ -3099,8 +3135,8 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> uint32_t i1 = j1 ^ s ? 0 : 1; uint32_t i2 = j2 ^ s ? 0 : 1; - return utils::sign_extend<25>((s << 24) | (i1 << 23) | (i2 << 22) - | (upper << 12) | (lower << 1)); + return Bits<25>::sign_extend32((s << 24) | (i1 << 23) | (i2 << 22) + | (upper << 12) | (lower << 1)); } // Insert OFFSET to a 32-bit THUMB branch and return the upper instruction. @@ -3123,9 +3159,9 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> uint32_t s = offset < 0 ? 1 : 0; uint32_t bits = static_cast(offset); return ((lower_insn & ~0x2fffU) - | ((((bits >> 23) & 1) ^ !s) << 13) - | ((((bits >> 22) & 1) ^ !s) << 11) - | ((bits >> 1) & 0x7ffU)); + | ((((bits >> 23) & 1) ^ !s) << 13) + | ((((bits >> 22) & 1) ^ !s) << 11) + | ((bits >> 1) & 0x7ffU)); } // Return the branch offset of a 32-bit THUMB conditional branch. @@ -3138,7 +3174,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> uint32_t lower = (lower_insn & 0x07ffU); uint32_t upper = (s << 8) | (j2 << 7) | (j1 << 6) | (upper_insn & 0x003fU); - return utils::sign_extend<21>((upper << 12) | (lower << 1)); + return Bits<21>::sign_extend32((upper << 12) | (lower << 1)); } // Insert OFFSET to a 32-bit THUMB conditional branch and return the upper @@ -3154,7 +3190,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // Insert OFFSET to a 32-bit THUMB conditional branch and return the lower // instruction. LOWER_INSN is the original lower instruction of the branch. - // Caller is reponsible for overflow checking. + // The caller is responsible for overflow checking. static inline uint16_t thumb32_cond_branch_lower(uint16_t lower_insn, int32_t offset) { @@ -3168,30 +3204,28 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_ABS8: S + A static inline typename This::Status - abs8(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + abs8(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval) { typedef typename elfcpp::Swap<8, big_endian>::Valtype Valtype; - typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype; Valtype* wv = reinterpret_cast(view); Valtype val = elfcpp::Swap<8, big_endian>::readval(wv); - Reltype addend = utils::sign_extend<8>(val); - Reltype x = psymval->value(object, addend); - val = utils::bit_select(val, x, 0xffU); + int32_t addend = Bits<8>::sign_extend32(val); + Arm_address x = psymval->value(object, addend); + val = Bits<32>::bit_select32(val, x, 0xffU); elfcpp::Swap<8, big_endian>::writeval(wv, val); // R_ARM_ABS8 permits signed or unsigned results. - int signed_x = static_cast(x); - return ((signed_x < -128 || signed_x > 255) + return (Bits<8>::has_signed_unsigned_overflow32(x) ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } // R_ARM_THM_ABS5: S + A static inline typename This::Status - thm_abs5(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + thm_abs5(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval) { typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; @@ -3200,20 +3234,17 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> Valtype val = elfcpp::Swap<16, big_endian>::readval(wv); Reltype addend = (val & 0x7e0U) >> 6; Reltype x = psymval->value(object, addend); - val = utils::bit_select(val, x << 6, 0x7e0U); + val = Bits<32>::bit_select32(val, x << 6, 0x7e0U); elfcpp::Swap<16, big_endian>::writeval(wv, val); - - // R_ARM_ABS16 permits signed or unsigned results. - int signed_x = static_cast(x); - return ((signed_x < -32768 || signed_x > 65535) + return (Bits<5>::has_overflow32(x) ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } // R_ARM_ABS12: S + A static inline typename This::Status - abs12(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + abs12(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval) { typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; @@ -3222,73 +3253,71 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> Valtype val = elfcpp::Swap<32, big_endian>::readval(wv); Reltype addend = val & 0x0fffU; Reltype x = psymval->value(object, addend); - val = utils::bit_select(val, x, 0x0fffU); + val = Bits<32>::bit_select32(val, x, 0x0fffU); elfcpp::Swap<32, big_endian>::writeval(wv, val); - return (utils::has_overflow<12>(x) + return (Bits<12>::has_overflow32(x) ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } // R_ARM_ABS16: S + A static inline typename This::Status - abs16(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + abs16(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval) { - typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; - typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype; - Valtype* wv = reinterpret_cast(view); - Valtype val = elfcpp::Swap<16, big_endian>::readval(wv); - Reltype addend = utils::sign_extend<16>(val); - Reltype x = psymval->value(object, addend); - val = utils::bit_select(val, x, 0xffffU); - elfcpp::Swap<16, big_endian>::writeval(wv, val); - return (utils::has_signed_unsigned_overflow<16>(x) + typedef typename elfcpp::Swap_unaligned<16, big_endian>::Valtype Valtype; + Valtype val = elfcpp::Swap_unaligned<16, big_endian>::readval(view); + int32_t addend = Bits<16>::sign_extend32(val); + Arm_address x = psymval->value(object, addend); + val = Bits<32>::bit_select32(val, x, 0xffffU); + elfcpp::Swap_unaligned<16, big_endian>::writeval(view, val); + + // R_ARM_ABS16 permits signed or unsigned results. + return (Bits<16>::has_signed_unsigned_overflow32(x) ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } // R_ARM_ABS32: (S + A) | T static inline typename This::Status - abs32(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + abs32(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address thumb_bit) { - typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; - Valtype* wv = reinterpret_cast(view); - Valtype addend = elfcpp::Swap<32, big_endian>::readval(wv); + typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype; + Valtype addend = elfcpp::Swap_unaligned<32, big_endian>::readval(view); Valtype x = psymval->value(object, addend) | thumb_bit; - elfcpp::Swap<32, big_endian>::writeval(wv, x); + elfcpp::Swap_unaligned<32, big_endian>::writeval(view, x); return This::STATUS_OKAY; } // R_ARM_REL32: (S + A) | T - P static inline typename This::Status - rel32(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + rel32(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address address, Arm_address thumb_bit) { - typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; - Valtype* wv = reinterpret_cast(view); - Valtype addend = elfcpp::Swap<32, big_endian>::readval(wv); + typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype; + Valtype addend = elfcpp::Swap_unaligned<32, big_endian>::readval(view); Valtype x = (psymval->value(object, addend) | thumb_bit) - address; - elfcpp::Swap<32, big_endian>::writeval(wv, x); + elfcpp::Swap_unaligned<32, big_endian>::writeval(view, x); return This::STATUS_OKAY; } // R_ARM_THM_JUMP24: (S + A) | T - P static typename This::Status - thm_jump19(unsigned char *view, const Arm_relobj* object, + thm_jump19(unsigned char* view, const Arm_relobj* object, const Symbol_value<32>* psymval, Arm_address address, Arm_address thumb_bit); // R_ARM_THM_JUMP6: S + A – P static inline typename This::Status - thm_jump6(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + thm_jump6(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address address) { @@ -3309,38 +3338,40 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_THM_JUMP8: S + A – P static inline typename This::Status - thm_jump8(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + thm_jump8(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address address) { typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; - typedef typename elfcpp::Swap<16, big_endian>::Valtype Reltype; Valtype* wv = reinterpret_cast(view); Valtype val = elfcpp::Swap<16, big_endian>::readval(wv); - Reltype addend = utils::sign_extend<8>((val & 0x00ff) << 1); - Reltype x = (psymval->value(object, addend) - address); - elfcpp::Swap<16, big_endian>::writeval(wv, (val & 0xff00) | ((x & 0x01fe) >> 1)); - return (utils::has_overflow<8>(x) + int32_t addend = Bits<8>::sign_extend32((val & 0x00ff) << 1); + int32_t x = (psymval->value(object, addend) - address); + elfcpp::Swap<16, big_endian>::writeval(wv, ((val & 0xff00) + | ((x & 0x01fe) >> 1))); + // We do a 9-bit overflow check because x is right-shifted by 1 bit. + return (Bits<9>::has_overflow32(x) ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } // R_ARM_THM_JUMP11: S + A – P static inline typename This::Status - thm_jump11(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + thm_jump11(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address address) { typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; - typedef typename elfcpp::Swap<16, big_endian>::Valtype Reltype; Valtype* wv = reinterpret_cast(view); Valtype val = elfcpp::Swap<16, big_endian>::readval(wv); - Reltype addend = utils::sign_extend<11>((val & 0x07ff) << 1); - Reltype x = (psymval->value(object, addend) - address); - elfcpp::Swap<16, big_endian>::writeval(wv, (val & 0xf800) | ((x & 0x0ffe) >> 1)); - return (utils::has_overflow<11>(x) + int32_t addend = Bits<11>::sign_extend32((val & 0x07ff) << 1); + int32_t x = (psymval->value(object, addend) - address); + elfcpp::Swap<16, big_endian>::writeval(wv, ((val & 0xf800) + | ((x & 0x0ffe) >> 1))); + // We do a 12-bit overflow check because x is right-shifted by 1 bit. + return (Bits<12>::has_overflow32(x) ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } @@ -3375,7 +3406,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_GOT_PREL: GOT(S) + A - P static inline typename This::Status - got_prel(unsigned char *view, + got_prel(unsigned char* view, Arm_address got_entry, Arm_address address) { @@ -3385,21 +3416,21 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_PREL: (S + A) | T - P static inline typename This::Status - prel31(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + prel31(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address address, Arm_address thumb_bit) { - typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; - Valtype* wv = reinterpret_cast(view); - Valtype val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype addend = utils::sign_extend<31>(val); + typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype; + Valtype val = elfcpp::Swap_unaligned<32, big_endian>::readval(view); + Valtype addend = Bits<31>::sign_extend32(val); Valtype x = (psymval->value(object, addend) | thumb_bit) - address; - val = utils::bit_select(val, x, 0x7fffffffU); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - return (utils::has_overflow<31>(x) ? - This::STATUS_OVERFLOW : This::STATUS_OKAY); + val = Bits<32>::bit_select32(val, x, 0x7fffffffU); + elfcpp::Swap_unaligned<32, big_endian>::writeval(view, val); + return (Bits<31>::has_overflow32(x) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); } // R_ARM_MOVW_ABS_NC: (S + A) | T (relative address base is ) @@ -3408,7 +3439,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_MOVW_BREL: ((S + A) | T) - B(S) static inline typename This::Status movw(unsigned char* view, - const Sized_relobj<32, big_endian>* object, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address relative_address_base, Arm_address thumb_bit, @@ -3422,7 +3453,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> - relative_address_base); val = This::insert_val_arm_movw_movt(val, x); elfcpp::Swap<32, big_endian>::writeval(wv, val); - return ((check_overflow && utils::has_overflow<16>(x)) + return ((check_overflow && Bits<16>::has_overflow32(x)) ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } @@ -3432,7 +3463,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_MOVT_BREL: S + A - B(S) static inline typename This::Status movt(unsigned char* view, - const Sized_relobj<32, big_endian>* object, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address relative_address_base) { @@ -3452,8 +3483,8 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_THM_MOVW_BREL_NC: ((S + A) | T) - B(S) // R_ARM_THM_MOVW_BREL: ((S + A) | T) - B(S) static inline typename This::Status - thm_movw(unsigned char *view, - const Sized_relobj<32, big_endian>* object, + thm_movw(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address relative_address_base, Arm_address thumb_bit, @@ -3470,8 +3501,8 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> val = This::insert_val_thumb_movw_movt(val, x); elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16); elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff); - return ((check_overflow && utils::has_overflow<16>(x)) - ? This::STATUS_OVERFLOW + return ((check_overflow && Bits<16>::has_overflow32(x)) + ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } @@ -3480,7 +3511,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_THM_MOVT_BREL: S + A - B(S) static inline typename This::Status thm_movt(unsigned char* view, - const Sized_relobj<32, big_endian>* object, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address relative_address_base) { @@ -3500,7 +3531,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_THM_ALU_PREL_11_0: ((S + A) | T) - Pa (Thumb32) static inline typename This::Status thm_alu11(unsigned char* view, - const Sized_relobj<32, big_endian>* object, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address address, Arm_address thumb_bit) @@ -3548,13 +3579,13 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> elfcpp::Swap<16, big_endian>::writeval(wv, insn >> 16); elfcpp::Swap<16, big_endian>::writeval(wv + 1, insn & 0xffff); return ((val > 0xfff) ? - This::STATUS_OVERFLOW : This::STATUS_OKAY); + This::STATUS_OVERFLOW : This::STATUS_OKAY); } // R_ARM_THM_PC8: S + A - Pa (Thumb) static inline typename This::Status thm_pc8(unsigned char* view, - const Sized_relobj<32, big_endian>* object, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address address) { @@ -3576,7 +3607,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_THM_PC12: S + A - Pa (Thumb32) static inline typename This::Status thm_pc12(unsigned char* view, - const Sized_relobj<32, big_endian>* object, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, Arm_address address) { @@ -3603,13 +3634,13 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> elfcpp::Swap<16, big_endian>::writeval(wv, insn >> 16); elfcpp::Swap<16, big_endian>::writeval(wv + 1, insn & 0xffff); return ((val > 0xfff) ? - This::STATUS_OVERFLOW : This::STATUS_OKAY); + This::STATUS_OVERFLOW : This::STATUS_OKAY); } // R_ARM_V4BX static inline typename This::Status v4bx(const Relocate_info<32, big_endian>* relinfo, - unsigned char *view, + unsigned char* view, const Arm_relobj* object, const Arm_address address, const bool is_interworking) @@ -3661,7 +3692,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_ALU_SB_G2: ((S + A) | T) - B(S) static inline typename This::Status arm_grp_alu(unsigned char* view, - const Sized_relobj<32, big_endian>* object, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, const int group, Arm_address address, @@ -3718,7 +3749,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_LDR_SB_G2: S + A - B(S) static inline typename This::Status arm_grp_ldr(unsigned char* view, - const Sized_relobj<32, big_endian>* object, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, const int group, Arm_address address) @@ -3756,7 +3787,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_LDRS_SB_G2: S + A - B(S) static inline typename This::Status arm_grp_ldrs(unsigned char* view, - const Sized_relobj<32, big_endian>* object, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, const int group, Arm_address address) @@ -3794,7 +3825,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // R_ARM_LDC_SB_G2: S + A - B(S) static inline typename This::Status arm_grp_ldc(unsigned char* view, - const Sized_relobj<32, big_endian>* object, + const Sized_relobj_file<32, big_endian>* object, const Symbol_value<32>* psymval, const int group, Arm_address address) @@ -3836,7 +3867,7 @@ typename Arm_relocate_functions::Status Arm_relocate_functions::arm_branch_common( unsigned int r_type, const Relocate_info<32, big_endian>* relinfo, - unsigned char *view, + unsigned char* view, const Sized_symbol<32>* gsym, const Arm_relobj* object, unsigned int r_sym, @@ -3848,9 +3879,9 @@ Arm_relocate_functions::arm_branch_common( typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; Valtype* wv = reinterpret_cast(view); Valtype val = elfcpp::Swap<32, big_endian>::readval(wv); - + bool insn_is_b = (((val >> 28) & 0xf) <= 0xe) - && ((val & 0x0f000000UL) == 0x0a000000UL); + && ((val & 0x0f000000UL) == 0x0a000000UL); bool insn_is_uncond_bl = (val & 0xff000000UL) == 0xeb000000UL; bool insn_is_cond_bl = (((val >> 28) & 0xf) < 0xe) && ((val & 0x0f000000UL) == 0x0b000000UL); @@ -3901,18 +3932,18 @@ Arm_relocate_functions::arm_branch_common( elfcpp::Swap<32, big_endian>::writeval(wv, val); return This::STATUS_OKAY; } - - Valtype addend = utils::sign_extend<26>(val << 2); + + Valtype addend = Bits<26>::sign_extend32(val << 2); Valtype branch_target = psymval->value(object, addend); int32_t branch_offset = branch_target - address; // We need a stub if the branch offset is too large or if we need // to switch mode. - bool may_use_blx = arm_target->may_use_blx(); + bool may_use_blx = arm_target->may_use_v5t_interworking(); Reloc_stub* stub = NULL; if (!parameters->options().relocatable() - && (utils::has_overflow<26>(branch_offset) + && (Bits<26>::has_overflow32(branch_offset) || ((thumb_bit != 0) && !(may_use_blx && r_type == elfcpp::R_ARM_CALL)))) { @@ -3934,7 +3965,7 @@ Arm_relocate_functions::arm_branch_common( thumb_bit = stub->stub_template()->entry_in_thumb_mode() ? 1 : 0; branch_target = stub_table->address() + stub->offset() + addend; branch_offset = branch_target - address; - gold_assert(!utils::has_overflow<26>(branch_offset)); + gold_assert(!Bits<26>::has_overflow32(branch_offset)); } } @@ -3947,10 +3978,11 @@ Arm_relocate_functions::arm_branch_common( val = (val & 0xffffff) | 0xfa000000 | ((branch_offset & 2) << 23); } - val = utils::bit_select(val, (branch_offset >> 2), 0xffffffUL); + val = Bits<32>::bit_select32(val, (branch_offset >> 2), 0xffffffUL); elfcpp::Swap<32, big_endian>::writeval(wv, val); - return (utils::has_overflow<26>(branch_offset) - ? This::STATUS_OVERFLOW : This::STATUS_OKAY); + return (Bits<26>::has_overflow32(branch_offset) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); } // Relocate THUMB long branches. This handles relocation types @@ -3964,7 +3996,7 @@ typename Arm_relocate_functions::Status Arm_relocate_functions::thumb_branch_common( unsigned int r_type, const Relocate_info<32, big_endian>* relinfo, - unsigned char *view, + unsigned char* view, const Sized_symbol<32>* gsym, const Arm_relobj* object, unsigned int r_sym, @@ -3982,7 +4014,7 @@ Arm_relocate_functions::thumb_branch_common( // into account. bool is_bl_insn = (lower_insn & 0x1000U) == 0x1000U; bool is_blx_insn = (lower_insn & 0x1000U) == 0x0000U; - + // Check that the instruction is valid. if (r_type == elfcpp::R_ARM_THM_CALL) { @@ -4005,7 +4037,7 @@ Arm_relocate_functions::thumb_branch_common( gold_warning(_("%s: Thumb BLX instruction targets " "thumb function '%s'."), object->name().c_str(), - (gsym ? gsym->name() : "(local)")); + (gsym ? gsym->name() : "(local)")); // Convert BLX to BL. lower_insn |= 0x1000U; } @@ -4034,14 +4066,14 @@ Arm_relocate_functions::thumb_branch_common( } return This::STATUS_OKAY; } - + int32_t addend = This::thumb32_branch_offset(upper_insn, lower_insn); Arm_address branch_target = psymval->value(object, addend); // For BLX, bit 1 of target address comes from bit 1 of base address. - bool may_use_blx = arm_target->may_use_blx(); + bool may_use_blx = arm_target->may_use_v5t_interworking(); if (thumb_bit == 0 && may_use_blx) - branch_target = utils::bit_select(branch_target, address, 0x2); + branch_target = Bits<32>::bit_select32(branch_target, address, 0x2); int32_t branch_offset = branch_target - address; @@ -4049,8 +4081,8 @@ Arm_relocate_functions::thumb_branch_common( // to switch mode. bool thumb2 = arm_target->using_thumb2(); if (!parameters->options().relocatable() - && ((!thumb2 && utils::has_overflow<23>(branch_offset)) - || (thumb2 && utils::has_overflow<25>(branch_offset)) + && ((!thumb2 && Bits<23>::has_overflow32(branch_offset)) + || (thumb2 && Bits<25>::has_overflow32(branch_offset)) || ((thumb_bit == 0) && (((r_type == elfcpp::R_ARM_THM_CALL) && !may_use_blx) || r_type == elfcpp::R_ARM_THM_JUMP24)))) @@ -4073,8 +4105,8 @@ Arm_relocate_functions::thumb_branch_common( gold_assert(stub != NULL); thumb_bit = stub->stub_template()->entry_in_thumb_mode() ? 1 : 0; branch_target = stub_table->address() + stub->offset() + addend; - if (thumb_bit == 0 && may_use_blx) - branch_target = utils::bit_select(branch_target, address, 0x2); + if (thumb_bit == 0 && may_use_blx) + branch_target = Bits<32>::bit_select32(branch_target, address, 0x2); branch_offset = branch_target - address; } } @@ -4111,11 +4143,11 @@ Arm_relocate_functions::thumb_branch_common( elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn); elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn); - gold_assert(!utils::has_overflow<25>(branch_offset)); + gold_assert(!Bits<25>::has_overflow32(branch_offset)); return ((thumb2 - ? utils::has_overflow<25>(branch_offset) - : utils::has_overflow<23>(branch_offset)) + ? Bits<25>::has_overflow32(branch_offset) + : Bits<23>::has_overflow32(branch_offset)) ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } @@ -4128,7 +4160,7 @@ Arm_relocate_functions::thumb_branch_common( template typename Arm_relocate_functions::Status Arm_relocate_functions::thm_jump19( - unsigned char *view, + unsigned char* view, const Arm_relobj* object, const Symbol_value<32>* psymval, Arm_address address, @@ -4160,7 +4192,7 @@ Arm_relocate_functions::thm_jump19( elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn); elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn); - return (utils::has_overflow<21>(branch_offset) + return (Bits<21>::has_overflow32(branch_offset) ? This::STATUS_OVERFLOW : This::STATUS_OKAY); } @@ -4175,12 +4207,22 @@ Target_arm::got_section(Symbol_table* symtab, Layout* layout) { gold_assert(symtab != NULL && layout != NULL); + // When using -z now, we can treat .got as a relro section. + // Without -z now, it is modified after program startup by lazy + // PLT relocations. + bool is_got_relro = parameters->options().now(); + Output_section_order got_order = (is_got_relro + ? ORDER_RELRO_LAST + : ORDER_DATA); + + // Unlike some targets (.e.g x86), ARM does not use separate .got and + // .got.plt sections in output. The output .got section contains both + // PLT and non-PLT GOT entries. this->got_ = new Arm_output_data_got(symtab, layout); layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, - (elfcpp::SHF_ALLOC - | elfcpp::SHF_WRITE), - this->got_, ORDER_RELRO, true); + (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE), + this->got_, got_order, is_got_relro); // The old GNU linker creates a .got.plt section. We just // create another set of data in the .got section. Note that we @@ -4188,9 +4230,8 @@ Target_arm::got_section(Symbol_table* symtab, Layout* layout) // might be empty. this->got_plt_ = new Output_data_space(4, "** GOT PLT"); layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, - (elfcpp::SHF_ALLOC - | elfcpp::SHF_WRITE), - this->got_plt_, ORDER_DATA, false); + (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE), + this->got_plt_, got_order, is_got_relro); // The first three entries are reserved. this->got_plt_->set_current_data_size(3 * 4); @@ -4290,11 +4331,11 @@ Stub_template::Stub_template( break; case Insn_template::THUMB32_TYPE: - if (insns[i].r_type() != elfcpp::R_ARM_NONE) + if (insns[i].r_type() != elfcpp::R_ARM_NONE) this->relocs_.push_back(Reloc(i, offset)); if (i == 0) this->entry_in_thumb_mode_ = true; - break; + break; case Insn_template::ARM_TYPE: // Handle cases where the target is encoded within the @@ -4312,7 +4353,7 @@ Stub_template::Stub_template( default: gold_unreachable(); } - offset += insn_size; + offset += insn_size; } this->size_ = offset; } @@ -4349,7 +4390,7 @@ Stub::do_fixed_endian_write(unsigned char* view, section_size_type view_size) elfcpp::Swap<16, big_endian>::writeval(pov, hi); elfcpp::Swap<16, big_endian>::writeval(pov + 2, lo); } - break; + break; case Insn_template::ARM_TYPE: case Insn_template::DATA_TYPE: elfcpp::Swap<32, big_endian>::writeval(pov, insns[i].data()); @@ -4360,7 +4401,7 @@ Stub::do_fixed_endian_write(unsigned char* view, section_size_type view_size) pov += insns[i].size(); } gold_assert(static_cast(pov - view) == view_size); -} +} // Reloc_stub::Key methods. @@ -4402,7 +4443,7 @@ Reloc_stub::Key::name() const // Determine the type of stub needed, if any, for a relocation of R_TYPE at // LOCATION to DESTINATION. // This code is based on the arm_type_of_stub function in -// bfd/elf32-arm.c. We have changed the interface a liitle to keep the Stub +// bfd/elf32-arm.c. We have changed the interface a little to keep the Stub // class simple. Stub_type @@ -4424,7 +4465,7 @@ Reloc_stub::stub_type_for_reloc( { const Target_arm* big_endian_target = Target_arm::default_target(); - may_use_blx = big_endian_target->may_use_blx(); + may_use_blx = big_endian_target->may_use_v5t_interworking(); should_force_pic_veneer = big_endian_target->should_force_pic_veneer(); thumb2 = big_endian_target->using_thumb2(); thumb_only = big_endian_target->using_thumb_only(); @@ -4433,21 +4474,23 @@ Reloc_stub::stub_type_for_reloc( { const Target_arm* little_endian_target = Target_arm::default_target(); - may_use_blx = little_endian_target->may_use_blx(); + may_use_blx = little_endian_target->may_use_v5t_interworking(); should_force_pic_veneer = little_endian_target->should_force_pic_veneer(); thumb2 = little_endian_target->using_thumb2(); thumb_only = little_endian_target->using_thumb_only(); } int64_t branch_offset; + bool output_is_position_independent = + parameters->options().output_is_position_independent(); if (r_type == elfcpp::R_ARM_THM_CALL || r_type == elfcpp::R_ARM_THM_JUMP24) { // For THUMB BLX instruction, bit 1 of target comes from bit 1 of the // base address (instruction address + 4). if ((r_type == elfcpp::R_ARM_THM_CALL) && may_use_blx && !target_is_thumb) - destination = utils::bit_select(destination, location, 0x2); + destination = Bits<32>::bit_select32(destination, location, 0x2); branch_offset = static_cast(destination) - location; - + // Handle cases where: // - this call goes too far (different Thumb/Thumb2 max // distance) @@ -4468,7 +4511,7 @@ Reloc_stub::stub_type_for_reloc( // Thumb to thumb. if (!thumb_only) { - stub_type = (parameters->options().shared() + stub_type = (output_is_position_independent || should_force_pic_veneer) // PIC stubs. ? ((may_use_blx @@ -4489,7 +4532,7 @@ Reloc_stub::stub_type_for_reloc( } else { - stub_type = (parameters->options().shared() + stub_type = (output_is_position_independent || should_force_pic_veneer) ? arm_stub_long_branch_thumb_only_pic // PIC stub. : arm_stub_long_branch_thumb_only; // non-PIC stub. @@ -4498,11 +4541,11 @@ Reloc_stub::stub_type_for_reloc( else { // Thumb to arm. - + // FIXME: We should check that the input section is from an // object that has interwork enabled. - stub_type = (parameters->options().shared() + stub_type = (output_is_position_independent || should_force_pic_veneer) // PIC stubs. ? ((may_use_blx @@ -4544,7 +4587,7 @@ Reloc_stub::stub_type_for_reloc( || (r_type == elfcpp::R_ARM_JUMP24) || (r_type == elfcpp::R_ARM_PLT32)) { - stub_type = (parameters->options().shared() + stub_type = (output_is_position_independent || should_force_pic_veneer) // PIC stubs. ? (may_use_blx @@ -4563,7 +4606,7 @@ Reloc_stub::stub_type_for_reloc( if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)) { - stub_type = (parameters->options().shared() + stub_type = (output_is_position_independent || should_force_pic_veneer) ? arm_stub_long_branch_any_arm_pic // PIC stubs. : arm_stub_long_branch_any_any; /// non-PIC. @@ -4599,16 +4642,16 @@ Stub_factory::Stub_factory() { // The instruction template sequences are declared as static // objects and initialized first time the constructor runs. - + // Arm/Thumb -> Arm/Thumb long branch stub. On V5T and above, use blx // to reach the stub if necessary. static const Insn_template elf32_arm_stub_long_branch_any_any[] = { Insn_template::arm_insn(0xe51ff004), // ldr pc, [pc, #-4] Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0), - // dcd R_ARM_ABS32(X) + // dcd R_ARM_ABS32(X) }; - + // V4T Arm -> Thumb long branch stub. Used on V4T where blx is not // available. static const Insn_template elf32_arm_stub_long_branch_v4t_arm_thumb[] = @@ -4616,9 +4659,9 @@ Stub_factory::Stub_factory() Insn_template::arm_insn(0xe59fc000), // ldr ip, [pc, #0] Insn_template::arm_insn(0xe12fff1c), // bx ip Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0), - // dcd R_ARM_ABS32(X) + // dcd R_ARM_ABS32(X) }; - + // Thumb -> Thumb long branch stub. Used on M-profile architectures. static const Insn_template elf32_arm_stub_long_branch_thumb_only[] = { @@ -4629,9 +4672,9 @@ Stub_factory::Stub_factory() Insn_template::thumb16_insn(0x4760), // bx ip Insn_template::thumb16_insn(0xbf00), // nop Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0), - // dcd R_ARM_ABS32(X) + // dcd R_ARM_ABS32(X) }; - + // V4T Thumb -> Thumb long branch stub. Using the stack is not // allowed. static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_thumb[] = @@ -4641,9 +4684,9 @@ Stub_factory::Stub_factory() Insn_template::arm_insn(0xe59fc000), // ldr ip, [pc, #0] Insn_template::arm_insn(0xe12fff1c), // bx ip Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0), - // dcd R_ARM_ABS32(X) + // dcd R_ARM_ABS32(X) }; - + // V4T Thumb -> ARM long branch stub. Used on V4T where blx is not // available. static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_arm[] = @@ -4652,9 +4695,9 @@ Stub_factory::Stub_factory() Insn_template::thumb16_insn(0x46c0), // nop Insn_template::arm_insn(0xe51ff004), // ldr pc, [pc, #-4] Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0), - // dcd R_ARM_ABS32(X) + // dcd R_ARM_ABS32(X) }; - + // V4T Thumb -> ARM short branch stub. Shorter variant of the above // one, when the destination is close enough. static const Insn_template elf32_arm_stub_short_branch_v4t_thumb_arm[] = @@ -4663,7 +4706,7 @@ Stub_factory::Stub_factory() Insn_template::thumb16_insn(0x46c0), // nop Insn_template::arm_rel_insn(0xea000000, -8), // b (X-8) }; - + // ARM/Thumb -> ARM long branch stub, PIC. On V5T and above, use // blx to reach the stub if necessary. static const Insn_template elf32_arm_stub_long_branch_any_arm_pic[] = @@ -4671,9 +4714,9 @@ Stub_factory::Stub_factory() Insn_template::arm_insn(0xe59fc000), // ldr r12, [pc] Insn_template::arm_insn(0xe08ff00c), // add pc, pc, ip Insn_template::data_word(0, elfcpp::R_ARM_REL32, -4), - // dcd R_ARM_REL32(X-4) + // dcd R_ARM_REL32(X-4) }; - + // ARM/Thumb -> Thumb long branch stub, PIC. On V5T and above, use // blx to reach the stub if necessary. We can not add into pc; // it is not guaranteed to mode switch (different in ARMv6 and @@ -4684,9 +4727,9 @@ Stub_factory::Stub_factory() Insn_template::arm_insn(0xe08fc00c), // add ip, pc, ip Insn_template::arm_insn(0xe12fff1c), // bx ip Insn_template::data_word(0, elfcpp::R_ARM_REL32, 0), - // dcd R_ARM_REL32(X) + // dcd R_ARM_REL32(X) }; - + // V4T ARM -> ARM long branch stub, PIC. static const Insn_template elf32_arm_stub_long_branch_v4t_arm_thumb_pic[] = { @@ -4694,9 +4737,9 @@ Stub_factory::Stub_factory() Insn_template::arm_insn(0xe08fc00c), // add ip, pc, ip Insn_template::arm_insn(0xe12fff1c), // bx ip Insn_template::data_word(0, elfcpp::R_ARM_REL32, 0), - // dcd R_ARM_REL32(X) + // dcd R_ARM_REL32(X) }; - + // V4T Thumb -> ARM long branch stub, PIC. static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_arm_pic[] = { @@ -4705,9 +4748,9 @@ Stub_factory::Stub_factory() Insn_template::arm_insn(0xe59fc000), // ldr ip, [pc, #0] Insn_template::arm_insn(0xe08cf00f), // add pc, ip, pc Insn_template::data_word(0, elfcpp::R_ARM_REL32, -4), - // dcd R_ARM_REL32(X) + // dcd R_ARM_REL32(X) }; - + // Thumb -> Thumb long branch stub, PIC. Used on M-profile // architectures. static const Insn_template elf32_arm_stub_long_branch_thumb_only_pic[] = @@ -4719,9 +4762,9 @@ Stub_factory::Stub_factory() Insn_template::thumb16_insn(0xbc01), // pop {r0} Insn_template::thumb16_insn(0x4760), // bx ip Insn_template::data_word(0, elfcpp::R_ARM_REL32, 4), - // dcd R_ARM_REL32(X) + // dcd R_ARM_REL32(X) }; - + // V4T Thumb -> Thumb long branch stub, PIC. Using the stack is not // allowed. static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_thumb_pic[] = @@ -4732,14 +4775,14 @@ Stub_factory::Stub_factory() Insn_template::arm_insn(0xe08fc00c), // add ip, pc, ip Insn_template::arm_insn(0xe12fff1c), // bx ip Insn_template::data_word(0, elfcpp::R_ARM_REL32, 0), - // dcd R_ARM_REL32(X) + // dcd R_ARM_REL32(X) }; - + // Cortex-A8 erratum-workaround stubs. - + // Stub used for conditional branches (which may be beyond +/-1MB away, // so we can't use a conditional branch to reach this stub). - + // original code: // // b X @@ -4750,21 +4793,21 @@ Stub_factory::Stub_factory() Insn_template::thumb16_bcond_insn(0xd001), // b.n true Insn_template::thumb32_b_insn(0xf000b800, -4), // b.w after Insn_template::thumb32_b_insn(0xf000b800, -4) // true: - // b.w X + // b.w X }; - + // Stub used for b.w and bl.w instructions. - + static const Insn_template elf32_arm_stub_a8_veneer_b[] = { Insn_template::thumb32_b_insn(0xf000b800, -4) // b.w dest }; - + static const Insn_template elf32_arm_stub_a8_veneer_bl[] = { Insn_template::thumb32_b_insn(0xf000b800, -4) // b.w dest }; - + // Stub used for Thumb-2 blx.w instructions. We modified the original blx.w // instruction (which switches to ARM mode) to point to this stub. Jump to // the real destination using an ARM-mode branch. @@ -4806,7 +4849,7 @@ Stub_factory::Stub_factory() // Stub_table methods. -// Removel all Cortex-A8 stub. +// Remove all Cortex-A8 stub. template void @@ -4985,7 +5028,7 @@ Stub_table::update_data_size_and_addralign() // Update prev_data_size_ and prev_addralign_. These will be used // as the current data size and address alignment for the next pass. bool changed = size != this->prev_data_size_; - this->prev_data_size_ = size; + this->prev_data_size_ = size; if (addralign != this->prev_addralign_) changed = true; @@ -5083,13 +5126,23 @@ Arm_input_section::init() Relobj* relobj = this->relobj(); unsigned int shndx = this->shndx(); - // Cache these to speed up size and alignment queries. It is too slow - // to call section_addraglin and section_size every time. + // We have to cache original size, alignment and contents to avoid locking + // the original file. this->original_addralign_ = convert_types(relobj->section_addralign(shndx)); + + // This is not efficient but we expect only a small number of relaxed + // input sections for stubs. + section_size_type section_size; + const unsigned char* section_contents = + relobj->section_contents(shndx, §ion_size, false); this->original_size_ = convert_types(relobj->section_size(shndx)); + gold_assert(this->original_contents_ == NULL); + this->original_contents_ = new unsigned char[section_size]; + memcpy(this->original_contents_, section_contents, section_size); + // We want to make this look like the original input section after // output sections are finalized. Output_section* os = relobj->output_section(shndx); @@ -5107,10 +5160,9 @@ void Arm_input_section::do_write(Output_file* of) { // We have to write out the original section content. - section_size_type section_size; - const unsigned char* section_contents = - this->relobj()->section_contents(this->shndx(), §ion_size, false); - of->write(this->offset(), section_contents, section_size); + gold_assert(this->original_contents_ != NULL); + of->write(this->offset(), this->original_contents_, + this->original_size_); // If this owns a stub table and it is not empty, write it. if (this->is_stub_table_owner() && !this->stub_table_->empty()) @@ -5169,9 +5221,6 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of) off_t offset = this->offset(); const section_size_type oview_size = 8; unsigned char* const oview = of->get_output_view(offset, oview_size); - - typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; - Valtype* wv = reinterpret_cast(oview); Output_section* os = this->relobj_->output_section(this->shndx_); gold_assert(os != NULL); @@ -5181,8 +5230,18 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of) Arm_address output_offset = arm_relobj->get_output_section_offset(this->shndx_); Arm_address section_start; + section_size_type section_size; + + // Find out the end of the text section referred by this. if (output_offset != Arm_relobj::invalid_address) - section_start = os->address() + output_offset; + { + section_start = os->address() + output_offset; + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_link(this->shndx_); + gold_assert(exidx_input_section != NULL); + section_size = + convert_to_section_size_type(exidx_input_section->text_size()); + } else { // Currently this only happens for a relaxed section. @@ -5190,20 +5249,22 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of) os->find_relaxed_input_section(this->relobj_, this->shndx_); gold_assert(poris != NULL); section_start = poris->address(); + section_size = convert_to_section_size_type(poris->data_size()); } // We always append this to the end of an EXIDX section. - Arm_address output_address = - section_start + this->relobj_->section_size(this->shndx_); + Arm_address output_address = section_start + section_size; // Write out the entry. The first word either points to the beginning // or after the end of a text section. The second word is the special // EXIDX_CANTUNWIND value. uint32_t prel31_offset = output_address - this->address(); - if (utils::has_overflow<31>(offset)) + if (Bits<31>::has_overflow32(offset)) gold_error(_("PREL31 overflow in EXIDX_CANTUNWIND entry")); - elfcpp::Swap<32, big_endian>::writeval(wv, prel31_offset & 0x7fffffffU); - elfcpp::Swap<32, big_endian>::writeval(wv + 1, elfcpp::EXIDX_CANTUNWIND); + elfcpp::Swap_unaligned<32, big_endian>::writeval(oview, + prel31_offset & 0x7fffffffU); + elfcpp::Swap_unaligned<32, big_endian>::writeval(oview + 4, + elfcpp::EXIDX_CANTUNWIND); of->write_output_view(this->offset(), oview_size, oview); } @@ -5226,9 +5287,59 @@ Arm_exidx_merged_section::Arm_exidx_merged_section( exidx_input_section_(exidx_input_section), section_offset_map_(section_offset_map) { + // If we retain or discard the whole EXIDX input section, we would + // not be here. + gold_assert(deleted_bytes != 0 + && deleted_bytes != this->exidx_input_section_.size()); + // Fix size here so that we do not need to implement set_final_data_size. - this->set_data_size(exidx_input_section.size() - deleted_bytes); + uint32_t size = exidx_input_section.size() - deleted_bytes; + this->set_data_size(size); this->fix_data_size(); + + // Allocate buffer for section contents and build contents. + this->section_contents_ = new unsigned char[size]; +} + +// Build the contents of a merged EXIDX output section. + +void +Arm_exidx_merged_section::build_contents( + const unsigned char* original_contents, + section_size_type original_size) +{ + // Go over spans of input offsets and write only those that are not + // discarded. + section_offset_type in_start = 0; + section_offset_type out_start = 0; + section_offset_type in_max = + convert_types(original_size); + section_offset_type out_max = + convert_types(this->data_size()); + for (Arm_exidx_section_offset_map::const_iterator p = + this->section_offset_map_.begin(); + p != this->section_offset_map_.end(); + ++p) + { + section_offset_type in_end = p->first; + gold_assert(in_end >= in_start); + section_offset_type out_end = p->second; + size_t in_chunk_size = convert_types(in_end - in_start + 1); + if (out_end != -1) + { + size_t out_chunk_size = + convert_types(out_end - out_start + 1); + + gold_assert(out_chunk_size == in_chunk_size + && in_end < in_max && out_end < out_max); + + memcpy(this->section_contents_ + out_start, + original_contents + in_start, + out_chunk_size); + out_start += out_chunk_size; + } + in_start += in_chunk_size; + } } // Given an input OBJECT, an input section index SHNDX within that @@ -5278,7 +5389,7 @@ Arm_exidx_merged_section::do_output_offset( // Offset is discarded owing to EXIDX entry merging. *poutput = -1; } - + return true; } @@ -5287,52 +5398,16 @@ Arm_exidx_merged_section::do_output_offset( void Arm_exidx_merged_section::do_write(Output_file* of) { - // If we retain or discard the whole EXIDX input section, we would - // not be here. - gold_assert(this->data_size() != this->exidx_input_section_.size() - && this->data_size() != 0); - off_t offset = this->offset(); const section_size_type oview_size = this->data_size(); unsigned char* const oview = of->get_output_view(offset, oview_size); - + Output_section* os = this->relobj()->output_section(this->shndx()); gold_assert(os != NULL); - // Get contents of EXIDX input section. - section_size_type section_size; - const unsigned char* section_contents = - this->relobj()->section_contents(this->shndx(), §ion_size, false); - gold_assert(section_size == this->exidx_input_section_.size()); - - // Go over spans of input offsets and write only those that are not - // discarded. - section_offset_type in_start = 0; - section_offset_type out_start = 0; - for(Arm_exidx_section_offset_map::const_iterator p = - this->section_offset_map_.begin(); - p != this->section_offset_map_.end(); - ++p) - { - section_offset_type in_end = p->first; - gold_assert(in_end >= in_start); - section_offset_type out_end = p->second; - size_t in_chunk_size = convert_types(in_end - in_start + 1); - if (out_end != -1) - { - size_t out_chunk_size = - convert_types(out_end - out_start + 1); - gold_assert(out_chunk_size == in_chunk_size); - memcpy(oview + out_start, section_contents + in_start, - out_chunk_size); - out_start += out_chunk_size; - } - in_start += in_chunk_size; - } - - gold_assert(convert_to_section_size_type(out_start) == oview_size); - of->write_output_view(this->offset(), oview_size, oview); -} + memcpy(oview, this->section_contents_, oview_size); + of->write_output_view(this->offset(), oview_size, oview); +} // Arm_exidx_fixup methods. @@ -5411,21 +5486,22 @@ Arm_exidx_fixup::update_offset_map( } // Process EXIDX_INPUT_SECTION for EXIDX entry merging. Return the number of -// bytes deleted. If some entries are merged, also store a pointer to a newly -// created Arm_exidx_section_offset_map object in *PSECTION_OFFSET_MAP. The -// caller owns the map and is responsible for releasing it after use. +// bytes deleted. SECTION_CONTENTS points to the contents of the EXIDX +// section and SECTION_SIZE is the number of bytes pointed by SECTION_CONTENTS. +// If some entries are merged, also store a pointer to a newly created +// Arm_exidx_section_offset_map object in *PSECTION_OFFSET_MAP. The caller +// owns the map and is responsible for releasing it after use. template uint32_t Arm_exidx_fixup::process_exidx_section( const Arm_exidx_input_section* exidx_input_section, + const unsigned char* section_contents, + section_size_type section_size, Arm_exidx_section_offset_map** psection_offset_map) { Relobj* relobj = exidx_input_section->relobj(); unsigned shndx = exidx_input_section->shndx(); - section_size_type section_size; - const unsigned char* section_contents = - relobj->section_contents(shndx, §ion_size, false); if ((section_size % 8) != 0) { @@ -5436,7 +5512,7 @@ Arm_exidx_fixup::process_exidx_section( this->last_unwind_type_ = UT_NONE; return 0; } - + uint32_t deleted_bytes = 0; bool prev_delete_entry = false; gold_assert(this->section_offset_map_ == NULL); @@ -5458,7 +5534,7 @@ Arm_exidx_fixup::process_exidx_section( // dropping. If there is no entry (x0, y0) for an input offset x0, // the output offset y0 of it is determined by the output offset y1 of // the smallest input offset x1 > x0 that there is an (x1, y1) entry - // in the map. If y1 is not -1, then y0 = y1 + x0 - x1. Othewise, y1 + // in the map. If y1 is not -1, then y0 = y1 + x0 - x1. Otherwise, y1 // y0 is also -1. if (delete_entry != prev_delete_entry && i != 0) this->update_offset_map(i - 1, deleted_bytes, prev_delete_entry); @@ -5469,7 +5545,7 @@ Arm_exidx_fixup::process_exidx_section( prev_delete_entry = delete_entry; } - + // If section offset map is not NULL, make an entry for the end of // section. if (this->section_offset_map_ != NULL) @@ -5478,7 +5554,7 @@ Arm_exidx_fixup::process_exidx_section( *psection_offset_map = this->section_offset_map_; this->section_offset_map_ = NULL; this->last_input_section_ = exidx_input_section; - + // Set the first output text section so that we can link the EXIDX output // section to it. Ignore any EXIDX input section that is completely merged. if (this->first_output_text_section_ == NULL @@ -5505,19 +5581,20 @@ Arm_output_section::create_stub_group( Input_section_list::const_iterator end, Input_section_list::const_iterator owner, Target_arm* target, - std::vector* new_relaxed_sections) + std::vector* new_relaxed_sections, + const Task* task) { // We use a different kind of relaxed section in an EXIDX section. // The static casting from Output_relaxed_input_section to // Arm_input_section is invalid in an EXIDX section. We are okay - // because we should not be calling this for an EXIDX section. + // because we should not be calling this for an EXIDX section. gold_assert(this->type() != elfcpp::SHT_ARM_EXIDX); // Currently we convert ordinary input sections into relaxed sections only // at this point but we may want to support creating relaxed input section // very early. So we check here to see if owner is already a relaxed // section. - + Arm_input_section* arm_input_section; if (owner->is_relaxed_input_section()) { @@ -5528,7 +5605,9 @@ Arm_output_section::create_stub_group( else { gold_assert(owner->is_input_section()); - // Create a new relaxed input section. + // Create a new relaxed input section. We need to lock the original + // file. + Task_lock_obj tl(task, owner->relobj()); arm_input_section = target->new_arm_input_section(owner->relobj(), owner->shndx()); new_relaxed_sections->push_back(arm_input_section); @@ -5539,7 +5618,7 @@ Arm_output_section::create_stub_group( target->new_stub_table(arm_input_section); arm_input_section->set_stub_table(stub_table); - + Input_section_list::const_iterator p = begin; Input_section_list::const_iterator prev_p; @@ -5564,7 +5643,7 @@ Arm_output_section::create_stub_group( // size is just below GROUP_SIZE. The last input section will be converted // into a stub table. If STUB_ALWAYS_AFTER_BRANCH is false, we also add // input section after the stub table, effectively double the group size. -// +// // This is similar to the group_sections() function in elf32-arm.c but is // implemented differently. @@ -5573,12 +5652,9 @@ void Arm_output_section::group_sections( section_size_type group_size, bool stubs_always_after_branch, - Target_arm* target) + Target_arm* target, + const Task* task) { - // We only care about sections containing code. - if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0) - return; - // States for grouping. typedef enum { @@ -5614,9 +5690,9 @@ Arm_output_section::group_sections( section_size_type section_begin_offset = align_address(off, p->addralign()); section_size_type section_end_offset = - section_begin_offset + p->data_size(); - - // Check to see if we should group the previously seens sections. + section_begin_offset + p->data_size(); + + // Check to see if we should group the previously seen sections. switch (state) { case NO_GROUP: @@ -5627,10 +5703,11 @@ Arm_output_section::group_sections( if (section_end_offset - group_begin_offset >= group_size) { if (stubs_always_after_branch) - { + { gold_assert(group_end != this->input_sections().end()); this->create_stub_group(group_begin, group_end, group_end, - target, &new_relaxed_sections); + target, &new_relaxed_sections, + task); state = NO_GROUP; } else @@ -5652,19 +5729,20 @@ Arm_output_section::group_sections( { gold_assert(group_end != this->input_sections().end()); this->create_stub_group(group_begin, group_end, stub_table, - target, &new_relaxed_sections); + target, &new_relaxed_sections, task); state = NO_GROUP; } break; default: gold_unreachable(); - } + } // If we see an input section and currently there is no group, start - // a new one. Skip any empty sections. + // a new one. Skip any empty sections. We look at the data size + // instead of calling p->relobj()->section_size() to avoid locking. if ((p->is_input_section() || p->is_relaxed_input_section()) - && (p->relobj()->section_size(p->shndx()) != 0)) + && (p->data_size() != 0)) { if (state == NO_GROUP) { @@ -5689,7 +5767,7 @@ Arm_output_section::group_sections( (state == FINDING_STUB_SECTION ? group_end : stub_table), - target, &new_relaxed_sections); + target, &new_relaxed_sections, task); } // Convert input section into relaxed input section in a batch. @@ -5724,8 +5802,7 @@ Arm_output_section::append_text_sections_to_list( { // We only care about plain or relaxed input sections. We also // ignore any merged sections. - if ((p->is_input_section() || p->is_relaxed_input_section()) - && p->data_size() != 0) + if (p->is_input_section() || p->is_relaxed_input_section()) list->push_back(Text_section_list::value_type(p->relobj(), p->shndx())); } @@ -5737,7 +5814,8 @@ Arm_output_section::fix_exidx_coverage( Layout* layout, const Text_section_list& sorted_text_sections, Symbol_table* symtab, - bool merge_exidx_entries) + bool merge_exidx_entries, + const Task* task) { // We should only do this for the EXIDX output section. gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX); @@ -5755,7 +5833,7 @@ Arm_output_section::fix_exidx_coverage( if (!this->input_sections().empty()) gold_error(_("Found non-EXIDX input sections in EXIDX output section")); - + // Go through all the known input sections and record them. typedef Unordered_set Section_id_set; typedef Unordered_map::fix_exidx_coverage( continue; } + // We need to access the contents of the EXIDX section, lock the + // object here. + Task_lock_obj tl(task, exidx_relobj); + section_size_type exidx_size; + const unsigned char* exidx_contents = + exidx_relobj->section_contents(exidx_shndx, &exidx_size, false); + // Fix up coverage and append input section to output data list. Arm_exidx_section_offset_map* section_offset_map = NULL; uint32_t deleted_bytes = - exidx_fixup.process_exidx_section(exidx_input_section, + exidx_fixup.process_exidx_section(exidx_input_section, + exidx_contents, + exidx_size, §ion_offset_map); if (deleted_bytes == exidx_input_section->size()) @@ -5841,10 +5928,14 @@ Arm_output_section::fix_exidx_coverage( // Some entries are merged. We need to convert this EXIDX input // section into a relaxed section. gold_assert(section_offset_map != NULL); + Arm_exidx_merged_section* merged_section = new Arm_exidx_merged_section(*exidx_input_section, *section_offset_map, deleted_bytes); - this->add_relaxed_input_section(merged_section); + merged_section->build_contents(exidx_contents, exidx_size); + + const std::string secname = exidx_relobj->section_name(exidx_shndx); + this->add_relaxed_input_section(layout, merged_section, secname); arm_relobj->convert_input_section_to_relaxed_section(exidx_shndx); // All local symbols defined in discarded portions of this input @@ -5861,7 +5952,7 @@ Arm_output_section::fix_exidx_coverage( this->add_script_input_section(*pis); } - processed_input_sections.insert(Section_id(exidx_relobj, exidx_shndx)); + processed_input_sections.insert(Section_id(exidx_relobj, exidx_shndx)); } // Insert an EXIDX_CANTUNWIND entry at the end of output if necessary. @@ -5896,7 +5987,7 @@ Arm_output_section::fix_exidx_coverage( arm_relobj->set_output_local_symbol_count_needs_update(); } } - + // Link exidx output section to the first seen output section and // set correct entry size. this->set_link_section(exidx_fixup.first_output_text_section()); @@ -5942,7 +6033,7 @@ Arm_relobj::section_is_scannable( const elfcpp::Shdr<32, big_endian>& shdr, unsigned int shndx, const Output_section* os, - const Symbol_table *symtab) + const Symbol_table* symtab) { // Skip any empty sections, unallocated sections or sections whose // type are not SHT_PROGBITS. @@ -5977,7 +6068,7 @@ bool Arm_relobj::section_needs_reloc_stub_scanning( const elfcpp::Shdr<32, big_endian>& shdr, const Relobj::Output_sections& out_sections, - const Symbol_table *symtab, + const Symbol_table* symtab, const unsigned char* pshdrs) { unsigned int sh_type = shdr.get_sh_type(); @@ -6103,7 +6194,7 @@ Arm_relobj::scan_section_for_cortex_a8_erratum( // scan. There are two reasons. First, we should look at THUMB code and // THUMB code only. Second, we only want to look at the 4K-page boundary // to speed up the scanning. - + while (p != this->mapping_symbols_info_.end() && p->first.first == shndx) { @@ -6122,7 +6213,7 @@ Arm_relobj::scan_section_for_cortex_a8_erratum( span_end = convert_to_section_size_type(next->first.second); else span_end = convert_to_section_size_type(shdr.get_sh_size()); - + if (((span_start + output_address) & ~0xfffUL) != ((span_end + output_address - 1) & ~0xfffUL)) { @@ -6133,7 +6224,7 @@ Arm_relobj::scan_section_for_cortex_a8_erratum( } } - p = next; + p = next; } } @@ -6248,8 +6339,8 @@ Arm_relobj::scan_sections_for_stubs( // harder because we cannot access this information. So we override the // do_count_local_symbol in parent and scan local symbols to mark // THUMB functions. This is not the most efficient way but I do not want to -// slow down other ports by calling a per symbol targer hook inside -// Sized_relobj::do_count_local_symbols. +// slow down other ports by calling a per symbol target hook inside +// Sized_relobj_file::do_count_local_symbols. template void @@ -6259,14 +6350,14 @@ Arm_relobj::do_count_local_symbols( { // We need to fix-up the values of any local symbols whose type are // STT_ARM_TFUNC. - + // Ask parent to count the local symbols. - Sized_relobj<32, big_endian>::do_count_local_symbols(pool, dynpool); + Sized_relobj_file<32, big_endian>::do_count_local_symbols(pool, dynpool); const unsigned int loccount = this->local_symbol_count(); if (loccount == 0) return; - // Intialize the thumb function bit-vector. + // Initialize the thumb function bit-vector. std::vector empty_vector(loccount, false); this->local_symbol_is_thumb_function_.swap(empty_vector); @@ -6296,7 +6387,7 @@ Arm_relobj::do_count_local_symbols( if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB) { this->error(_("symbol table name section has wrong type: %u"), - static_cast(strtabshdr.get_sh_type())); + static_cast(strtabshdr.get_sh_type())); return; } const char* pnames = @@ -6309,7 +6400,7 @@ Arm_relobj::do_count_local_symbols( // Skip the first dummy symbol. psyms += sym_size; - typename Sized_relobj<32, big_endian>::Local_values* plocal_values = + typename Sized_relobj_file<32, big_endian>::Local_values* plocal_values = this->local_values(); for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size) { @@ -6351,11 +6442,12 @@ Arm_relobj::do_relocate_sections( const Symbol_table* symtab, const Layout* layout, const unsigned char* pshdrs, - typename Sized_relobj<32, big_endian>::Views* pviews) + Output_file* of, + typename Sized_relobj_file<32, big_endian>::Views* pviews) { // Call parent to relocate sections. - Sized_relobj<32, big_endian>::do_relocate_sections(symtab, layout, pshdrs, - pviews); + Sized_relobj_file<32, big_endian>::do_relocate_sections(symtab, layout, + pshdrs, of, pviews); // We do not generate stubs if doing a relocatable link. if (parameters->options().relocatable()) @@ -6403,7 +6495,7 @@ Arm_relobj::do_relocate_sections( unsigned char* view = (*pviews)[i].view + offset; Arm_address address = stub_table->address(); section_size_type view_size = stub_table->data_size(); - + stub_table->relocate_stubs(&relinfo, arm_target, os, view, address, view_size); } @@ -6440,9 +6532,9 @@ Arm_relobj::do_relocate_sections( } } -// Find the linked text section of an EXIDX section by looking the the first +// Find the linked text section of an EXIDX section by looking at the first // relocation. 4.4.1 of the EHABI specifications says that an EXIDX section -// must be linked to to its associated code section via the sh_link field of +// must be linked to its associated code section via the sh_link field of // its section header. However, some tools are broken and the link is not // always set. LD just drops such an EXIDX section silently, causing the // associated code not unwindabled. Here we try a little bit harder to @@ -6461,7 +6553,7 @@ Arm_relobj::find_linked_text_section( unsigned int* pshndx) { elfcpp::Shdr<32, big_endian> shdr(pshdr); - + // If there is no relocation, we cannot find the linked text section. size_t reloc_size; if (shdr.get_sh_type() == elfcpp::SHT_REL) @@ -6469,10 +6561,10 @@ Arm_relobj::find_linked_text_section( else reloc_size = elfcpp::Elf_sizes<32>::rela_size; size_t reloc_count = shdr.get_sh_size() / reloc_size; - + // Get the relocations. const unsigned char* prelocs = - this->get_view(shdr.get_sh_offset(), shdr.get_sh_size(), true, false); + this->get_view(shdr.get_sh_offset(), shdr.get_sh_size(), true, false); // Find the REL31 relocation for the first word of the first EXIDX entry. for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size) @@ -6536,7 +6628,8 @@ Arm_relobj::make_exidx_input_section( // Create an Arm_exidx_input_section object for this EXIDX section. Arm_exidx_input_section* exidx_input_section = new Arm_exidx_input_section(this, shndx, text_shndx, shdr.get_sh_size(), - shdr.get_sh_addralign()); + shdr.get_sh_addralign(), + text_shdr.get_sh_size()); gold_assert(this->exidx_section_map_[shndx] == NULL); this->exidx_section_map_[shndx] = exidx_input_section; @@ -6547,7 +6640,7 @@ Arm_relobj::make_exidx_input_section( this->section_name(shndx).c_str(), shndx, text_shndx, this->name().c_str()); exidx_input_section->set_has_errors(); - } + } else if (this->exidx_section_map_[text_shndx] != NULL) { unsigned other_exidx_shndx = @@ -6574,7 +6667,7 @@ Arm_relobj::make_exidx_input_section( exidx_input_section->set_has_errors(); } else if ((text_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) == 0) - // I would like to make this an error but currenlty ld just ignores + // I would like to make this an error but currently ld just ignores // this. gold_warning(_("EXIDX section %s(%u) links to non-executable section " "%s(%u) in %s"), @@ -6590,7 +6683,7 @@ void Arm_relobj::do_read_symbols(Read_symbols_data* sd) { // Call parent class to read symbol information. - Sized_relobj<32, big_endian>::do_read_symbols(sd); + Sized_relobj_file<32, big_endian>::do_read_symbols(sd); // If this input file is a binary file, it has no processor // specific flags and attributes section. @@ -6614,7 +6707,7 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) std::vector deferred_exidx_sections; const size_t shdr_size = elfcpp::Elf_sizes<32>::shdr_size; const unsigned char* pshdrs = sd->section_headers->data(); - const unsigned char *ps = pshdrs + shdr_size; + const unsigned char* ps = pshdrs + shdr_size; bool must_merge_flags_and_attributes = false; for (unsigned int i = 1; i < this->shnum(); ++i, ps += shdr_size) { @@ -6638,14 +6731,14 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) if (shdr.get_sh_type() == elfcpp::SHT_ARM_ATTRIBUTES) { - gold_assert(this->attributes_section_data_ == NULL); + gold_assert(this->attributes_section_data_ == NULL); section_offset_type section_offset = shdr.get_sh_offset(); section_size_type section_size = convert_to_section_size_type(shdr.get_sh_size()); - File_view* view = this->get_lasting_view(section_offset, - section_size, true, false); + const unsigned char* view = + this->get_view(section_offset, section_size, true, false); this->attributes_section_data_ = - new Attributes_section_data(view->data(), section_size); + new Attributes_section_data(view, section_size); } else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX) { @@ -6658,6 +6751,10 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) + text_shndx * shdr_size); this->make_exidx_input_section(i, shdr, text_shndx, text_shdr); } + // EHABI 4.4.1 requires that SHF_LINK_ORDER flag to be set. + if ((shdr.get_sh_flags() & elfcpp::SHF_LINK_ORDER) == 0) + gold_warning(_("SHF_LINK_ORDER not set in EXIDX section %s of %s"), + this->section_name(i).c_str(), this->name().c_str()); } } @@ -6669,7 +6766,7 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) return; } - // Some tools are broken and they do not set the link of EXIDX sections. + // Some tools are broken and they do not set the link of EXIDX sections. // We look at the first relocation to figure out the linked sections. if (!deferred_exidx_sections.empty()) { @@ -6715,8 +6812,8 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(), locsize, true, true); - // Process the deferred EXIDX sections. - for(unsigned int i = 0; i < deferred_exidx_sections.size(); ++i) + // Process the deferred EXIDX sections. + for (unsigned int i = 0; i < deferred_exidx_sections.size(); ++i) { unsigned int shndx = deferred_exidx_sections[i]; elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size); @@ -6733,8 +6830,8 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) } // Process relocations for garbage collection. The ARM target uses .ARM.exidx -// sections for unwinding. These sections are referenced implicitly by -// text sections linked in the section headers. If we ignore these implict +// sections for unwinding. These sections are referenced implicitly by +// text sections linked in the section headers. If we ignore these implicit // references, the .ARM.exidx sections and any .ARM.extab sections they use // will be garbage-collected incorrectly. Hence we override the same function // in the base class to handle these implicit references. @@ -6746,13 +6843,13 @@ Arm_relobj::do_gc_process_relocs(Symbol_table* symtab, Read_relocs_data* rd) { // First, call base class method to process relocations in this object. - Sized_relobj<32, big_endian>::do_gc_process_relocs(symtab, layout, rd); + Sized_relobj_file<32, big_endian>::do_gc_process_relocs(symtab, layout, rd); // If --gc-sections is not specified, there is nothing more to do. // This happens when --icf is used but --gc-sections is not. if (!parameters->options().gc_sections()) return; - + unsigned int shnum = this->shnum(); const unsigned int shdr_size = elfcpp::Elf_sizes<32>::shdr_size; const unsigned char* pshdrs = this->get_view(this->elf_file()->shoff(), @@ -6811,7 +6908,7 @@ Arm_relobj::update_output_local_symbol_count() // Loop over the local symbols. - typedef typename Sized_relobj<32, big_endian>::Output_sections + typedef typename Sized_relobj_file<32, big_endian>::Output_sections Output_sections; const Output_sections& out_sections(this->output_sections()); unsigned int shnum = this->shnum(); @@ -6857,7 +6954,7 @@ Arm_relobj::update_output_local_symbol_count() // that is discarded due to entry merging. lv.set_no_output_symtab_entry(); continue; - } + } } } @@ -6890,7 +6987,7 @@ Arm_dynobj::do_read_symbols(Read_symbols_data* sd) // We read from the end because gas seems to put it near the end of // the section headers. const size_t shdr_size = elfcpp::Elf_sizes<32>::shdr_size; - const unsigned char *ps = + const unsigned char* ps = sd->section_headers->data() + shdr_size * (this->shnum() - 1); for (unsigned int i = this->shnum(); i > 0; --i, ps -= shdr_size) { @@ -6900,10 +6997,10 @@ Arm_dynobj::do_read_symbols(Read_symbols_data* sd) section_offset_type section_offset = shdr.get_sh_offset(); section_size_type section_size = convert_to_section_size_type(shdr.get_sh_size()); - File_view* view = this->get_lasting_view(section_offset, - section_size, true, false); + const unsigned char* view = + this->get_view(section_offset, section_size, true, false); this->attributes_section_data_ = - new Attributes_section_data(view->data(), section_size); + new Attributes_section_data(view, section_size); break; } } @@ -6920,8 +7017,8 @@ Stub_addend_reader::operator()( const unsigned char* view, const typename Reloc_types::Reloc&) const { - typedef struct Arm_relocate_functions RelocFuncs; - + typedef class Arm_relocate_functions RelocFuncs; + switch (r_type) { case elfcpp::R_ARM_CALL: @@ -6931,7 +7028,7 @@ Stub_addend_reader::operator()( typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; const Valtype* wv = reinterpret_cast(view); Valtype val = elfcpp::Swap<32, big_endian>::readval(wv); - return utils::sign_extend<26>(val << 2); + return Bits<26>::sign_extend32(val << 2); } case elfcpp::R_ARM_THM_CALL: @@ -6979,7 +7076,7 @@ Arm_output_data_got::add_tls_gd32_with_static_reloc( // We are doing a static link. Just mark it as belong to module 1, // the executable. unsigned int got_offset = this->add_constant(1); - gsym->set_got_offset(got_type, got_offset); + gsym->set_got_offset(got_type, got_offset); got_offset = this->add_constant(0); this->static_relocs_.push_back(Static_reloc(got_offset, elfcpp::R_ARM_TLS_DTPOFF32, @@ -6992,7 +7089,7 @@ template void Arm_output_data_got::add_tls_gd32_with_static_reloc( unsigned int got_type, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int index) { if (object->local_has_got_offset(index, got_type)) @@ -7003,8 +7100,8 @@ Arm_output_data_got::add_tls_gd32_with_static_reloc( unsigned int got_offset = this->add_constant(1); object->set_local_got_offset(index, got_type, got_offset); got_offset = this->add_constant(0); - this->static_relocs_.push_back(Static_reloc(got_offset, - elfcpp::R_ARM_TLS_DTPOFF32, + this->static_relocs_.push_back(Static_reloc(got_offset, + elfcpp::R_ARM_TLS_DTPOFF32, object, index)); } @@ -7028,7 +7125,7 @@ Arm_output_data_got::do_write(Output_file* of) Output_segment* tls_segment = this->layout_->tls_segment(); gold_assert(tls_segment != NULL); - + // The thread pointer $tp points to the TCB, which is followed by the // TLS. So we need to adjust $tp relative addressing by this amount. Arm_address aligned_tcb_size = @@ -7037,11 +7134,11 @@ Arm_output_data_got::do_write(Output_file* of) for (size_t i = 0; i < this->static_relocs_.size(); ++i) { Static_reloc& reloc(this->static_relocs_[i]); - + Arm_address value; if (!reloc.symbol_is_global()) { - Sized_relobj<32, big_endian>* object = reloc.relobj(); + Sized_relobj_file<32, big_endian>* object = reloc.relobj(); const Symbol_value<32>* psymval = reloc.relobj()->local_symbol(reloc.index()); @@ -7060,7 +7157,7 @@ Arm_output_data_got::do_write(Output_file* of) reloc.index(), reloc.relobj()->name().c_str()); continue; } - + value = psymval->value(object, 0); } else @@ -7116,6 +7213,9 @@ Arm_output_data_got::do_write(Output_file* of) } // A class to handle the PLT data. +// This is an abstract base class that handles most of the linker details +// but does not know the actual contents of PLT entries. The derived +// classes below fill in those details. template class Output_data_plt_arm : public Output_section_data @@ -7124,7 +7224,7 @@ class Output_data_plt_arm : public Output_section_data typedef Output_data_reloc Reloc_section; - Output_data_plt_arm(Layout*, Output_data_space*); + Output_data_plt_arm(Layout*, uint64_t addralign, Output_data_space*); // Add an entry to the PLT. void @@ -7141,16 +7241,49 @@ class Output_data_plt_arm : public Output_section_data { return this->count_; } // Return the offset of the first non-reserved PLT entry. - static unsigned int - first_plt_entry_offset() - { return sizeof(first_plt_entry); } + unsigned int + first_plt_entry_offset() const + { return this->do_first_plt_entry_offset(); } // Return the size of a PLT entry. - static unsigned int - get_plt_entry_size() - { return sizeof(plt_entry); } + unsigned int + get_plt_entry_size() const + { return this->do_get_plt_entry_size(); } protected: + // Fill in the first PLT entry. + void + fill_first_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address) + { this->do_fill_first_plt_entry(pov, got_address, plt_address); } + + void + fill_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset) + { do_fill_plt_entry(pov, got_address, plt_address, got_offset, plt_offset); } + + virtual unsigned int + do_first_plt_entry_offset() const = 0; + + virtual unsigned int + do_get_plt_entry_size() const = 0; + + virtual void + do_fill_first_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address) = 0; + + virtual void + do_fill_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset) = 0; + void do_adjust_output_section(Output_section* os); @@ -7160,18 +7293,12 @@ class Output_data_plt_arm : public Output_section_data { mapfile->print_output_data(this, _("** PLT")); } private: - // Template for the first PLT entry. - static const uint32_t first_plt_entry[5]; - - // Template for subsequent PLT entries. - static const uint32_t plt_entry[3]; - // Set the final size. void set_final_data_size() { - this->set_data_size(sizeof(first_plt_entry) - + this->count_ * sizeof(plt_entry)); + this->set_data_size(this->first_plt_entry_offset() + + this->count_ * this->get_plt_entry_size()); } // Write out the PLT data. @@ -7192,8 +7319,9 @@ class Output_data_plt_arm : public Output_section_data template Output_data_plt_arm::Output_data_plt_arm(Layout* layout, + uint64_t addralign, Output_data_space* got_plt) - : Output_section_data(4), got_plt_(got_plt), count_(0) + : Output_section_data(addralign), got_plt_(got_plt), count_(0) { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, @@ -7218,8 +7346,8 @@ Output_data_plt_arm::add_entry(Symbol* gsym) // Note that when setting the PLT offset we skip the initial // reserved PLT entry. - gsym->set_plt_offset((this->count_) * sizeof(plt_entry) - + sizeof(first_plt_entry)); + gsym->set_plt_offset((this->count_) * this->get_plt_entry_size() + + this->first_plt_entry_offset()); ++this->count_; @@ -7240,6 +7368,45 @@ Output_data_plt_arm::add_entry(Symbol* gsym) // appear in the relocations. } +template +class Output_data_plt_arm_standard : public Output_data_plt_arm +{ + public: + Output_data_plt_arm_standard(Layout* layout, Output_data_space* got_plt) + : Output_data_plt_arm(layout, 4, got_plt) + { } + + protected: + // Return the offset of the first non-reserved PLT entry. + virtual unsigned int + do_first_plt_entry_offset() const + { return sizeof(first_plt_entry); } + + // Return the size of a PLT entry. + virtual unsigned int + do_get_plt_entry_size() const + { return sizeof(plt_entry); } + + virtual void + do_fill_first_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address); + + virtual void + do_fill_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset); + + private: + // Template for the first PLT entry. + static const uint32_t first_plt_entry[5]; + + // Template for subsequent PLT entries. + static const uint32_t plt_entry[3]; +}; + // ARM PLTs. // FIXME: This is not very flexible. Right now this has only been tested // on armv5te. If we are to support additional architecture features like @@ -7247,25 +7414,63 @@ Output_data_plt_arm::add_entry(Symbol* gsym) // The first entry in the PLT. template -const uint32_t Output_data_plt_arm::first_plt_entry[5] = +const uint32_t Output_data_plt_arm_standard::first_plt_entry[5] = { 0xe52de004, // str lr, [sp, #-4]! 0xe59fe004, // ldr lr, [pc, #4] - 0xe08fe00e, // add lr, pc, lr + 0xe08fe00e, // add lr, pc, lr 0xe5bef008, // ldr pc, [lr, #8]! 0x00000000, // &GOT[0] - . }; +template +void +Output_data_plt_arm_standard::do_fill_first_plt_entry( + unsigned char* pov, + Arm_address got_address, + Arm_address plt_address) +{ + // Write first PLT entry. All but the last word are constants. + const size_t num_first_plt_words = (sizeof(first_plt_entry) + / sizeof(plt_entry[0])); + for (size_t i = 0; i < num_first_plt_words - 1; i++) + elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]); + // Last word in first PLT entry is &GOT[0] - . + elfcpp::Swap<32, big_endian>::writeval(pov + 16, + got_address - (plt_address + 16)); +} + // Subsequent entries in the PLT. template -const uint32_t Output_data_plt_arm::plt_entry[3] = +const uint32_t Output_data_plt_arm_standard::plt_entry[3] = { 0xe28fc600, // add ip, pc, #0xNN00000 0xe28cca00, // add ip, ip, #0xNN000 0xe5bcf000, // ldr pc, [ip, #0xNNN]! }; +template +void +Output_data_plt_arm_standard::do_fill_plt_entry( + unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset) +{ + int32_t offset = ((got_address + got_offset) + - (plt_address + plt_offset + 8)); + + gold_assert(offset >= 0 && offset < 0x0fffffff); + uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff); + elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0); + uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1); + uint32_t plt_insn2 = plt_entry[2] | (offset & 0xfff); + elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2); +} + // Write out the PLT. This uses the hand-coded instructions above, // and adjusts them as needed. This is all specified by the arm ELF // Processor Supplement. @@ -7289,46 +7494,29 @@ Output_data_plt_arm::do_write(Output_file* of) Arm_address plt_address = this->address(); Arm_address got_address = this->got_plt_->address(); - // Write first PLT entry. All but the last word are constants. - const size_t num_first_plt_words = (sizeof(first_plt_entry) - / sizeof(plt_entry[0])); - for (size_t i = 0; i < num_first_plt_words - 1; i++) - elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]); - // Last word in first PLT entry is &GOT[0] - . - elfcpp::Swap<32, big_endian>::writeval(pov + 16, - got_address - (plt_address + 16)); - pov += sizeof(first_plt_entry); + // Write first PLT entry. + this->fill_first_plt_entry(pov, got_address, plt_address); + pov += this->first_plt_entry_offset(); unsigned char* got_pov = got_view; memset(got_pov, 0, 12); got_pov += 12; - const int rel_size = elfcpp::Elf_sizes<32>::rel_size; - unsigned int plt_offset = sizeof(first_plt_entry); - unsigned int plt_rel_offset = 0; + unsigned int plt_offset = this->first_plt_entry_offset(); unsigned int got_offset = 12; const unsigned int count = this->count_; for (unsigned int i = 0; i < count; ++i, - pov += sizeof(plt_entry), + pov += this->get_plt_entry_size(), got_pov += 4, - plt_offset += sizeof(plt_entry), - plt_rel_offset += rel_size, + plt_offset += this->get_plt_entry_size(), got_offset += 4) { // Set and adjust the PLT entry itself. - int32_t offset = ((got_address + got_offset) - - (plt_address + plt_offset + 8)); - - gold_assert(offset >= 0 && offset < 0x0fffffff); - uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff); - elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0); - uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff); - elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1); - uint32_t plt_insn2 = plt_entry[2] | (offset & 0xfff); - elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2); + this->fill_plt_entry(pov, got_address, plt_address, + got_offset, plt_offset); // Set the entry in the GOT. elfcpp::Swap<32, big_endian>::writeval(got_pov, plt_address); @@ -7356,7 +7544,8 @@ Target_arm::make_plt_entry(Symbol_table* symtab, Layout* layout, // Create the GOT sections first. this->got_section(symtab, layout); - this->plt_ = new Output_data_plt_arm(layout, this->got_plt_); + this->plt_ = this->make_data_plt(layout, this->got_plt_); + layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR), @@ -7382,7 +7571,7 @@ template unsigned int Target_arm::first_plt_entry_offset() const { - return Output_data_plt_arm::first_plt_entry_offset(); + return this->plt_->first_plt_entry_offset(); } // Return the size of each PLT entry. @@ -7391,7 +7580,7 @@ template unsigned int Target_arm::plt_entry_size() const { - return Output_data_plt_arm::get_plt_entry_size(); + return this->plt_->get_plt_entry_size(); } // Get the section to use for TLS_DESC relocations. @@ -7439,7 +7628,7 @@ unsigned int Target_arm::got_mod_index_entry( Symbol_table* symtab, Layout* layout, - Sized_relobj<32, big_endian>* object) + Sized_relobj_file<32, big_endian>* object) { if (this->got_mod_index_offset_ == -1U) { @@ -7478,12 +7667,134 @@ Target_arm::optimize_tls_reloc(bool, int) return tls::TLSOPT_NONE; } +// Get the Reference_flags for a particular relocation. + +template +int +Target_arm::Scan::get_reference_flags(unsigned int r_type) +{ + switch (r_type) + { + case elfcpp::R_ARM_NONE: + case elfcpp::R_ARM_V4BX: + case elfcpp::R_ARM_GNU_VTENTRY: + case elfcpp::R_ARM_GNU_VTINHERIT: + // No symbol reference. + return 0; + + case elfcpp::R_ARM_ABS32: + case elfcpp::R_ARM_ABS16: + case elfcpp::R_ARM_ABS12: + case elfcpp::R_ARM_THM_ABS5: + case elfcpp::R_ARM_ABS8: + case elfcpp::R_ARM_BASE_ABS: + case elfcpp::R_ARM_MOVW_ABS_NC: + case elfcpp::R_ARM_MOVT_ABS: + case elfcpp::R_ARM_THM_MOVW_ABS_NC: + case elfcpp::R_ARM_THM_MOVT_ABS: + case elfcpp::R_ARM_ABS32_NOI: + return Symbol::ABSOLUTE_REF; + + case elfcpp::R_ARM_REL32: + case elfcpp::R_ARM_LDR_PC_G0: + case elfcpp::R_ARM_SBREL32: + case elfcpp::R_ARM_THM_PC8: + case elfcpp::R_ARM_BASE_PREL: + case elfcpp::R_ARM_MOVW_PREL_NC: + case elfcpp::R_ARM_MOVT_PREL: + case elfcpp::R_ARM_THM_MOVW_PREL_NC: + case elfcpp::R_ARM_THM_MOVT_PREL: + case elfcpp::R_ARM_THM_ALU_PREL_11_0: + case elfcpp::R_ARM_THM_PC12: + case elfcpp::R_ARM_REL32_NOI: + case elfcpp::R_ARM_ALU_PC_G0_NC: + case elfcpp::R_ARM_ALU_PC_G0: + case elfcpp::R_ARM_ALU_PC_G1_NC: + case elfcpp::R_ARM_ALU_PC_G1: + case elfcpp::R_ARM_ALU_PC_G2: + case elfcpp::R_ARM_LDR_PC_G1: + case elfcpp::R_ARM_LDR_PC_G2: + case elfcpp::R_ARM_LDRS_PC_G0: + case elfcpp::R_ARM_LDRS_PC_G1: + case elfcpp::R_ARM_LDRS_PC_G2: + case elfcpp::R_ARM_LDC_PC_G0: + case elfcpp::R_ARM_LDC_PC_G1: + case elfcpp::R_ARM_LDC_PC_G2: + case elfcpp::R_ARM_ALU_SB_G0_NC: + case elfcpp::R_ARM_ALU_SB_G0: + case elfcpp::R_ARM_ALU_SB_G1_NC: + case elfcpp::R_ARM_ALU_SB_G1: + case elfcpp::R_ARM_ALU_SB_G2: + case elfcpp::R_ARM_LDR_SB_G0: + case elfcpp::R_ARM_LDR_SB_G1: + case elfcpp::R_ARM_LDR_SB_G2: + case elfcpp::R_ARM_LDRS_SB_G0: + case elfcpp::R_ARM_LDRS_SB_G1: + case elfcpp::R_ARM_LDRS_SB_G2: + case elfcpp::R_ARM_LDC_SB_G0: + case elfcpp::R_ARM_LDC_SB_G1: + case elfcpp::R_ARM_LDC_SB_G2: + case elfcpp::R_ARM_MOVW_BREL_NC: + case elfcpp::R_ARM_MOVT_BREL: + case elfcpp::R_ARM_MOVW_BREL: + case elfcpp::R_ARM_THM_MOVW_BREL_NC: + case elfcpp::R_ARM_THM_MOVT_BREL: + case elfcpp::R_ARM_THM_MOVW_BREL: + case elfcpp::R_ARM_GOTOFF32: + case elfcpp::R_ARM_GOTOFF12: + case elfcpp::R_ARM_SBREL31: + return Symbol::RELATIVE_REF; + + case elfcpp::R_ARM_PLT32: + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_THM_JUMP24: + case elfcpp::R_ARM_THM_JUMP19: + case elfcpp::R_ARM_THM_JUMP6: + case elfcpp::R_ARM_THM_JUMP11: + case elfcpp::R_ARM_THM_JUMP8: + // R_ARM_PREL31 is not used to relocate call/jump instructions but + // in unwind tables. It may point to functions via PLTs. + // So we treat it like call/jump relocations above. + case elfcpp::R_ARM_PREL31: + return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF; + + case elfcpp::R_ARM_GOT_BREL: + case elfcpp::R_ARM_GOT_ABS: + case elfcpp::R_ARM_GOT_PREL: + // Absolute in GOT. + return Symbol::ABSOLUTE_REF; + + case elfcpp::R_ARM_TLS_GD32: // Global-dynamic + case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic + case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic + case elfcpp::R_ARM_TLS_IE32: // Initial-exec + case elfcpp::R_ARM_TLS_LE32: // Local-exec + return Symbol::TLS_REF; + + case elfcpp::R_ARM_TARGET1: + case elfcpp::R_ARM_TARGET2: + case elfcpp::R_ARM_COPY: + case elfcpp::R_ARM_GLOB_DAT: + case elfcpp::R_ARM_JUMP_SLOT: + case elfcpp::R_ARM_RELATIVE: + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_LDR_SBREL_11_0_NC: + case elfcpp::R_ARM_ALU_SBREL_19_12_NC: + case elfcpp::R_ARM_ALU_SBREL_27_20_CK: + default: + // Not expected. We will give an error later. + return 0; + } +} + // Report an unsupported relocation against a local symbol. template void Target_arm::Scan::unsupported_reloc_local( - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int r_type) { gold_error(_("%s: unsupported reloc %u against local symbol"), @@ -7551,13 +7862,17 @@ inline void Target_arm::Scan::local(Symbol_table* symtab, Layout* layout, Target_arm* target, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int data_shndx, Output_section* output_section, const elfcpp::Rel<32, big_endian>& reloc, unsigned int r_type, - const elfcpp::Sym<32, big_endian>& lsym) + const elfcpp::Sym<32, big_endian>& lsym, + bool is_discarded) { + if (is_discarded) + return; + r_type = get_real_reloc_type(r_type); switch (r_type) { @@ -7579,8 +7894,8 @@ Target_arm::Scan::local(Symbol_table* symtab, { Reloc_section* rel_dyn = target->rel_dyn_section(layout); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - // If we are to add more other reloc types than R_ARM_ABS32, - // we need to add check_non_pic(object, r_type) here. + // If we are to add more other reloc types than R_ARM_ABS32, + // we need to add check_non_pic(object, r_type) here. rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE, output_section, data_shndx, reloc.get_r_offset()); @@ -7602,16 +7917,16 @@ Target_arm::Scan::local(Symbol_table* symtab, // data section, we need to be careful not to apply this // relocation statically. if (parameters->options().output_is_position_independent()) - { + { check_non_pic(object, r_type); - Reloc_section* rel_dyn = target->rel_dyn_section(layout); + Reloc_section* rel_dyn = target->rel_dyn_section(layout); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - if (lsym.get_st_type() != elfcpp::STT_SECTION) + if (lsym.get_st_type() != elfcpp::STT_SECTION) rel_dyn->add_local(object, r_sym, r_type, output_section, data_shndx, reloc.get_r_offset()); - else - { - gold_assert(lsym.get_st_value() == 0); + else + { + gold_assert(lsym.get_st_value() == 0); unsigned int shndx = lsym.get_st_shndx(); bool is_ordinary; shndx = object->adjust_sym_shndx(r_sym, shndx, @@ -7623,11 +7938,10 @@ Target_arm::Scan::local(Symbol_table* symtab, rel_dyn->add_local_section(object, shndx, r_type, output_section, data_shndx, reloc.get_r_offset()); - } - } + } + } break; - case elfcpp::R_ARM_PC24: case elfcpp::R_ARM_REL32: case elfcpp::R_ARM_LDR_PC_G0: case elfcpp::R_ARM_SBREL32: @@ -7638,9 +7952,6 @@ Target_arm::Scan::local(Symbol_table* symtab, case elfcpp::R_ARM_CALL: case elfcpp::R_ARM_JUMP24: case elfcpp::R_ARM_THM_JUMP24: - case elfcpp::R_ARM_LDR_SBREL_11_0_NC: - case elfcpp::R_ARM_ALU_SBREL_19_12_NC: - case elfcpp::R_ARM_ALU_SBREL_27_20_CK: case elfcpp::R_ARM_SBREL31: case elfcpp::R_ARM_PREL31: case elfcpp::R_ARM_MOVW_PREL_NC: @@ -7745,18 +8056,18 @@ Target_arm::Scan::local(Symbol_table* symtab, { bool output_is_shared = parameters->options().shared(); const tls::Tls_optimization optimized_type - = Target_arm::optimize_tls_reloc(!output_is_shared, + = Target_arm::optimize_tls_reloc(!output_is_shared, r_type); switch (r_type) { case elfcpp::R_ARM_TLS_GD32: // Global-dynamic if (optimized_type == tls::TLSOPT_NONE) { - // Create a pair of GOT entries for the module index and - // dtv-relative offset. - Arm_output_data_got* got - = target->got_section(symtab, layout); - unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + // Create a pair of GOT entries for the module index and + // dtv-relative offset. + Arm_output_data_got* got + = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); unsigned int shndx = lsym.get_st_shndx(); bool is_ordinary; shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary); @@ -7771,7 +8082,7 @@ Target_arm::Scan::local(Symbol_table* symtab, got->add_local_pair_with_rel(object, r_sym, shndx, GOT_TYPE_TLS_PAIR, target->rel_dyn_section(layout), - elfcpp::R_ARM_TLS_DTPMOD32, 0); + elfcpp::R_ARM_TLS_DTPMOD32); else got->add_tls_gd32_with_static_reloc(GOT_TYPE_TLS_PAIR, object, r_sym); @@ -7784,8 +8095,8 @@ Target_arm::Scan::local(Symbol_table* symtab, case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic if (optimized_type == tls::TLSOPT_NONE) { - // Create a GOT entry for the module index. - target->got_mod_index_entry(symtab, layout, object); + // Create a GOT entry for the module index. + target->got_mod_index_entry(symtab, layout, object); } else // FIXME: TLS optimization not supported yet. @@ -7828,9 +8139,9 @@ Target_arm::Scan::local(Symbol_table* symtab, layout->set_has_static_tls(); if (output_is_shared) { - // We need to create a dynamic relocation. - gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION); - unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + // We need to create a dynamic relocation. + gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION); + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); Reloc_section* rel_dyn = target->rel_dyn_section(layout); rel_dyn->add_local(object, r_sym, elfcpp::R_ARM_TLS_TPOFF32, output_section, data_shndx, @@ -7844,6 +8155,10 @@ Target_arm::Scan::local(Symbol_table* symtab, } break; + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_LDR_SBREL_11_0_NC: + case elfcpp::R_ARM_ALU_SBREL_19_12_NC: + case elfcpp::R_ARM_ALU_SBREL_27_20_CK: default: unsupported_reloc_local(object, r_type); break; @@ -7855,7 +8170,7 @@ Target_arm::Scan::local(Symbol_table* symtab, template void Target_arm::Scan::unsupported_reloc_global( - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int r_type, Symbol* gsym) { @@ -7897,7 +8212,7 @@ Target_arm::Scan::local_reloc_may_be_function_pointer( Symbol_table*, Layout*, Target_arm* target, - Sized_relobj<32, big_endian>*, + Sized_relobj_file<32, big_endian>*, unsigned int, Output_section*, const elfcpp::Rel<32, big_endian>&, @@ -7914,7 +8229,7 @@ Target_arm::Scan::global_reloc_may_be_function_pointer( Symbol_table*, Layout*, Target_arm* target, - Sized_relobj<32, big_endian>*, + Sized_relobj_file<32, big_endian>*, unsigned int, Output_section*, const elfcpp::Rel<32, big_endian>&, @@ -7936,7 +8251,7 @@ inline void Target_arm::Scan::global(Symbol_table* symtab, Layout* layout, Target_arm* target, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int data_shndx, Output_section* output_section, const elfcpp::Rel<32, big_endian>& reloc, @@ -7972,42 +8287,42 @@ Target_arm::Scan::global(Symbol_table* symtab, case elfcpp::R_ARM_ABS32_NOI: // Absolute addressing relocations. { - // Make a PLT entry if necessary. - if (this->symbol_needs_plt_entry(gsym)) - { - 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. - if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF)) - { - if (gsym->may_need_copy_reloc()) - { - target->copy_reloc(symtab, layout, object, - data_shndx, output_section, gsym, reloc); - } - else if ((r_type == elfcpp::R_ARM_ABS32 + // Make a PLT entry if necessary. + if (this->symbol_needs_plt_entry(gsym)) + { + 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. + if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type))) + { + if (gsym->may_need_copy_reloc()) + { + target->copy_reloc(symtab, layout, object, + data_shndx, output_section, gsym, reloc); + } + else if ((r_type == elfcpp::R_ARM_ABS32 || r_type == elfcpp::R_ARM_ABS32_NOI) - && gsym->can_use_relative_reloc(false)) - { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_global_relative(gsym, elfcpp::R_ARM_RELATIVE, - output_section, object, - data_shndx, reloc.get_r_offset()); - } - else - { + && gsym->can_use_relative_reloc(false)) + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_global_relative(gsym, elfcpp::R_ARM_RELATIVE, + output_section, object, + data_shndx, reloc.get_r_offset()); + } + else + { check_non_pic(object, r_type); - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_global(gsym, r_type, output_section, object, - data_shndx, reloc.get_r_offset()); - } - } + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_global(gsym, r_type, output_section, object, + data_shndx, reloc.get_r_offset()); + } + } } break; @@ -8016,15 +8331,12 @@ Target_arm::Scan::global(Symbol_table* symtab, // We need a GOT section. target->got_section(symtab, layout); break; - + case elfcpp::R_ARM_REL32: case elfcpp::R_ARM_LDR_PC_G0: case elfcpp::R_ARM_SBREL32: case elfcpp::R_ARM_THM_PC8: case elfcpp::R_ARM_BASE_PREL: - case elfcpp::R_ARM_LDR_SBREL_11_0_NC: - case elfcpp::R_ARM_ALU_SBREL_19_12_NC: - case elfcpp::R_ARM_ALU_SBREL_27_20_CK: case elfcpp::R_ARM_MOVW_PREL_NC: case elfcpp::R_ARM_MOVT_PREL: case elfcpp::R_ARM_THM_MOVW_PREL_NC: @@ -8068,8 +8380,7 @@ Target_arm::Scan::global(Symbol_table* symtab, // Relative addressing relocations. { // Make a dynamic relocation if necessary. - int flags = Symbol::NON_PIC_REF; - if (gsym->needs_dynamic_reloc(flags)) + if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type))) { if (target->may_need_copy_reloc(gsym)) { @@ -8087,7 +8398,6 @@ Target_arm::Scan::global(Symbol_table* symtab, } break; - case elfcpp::R_ARM_PC24: case elfcpp::R_ARM_THM_CALL: case elfcpp::R_ARM_PLT32: case elfcpp::R_ARM_CALL: @@ -8102,7 +8412,7 @@ Target_arm::Scan::global(Symbol_table* symtab, // All the relocation above are branches except for the PREL31 ones. // A PREL31 relocation can point to a personality function in a shared // library. In that case we want to use a PLT because we want to - // call the personality routine and the dyanmic linkers we care about + // call the personality routine and the dynamic linkers we care about // do not support dynamic PREL31 relocations. An REL31 relocation may // point to a function whose unwinding behaviour is being described but // we will not mistakenly generate a PLT for that because we should use @@ -8138,7 +8448,9 @@ Target_arm::Scan::global(Symbol_table* symtab, Reloc_section* rel_dyn = target->rel_dyn_section(layout); if (gsym->is_from_dynobj() || gsym->is_undefined() - || gsym->is_preemptible()) + || gsym->is_preemptible() + || (gsym->visibility() == elfcpp::STV_PROTECTED + && parameters->options().shared())) got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rel_dyn, elfcpp::R_ARM_GLOB_DAT); else @@ -8176,16 +8488,16 @@ Target_arm::Scan::global(Symbol_table* symtab, { const bool is_final = gsym->final_value_is_known(); const tls::Tls_optimization optimized_type - = Target_arm::optimize_tls_reloc(is_final, r_type); + = Target_arm::optimize_tls_reloc(is_final, r_type); switch (r_type) { case elfcpp::R_ARM_TLS_GD32: // Global-dynamic if (optimized_type == tls::TLSOPT_NONE) { - // Create a pair of GOT entries for the module index and - // dtv-relative offset. - Arm_output_data_got* got - = target->got_section(symtab, layout); + // Create a pair of GOT entries for the module index and + // dtv-relative offset. + Arm_output_data_got* got + = target->got_section(symtab, layout); if (!parameters->doing_static_link()) got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR, target->rel_dyn_section(layout), @@ -8202,8 +8514,8 @@ Target_arm::Scan::global(Symbol_table* symtab, case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic if (optimized_type == tls::TLSOPT_NONE) { - // Create a GOT entry for the module index. - target->got_mod_index_entry(symtab, layout, object); + // Create a GOT entry for the module index. + target->got_mod_index_entry(symtab, layout, object); } else // FIXME: TLS optimization not supported yet. @@ -8242,11 +8554,11 @@ Target_arm::Scan::global(Symbol_table* symtab, layout->set_has_static_tls(); if (parameters->options().shared()) { - // We need to create a dynamic relocation. - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_global(gsym, elfcpp::R_ARM_TLS_TPOFF32, + // We need to create a dynamic relocation. + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_global(gsym, elfcpp::R_ARM_TLS_TPOFF32, output_section, object, - data_shndx, reloc.get_r_offset()); + data_shndx, reloc.get_r_offset()); } break; @@ -8256,6 +8568,10 @@ Target_arm::Scan::global(Symbol_table* symtab, } break; + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_LDR_SBREL_11_0_NC: + case elfcpp::R_ARM_ALU_SBREL_19_12_NC: + case elfcpp::R_ARM_ALU_SBREL_27_20_CK: default: unsupported_reloc_global(object, r_type, gsym); break; @@ -8266,17 +8582,18 @@ Target_arm::Scan::global(Symbol_table* symtab, template void -Target_arm::gc_process_relocs(Symbol_table* symtab, - Layout* layout, - Sized_relobj<32, big_endian>* object, - unsigned int data_shndx, - unsigned int, - 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) +Target_arm::gc_process_relocs( + Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, big_endian>* object, + unsigned int data_shndx, + unsigned int, + 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) { typedef Target_arm Arm; typedef typename Target_arm::Scan Scan; @@ -8302,7 +8619,7 @@ template void Target_arm::scan_relocs(Symbol_table* symtab, Layout* layout, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int data_shndx, unsigned int sh_type, const unsigned char* prelocs, @@ -8341,7 +8658,7 @@ void Target_arm::do_finalize_sections( Layout* layout, const Input_objects* input_objects, - Symbol_table* symtab) + Symbol_table*) { bool merged_any_attributes = false; // Merge processor-specific flags. @@ -8360,7 +8677,7 @@ Target_arm::do_finalize_sections( arm_relobj->attributes_section_data()); merged_any_attributes = true; } - } + } for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin(); p != input_objects->dynobj_end(); @@ -8382,12 +8699,8 @@ Target_arm::do_finalize_sections( if (this->attributes_section_data_ == NULL) this->attributes_section_data_ = new Attributes_section_data(NULL, 0); - // Check BLX use. const Object_attribute* cpu_arch_attr = this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch); - if (cpu_arch_attr->int_value() > elfcpp::TAG_CPU_ARCH_V4) - this->set_may_use_blx(true); - // Check if we need to use Cortex-A8 workaround. if (parameters->options().user_set_fix_cortex_a8()) this->fix_cortex_a8_ = parameters->options().fix_cortex_a8(); @@ -8395,22 +8708,22 @@ Target_arm::do_finalize_sections( { // If neither --fix-cortex-a8 nor --no-fix-cortex-a8 is used, turn on // Cortex-A8 erratum workaround for ARMv7-A or ARMv7 with unknown - // profile. + // profile. const Object_attribute* cpu_arch_profile_attr = this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch_profile); this->fix_cortex_a8_ = (cpu_arch_attr->int_value() == elfcpp::TAG_CPU_ARCH_V7 - && (cpu_arch_profile_attr->int_value() == 'A' - || cpu_arch_profile_attr->int_value() == 0)); + && (cpu_arch_profile_attr->int_value() == 'A' + || cpu_arch_profile_attr->int_value() == 0)); } - + // Check if we can use V4BX interworking. // The V4BX interworking stub contains BX instruction, // which is not specified for some profiles. if (this->fix_v4bx() == General_options::FIX_V4BX_INTERWORKING - && !this->may_use_blx()) + && !this->may_use_v4t_interworking()) gold_error(_("unable to provide V4BX reloc interworking fix up; " - "the target profile does not support BX instruction")); + "the target profile does not support BX instruction")); // Fill in some more dynamic tags. const Reloc_section* rel_plt = (this->plt_ == NULL @@ -8426,32 +8739,24 @@ Target_arm::do_finalize_sections( // Handle the .ARM.exidx section. Output_section* exidx_section = layout->find_output_section(".ARM.exidx"); - if (exidx_section != NULL - && exidx_section->type() == elfcpp::SHT_ARM_EXIDX - && !parameters->options().relocatable()) - { - // Create __exidx_start and __exdix_end symbols. - symtab->define_in_output_data("__exidx_start", NULL, - Symbol_table::PREDEFINED, - exidx_section, 0, 0, elfcpp::STT_OBJECT, - elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0, - false, true); - symtab->define_in_output_data("__exidx_end", NULL, - Symbol_table::PREDEFINED, - exidx_section, 0, 0, elfcpp::STT_OBJECT, - elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0, - true, true); - // For the ARM target, we need to add a PT_ARM_EXIDX segment for - // the .ARM.exidx section. - if (!layout->script_options()->saw_phdrs_clause()) + if (!parameters->options().relocatable()) + { + if (exidx_section != NULL + && exidx_section->type() == elfcpp::SHT_ARM_EXIDX) { - gold_assert(layout->find_output_segment(elfcpp::PT_ARM_EXIDX, 0, 0) - == NULL); - Output_segment* exidx_segment = - layout->make_output_segment(elfcpp::PT_ARM_EXIDX, elfcpp::PF_R); - exidx_segment->add_output_section_to_nonload(exidx_section, - elfcpp::PF_R); + // For the ARM target, we need to add a PT_ARM_EXIDX segment for + // the .ARM.exidx section. + if (!layout->script_options()->saw_phdrs_clause()) + { + gold_assert(layout->find_output_segment(elfcpp::PT_ARM_EXIDX, 0, + 0) + == NULL); + Output_segment* exidx_segment = + layout->make_output_segment(elfcpp::PT_ARM_EXIDX, elfcpp::PF_R); + exidx_segment->add_output_section_to_nonload(exidx_section, + elfcpp::PF_R); + } } } @@ -8489,7 +8794,7 @@ template inline bool Target_arm::Relocate::should_apply_static_reloc( const Sized_symbol<32>* gsym, - int ref_flags, + unsigned int r_type, bool is_32bit, Output_section* output_section) { @@ -8499,6 +8804,8 @@ Target_arm::Relocate::should_apply_static_reloc( if ((output_section->flags() & elfcpp::SHF_ALLOC) == 0) return true; + int ref_flags = Scan::get_reference_flags(r_type); + // For local symbols, we will have created a non-RELATIVE dynamic // relocation only if (a) the output is position independent, // (b) the relocation is absolute (not pc- or segment-relative), and @@ -8526,7 +8833,7 @@ inline bool Target_arm::Relocate::relocate( const Relocate_info<32, big_endian>* relinfo, Target_arm* target, - Output_section *output_section, + Output_section* output_section, size_t relnum, const elfcpp::Rel<32, big_endian>& rel, unsigned int r_type, @@ -8536,6 +8843,9 @@ Target_arm::Relocate::relocate( Arm_address address, section_size_type view_size) { + if (view == NULL) + return true; + typedef Arm_relocate_functions Arm_relocate_functions; r_type = get_real_reloc_type(r_type); @@ -8554,18 +8864,57 @@ Target_arm::Relocate::relocate( const Arm_relobj* object = Arm_relobj::as_arm_relobj(relinfo->object); - // If the final branch target of a relocation is THUMB instruction, this - // is 1. Otherwise it is 0. - Arm_address thumb_bit = 0; - Symbol_value<32> symval; - bool is_weakly_undefined_without_plt = false; - if (relnum != Target_arm::fake_relnum_for_stubs) + // If the final branch target of a relocation is THUMB instruction, this + // is 1. Otherwise it is 0. + Arm_address thumb_bit = 0; + Symbol_value<32> symval; + bool is_weakly_undefined_without_plt = false; + bool have_got_offset = false; + unsigned int got_offset = 0; + + // If the relocation uses the GOT entry of a symbol instead of the symbol + // itself, we don't care about whether the symbol is defined or what kind + // of symbol it is. + if (reloc_property->uses_got_entry()) + { + // Get the GOT offset. + // The GOT pointer points to the end of the GOT section. + // We need to subtract the size of the GOT section to get + // the actual offset to use in the relocation. + // TODO: We should move GOT offset computing code in TLS relocations + // to here. + switch (r_type) + { + case elfcpp::R_ARM_GOT_BREL: + case elfcpp::R_ARM_GOT_PREL: + if (gsym != NULL) + { + gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD)); + got_offset = (gsym->got_offset(GOT_TYPE_STANDARD) + - target->got_size()); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.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) + - target->got_size()); + } + have_got_offset = true; + break; + + default: + break; + } + } + else if (relnum != Target_arm::fake_relnum_for_stubs) { if (gsym != NULL) { // This is a global symbol. Determine if we use PLT and if the // final target is THUMB. - if (gsym->use_plt_offset(reloc_is_non_pic(r_type))) + if (gsym->use_plt_offset(Scan::get_reference_flags(r_type))) { // This uses a PLT, change the symbol value. symval.set_output_value(target->plt_section()->address() @@ -8602,8 +8951,8 @@ Target_arm::Relocate::relocate( } else { - // This is a local symbol. Determine if the final target is THUMB. - // We saved this information when all the local symbols were read. + // This is a local symbol. Determine if the final target is THUMB. + // We saved this information when all the local symbols were read. elfcpp::Elf_types<32>::Elf_WXword r_info = rel.get_r_info(); unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info); thumb_bit = object->local_symbol_is_thumb_function(r_sym) ? 1 : 0; @@ -8619,43 +8968,13 @@ Target_arm::Relocate::relocate( // Strip LSB if this points to a THUMB target. if (thumb_bit != 0 - && reloc_property->uses_thumb_bit() + && reloc_property->uses_thumb_bit() && ((psymval->value(object, 0) & 1) != 0)) { Arm_address stripped_value = psymval->value(object, 0) & ~static_cast(1); symval.set_output_value(stripped_value); psymval = &symval; - } - - // Get the GOT offset if needed. - // The GOT pointer points to the end of the GOT section. - // We need to subtract the size of the GOT section to get - // the actual offset to use in the relocation. - bool have_got_offset = false; - unsigned int got_offset = 0; - switch (r_type) - { - case elfcpp::R_ARM_GOT_BREL: - case elfcpp::R_ARM_GOT_PREL: - if (gsym != NULL) - { - gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD)); - got_offset = (gsym->got_offset(GOT_TYPE_STANDARD) - - target->got_size()); - } - else - { - unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.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) - - target->got_size()); - } - have_got_offset = true; - break; - - default: - break; } // To look up relocation stubs, we need to pass the symbol table index of @@ -8707,9 +9026,9 @@ Target_arm::Relocate::relocate( relative_address_base = address & 0xfffffffcU; break; default: - gold_unreachable(); + gold_unreachable(); } - + typename Arm_relocate_functions::Status reloc_status = Arm_relocate_functions::STATUS_OKAY; bool check_overflow = reloc_property->checks_overflow(); @@ -8719,62 +9038,53 @@ Target_arm::Relocate::relocate( break; case elfcpp::R_ARM_ABS8: - if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false, - output_section)) + if (should_apply_static_reloc(gsym, r_type, false, output_section)) reloc_status = Arm_relocate_functions::abs8(view, object, psymval); break; case elfcpp::R_ARM_ABS12: - if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false, - output_section)) + if (should_apply_static_reloc(gsym, r_type, false, output_section)) reloc_status = Arm_relocate_functions::abs12(view, object, psymval); break; case elfcpp::R_ARM_ABS16: - if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false, - output_section)) + if (should_apply_static_reloc(gsym, r_type, false, output_section)) reloc_status = Arm_relocate_functions::abs16(view, object, psymval); break; case elfcpp::R_ARM_ABS32: - if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true, - output_section)) + if (should_apply_static_reloc(gsym, r_type, true, output_section)) reloc_status = Arm_relocate_functions::abs32(view, object, psymval, thumb_bit); break; case elfcpp::R_ARM_ABS32_NOI: - if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true, - output_section)) + if (should_apply_static_reloc(gsym, r_type, true, output_section)) // No thumb bit for this relocation: (S + A) reloc_status = Arm_relocate_functions::abs32(view, object, psymval, 0); break; case elfcpp::R_ARM_MOVW_ABS_NC: - if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false, - output_section)) + if (should_apply_static_reloc(gsym, r_type, false, output_section)) reloc_status = Arm_relocate_functions::movw(view, object, psymval, 0, thumb_bit, check_overflow); break; case elfcpp::R_ARM_MOVT_ABS: - if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false, - output_section)) + if (should_apply_static_reloc(gsym, r_type, false, output_section)) reloc_status = Arm_relocate_functions::movt(view, object, psymval, 0); break; case elfcpp::R_ARM_THM_MOVW_ABS_NC: - if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false, - output_section)) + if (should_apply_static_reloc(gsym, r_type, false, output_section)) reloc_status = Arm_relocate_functions::thm_movw(view, object, psymval, - 0, thumb_bit, false); + 0, thumb_bit, false); break; case elfcpp::R_ARM_THM_MOVT_ABS: - if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false, - output_section)) + if (should_apply_static_reloc(gsym, r_type, false, output_section)) reloc_status = Arm_relocate_functions::thm_movt(view, object, psymval, 0); break; @@ -8810,15 +9120,14 @@ Target_arm::Relocate::relocate( Arm_relocate_functions::thm_movt(view, object, psymval, relative_address_base); break; - + case elfcpp::R_ARM_REL32: reloc_status = Arm_relocate_functions::rel32(view, object, psymval, address, thumb_bit); break; case elfcpp::R_ARM_THM_ABS5: - if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false, - output_section)) + if (should_apply_static_reloc(gsym, r_type, false, output_section)) reloc_status = Arm_relocate_functions::thm_abs5(view, object, psymval); break; @@ -8848,13 +9157,8 @@ Target_arm::Relocate::relocate( break; case elfcpp::R_ARM_BASE_ABS: - { - if (!should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false, - output_section)) - break; - + if (should_apply_static_reloc(gsym, r_type, false, output_section)) reloc_status = Arm_relocate_functions::base_abs(view, sym_origin); - } break; case elfcpp::R_ARM_GOT_BREL: @@ -8885,7 +9189,7 @@ Target_arm::Relocate::relocate( && !gsym->is_from_dynobj() && !gsym->is_preemptible())); reloc_status = - Arm_relocate_functions::arm_branch_common( + Arm_relocate_functions::arm_branch_common( r_type, relinfo, view, gsym, object, r_sym, psymval, address, thumb_bit, is_weakly_undefined_without_plt); break; @@ -9008,8 +9312,15 @@ Target_arm::Relocate::relocate( view, address, view_size); break; + // The known and unknown unsupported and/or deprecated relocations. + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_LDR_SBREL_11_0_NC: + case elfcpp::R_ARM_ALU_SBREL_19_12_NC: + case elfcpp::R_ARM_ALU_SBREL_27_20_CK: default: - gold_unreachable(); + // Just silently leave the method. We should get an appropriate error + // message in the scan methods. + break; } // Report any errors. @@ -9057,7 +9368,7 @@ Target_arm::Relocate::relocate_tls( typedef Relocate_functions<32, big_endian> RelocFuncs; Output_segment* tls_segment = relinfo->layout->tls_segment(); - const Sized_relobj<32, big_endian>* object = relinfo->object; + const Sized_relobj_file<32, big_endian>* object = relinfo->object; elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(object, 0); @@ -9069,103 +9380,103 @@ Target_arm::Relocate::relocate_tls( switch (r_type) { case elfcpp::R_ARM_TLS_GD32: // Global-dynamic - { - unsigned int got_type = GOT_TYPE_TLS_PAIR; - unsigned int got_offset; - if (gsym != NULL) - { - gold_assert(gsym->has_got_offset(got_type)); - got_offset = gsym->got_offset(got_type) - target->got_size(); - } - else - { - unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); - gold_assert(object->local_has_got_offset(r_sym, got_type)); - got_offset = (object->local_got_offset(r_sym, got_type) + { + unsigned int got_type = GOT_TYPE_TLS_PAIR; + unsigned int got_offset; + if (gsym != NULL) + { + gold_assert(gsym->has_got_offset(got_type)); + got_offset = gsym->got_offset(got_type) - target->got_size(); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym, got_type)); + got_offset = (object->local_got_offset(r_sym, got_type) - target->got_size()); - } - if (optimized_type == tls::TLSOPT_NONE) - { + } + if (optimized_type == tls::TLSOPT_NONE) + { Arm_address got_entry = target->got_plt_section()->address() + got_offset; - - // Relocate the field with the PC relative offset of the pair of - // GOT entries. - RelocFuncs::pcrel32(view, got_entry, address); - return ArmRelocFuncs::STATUS_OKAY; - } - } + + // Relocate the field with the PC relative offset of the pair of + // GOT entries. + RelocFuncs::pcrel32_unaligned(view, got_entry, address); + return ArmRelocFuncs::STATUS_OKAY; + } + } break; case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic if (optimized_type == tls::TLSOPT_NONE) - { - // Relocate the field with the offset of the GOT entry for - // the module index. - unsigned int got_offset; - got_offset = (target->got_mod_index_entry(NULL, NULL, NULL) + { + // Relocate the field with the offset of the GOT entry for + // the module index. + unsigned int got_offset; + got_offset = (target->got_mod_index_entry(NULL, NULL, NULL) - target->got_size()); Arm_address got_entry = target->got_plt_section()->address() + got_offset; - // Relocate the field with the PC relative offset of the pair of - // GOT entries. - RelocFuncs::pcrel32(view, got_entry, address); + // Relocate the field with the PC relative offset of the pair of + // GOT entries. + RelocFuncs::pcrel32_unaligned(view, got_entry, address); return ArmRelocFuncs::STATUS_OKAY; - } + } break; case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic - RelocFuncs::rel32(view, value); + RelocFuncs::rel32_unaligned(view, value); return ArmRelocFuncs::STATUS_OKAY; case elfcpp::R_ARM_TLS_IE32: // Initial-exec if (optimized_type == tls::TLSOPT_NONE) - { - // Relocate the field with the offset of the GOT entry for - // the tp-relative offset of the symbol. + { + // Relocate the field with the offset of the GOT entry for + // the tp-relative offset of the symbol. unsigned int got_type = GOT_TYPE_TLS_OFFSET; - unsigned int got_offset; - if (gsym != NULL) - { - gold_assert(gsym->has_got_offset(got_type)); - got_offset = gsym->got_offset(got_type); - } - else - { - unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); - gold_assert(object->local_has_got_offset(r_sym, got_type)); - got_offset = object->local_got_offset(r_sym, got_type); - } - - // All GOT offsets are relative to the end of the GOT. - got_offset -= target->got_size(); + unsigned int got_offset; + if (gsym != NULL) + { + gold_assert(gsym->has_got_offset(got_type)); + got_offset = gsym->got_offset(got_type); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym, got_type)); + got_offset = object->local_got_offset(r_sym, got_type); + } + + // All GOT offsets are relative to the end of the GOT. + got_offset -= target->got_size(); Arm_address got_entry = target->got_plt_section()->address() + got_offset; - // Relocate the field with the PC relative offset of the GOT entry. - RelocFuncs::pcrel32(view, got_entry, address); + // Relocate the field with the PC relative offset of the GOT entry. + RelocFuncs::pcrel32_unaligned(view, got_entry, address); return ArmRelocFuncs::STATUS_OKAY; - } + } break; case elfcpp::R_ARM_TLS_LE32: // Local-exec // If we're creating a shared library, a dynamic relocation will // have been created for this location, so do not apply it now. if (!parameters->options().shared()) - { - gold_assert(tls_segment != NULL); + { + gold_assert(tls_segment != NULL); // $tp points to the TCB, which is followed by the TLS, so we // need to add TCB size to the offset. Arm_address aligned_tcb_size = align_address(ARM_TCB_SIZE, tls_segment->maximum_alignment()); - RelocFuncs::rel32(view, value + aligned_tcb_size); + RelocFuncs::rel32_unaligned(view, value + aligned_tcb_size); - } + } return ArmRelocFuncs::STATUS_OKAY; - + default: gold_unreachable(); } @@ -9219,7 +9530,7 @@ Target_arm::relocate_section( } gold::relocate_section<32, big_endian, Target_arm, elfcpp::SHT_REL, - Arm_relocate>( + Arm_relocate, gold::Default_comdat_behavior>( relinfo, this, prelocs, @@ -9263,7 +9574,7 @@ void Target_arm::scan_relocatable_relocs( Symbol_table* symtab, Layout* layout, - Sized_relobj<32, big_endian>* object, + Sized_relobj_file<32, big_endian>* object, unsigned int data_shndx, unsigned int sh_type, const unsigned char* prelocs, @@ -9294,17 +9605,17 @@ Target_arm::scan_relocatable_relocs( rr); } -// Relocate a section during a relocatable link. +// Emit relocations for a section. template void -Target_arm::relocate_for_relocatable( +Target_arm::relocate_relocs( const Relocate_info<32, big_endian>* relinfo, unsigned int sh_type, const unsigned char* prelocs, size_t reloc_count, Output_section* output_section, - off_t offset_in_output_section, + typename elfcpp::Elf_types<32>::Elf_Off offset_in_output_section, const Relocatable_relocs* rr, unsigned char* view, Arm_address view_address, @@ -9314,7 +9625,7 @@ Target_arm::relocate_for_relocatable( { gold_assert(sh_type == elfcpp::SHT_REL); - gold::relocate_for_relocatable<32, big_endian, elfcpp::SHT_REL>( + gold::relocate_relocs<32, big_endian, elfcpp::SHT_REL>( relinfo, prelocs, reloc_count, @@ -9339,7 +9650,7 @@ Target_arm::relocate_special_relocatable( const unsigned char* preloc_in, size_t relnum, Output_section* output_section, - off_t offset_in_output_section, + typename elfcpp::Elf_types<32>::Elf_Off offset_in_output_section, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr view_address, section_size_type, @@ -9394,10 +9705,10 @@ Target_arm::relocate_special_relocatable( else { section_offset_type sot_offset = - convert_types(offset); + convert_types(offset); section_offset_type new_sot_offset = - output_section->output_offset(object, relinfo->data_shndx, - sot_offset); + output_section->output_offset(object, relinfo->data_shndx, + sot_offset); gold_assert(new_sot_offset != -1); new_offset = new_sot_offset; } @@ -9409,7 +9720,7 @@ Target_arm::relocate_special_relocatable( { new_offset += view_address; if (offset_in_output_section != invalid_address) - new_offset -= offset_in_output_section; + new_offset -= offset_in_output_section; } reloc_write.put_r_offset(new_offset); @@ -9431,14 +9742,14 @@ Target_arm::relocate_special_relocatable( Arm_address thumb_bit = object->local_symbol_is_thumb_function(r_sym) ? 1 : 0; if (thumb_bit != 0 - && arp->uses_thumb_bit() + && arp->uses_thumb_bit() && ((psymval->value(object, 0) & 1) != 0)) { Arm_address stripped_value = psymval->value(object, 0) & ~static_cast(1); symval.set_output_value(stripped_value); psymval = &symval; - } + } unsigned char* paddend = view + offset; typename Arm_relocate_functions::Status reloc_status = @@ -9496,7 +9807,7 @@ Target_arm::relocate_special_relocatable( case elfcpp::R_ARM_JUMP24: case elfcpp::R_ARM_XPC25: reloc_status = - Arm_relocate_functions::arm_branch_common( + Arm_relocate_functions::arm_branch_common( r_type, relinfo, paddend, NULL, object, 0, psymval, 0, thumb_bit, false); break; @@ -9630,7 +9941,7 @@ Target_arm::do_dynsym_value(const Symbol* gsym) const // template unsigned int -Target_arm::get_real_reloc_type (unsigned int r_type) +Target_arm::get_real_reloc_type(unsigned int r_type) { switch (r_type) { @@ -9639,7 +9950,7 @@ Target_arm::get_real_reloc_type (unsigned int r_type) return elfcpp::R_ARM_ABS32; case elfcpp::R_ARM_TARGET2: - // This can be any reloc type but ususally is R_ARM_GOT_PREL + // This can be any reloc type but usually is R_ARM_GOT_PREL return elfcpp::R_ARM_GOT_PREL; default: @@ -9717,15 +10028,16 @@ template void Target_arm::do_adjust_elf_header( unsigned char* view, - int len) const + int len) { gold_assert(len == elfcpp::Elf_sizes<32>::ehdr_size); elfcpp::Ehdr<32, big_endian> ehdr(view); + elfcpp::Elf_Word flags = this->processor_specific_flags(); unsigned char e_ident[elfcpp::EI_NIDENT]; memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT); - if (elfcpp::arm_eabi_version(this->processor_specific_flags()) + if (elfcpp::arm_eabi_version(flags) == elfcpp::EF_ARM_EABI_UNKNOWN) e_ident[elfcpp::EI_OSABI] = elfcpp::ELFOSABI_ARM; else @@ -9734,14 +10046,29 @@ Target_arm::do_adjust_elf_header( // FIXME: Do EF_ARM_BE8 adjustment. + // If we're working in EABI_VER5, set the hard/soft float ABI flags + // as appropriate. + if (elfcpp::arm_eabi_version(flags) == elfcpp::EF_ARM_EABI_VER5) + { + elfcpp::Elf_Half type = ehdr.get_e_type(); + if (type == elfcpp::ET_EXEC || type == elfcpp::ET_DYN) + { + Object_attribute* attr = this->get_aeabi_object_attribute(elfcpp::Tag_ABI_VFP_args); + if (attr->int_value()) + flags |= elfcpp::EF_ARM_ABI_FLOAT_HARD; + else + flags |= elfcpp::EF_ARM_ABI_FLOAT_SOFT; + this->set_processor_specific_flags(flags); + } + } elfcpp::Ehdr_write<32, big_endian> oehdr(view); oehdr.put_e_ident(e_ident); } // do_make_elf_object to override the same function in the base class. -// We need to use a target-specific sub-class of Sized_relobj<32, big_endian> -// to store ARM specific information. Hence we need to have our own -// ELF object creation. +// We need to use a target-specific sub-class of +// Sized_relobj_file<32, big_endian> to store ARM specific information. +// Hence we need to have our own ELF object creation. template Object* @@ -9751,24 +10078,27 @@ Target_arm::do_make_elf_object( off_t offset, const elfcpp::Ehdr<32, big_endian>& ehdr) { int et = ehdr.get_e_type(); - if (et == elfcpp::ET_REL) + // ET_EXEC files are valid input for --just-symbols/-R, + // and we treat them as relocatable objects. + if (et == elfcpp::ET_REL + || (et == elfcpp::ET_EXEC && input_file->just_symbols())) { Arm_relobj* obj = - new Arm_relobj(name, input_file, offset, ehdr); + new Arm_relobj(name, input_file, offset, ehdr); obj->setup(); return obj; } else if (et == elfcpp::ET_DYN) { Sized_dynobj<32, big_endian>* obj = - new Arm_dynobj(name, input_file, offset, ehdr); + new Arm_dynobj(name, input_file, offset, ehdr); obj->setup(); return obj; } else { gold_error(_("%s: unsupported ELF file type %d"), - name.c_str(), et); + name.c_str(), et); return NULL; } } @@ -9782,7 +10112,7 @@ int Target_arm::get_secondary_compatible_arch( const Attributes_section_data* pasd) { - const Object_attribute *known_attributes = + const Object_attribute* known_attributes = pasd->known_attributes(Object_attribute::OBJ_ATTR_PROC); // Note: the tag and its argument below are uleb128 values, though @@ -9808,7 +10138,7 @@ Target_arm::set_secondary_compatible_arch( Attributes_section_data* pasd, int arch) { - Object_attribute *known_attributes = + Object_attribute* known_attributes = pasd->known_attributes(Object_attribute::OBJ_ATTR_PROC); if (arch == -1) @@ -9947,7 +10277,7 @@ Target_arm::tag_cpu_arch_combine( T(V7E_M), // V7E_M. T(V4T_PLUS_V6_M) // V4T plus V6_M. }; - static const int *comb[] = + static const int* comb[] = { v6t2, v6k, @@ -9961,7 +10291,7 @@ Target_arm::tag_cpu_arch_combine( // Check we've not got a higher architecture than we know about. - if (oldtag >= elfcpp::MAX_TAG_CPU_ARCH || newtag >= elfcpp::MAX_TAG_CPU_ARCH) + if (oldtag > elfcpp::MAX_TAG_CPU_ARCH || newtag > elfcpp::MAX_TAG_CPU_ARCH) { gold_error(_("%s: unknown CPU architecture"), name); return -1; @@ -10015,7 +10345,7 @@ template std::string Target_arm::aeabi_enum_name(unsigned int value) { - static const char *aeabi_enum_names[] = + static const char* aeabi_enum_names[] = { "", "variable-size", "32-bit", "" }; const size_t aeabi_enum_names_size = sizeof(aeabi_enum_names) / sizeof(aeabi_enum_names[0]); @@ -10036,7 +10366,7 @@ template std::string Target_arm::tag_cpu_name_value(unsigned int value) { - static const char *name_table[] = { + static const char* name_table[] = { // These aren't real CPU names, but we can't guess // that from the architecture version alone. "Pre v4", @@ -10063,7 +10393,50 @@ Target_arm::tag_cpu_name_value(unsigned int value) char buffer[100]; sprintf(buffer, "", value); return std::string(buffer); - } + } +} + +// Query attributes object to see if integer divide instructions may be +// present in an object. + +template +bool +Target_arm::attributes_accept_div(int arch, int profile, + const Object_attribute* div_attr) +{ + switch (div_attr->int_value()) + { + case 0: + // Integer divide allowed if instruction contained in + // archetecture. + if (arch == elfcpp::TAG_CPU_ARCH_V7 && (profile == 'R' || profile == 'M')) + return true; + else if (arch >= elfcpp::TAG_CPU_ARCH_V7E_M) + return true; + else + return false; + + case 1: + // Integer divide explicitly prohibited. + return false; + + default: + // Unrecognised case - treat as allowing divide everywhere. + case 2: + // Integer divide allowed in ARM state. + return true; + } +} + +// Query attributes object to see if integer divide instructions are +// forbidden to be in the object. This is not the inverse of +// attributes_accept_div. + +template +bool +Target_arm::attributes_forbid_div(const Object_attribute* div_attr) +{ + return div_attr->int_value() == 1; } // Merge object attributes from input file called NAME with those of the @@ -10093,7 +10466,7 @@ Target_arm::merge_object_attributes( { if (out_attr[elfcpp::Tag_MPextension_use].int_value() != 0 && out_attr[elfcpp::Tag_MPextension_use_legacy].int_value() - != out_attr[elfcpp::Tag_MPextension_use].int_value()) + != out_attr[elfcpp::Tag_MPextension_use].int_value()) { gold_error(_("%s has both the current and legacy " "Tag_MPextension_use attributes"), @@ -10123,7 +10496,7 @@ Target_arm::merge_object_attributes( in_attr[elfcpp::Tag_ABI_VFP_args].int_value()); else if (in_attr[elfcpp::Tag_ABI_FP_number_model].int_value() != 0 && parameters->options().warn_mismatch()) - gold_error(_("%s uses VFP register arguments, output does not"), + gold_error(_("%s uses VFP register arguments, output does not"), name); } @@ -10223,7 +10596,7 @@ Target_arm::merge_object_attributes( || (out_attr[elfcpp::Tag_ABI_align8_preserved].int_value() == 0))) { - // This error message should be enabled once all non-conformant + // This error message should be enabled once all non-conforming // binaries in the toolchain have had the attributes set // properly. // gold_error(_("output 8-byte data alignment conflicts with %s"), @@ -10400,7 +10773,7 @@ Target_arm::merge_object_attributes( } break; case elfcpp::Tag_ABI_VFP_args: - // Aready done. + // Already done. break; case elfcpp::Tag_ABI_WMMX_args: if (in_attr[i].int_value() != out_attr[i].int_value() @@ -10435,27 +10808,33 @@ Target_arm::merge_object_attributes( break; case elfcpp::Tag_DIV_use: - // This tag is set to zero if we can use UDIV and SDIV in Thumb - // mode on a v7-M or v7-R CPU; to one if we can not use UDIV or - // SDIV at all; and to two if we can use UDIV or SDIV on a v7-A - // CPU. We will merge as follows: If the input attribute's value - // is one then the output attribute's value remains unchanged. If - // the input attribute's value is zero or two then if the output - // attribute's value is one the output value is set to the input - // value, otherwise the output value must be the same as the - // inputs. */ - if (in_attr[i].int_value() != 1 && out_attr[i].int_value() != 1) - { - if (in_attr[i].int_value() != out_attr[i].int_value()) - { - gold_error(_("DIV usage mismatch between %s and output"), - name); - } - } - - if (in_attr[i].int_value() != 1) - out_attr[i].set_int_value(in_attr[i].int_value()); - + { + // A value of zero on input means that the divide + // instruction may be used if available in the base + // architecture as specified via Tag_CPU_arch and + // Tag_CPU_arch_profile. A value of 1 means that the user + // did not want divide instructions. A value of 2 + // explicitly means that divide instructions were allowed + // in ARM and Thumb state. + int arch = this-> + get_aeabi_object_attribute(elfcpp::Tag_CPU_arch)-> + int_value(); + int profile = this-> + get_aeabi_object_attribute(elfcpp::Tag_CPU_arch_profile)-> + int_value(); + if (in_attr[i].int_value() == out_attr[i].int_value()) + { + // Do nothing. + } + else if (attributes_forbid_div(&in_attr[i]) + && !attributes_accept_div(arch, profile, &out_attr[i])) + out_attr[i].set_int_value(1); + else if (attributes_forbid_div(&out_attr[i]) + && attributes_accept_div(arch, profile, &in_attr[i])) + out_attr[i].set_int_value(in_attr[i].int_value()); + else if (in_attr[i].int_value() == 2) + out_attr[i].set_int_value(in_attr[i].int_value()); + } break; case elfcpp::Tag_MPextension_use_legacy: @@ -10468,7 +10847,7 @@ Target_arm::merge_object_attributes( != in_attr[i].int_value()) { gold_error(_("%s has has both the current and legacy " - "Tag_MPextension_use attributes"), + "Tag_MPextension_use attributes"), name); } } @@ -10564,7 +10943,7 @@ Target_arm::merge_object_attributes( err_tag = out_iter->first; int saved_tag = out_iter->first; delete out_iter->second; - out_other_attributes->erase(out_iter); + out_other_attributes->erase(out_iter); out_iter = out_other_attributes->upper_bound(saved_tag); } else if (in_iter != in_other_attributes->end() @@ -10642,7 +11021,7 @@ Target_arm::new_arm_input_section( // for this input section already. gold_assert(ins.second); - return arm_input_section; + return arm_input_section; } // Find the Arm_input_section object corresponding to the SHNDX-th input @@ -10690,8 +11069,6 @@ Target_arm::scan_reloc_for_stub( elfcpp::Elf_types<32>::Elf_Swxword addend, Arm_address address) { - typedef typename Target_arm::Relocate Relocate; - const Arm_relobj* arm_relobj = Arm_relobj::as_arm_relobj(relinfo->object); @@ -10701,7 +11078,7 @@ Target_arm::scan_reloc_for_stub( { // This is a global symbol. Determine if we use PLT and if the // final target is THUMB. - if (gsym->use_plt_offset(Relocate::reloc_is_non_pic(r_type))) + if (gsym->use_plt_offset(Scan::get_reference_flags(r_type))) { // This uses a PLT, change the symbol value. symval.set_output_value(this->plt_section()->address() @@ -10739,7 +11116,7 @@ Target_arm::scan_reloc_for_stub( psymval->value(arm_relobj, 0) & ~static_cast(1); symval.set_output_value(stripped_value); psymval = &symval; - } + } // Get the symbol value. Symbol_value<32>::Value value = psymval->value(arm_relobj, 0); @@ -10773,10 +11150,10 @@ Target_arm::scan_reloc_for_stub( if (stub_type != arm_stub_none) { // Try looking up an existing stub from a stub table. - Stub_table* stub_table = + Stub_table* stub_table = arm_relobj->stub_table(relinfo->data_shndx); gold_assert(stub_table != NULL); - + // Locate stub by destination. Reloc_stub::Key stub_key(stub_type, gsym, arm_relobj, r_sym, addend); @@ -10850,6 +11227,7 @@ Target_arm::scan_reloc_section_for_stubs( Arm_relobj::as_arm_relobj(relinfo->object); unsigned int local_count = arm_object->local_symbol_count(); + gold::Default_comdat_behavior default_comdat_behavior; Comdat_behavior comdat_behavior = CB_UNDETERMINED; for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size) @@ -10864,13 +11242,13 @@ Target_arm::scan_reloc_section_for_stubs( // Only a few relocation types need stubs. if ((r_type != elfcpp::R_ARM_CALL) - && (r_type != elfcpp::R_ARM_JUMP24) - && (r_type != elfcpp::R_ARM_PLT32) - && (r_type != elfcpp::R_ARM_THM_CALL) - && (r_type != elfcpp::R_ARM_THM_XPC22) - && (r_type != elfcpp::R_ARM_THM_JUMP24) - && (r_type != elfcpp::R_ARM_THM_JUMP19) - && (r_type != elfcpp::R_ARM_V4BX)) + && (r_type != elfcpp::R_ARM_JUMP24) + && (r_type != elfcpp::R_ARM_PLT32) + && (r_type != elfcpp::R_ARM_THM_CALL) + && (r_type != elfcpp::R_ARM_THM_XPC22) + && (r_type != elfcpp::R_ARM_THM_JUMP24) + && (r_type != elfcpp::R_ARM_THM_JUMP19) + && (r_type != elfcpp::R_ARM_V4BX)) continue; section_offset_type offset = @@ -10909,7 +11287,7 @@ Target_arm::scan_reloc_section_for_stubs( { // create a new stub and add it to stub table. Arm_v4bx_stub* stub = - this->stub_factory().make_arm_v4bx_stub(reg); + this->stub_factory().make_arm_v4bx_stub(reg); gold_assert(stub != NULL); stub_table->add_arm_v4bx_stub(stub); } @@ -10927,56 +11305,66 @@ Target_arm::scan_reloc_section_for_stubs( Symbol_value<32> symval; const Symbol_value<32> *psymval; + bool is_defined_in_discarded_section; + unsigned int shndx; if (r_sym < local_count) { sym = NULL; psymval = arm_object->local_symbol(r_sym); - // If the local symbol belongs to a section we are discarding, - // and that section is a debug section, try to find the - // corresponding kept section and map this symbol to its - // counterpart in the kept section. The symbol must not - // correspond to a section we are folding. + // If the local symbol belongs to a section we are discarding, + // and that section is a debug section, try to find the + // corresponding kept section and map this symbol to its + // counterpart in the kept section. The symbol must not + // correspond to a section we are folding. bool is_ordinary; - unsigned int shndx = psymval->input_shndx(&is_ordinary); - if (is_ordinary - && shndx != elfcpp::SHN_UNDEF - && !arm_object->is_section_included(shndx) - && !(relinfo->symtab->is_section_folded(arm_object, shndx))) + shndx = psymval->input_shndx(&is_ordinary); + is_defined_in_discarded_section = + (is_ordinary + && shndx != elfcpp::SHN_UNDEF + && !arm_object->is_section_included(shndx) + && !relinfo->symtab->is_section_folded(arm_object, shndx)); + + // We need to compute the would-be final value of this local + // symbol. + if (!is_defined_in_discarded_section) { - if (comdat_behavior == CB_UNDETERMINED) - { - std::string name = - arm_object->section_name(relinfo->data_shndx); - comdat_behavior = get_comdat_behavior(name.c_str()); - } - if (comdat_behavior == CB_PRETEND) - { - bool found; - typename elfcpp::Elf_types<32>::Elf_Addr value = - arm_object->map_to_kept_section(shndx, &found); - if (found) - symval.set_output_value(value + psymval->input_value()); - else - symval.set_output_value(0); - } + typedef Sized_relobj_file<32, big_endian> ObjType; + typename ObjType::Compute_final_local_value_status status = + arm_object->compute_final_local_value(r_sym, psymval, &symval, + relinfo->symtab); + if (status == ObjType::CFLV_OK) + { + // Currently we cannot handle a branch to a target in + // a merged section. If this is the case, issue an error + // and also free the merge symbol value. + if (!symval.has_output_value()) + { + const std::string& section_name = + arm_object->section_name(shndx); + arm_object->error(_("cannot handle branch to local %u " + "in a merged section %s"), + r_sym, section_name.c_str()); + } + psymval = &symval; + } else - { - symval.set_output_value(0); - } - symval.set_no_output_symtab_entry(); - psymval = &symval; + { + // We cannot determine the final value. + continue; + } } } else { - const Symbol* gsym = arm_object->global_symbol(r_sym); + const Symbol* gsym; + gsym = arm_object->global_symbol(r_sym); gold_assert(gsym != NULL); if (gsym->is_forwarder()) gsym = relinfo->symtab->resolve_forwards(gsym); sym = static_cast*>(gsym); - if (sym->has_symtab_index()) + if (sym->has_symtab_index() && sym->symtab_index() != -1U) symval.set_output_symtab_index(sym->symtab_index()); else symval.set_no_output_symtab_entry(); @@ -10993,9 +11381,53 @@ Target_arm::scan_reloc_section_for_stubs( // Skip this if the symbol has not output section. if (status == Symbol_table::CFVS_NO_OUTPUT_SECTION) continue; - symval.set_output_value(value); + + if (gsym->type() == elfcpp::STT_TLS) + symval.set_is_tls_symbol(); + else if (gsym->type() == elfcpp::STT_GNU_IFUNC) + symval.set_is_ifunc_symbol(); psymval = &symval; + + is_defined_in_discarded_section = + (gsym->is_defined_in_discarded_section() + && gsym->is_undefined()); + shndx = 0; + } + + Symbol_value<32> symval2; + if (is_defined_in_discarded_section) + { + if (comdat_behavior == CB_UNDETERMINED) + { + std::string name = arm_object->section_name(relinfo->data_shndx); + comdat_behavior = default_comdat_behavior.get(name.c_str()); + } + if (comdat_behavior == CB_PRETEND) + { + // FIXME: This case does not work for global symbols. + // We have no place to store the original section index. + // Fortunately this does not matter for comdat sections, + // only for sections explicitly discarded by a linker + // script. + bool found; + typename elfcpp::Elf_types<32>::Elf_Addr value = + arm_object->map_to_kept_section(shndx, &found); + if (found) + symval2.set_output_value(value + psymval->input_value()); + else + symval2.set_output_value(0); + } + else + { + if (comdat_behavior == CB_WARNING) + gold_warning_at_location(relinfo, i, offset, + _("relocation refers to discarded " + "section")); + symval2.set_output_value(0); + } + symval2.set_no_output_symtab_entry(); + psymval = &symval2; } // If symbol is a section symbol, we don't know the actual type of @@ -11051,12 +11483,12 @@ Target_arm::scan_section_for_stubs( // Group input sections for stub generation. // -// We goup input sections in an output sections so that the total size, +// We group input sections in an output section so that the total size, // including any padding space due to alignment is smaller than GROUP_SIZE // unless the only input section in group is bigger than GROUP_SIZE already. // Then an ARM stub table is created to follow the last input section // in group. For each group an ARM stub table is created an is placed -// after the last group. If STUB_ALWATS_AFTER_BRANCH is false, we further +// after the last group. If STUB_ALWAYS_AFTER_BRANCH is false, we further // extend the group after the stub table. template @@ -11064,11 +11496,12 @@ void Target_arm::group_sections( Layout* layout, section_size_type group_size, - bool stubs_always_after_branch) + bool stubs_always_after_branch, + const Task* task) { // Group input sections and insert stub table Layout::Section_list section_list; - layout->get_allocated_sections(§ion_list); + layout->get_executable_sections(§ion_list); for (Layout::Section_list::const_iterator p = section_list.begin(); p != section_list.end(); ++p) @@ -11076,7 +11509,7 @@ Target_arm::group_sections( Arm_output_section* output_section = Arm_output_section::as_arm_output_section(*p); output_section->group_sections(group_size, stubs_always_after_branch, - this); + this, task); } } @@ -11088,7 +11521,8 @@ Target_arm::do_relax( int pass, const Input_objects* input_objects, Symbol_table* symtab, - Layout* layout) + Layout* layout, + const Task* task) { // No need to generate stubs if this is a relocatable link. gold_assert(!parameters->options().relocatable()); @@ -11101,7 +11535,7 @@ Target_arm::do_relax( { // Determine the stub group size. The group size is the absolute // value of the parameter --stub-group-size. If --stub-group-size - // is passed a negative value, we restict stubs to be always after + // is passed a negative value, we restrict stubs to be always after // the stubbed branches. int32_t stub_group_size_param = parameters->options().stub_group_size(); @@ -11137,8 +11571,8 @@ Target_arm::do_relax( stub_group_size = std::max(stub_group_size, cortex_a8_group_size); } - group_sections(layout, stub_group_size, stubs_always_after_branch); - + group_sections(layout, stub_group_size, stubs_always_after_branch, task); + // Also fix .ARM.exidx section coverage. Arm_output_section* exidx_output_section = NULL; for (Layout::Section_list::const_iterator p = @@ -11161,7 +11595,7 @@ Target_arm::do_relax( if (exidx_output_section != NULL) { this->fix_exidx_coverage(layout, input_objects, exidx_output_section, - symtab); + symtab, task); done_exidx_fixup = true; } } @@ -11202,7 +11636,7 @@ Target_arm::do_relax( ++sp) (*sp)->remove_all_cortex_a8_stubs(); } - + // Scan relocs for relocation stubs for (Input_objects::Relobj_iterator op = input_objects->relobj_begin(); op != input_objects->relobj_end(); @@ -11210,6 +11644,9 @@ Target_arm::do_relax( { Arm_relobj* arm_relobj = Arm_relobj::as_arm_relobj(*op); + // Lock the object so we can read from it. This is only called + // single-threaded from Layout::finalize, so it is OK to lock. + Task_lock_obj tl(task, arm_relobj); arm_relobj->scan_sections_for_stubs(this, symtab, layout); } @@ -11240,7 +11677,7 @@ Target_arm::do_relax( // need to update output sections, so we record all output sections needing // update above and scan the sections here to find out what sections need // to be updated. - for(Layout::Section_list::const_iterator p = layout->section_list().begin(); + for (Layout::Section_list::const_iterator p = layout->section_list().begin(); p != layout->section_list().end(); ++p) { @@ -11272,7 +11709,11 @@ Target_arm::do_relax( // symbols defined in parts of input sections that are discarded by // relaxation. if (arm_relobj->output_local_symbol_count_needs_update()) - arm_relobj->update_output_local_symbol_count(); + { + // We need to lock the object's file to update it. + Task_lock_obj tl(task, arm_relobj); + arm_relobj->update_output_local_symbol_count(); + } } } @@ -11360,7 +11801,7 @@ Target_arm::do_attributes_order(int num) const { // Reorder the known object attributes in output. We want to move // Tag_conformance to position 4 and Tag_conformance to position 5 - // and shift eveything between 4 .. Tag_conformance - 1 to make room. + // and shift everything between 4 .. Tag_conformance - 1 to make room. if (num == 4) return elfcpp::Tag_conformance; if (num == 5) @@ -11411,16 +11852,16 @@ Target_arm::scan_span_for_cortex_a8_erratum( // Encoding T4: B.W. is_b = (insn & 0xf800d000U) == 0xf0009000U; // Encoding T1: BL.W. - is_bl = (insn & 0xf800d000U) == 0xf000d000U; - // Encoding T2: BLX.W. - is_blx = (insn & 0xf800d000U) == 0xf000c000U; + is_bl = (insn & 0xf800d000U) == 0xf000d000U; + // Encoding T2: BLX.W. + is_blx = (insn & 0xf800d000U) == 0xf000c000U; // Encoding T3: B.W (not permitted in IT block). is_bcc = ((insn & 0xf800d000U) == 0xf0008000U && (insn & 0x07f00000U) != 0x03800000U); } bool is_32bit_branch = is_b || is_bl || is_blx || is_bcc; - + // If this instruction is a 32-bit THUMB branch that crosses a 4K // page boundary and it follows 32-bit non-branch instruction, // we need to work around. @@ -11455,7 +11896,7 @@ Target_arm::scan_span_for_cortex_a8_erratum( // Check if we have an offending branch instruction. uint16_t upper_insn = (insn >> 16) & 0xffffU; uint16_t lower_insn = insn & 0xffffU; - typedef struct Arm_relocate_functions RelocFuncs; + typedef class Arm_relocate_functions RelocFuncs; if (cortex_a8_reloc != NULL && cortex_a8_reloc->reloc_stub() != NULL) @@ -11475,7 +11916,7 @@ Target_arm::scan_span_for_cortex_a8_erratum( offset = RelocFuncs::thumb32_branch_offset(upper_insn, lower_insn); if (is_blx) - offset &= ~3; + offset &= ~3; stub_type = (is_blx ? arm_stub_a8_veneer_blx @@ -11492,7 +11933,7 @@ Target_arm::scan_span_for_cortex_a8_erratum( // an ARM instruction. If we were not making a stub, // the BL would have been converted to a BLX. Use the // BLX stub instead in that case. - if (this->may_use_blx() && force_target_arm + if (this->may_use_v5t_interworking() && force_target_arm && stub_type == arm_stub_a8_veneer_bl) { stub_type = arm_stub_a8_veneer_blx; @@ -11512,17 +11953,17 @@ Target_arm::scan_span_for_cortex_a8_erratum( if (is_blx) pc_for_insn &= ~3; - // If we found a relocation, use the proper destination, + // If we found a relocation, use the proper destination, // not the offset in the (unrelocated) instruction. // Note this is always done if we switched the stub type above. - if (cortex_a8_reloc != NULL) - offset = (off_t) (cortex_a8_reloc->destination() - pc_for_insn); + if (cortex_a8_reloc != NULL) + offset = (off_t) (cortex_a8_reloc->destination() - pc_for_insn); - Arm_address target = (pc_for_insn + offset) | (is_blx ? 0 : 1); + Arm_address target = (pc_for_insn + offset) | (is_blx ? 0 : 1); // Add a new stub if destination address in in the same page. - if (((address + i) & ~0xfffU) == (target & ~0xfffU)) - { + if (((address + i) & ~0xfffU) == (target & ~0xfffU)) + { Cortex_a8_stub* stub = this->stub_factory_.make_cortex_a8_stub(stub_type, arm_relobj, shndx, @@ -11532,9 +11973,9 @@ Target_arm::scan_span_for_cortex_a8_erratum( arm_relobj->stub_table(shndx); gold_assert(stub_table != NULL); stub_table->add_cortex_a8_stub(address + i, stub); - } - } - } + } + } + } i += insn_32bit ? 4 : 2; last_was_32bit = insn_32bit; @@ -11558,11 +11999,11 @@ Target_arm::apply_cortex_a8_workaround( Valtype lower_insn = elfcpp::Swap<16, big_endian>::readval(wv + 1); off_t branch_offset = stub_address - (insn_address + 4); - typedef struct Arm_relocate_functions RelocFuncs; + typedef class Arm_relocate_functions RelocFuncs; switch (stub->stub_template()->type()) { case arm_stub_a8_veneer_b_cond: - // For a conditional branch, we re-write it to be a uncondition + // For a conditional branch, we re-write it to be an unconditional // branch to the stub. We use the THUMB-2 encoding here. upper_insn = 0xf000U; lower_insn = 0xb800U; @@ -11578,7 +12019,7 @@ Target_arm::apply_cortex_a8_workaround( branch_offset = (branch_offset + 2) & ~3; // Put BRANCH_OFFSET back into the insn. - gold_assert(!utils::has_overflow<25>(branch_offset)); + gold_assert(!Bits<25>::has_overflow32(branch_offset)); upper_insn = RelocFuncs::thumb32_branch_upper(upper_insn, branch_offset); lower_insn = RelocFuncs::thumb32_branch_lower(lower_insn, branch_offset); break; @@ -11592,13 +12033,17 @@ Target_arm::apply_cortex_a8_workaround( elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn); } +// Target selector for ARM. Note this is never instantiated directly. +// It's only used in Target_selector_arm_nacl, below. + template class Target_selector_arm : public Target_selector { public: Target_selector_arm() : Target_selector(elfcpp::EM_ARM, 32, big_endian, - (big_endian ? "elf32-bigarm" : "elf32-littlearm")) + (big_endian ? "elf32-bigarm" : "elf32-littlearm"), + (big_endian ? "armelfb" : "armelf")) { } Target* @@ -11614,7 +12059,8 @@ Target_arm::fix_exidx_coverage( Layout* layout, const Input_objects* input_objects, Arm_output_section* exidx_section, - Symbol_table* symtab) + Symbol_table* symtab, + const Task* task) { // We need to look at all the input sections in output in ascending // order of of output address. We do that by building a sorted list @@ -11644,7 +12090,7 @@ Target_arm::fix_exidx_coverage( if (!exidx_input_section->has_errors()) { unsigned int text_shndx = exidx_input_section->link(); - Output_section *os = arm_relobj->output_section(text_shndx); + Output_section* os = arm_relobj->output_section(text_shndx); if (os != NULL && (os->flags() & elfcpp::SHF_ALLOC) != 0) sorted_output_sections.insert(os); } @@ -11655,7 +12101,7 @@ Target_arm::fix_exidx_coverage( typedef typename Arm_output_section::Text_section_list Text_section_list; Text_section_list sorted_text_sections; - for(typename Sorted_output_section_list::iterator p = + for (typename Sorted_output_section_list::iterator p = sorted_output_sections.begin(); p != sorted_output_sections.end(); ++p) @@ -11663,13 +12109,279 @@ Target_arm::fix_exidx_coverage( Arm_output_section* arm_output_section = Arm_output_section::as_arm_output_section(*p); arm_output_section->append_text_sections_to_list(&sorted_text_sections); - } + } exidx_section->fix_exidx_coverage(layout, sorted_text_sections, symtab, - merge_exidx_entries()); + merge_exidx_entries(), task); +} + +template +void +Target_arm::do_define_standard_symbols( + Symbol_table* symtab, + Layout* layout) +{ + // Handle the .ARM.exidx section. + Output_section* exidx_section = layout->find_output_section(".ARM.exidx"); + + if (exidx_section != NULL) + { + // Create __exidx_start and __exidx_end symbols. + symtab->define_in_output_data("__exidx_start", + NULL, // version + Symbol_table::PREDEFINED, + exidx_section, + 0, // value + 0, // symsize + elfcpp::STT_NOTYPE, + elfcpp::STB_GLOBAL, + elfcpp::STV_HIDDEN, + 0, // nonvis + false, // offset_is_from_end + true); // only_if_ref + + symtab->define_in_output_data("__exidx_end", + NULL, // version + Symbol_table::PREDEFINED, + exidx_section, + 0, // value + 0, // symsize + elfcpp::STT_NOTYPE, + elfcpp::STB_GLOBAL, + elfcpp::STV_HIDDEN, + 0, // nonvis + true, // offset_is_from_end + true); // only_if_ref + } + else + { + // Define __exidx_start and __exidx_end even when .ARM.exidx + // section is missing to match ld's behaviour. + symtab->define_as_constant("__exidx_start", NULL, + Symbol_table::PREDEFINED, + 0, 0, elfcpp::STT_OBJECT, + elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0, + true, false); + symtab->define_as_constant("__exidx_end", NULL, + Symbol_table::PREDEFINED, + 0, 0, elfcpp::STT_OBJECT, + elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0, + true, false); + } +} + +// NaCl variant. It uses different PLT contents. + +template +class Output_data_plt_arm_nacl; + +template +class Target_arm_nacl : public Target_arm +{ + public: + Target_arm_nacl() + : Target_arm(&arm_nacl_info) + { } + + protected: + virtual Output_data_plt_arm* + do_make_data_plt(Layout* layout, Output_data_space* got_plt) + { return new Output_data_plt_arm_nacl(layout, got_plt); } + + private: + static const Target::Target_info arm_nacl_info; +}; + +template +const Target::Target_info Target_arm_nacl::arm_nacl_info = +{ + 32, // size + big_endian, // is_big_endian + elfcpp::EM_ARM, // machine_code + false, // has_make_symbol + false, // has_resolve + false, // has_code_fill + true, // is_default_stack_executable + false, // can_icf_inline_merge_sections + '\0', // wrap_char + "/lib/ld-nacl-arm.so.1", // dynamic_linker + 0x20000, // default_text_segment_address + 0x10000, // abi_pagesize (overridable by -z max-page-size) + 0x10000, // common_pagesize (overridable by -z common-page-size) + true, // isolate_execinstr + 0x10000000, // rosegment_gap + elfcpp::SHN_UNDEF, // small_common_shndx + elfcpp::SHN_UNDEF, // large_common_shndx + 0, // small_common_section_flags + 0, // large_common_section_flags + ".ARM.attributes", // attributes_section + "aeabi", // attributes_vendor + "_start" // entry_symbol_name +}; + +template +class Output_data_plt_arm_nacl : public Output_data_plt_arm +{ + public: + Output_data_plt_arm_nacl(Layout* layout, Output_data_space* got_plt) + : Output_data_plt_arm(layout, 16, got_plt) + { } + + protected: + // Return the offset of the first non-reserved PLT entry. + virtual unsigned int + do_first_plt_entry_offset() const + { return sizeof(first_plt_entry); } + + // Return the size of a PLT entry. + virtual unsigned int + do_get_plt_entry_size() const + { return sizeof(plt_entry); } + + virtual void + do_fill_first_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address); + + virtual void + do_fill_plt_entry(unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset); + + private: + inline uint32_t arm_movw_immediate(uint32_t value) + { + return (value & 0x00000fff) | ((value & 0x0000f000) << 4); + } + + inline uint32_t arm_movt_immediate(uint32_t value) + { + return ((value & 0x0fff0000) >> 16) | ((value & 0xf0000000) >> 12); + } + + // Template for the first PLT entry. + static const uint32_t first_plt_entry[16]; + + // Template for subsequent PLT entries. + static const uint32_t plt_entry[4]; +}; + +// The first entry in the PLT. +template +const uint32_t Output_data_plt_arm_nacl::first_plt_entry[16] = +{ + // First bundle: + 0xe300c000, // movw ip, #:lower16:&GOT[2]-.+8 + 0xe340c000, // movt ip, #:upper16:&GOT[2]-.+8 + 0xe08cc00f, // add ip, ip, pc + 0xe52dc008, // str ip, [sp, #-8]! + // Second bundle: + 0xe3ccc103, // bic ip, ip, #0xc0000000 + 0xe59cc000, // ldr ip, [ip] + 0xe3ccc13f, // bic ip, ip, #0xc000000f + 0xe12fff1c, // bx ip + // Third bundle: + 0xe320f000, // nop + 0xe320f000, // nop + 0xe320f000, // nop + // .Lplt_tail: + 0xe50dc004, // str ip, [sp, #-4] + // Fourth bundle: + 0xe3ccc103, // bic ip, ip, #0xc0000000 + 0xe59cc000, // ldr ip, [ip] + 0xe3ccc13f, // bic ip, ip, #0xc000000f + 0xe12fff1c, // bx ip +}; + +template +void +Output_data_plt_arm_nacl::do_fill_first_plt_entry( + unsigned char* pov, + Arm_address got_address, + Arm_address plt_address) +{ + // Write first PLT entry. All but first two words are constants. + const size_t num_first_plt_words = (sizeof(first_plt_entry) + / sizeof(first_plt_entry[0])); + + int32_t got_displacement = got_address + 8 - (plt_address + 16); + + elfcpp::Swap<32, big_endian>::writeval + (pov + 0, first_plt_entry[0] | arm_movw_immediate (got_displacement)); + elfcpp::Swap<32, big_endian>::writeval + (pov + 4, first_plt_entry[1] | arm_movt_immediate (got_displacement)); + + for (size_t i = 2; i < num_first_plt_words; ++i) + elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]); +} + +// Subsequent entries in the PLT. + +template +const uint32_t Output_data_plt_arm_nacl::plt_entry[4] = +{ + 0xe300c000, // movw ip, #:lower16:&GOT[n]-.+8 + 0xe340c000, // movt ip, #:upper16:&GOT[n]-.+8 + 0xe08cc00f, // add ip, ip, pc + 0xea000000, // b .Lplt_tail +}; + +template +void +Output_data_plt_arm_nacl::do_fill_plt_entry( + unsigned char* pov, + Arm_address got_address, + Arm_address plt_address, + unsigned int got_offset, + unsigned int plt_offset) +{ + // Calculate the displacement between the PLT slot and the + // common tail that's part of the special initial PLT slot. + int32_t tail_displacement = (plt_address + (11 * sizeof(uint32_t)) + - (plt_address + plt_offset + + sizeof(plt_entry) + sizeof(uint32_t))); + gold_assert((tail_displacement & 3) == 0); + tail_displacement >>= 2; + + gold_assert ((tail_displacement & 0xff000000) == 0 + || (-tail_displacement & 0xff000000) == 0); + + // Calculate the displacement between the PLT slot and the entry + // in the GOT. The offset accounts for the value produced by + // adding to pc in the penultimate instruction of the PLT stub. + const int32_t got_displacement = (got_address + got_offset + - (plt_address + sizeof(plt_entry))); + + elfcpp::Swap<32, big_endian>::writeval + (pov + 0, plt_entry[0] | arm_movw_immediate (got_displacement)); + elfcpp::Swap<32, big_endian>::writeval + (pov + 4, plt_entry[1] | arm_movt_immediate (got_displacement)); + elfcpp::Swap<32, big_endian>::writeval + (pov + 8, plt_entry[2]); + elfcpp::Swap<32, big_endian>::writeval + (pov + 12, plt_entry[3] | (tail_displacement & 0x00ffffff)); } -Target_selector_arm target_selector_arm; -Target_selector_arm target_selector_armbe; +// Target selectors. + +template +class Target_selector_arm_nacl + : public Target_selector_nacl, + Target_arm_nacl > +{ + public: + Target_selector_arm_nacl() + : Target_selector_nacl, + Target_arm_nacl >( + "arm", + big_endian ? "elf32-bigarm-nacl" : "elf32-littlearm-nacl", + big_endian ? "armelfb_nacl" : "armelf_nacl") + { } +}; + +Target_selector_arm_nacl target_selector_arm; +Target_selector_arm_nacl target_selector_armbe; } // End anonymous namespace.