X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fi386.cc;h=2d8efdd5ecb2ed3d6b7695fd4a495c359a825530;hb=dceae3c154edcb9aada9f94452a72548a82914f5;hp=7bd5a3a30bd36bb99114a1317165792b8fd0bc82;hpb=9a2d69841557c502021be98221a796ebe253fa09;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/i386.cc b/gold/i386.cc index 7bd5a3a30b..2d8efdd5ec 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -57,7 +57,7 @@ class Target_i386 : public Sized_target<32, false> Target_i386() : Sized_target<32, false>(&i386_info), got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL), - copy_relocs_(NULL), dynbss_(NULL) + copy_relocs_(NULL), dynbss_(NULL), got_mod_index_offset_(-1U) { } // Scan the relocations to look for symbol adjustments. @@ -94,11 +94,42 @@ class Target_i386 : public Sized_target<32, false> bool needs_special_offset_handling, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr view_address, - off_t view_size); + section_size_type view_size); + + // Scan the relocs during a relocatable link. + void + scan_relocatable_relocs(const General_options& options, + Symbol_table* symtab, + Layout* layout, + Sized_relobj<32, false>* object, + unsigned int data_shndx, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + size_t local_symbol_count, + const unsigned char* plocal_symbols, + Relocatable_relocs*); + + // Relocate a section during a relocatable link. + void + relocate_for_relocatable(const Relocate_info<32, false>*, + 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, + elfcpp::Elf_types<32>::Elf_Addr view_address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size); // Return a string used to fill a code section with nops. std::string - do_code_fill(off_t length); + do_code_fill(section_size_type length); // Return whether SYM is defined by the ABI. bool @@ -106,7 +137,7 @@ class Target_i386 : public Sized_target<32, false> { return strcmp(sym->name(), "___tls_get_addr") == 0; } // Return the size of the GOT section. - off_t + section_size_type got_size() { gold_assert(this->got_ != NULL); @@ -122,6 +153,7 @@ class Target_i386 : public Sized_target<32, false> Layout* layout, Target_i386* target, Sized_relobj<32, false>* object, unsigned int data_shndx, + Output_section* output_section, const elfcpp::Rel<32, false>& reloc, unsigned int r_type, const elfcpp::Sym<32, false>& lsym); @@ -130,6 +162,7 @@ class Target_i386 : public Sized_target<32, false> Layout* layout, Target_i386* target, Sized_relobj<32, false>* object, unsigned int data_shndx, + Output_section* output_section, const elfcpp::Rel<32, false>& reloc, unsigned int r_type, Symbol* gsym); @@ -162,8 +195,7 @@ class Target_i386 : public Sized_target<32, false> // Return whether the static relocation needs to be applied. inline bool should_apply_static_reloc(const Sized_symbol<32>* gsym, - bool is_absolute_ref, - bool is_function_call, + int ref_flags, bool is_32bit); // Do a relocation. Return false if the caller should not issue @@ -174,16 +206,26 @@ class Target_i386 : public Sized_target<32, false> unsigned int r_type, const Sized_symbol<32>*, const Symbol_value<32>*, unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, - off_t); + section_size_type); private: // Do a TLS relocation. inline void - relocate_tls(const Relocate_info<32, false>*, size_t relnum, - const elfcpp::Rel<32, false>&, + relocate_tls(const Relocate_info<32, false>*, Target_i386* target, + size_t relnum, const elfcpp::Rel<32, false>&, unsigned int r_type, const Sized_symbol<32>*, const Symbol_value<32>*, - unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t); + unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, + section_size_type); + + // Do a TLS General-Dynamic to Initial-Exec transition. + inline void + tls_gd_to_ie(const Relocate_info<32, false>*, size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>&, unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size); // Do a TLS General-Dynamic to Local-Exec transition. inline void @@ -192,7 +234,7 @@ class Target_i386 : public Sized_target<32, false> const elfcpp::Rel<32, false>&, unsigned int r_type, elfcpp::Elf_types<32>::Elf_Addr value, unsigned char* view, - off_t view_size); + section_size_type view_size); // Do a TLS Local-Dynamic to Local-Exec transition. inline void @@ -201,7 +243,7 @@ class Target_i386 : public Sized_target<32, false> const elfcpp::Rel<32, false>&, unsigned int r_type, elfcpp::Elf_types<32>::Elf_Addr value, unsigned char* view, - off_t view_size); + section_size_type view_size); // Do a TLS Initial-Exec to Local-Exec transition. static inline void @@ -210,7 +252,7 @@ class Target_i386 : public Sized_target<32, false> const elfcpp::Rel<32, false>&, unsigned int r_type, elfcpp::Elf_types<32>::Elf_Addr value, unsigned char* view, - off_t view_size); + section_size_type view_size); // We need to keep track of which type of local dynamic relocation // we have seen, so that we can optimize R_386_TLS_LDO_32 correctly. @@ -229,6 +271,15 @@ class Target_i386 : public Sized_target<32, false> Local_dynamic_type local_dynamic_type_; }; + // A class which returns the size required for a relocation type, + // used while scanning relocs during a relocatable link. + class Relocatable_size_for_reloc + { + public: + unsigned int + get_size_for_reloc(unsigned int, Relobj*); + }; + // Adjust TLS relocation type based on the options and whether this // is a local symbol. static tls::Tls_optimization @@ -250,6 +301,11 @@ class Target_i386 : public Sized_target<32, false> void make_plt_entry(Symbol_table*, Layout*, Symbol*); + // Create a GOT entry for the TLS module index. + unsigned int + got_mod_index_entry(Symbol_table* symtab, Layout* layout, + Sized_relobj<32, false>* object); + // Get the PLT section. const Output_data_plt_i386* plt_section() const @@ -277,7 +333,7 @@ class Target_i386 : public Sized_target<32, false> void copy_reloc(const General_options*, Symbol_table*, Layout*, Sized_relobj<32, false>*, unsigned int, - Symbol*, const elfcpp::Rel<32, false>&); + Output_section*, Symbol*, const elfcpp::Rel<32, false>&); // Information about this specific target which we pass to the // general Target structure. @@ -295,6 +351,8 @@ class Target_i386 : public Sized_target<32, false> Copy_relocs<32, false>* 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_; }; const Target::Target_info Target_i386::i386_info = @@ -337,10 +395,10 @@ Target_i386::got_section(Symbol_table* symtab, Layout* layout) this->got_plt_); // The first three entries are reserved. - this->got_plt_->set_space_size(3 * 4); + this->got_plt_->set_current_data_size(3 * 4); // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT. - symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL, + symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL, this->got_plt_, 0, 0, elfcpp::STT_OBJECT, elfcpp::STB_LOCAL, @@ -406,7 +464,7 @@ class Output_data_plt_i386 : public Output_section_data // Set the final size. void - do_set_address(uint64_t, off_t) + set_final_data_size() { this->set_data_size((this->count_ + 1) * plt_entry_size); } // Write out the PLT data. @@ -455,12 +513,12 @@ Output_data_plt_i386::add_entry(Symbol* gsym) ++this->count_; - off_t got_offset = this->got_plt_->data_size(); + section_offset_type got_offset = this->got_plt_->current_data_size(); // Every PLT entry needs a GOT entry which points back to the PLT // entry (this will be changed by the dynamic linker, normally // lazily when the function is called). - this->got_plt_->set_space_size(got_offset + 4); + this->got_plt_->set_current_data_size(got_offset + 4); // Every PLT entry needs a reloc. gsym->set_needs_dynsym_entry(); @@ -524,11 +582,13 @@ void Output_data_plt_i386::do_write(Output_file* of) { const off_t offset = this->offset(); - const off_t oview_size = this->data_size(); + const section_size_type oview_size = + convert_to_section_size_type(this->data_size()); unsigned char* const oview = of->get_output_view(offset, oview_size); const off_t got_file_offset = this->got_plt_->offset(); - const off_t got_size = this->got_plt_->data_size(); + const section_size_type got_size = + convert_to_section_size_type(this->got_plt_->data_size()); unsigned char* const got_view = of->get_output_view(got_file_offset, got_size); @@ -590,8 +650,8 @@ Output_data_plt_i386::do_write(Output_file* of) elfcpp::Swap<32, false>::writeval(got_pov, plt_address + plt_offset + 6); } - gold_assert(pov - oview == oview_size); - gold_assert(got_pov - got_view == got_size); + gold_assert(static_cast(pov - oview) == oview_size); + gold_assert(static_cast(got_pov - got_view) == got_size); of->write_output_view(offset, oview_size, oview); of->write_output_view(got_file_offset, got_size, got_view); @@ -620,6 +680,26 @@ Target_i386::make_plt_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym) this->plt_->add_entry(gsym); } +// Create a GOT entry for the TLS module index. + +unsigned int +Target_i386::got_mod_index_entry(Symbol_table* symtab, Layout* layout, + Sized_relobj<32, false>* object) +{ + if (this->got_mod_index_offset_ == -1U) + { + gold_assert(symtab != NULL && layout != NULL && object != NULL); + Reloc_section* rel_dyn = this->rel_dyn_section(layout); + Output_data_got<32, false>* got = this->got_section(symtab, layout); + unsigned int got_offset = got->add_constant(0); + rel_dyn->add_local(object, 0, elfcpp::R_386_TLS_DTPMOD32, got, + got_offset); + got->add_constant(0); + this->got_mod_index_offset_ = got_offset; + } + return this->got_mod_index_offset_; +} + // Handle a relocation against a non-function symbol defined in a // dynamic object. The traditional way to handle this is to generate // a COPY relocation to copy the variable at runtime from the shared @@ -641,7 +721,9 @@ Target_i386::copy_reloc(const General_options* options, Symbol_table* symtab, Layout* layout, Sized_relobj<32, false>* object, - unsigned int data_shndx, Symbol* gsym, + unsigned int data_shndx, + Output_section* output_section, + Symbol* gsym, const elfcpp::Rel<32, false>& rel) { Sized_symbol<32>* ssym; @@ -656,7 +738,7 @@ Target_i386::copy_reloc(const General_options* options, // symbol, then we will emit the relocation. if (this->copy_relocs_ == NULL) this->copy_relocs_ = new Copy_relocs<32, false>(); - this->copy_relocs_->save(ssym, object, data_shndx, rel); + this->copy_relocs_->save(ssym, object, data_shndx, output_section, rel); } else { @@ -687,12 +769,13 @@ Target_i386::copy_reloc(const General_options* options, if (align > dynbss->addralign()) dynbss->set_space_alignment(align); - off_t dynbss_size = dynbss->data_size(); + section_size_type dynbss_size = + convert_to_section_size_type(dynbss->current_data_size()); dynbss_size = align_address(dynbss_size, align); - off_t offset = dynbss_size; - dynbss->set_space_size(dynbss_size + symsize); + section_size_type offset = dynbss_size; + dynbss->set_current_data_size(dynbss_size + symsize); - symtab->define_with_copy_reloc(this, ssym, dynbss, offset); + symtab->define_with_copy_reloc(ssym, dynbss, offset); // Add the COPY reloc. Reloc_section* rel_dyn = this->rel_dyn_section(layout); @@ -776,9 +859,10 @@ Target_i386::Scan::local(const General_options&, Target_i386* target, Sized_relobj<32, false>* object, unsigned int data_shndx, + Output_section* output_section, const elfcpp::Rel<32, false>& reloc, unsigned int r_type, - const elfcpp::Sym<32, false>&) + const elfcpp::Sym<32, false>& lsym) { switch (r_type) { @@ -797,8 +881,10 @@ Target_i386::Scan::local(const General_options&, if (parameters->output_is_position_independent()) { Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx, - reloc.get_r_offset()); + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + rel_dyn->add_local_relative(object, r_sym, elfcpp::R_386_RELATIVE, + output_section, data_shndx, + reloc.get_r_offset()); } break; @@ -812,9 +898,19 @@ Target_i386::Scan::local(const General_options&, if (parameters->output_is_position_independent()) { Reloc_section* rel_dyn = target->rel_dyn_section(layout); - unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - rel_dyn->add_local(object, r_sym, r_type, data_shndx, - reloc.get_r_offset()); + if (lsym.get_st_type() != elfcpp::STT_SECTION) + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + 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); + rel_dyn->add_local_section(object, lsym.get_st_shndx(), + r_type, output_section, + data_shndx, reloc.get_r_offset()); + } } break; @@ -842,12 +938,15 @@ Target_i386::Scan::local(const General_options&, if (got->add_local(object, r_sym)) { // If we are generating a shared object, we need to add a - // dynamic RELATIVE relocation for this symbol. + // dynamic RELATIVE relocation for this symbol's GOT entry. if (parameters->output_is_position_independent()) { Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, - data_shndx, reloc.get_r_offset()); + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + rel_dyn->add_local_relative(object, r_sym, + elfcpp::R_386_RELATIVE, + got, + object->local_got_offset(r_sym)); } } } @@ -887,18 +986,37 @@ Target_i386::Scan::local(const General_options&, switch (r_type) { case elfcpp::R_386_TLS_GD: // Global-dynamic + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a pair of GOT entries for the module index and + // dtv-relative offset. + Output_data_got<32, false>* got + = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + got->add_local_tls_with_rel(object, r_sym, + lsym.get_st_shndx(), true, + target->rel_dyn_section(layout), + elfcpp::R_386_TLS_DTPMOD32); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); + break; + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva) case elfcpp::R_386_TLS_DESC_CALL: - // FIXME: If not relaxing to LE, we need to generate - // DTPMOD32 and DTPOFF32 relocs. - if (optimized_type != tls::TLSOPT_TO_LE) - unsupported_reloc_local(object, r_type); + // FIXME: If not relaxing to LE, we need to generate + // a GOT entry with an R_386_TLS_DESC reloc. + if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); break; case elfcpp::R_386_TLS_LDM: // Local-dynamic - // FIXME: If not relaxing to LE, we need to generate a - // DTPMOD32 reloc. - if (optimized_type != tls::TLSOPT_TO_LE) + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a GOT entry for the module index. + target->got_mod_index_entry(symtab, layout, object); + } + else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); break; @@ -908,17 +1026,52 @@ Target_i386::Scan::local(const General_options&, case elfcpp::R_386_TLS_IE: // Initial-exec case elfcpp::R_386_TLS_IE_32: case elfcpp::R_386_TLS_GOTIE: - // FIXME: If not relaxing to LE, we need to generate a - // TPOFF or TPOFF32 reloc. - if (optimized_type != tls::TLSOPT_TO_LE) + layout->set_has_static_tls(); + if (optimized_type == tls::TLSOPT_NONE) + { + // For the R_386_TLS_IE relocation, we need to create a + // dynamic relocation when building a shared library. + if (r_type == elfcpp::R_386_TLS_IE + && parameters->output_is_shared()) + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + unsigned int r_sym + = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + rel_dyn->add_local_relative(object, r_sym, + elfcpp::R_386_RELATIVE, + output_section, data_shndx, + reloc.get_r_offset()); + } + // Create a GOT entry for the tp-relative offset. + Output_data_got<32, false>* got + = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32 + ? elfcpp::R_386_TLS_TPOFF32 + : elfcpp::R_386_TLS_TPOFF); + got->add_local_with_rel(object, r_sym, + target->rel_dyn_section(layout), + dyn_r_type); + } + else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); break; case elfcpp::R_386_TLS_LE: // Local-exec case elfcpp::R_386_TLS_LE_32: - // FIXME: If generating a shared object, we need to copy - // this relocation into the object. - gold_assert(!output_is_shared); + 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()); + unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32 + ? elfcpp::R_386_TLS_TPOFF32 + : elfcpp::R_386_TLS_TPOFF); + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_local(object, r_sym, dyn_r_type, output_section, + data_shndx, reloc.get_r_offset()); + } break; default: @@ -951,7 +1104,7 @@ Target_i386::Scan::unsupported_reloc_global(Sized_relobj<32, false>* object, Symbol* gsym) { gold_error(_("%s: unsupported reloc %u against global symbol %s"), - object->name().c_str(), r_type, gsym->name()); + object->name().c_str(), r_type, gsym->demangled_name().c_str()); } // Scan a relocation for a global symbol. @@ -963,6 +1116,7 @@ Target_i386::Scan::global(const General_options& options, Target_i386* target, Sized_relobj<32, false>* object, unsigned int data_shndx, + Output_section* output_section, const elfcpp::Rel<32, false>& reloc, unsigned int r_type, Symbol* gsym) @@ -986,29 +1140,30 @@ Target_i386::Scan::global(const General_options& options, // 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()) + if (gsym->is_from_dynobj() && !parameters->output_is_shared()) gsym->set_needs_dynsym_value(); } // Make a dynamic relocation if necessary. - if (gsym->needs_dynamic_reloc(true, false)) + if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF)) { if (target->may_need_copy_reloc(gsym)) { - target->copy_reloc(&options, symtab, layout, object, data_shndx, - gsym, reloc); + target->copy_reloc(&options, symtab, layout, object, + data_shndx, output_section, gsym, reloc); } else if (r_type == elfcpp::R_386_32 && gsym->can_use_relative_reloc(false)) { Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx, - reloc.get_r_offset()); + rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE, + output_section, object, + data_shndx, reloc.get_r_offset()); } else { Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_global(gsym, r_type, object, data_shndx, - reloc.get_r_offset()); + rel_dyn->add_global(gsym, r_type, output_section, object, + data_shndx, reloc.get_r_offset()); } } } @@ -1020,21 +1175,33 @@ Target_i386::Scan::global(const General_options& options, { // Make a PLT entry if necessary. if (gsym->needs_plt_entry()) - target->make_plt_entry(symtab, layout, gsym); + { + // These relocations are used for function calls only in + // non-PIC code. For a 32-bit relocation in a shared library, + // we'll need a text relocation anyway, so we can skip the + // PLT entry and let the dynamic linker bind the call directly + // to the target. For smaller relocations, we should use a + // PLT entry to ensure that the call can reach. + if (!parameters->output_is_shared() + || r_type != elfcpp::R_386_PC32) + target->make_plt_entry(symtab, layout, gsym); + } // Make a dynamic relocation if necessary. - bool is_function_call = (gsym->type() == elfcpp::STT_FUNC); - if (gsym->needs_dynamic_reloc(false, is_function_call)) + int flags = Symbol::NON_PIC_REF; + if (gsym->type() == elfcpp::STT_FUNC) + flags |= Symbol::FUNCTION_CALL; + if (gsym->needs_dynamic_reloc(flags)) { if (target->may_need_copy_reloc(gsym)) { - target->copy_reloc(&options, symtab, layout, object, data_shndx, - gsym, reloc); + target->copy_reloc(&options, symtab, layout, object, + data_shndx, output_section, gsym, reloc); } else { Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_global(gsym, r_type, object, data_shndx, - reloc.get_r_offset()); + rel_dyn->add_global(gsym, r_type, output_section, object, + data_shndx, reloc.get_r_offset()); } } } @@ -1044,24 +1211,22 @@ Target_i386::Scan::global(const General_options& options, { // The symbol requires a GOT entry. Output_data_got<32, false>* got = target->got_section(symtab, layout); - if (got->add_global(gsym)) - { + if (gsym->final_value_is_known()) + got->add_global(gsym); + else + { // If this symbol is not fully resolved, we need to add a - // dynamic relocation for it. - if (!gsym->final_value_is_known()) + // GOT entry with a dynamic relocation. + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + if (gsym->is_from_dynobj() + || gsym->is_undefined() + || gsym->is_preemptible()) + got->add_global_with_rel(gsym, rel_dyn, elfcpp::R_386_GLOB_DAT); + else { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - if (gsym->is_from_dynobj() - || gsym->is_preemptible()) - rel_dyn->add_global(gsym, elfcpp::R_386_GLOB_DAT, got, - gsym->got_offset()); - else - { - rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, - got, gsym->got_offset()); - // Make sure we write the link-time value to the GOT. - gsym->set_needs_value_in_got(); - } + if (got->add_global(gsym)) + rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE, + got, gsym->got_offset()); } } } @@ -1122,18 +1287,45 @@ Target_i386::Scan::global(const General_options& options, switch (r_type) { case elfcpp::R_386_TLS_GD: // Global-dynamic + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a pair of GOT entries for the module index and + // dtv-relative offset. + Output_data_got<32, false>* got + = target->got_section(symtab, layout); + got->add_global_tls_with_rel(gsym, + target->rel_dyn_section(layout), + elfcpp::R_386_TLS_DTPMOD32, + elfcpp::R_386_TLS_DTPOFF32); + } + else if (optimized_type == tls::TLSOPT_TO_IE) + { + // Create a GOT entry for the tp-relative offset. + Output_data_got<32, false>* got + = target->got_section(symtab, layout); + got->add_global_with_rel(gsym, target->rel_dyn_section(layout), + elfcpp::R_386_TLS_TPOFF32); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_global(object, r_type, gsym); + break; + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (~oliva url) case elfcpp::R_386_TLS_DESC_CALL: - // FIXME: If not relaxing to LE, we need to generate - // DTPMOD32 and DTPOFF32 relocs. - if (optimized_type != tls::TLSOPT_TO_LE) - unsupported_reloc_global(object, r_type, gsym); + // FIXME: If not relaxing to LE, we need to generate + // a GOT entry with an R_386_TLS_DESC reloc. + if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_global(object, r_type, gsym); + unsupported_reloc_global(object, r_type, gsym); break; case elfcpp::R_386_TLS_LDM: // Local-dynamic - // FIXME: If not relaxing to LE, we need to generate a - // DTPMOD32 reloc. - if (optimized_type != tls::TLSOPT_TO_LE) + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a GOT entry for the module index. + target->got_mod_index_entry(symtab, layout, object); + } + else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_global(object, r_type, gsym); break; @@ -1143,17 +1335,47 @@ Target_i386::Scan::global(const General_options& options, case elfcpp::R_386_TLS_IE: // Initial-exec case elfcpp::R_386_TLS_IE_32: case elfcpp::R_386_TLS_GOTIE: - // FIXME: If not relaxing to LE, we need to generate a - // TPOFF or TPOFF32 reloc. - if (optimized_type != tls::TLSOPT_TO_LE) + layout->set_has_static_tls(); + if (optimized_type == tls::TLSOPT_NONE) + { + // For the R_386_TLS_IE relocation, we need to create a + // dynamic relocation when building a shared library. + if (r_type == elfcpp::R_386_TLS_IE + && parameters->output_is_shared()) + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE, + output_section, object, + data_shndx, + reloc.get_r_offset()); + } + // Create a GOT entry for the tp-relative offset. + Output_data_got<32, false>* got + = target->got_section(symtab, layout); + unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32 + ? elfcpp::R_386_TLS_TPOFF32 + : elfcpp::R_386_TLS_TPOFF); + got->add_global_with_rel(gsym, + target->rel_dyn_section(layout), + dyn_r_type); + } + else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_global(object, r_type, gsym); break; case elfcpp::R_386_TLS_LE: // Local-exec case elfcpp::R_386_TLS_LE_32: - // FIXME: If generating a shared object, we need to copy - // this relocation into the object. - gold_assert(!parameters->output_is_shared()); + layout->set_has_static_tls(); + if (parameters->output_is_shared()) + { + // We need to create a dynamic relocation. + unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32 + ? elfcpp::R_386_TLS_TPOFF32 + : elfcpp::R_386_TLS_TPOFF); + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_global(gsym, dyn_r_type, output_section, object, + data_shndx, reloc.get_r_offset()); + } break; default: @@ -1275,8 +1497,7 @@ Target_i386::do_finalize_sections(Layout* layout) inline bool Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym, - bool is_absolute_ref, - bool is_function_call, + int ref_flags, bool is_32bit) { // For local symbols, we will have created a non-RELATIVE dynamic @@ -1285,12 +1506,18 @@ Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym, // (c) the relocation is not 32 bits wide. if (gsym == NULL) return !(parameters->output_is_position_independent() - && is_absolute_ref + && (ref_flags & Symbol::ABSOLUTE_REF) && !is_32bit); - // For global symbols, we use the same helper routines used in the scan pass. - return !(gsym->needs_dynamic_reloc(is_absolute_ref, is_function_call) - && !gsym->can_use_relative_reloc(is_function_call)); + // For global symbols, we use the same helper routines used in the + // scan pass. If we did not create a dynamic relocation, or if we + // created a RELATIVE dynamic relocation, we should apply the static + // relocation. + bool has_dyn = gsym->needs_dynamic_reloc(ref_flags); + bool is_rel = (ref_flags & Symbol::ABSOLUTE_REF) + && gsym->can_use_relative_reloc(ref_flags + & Symbol::FUNCTION_CALL); + return !has_dyn || is_rel; } // Perform a relocation. @@ -1305,7 +1532,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, const Symbol_value<32>* psymval, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr address, - off_t view_size) + section_size_type view_size) { if (this->skip_call_tls_get_addr_) { @@ -1323,11 +1550,15 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, // Pick the value to use for symbols defined in shared objects. Symbol_value<32> symval; + bool is_nonpic = (r_type == elfcpp::R_386_PC8 + || r_type == elfcpp::R_386_PC16 + || r_type == elfcpp::R_386_PC32); if (gsym != NULL && (gsym->is_from_dynobj() || (parameters->output_is_shared() - && gsym->is_preemptible())) - && gsym->has_plt_offset()) + && (gsym->is_undefined() || gsym->is_preemptible()))) + && gsym->has_plt_offset() + && (!is_nonpic || !parameters->output_is_shared())) { symval.set_output_value(target->plt_section()->address() + gsym->plt_offset()); @@ -1353,6 +1584,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, else { unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym)); got_offset = object->local_got_offset(r_sym) - target->got_size(); } have_got_offset = true; @@ -1370,43 +1602,46 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, break; case elfcpp::R_386_32: - if (should_apply_static_reloc(gsym, true, false, true)) + if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true)) Relocate_functions<32, false>::rel32(view, object, psymval); break; case elfcpp::R_386_PC32: { - bool is_function_call = (gsym != NULL - && gsym->type() == elfcpp::STT_FUNC); - if (should_apply_static_reloc(gsym, false, is_function_call, true)) + int ref_flags = Symbol::NON_PIC_REF; + if (gsym != NULL && gsym->type() == elfcpp::STT_FUNC) + ref_flags |= Symbol::FUNCTION_CALL; + if (should_apply_static_reloc(gsym, ref_flags, true)) Relocate_functions<32, false>::pcrel32(view, object, psymval, address); } break; case elfcpp::R_386_16: - if (should_apply_static_reloc(gsym, true, false, false)) + if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false)) Relocate_functions<32, false>::rel16(view, object, psymval); break; case elfcpp::R_386_PC16: { - bool is_function_call = (gsym != NULL - && gsym->type() == elfcpp::STT_FUNC); - if (should_apply_static_reloc(gsym, false, is_function_call, false)) + int ref_flags = Symbol::NON_PIC_REF; + if (gsym != NULL && gsym->type() == elfcpp::STT_FUNC) + ref_flags |= Symbol::FUNCTION_CALL; + if (should_apply_static_reloc(gsym, ref_flags, false)) Relocate_functions<32, false>::pcrel32(view, object, psymval, address); } break; case elfcpp::R_386_8: - if (should_apply_static_reloc(gsym, true, false, false)) + if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false)) Relocate_functions<32, false>::rel8(view, object, psymval); break; case elfcpp::R_386_PC8: { - bool is_function_call = (gsym != NULL - && gsym->type() == elfcpp::STT_FUNC); - if (should_apply_static_reloc(gsym, false, is_function_call, false)) + int ref_flags = Symbol::NON_PIC_REF; + if (gsym != NULL && gsym->type() == elfcpp::STT_FUNC) + ref_flags |= Symbol::FUNCTION_CALL; + if (should_apply_static_reloc(gsym, ref_flags, false)) Relocate_functions<32, false>::pcrel32(view, object, psymval, address); } break; @@ -1414,7 +1649,10 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, case elfcpp::R_386_PLT32: gold_assert(gsym == NULL || gsym->has_plt_offset() - || gsym->final_value_is_known()); + || gsym->final_value_is_known() + || (gsym->is_defined() + && !gsym->is_from_dynobj() + && !gsym->is_preemptible())); Relocate_functions<32, false>::pcrel32(view, object, psymval, address); break; @@ -1468,8 +1706,8 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, case elfcpp::R_386_TLS_GOTIE: case elfcpp::R_386_TLS_LE: // Local-exec case elfcpp::R_386_TLS_LE_32: - this->relocate_tls(relinfo, relnum, rel, r_type, gsym, psymval, view, - address, view_size); + this->relocate_tls(relinfo, target, relnum, rel, r_type, gsym, psymval, + view, address, view_size); break; case elfcpp::R_386_32PLT: @@ -1496,6 +1734,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, inline void Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, + Target_i386* target, size_t relnum, const elfcpp::Rel<32, false>& rel, unsigned int r_type, @@ -1503,17 +1742,13 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, const Symbol_value<32>* psymval, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr, - off_t view_size) + section_size_type view_size) { Output_segment* tls_segment = relinfo->layout->tls_segment(); - if (tls_segment == NULL) - { - gold_error_at_location(relinfo, relnum, rel.get_r_offset(), - _("TLS reloc but no TLS segment")); - return; - } - elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(relinfo->object, 0); + const Sized_relobj<32, false>* object = relinfo->object; + + elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(object, 0); const bool is_final = (gsym == NULL ? !parameters->output_is_position_independent() @@ -1525,11 +1760,42 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, case elfcpp::R_386_TLS_GD: // Global-dynamic if (optimized_type == tls::TLSOPT_TO_LE) { + gold_assert(tls_segment != NULL); this->tls_gd_to_le(relinfo, relnum, tls_segment, rel, r_type, value, view, view_size); break; } + else + { + unsigned int got_offset; + if (gsym != NULL) + { + gold_assert(gsym->has_tls_got_offset(true)); + got_offset = gsym->tls_got_offset(true) - target->got_size(); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); + gold_assert(object->local_has_tls_got_offset(r_sym, true)); + got_offset = (object->local_tls_got_offset(r_sym, true) + - target->got_size()); + } + if (optimized_type == tls::TLSOPT_TO_IE) + { + gold_assert(tls_segment != NULL); + this->tls_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type, + got_offset, view, view_size); + break; + } + else if (optimized_type == tls::TLSOPT_NONE) + { + // Relocate the field with the offset of the pair of GOT + // entries. + Relocate_functions<32, false>::rel32(view, got_offset); + break; + } + } gold_error_at_location(relinfo, relnum, rel.get_r_offset(), _("unsupported reloc %u"), r_type); @@ -1553,10 +1819,21 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU; if (optimized_type == tls::TLSOPT_TO_LE) { + gold_assert(tls_segment != NULL); this->tls_ld_to_le(relinfo, relnum, tls_segment, rel, r_type, value, view, view_size); break; } + else 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) + - target->got_size()); + Relocate_functions<32, false>::rel32(view, got_offset); + break; + } gold_error_at_location(relinfo, relnum, rel.get_r_offset(), _("unsupported reloc %u"), r_type); @@ -1566,13 +1843,11 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, // This reloc can appear in debugging sections, in which case we // won't see the TLS_LDM reloc. The local_dynamic_type field // tells us this. - if (optimized_type != tls::TLSOPT_TO_LE - || this->local_dynamic_type_ == LOCAL_DYNAMIC_NONE) - value = value - tls_segment->vaddr(); - else if (this->local_dynamic_type_ == LOCAL_DYNAMIC_GNU) - value = value - (tls_segment->vaddr() + tls_segment->memsz()); - else - value = tls_segment->vaddr() + tls_segment->memsz() - value; + if (optimized_type == tls::TLSOPT_TO_LE) + { + gold_assert(tls_segment != NULL); + value -= tls_segment->memsz(); + } Relocate_functions<32, false>::rel32(view, value); break; @@ -1581,24 +1856,62 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, case elfcpp::R_386_TLS_IE_32: if (optimized_type == tls::TLSOPT_TO_LE) { + gold_assert(tls_segment != NULL); Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment, rel, r_type, value, view, view_size); break; } + else if (optimized_type == tls::TLSOPT_NONE) + { + // Relocate the field with the offset of the GOT entry for + // the tp-relative offset of the symbol. + unsigned int got_offset; + if (gsym != NULL) + { + gold_assert(gsym->has_got_offset()); + got_offset = gsym->got_offset(); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym)); + got_offset = object->local_got_offset(r_sym); + } + // For the R_386_TLS_IE relocation, we need to apply the + // absolute address of the GOT entry. + if (r_type == elfcpp::R_386_TLS_IE) + got_offset += target->got_plt_section()->address(); + // All GOT offsets are relative to the end of the GOT. + got_offset -= target->got_size(); + Relocate_functions<32, false>::rel32(view, got_offset); + break; + } gold_error_at_location(relinfo, relnum, rel.get_r_offset(), _("unsupported reloc %u"), r_type); break; case elfcpp::R_386_TLS_LE: // Local-exec - value = value - (tls_segment->vaddr() + tls_segment->memsz()); - Relocate_functions<32, false>::rel32(view, value); + // 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->output_is_shared()) + { + gold_assert(tls_segment != NULL); + value -= tls_segment->memsz(); + Relocate_functions<32, false>::rel32(view, value); + } break; case elfcpp::R_386_TLS_LE_32: - value = tls_segment->vaddr() + tls_segment->memsz() - value; - Relocate_functions<32, false>::rel32(view, value); + // 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->output_is_shared()) + { + gold_assert(tls_segment != NULL); + value = tls_segment->memsz() - value; + Relocate_functions<32, false>::rel32(view, value); + } break; } } @@ -1614,7 +1927,7 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, unsigned int, elfcpp::Elf_types<32>::Elf_Addr value, unsigned char* view, - off_t view_size) + section_size_type view_size) { // leal foo(,%reg,1),%eax; call ___tls_get_addr // ==> movl %gs:0,%eax; subl $foo@tpoff,%eax @@ -1645,7 +1958,7 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, { tls::check_tls(relinfo, relnum, rel.get_r_offset(), (op1 & 0xf8) == 0x80 && (op1 & 7) != 4); - if (static_cast(rel.get_r_offset() + 9) < view_size + if (rel.get_r_offset() + 9 < view_size && view[9] == 0x90) { // There is a trailing nop. Use the size byte subl. @@ -1659,7 +1972,75 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, } } - value = tls_segment->vaddr() + tls_segment->memsz() - value; + value = tls_segment->memsz() - value; + Relocate_functions<32, false>::rel32(view + roff, value); + + // The next reloc should be a PLT32 reloc against __tls_get_addr. + // We can skip it. + this->skip_call_tls_get_addr_ = true; +} + +// Do a relocation in which we convert a TLS General-Dynamic to an +// Initial-Exec. + +inline void +Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo, + size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>& rel, + unsigned int, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size) +{ + // leal foo(,%ebx,1),%eax; call ___tls_get_addr + // ==> movl %gs:0,%eax; addl foo@gotntpoff(%ebx),%eax + + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 9); + + unsigned char op1 = view[-1]; + unsigned char op2 = view[-2]; + + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + op2 == 0x8d || op2 == 0x04); + tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[4] == 0xe8); + + int roff = 5; + + // FIXME: For now, support only one form. + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + op1 == 0x8d && op2 == 0x04); + + if (op2 == 0x04) + { + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -3); + tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[-3] == 0x8d); + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + ((op1 & 0xc7) == 0x05 && op1 != (4 << 3))); + memcpy(view - 3, "\x65\xa1\0\0\0\0\x03\x83\0\0\0", 12); + } + else + { + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + (op1 & 0xf8) == 0x80 && (op1 & 7) != 4); + if (rel.get_r_offset() + 9 < view_size + && view[9] == 0x90) + { + // FIXME: This is not the right instruction sequence. + // There is a trailing nop. Use the size byte subl. + memcpy(view - 2, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); + roff = 6; + } + else + { + // FIXME: This is not the right instruction sequence. + // Use the five byte subl. + memcpy(view - 2, "\x65\xa1\0\0\0\0\x2d\0\0\0", 11); + } + } + + value = tls_segment->memsz() - value; Relocate_functions<32, false>::rel32(view + roff, value); // The next reloc should be a PLT32 reloc against __tls_get_addr. @@ -1678,7 +2059,7 @@ Target_i386::Relocate::tls_ld_to_le(const Relocate_info<32, false>* relinfo, unsigned int, elfcpp::Elf_types<32>::Elf_Addr, unsigned char* view, - off_t view_size) + section_size_type view_size) { // leal foo(%reg), %eax; call ___tls_get_addr // ==> movl %gs:0,%eax; nop; leal 0(%esi,1),%esi @@ -1710,7 +2091,7 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo, unsigned int r_type, elfcpp::Elf_types<32>::Elf_Addr value, unsigned char* view, - off_t view_size) + section_size_type view_size) { // We have to actually change the instructions, which means that we // need to examine the opcodes to figure out which instruction we @@ -1788,7 +2169,7 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo, tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0); } - value = tls_segment->vaddr() + tls_segment->memsz() - value; + value = tls_segment->memsz() - value; if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE) value = - value; @@ -1806,7 +2187,7 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo, bool needs_special_offset_handling, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr address, - off_t view_size) + section_size_type view_size) { gold_assert(sh_type == elfcpp::SHT_REL); @@ -1823,6 +2204,148 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo, view_size); } +// Return the size of a relocation while scanning during a relocatable +// link. + +unsigned int +Target_i386::Relocatable_size_for_reloc::get_size_for_reloc( + unsigned int r_type, + Relobj* object) +{ + switch (r_type) + { + case elfcpp::R_386_NONE: + case elfcpp::R_386_GNU_VTINHERIT: + case elfcpp::R_386_GNU_VTENTRY: + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_LDM: // Local-dynamic + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_LE: // Local-exec + case elfcpp::R_386_TLS_LE_32: + return 0; + + case elfcpp::R_386_32: + case elfcpp::R_386_PC32: + case elfcpp::R_386_GOT32: + case elfcpp::R_386_PLT32: + case elfcpp::R_386_GOTOFF: + case elfcpp::R_386_GOTPC: + return 4; + + case elfcpp::R_386_16: + case elfcpp::R_386_PC16: + return 2; + + case elfcpp::R_386_8: + case elfcpp::R_386_PC8: + return 1; + + // These are relocations which should only be seen by the + // dynamic linker, and should never be seen here. + case elfcpp::R_386_COPY: + case elfcpp::R_386_GLOB_DAT: + case elfcpp::R_386_JUMP_SLOT: + case elfcpp::R_386_RELATIVE: + case elfcpp::R_386_TLS_TPOFF: + case elfcpp::R_386_TLS_DTPMOD32: + case elfcpp::R_386_TLS_DTPOFF32: + case elfcpp::R_386_TLS_TPOFF32: + case elfcpp::R_386_TLS_DESC: + object->error(_("unexpected reloc %u in object file"), r_type); + return 0; + + case elfcpp::R_386_32PLT: + case elfcpp::R_386_TLS_GD_32: + case elfcpp::R_386_TLS_GD_PUSH: + case elfcpp::R_386_TLS_GD_CALL: + case elfcpp::R_386_TLS_GD_POP: + case elfcpp::R_386_TLS_LDM_32: + case elfcpp::R_386_TLS_LDM_PUSH: + case elfcpp::R_386_TLS_LDM_CALL: + case elfcpp::R_386_TLS_LDM_POP: + case elfcpp::R_386_USED_BY_INTEL_200: + default: + object->error(_("unsupported reloc %u in object file"), r_type); + return 0; + } +} + +// Scan the relocs during a relocatable link. + +void +Target_i386::scan_relocatable_relocs(const General_options& options, + Symbol_table* symtab, + Layout* layout, + Sized_relobj<32, false>* object, + unsigned int data_shndx, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + size_t local_symbol_count, + const unsigned char* plocal_symbols, + Relocatable_relocs* rr) +{ + gold_assert(sh_type == elfcpp::SHT_REL); + + typedef gold::Default_scan_relocatable_relocs Scan_relocatable_relocs; + + gold::scan_relocatable_relocs<32, false, Target_i386, elfcpp::SHT_REL, + Scan_relocatable_relocs>( + options, + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols, + rr); +} + +// Relocate a section during a relocatable link. + +void +Target_i386::relocate_for_relocatable( + const Relocate_info<32, false>* relinfo, + 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* rr, + unsigned char* view, + elfcpp::Elf_types<32>::Elf_Addr view_address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size) +{ + gold_assert(sh_type == elfcpp::SHT_REL); + + gold::relocate_for_relocatable<32, false, Target_i386, elfcpp::SHT_REL>( + relinfo, + prelocs, + reloc_count, + output_section, + offset_in_output_section, + rr, + view, + view_address, + view_size, + reloc_view, + reloc_view_size); +} + // Return the value to use for a dynamic which requires special // treatment. This is how we support equality comparisons of function // pointers across shared library boundaries, as described in the @@ -1839,7 +2362,7 @@ Target_i386::do_dynsym_value(const Symbol* gsym) const // the specified length. std::string -Target_i386::do_code_fill(off_t length) +Target_i386::do_code_fill(section_size_type length) { if (length >= 16) {