X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fi386.cc;h=448453aa349505c7234a2d4c4821679159fa0ee9;hb=c55fe0967e9ec38c1e9d9d3ffc4db30a49323302;hp=488da799f8054c0e05071bc9c6c2d31ec8d002cb;hpb=a3ad94edd406b9abc26493761764d4034dda69fa;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/i386.cc b/gold/i386.cc index 488da799f8..448453aa34 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -27,9 +27,12 @@ class Output_data_plt_i386; class Target_i386 : public Sized_target<32, false> { public: + typedef Output_data_reloc Reloc_section; + Target_i386() : Sized_target<32, false>(&i386_info), - got_(NULL), plt_(NULL), got_plt_(NULL) + got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL), + copy_relocs_(NULL), dynbss_(NULL) { } // Scan the relocations to look for symbol adjustments. @@ -46,6 +49,10 @@ class Target_i386 : public Sized_target<32, false> const unsigned char* plocal_symbols, Symbol** global_symbols); + // Finalize the sections. + void + do_finalize_sections(const General_options*, Layout*); + // Relocate a section. void relocate_section(const Relocate_info<32, false>*, @@ -102,7 +109,7 @@ class Target_i386 : public Sized_target<32, false> relocate(const Relocate_info<32, false>*, Target_i386*, size_t relnum, const elfcpp::Rel<32, false>&, unsigned int r_type, const Sized_symbol<32>*, - elfcpp::Elf_types<32>::Elf_Addr, + const Symbol_value<32>*, unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t); @@ -112,7 +119,7 @@ class Target_i386 : public Sized_target<32, false> relocate_tls(const Relocate_info<32, false>*, size_t relnum, const elfcpp::Rel<32, false>&, unsigned int r_type, const Sized_symbol<32>*, - elfcpp::Elf_types<32>::Elf_Addr, + const Symbol_value<32>*, unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t); // Do a TLS Initial-Exec to Local-Exec transition. @@ -170,9 +177,14 @@ class Target_i386 : public Sized_target<32, false> return this->plt_; } + // Get the dynamic reloc section, creating it if necessary. + Reloc_section* + rel_dyn_section(Layout*); + // Copy a relocation against a global symbol. void - copy_reloc(const General_options*, Sized_relobj<32, false>*, unsigned int, + copy_reloc(const General_options*, Symbol_table*, Layout*, + Sized_relobj<32, false>*, unsigned int, Symbol*, const elfcpp::Rel<32, false>&); // Information about this specific target which we pass to the @@ -185,6 +197,12 @@ class Target_i386 : public Sized_target<32, false> Output_data_plt_i386* plt_; // The GOT PLT section. Output_data_space* got_plt_; + // The dynamic reloc section. + Reloc_section* rel_dyn_; + // Relocs saved to avoid a COPY reloc. + Copy_relocs<32, false>* copy_relocs_; + // Space for variables copied with a COPY reloc. + Output_data_space* dynbss_; }; const Target::Target_info Target_i386::i386_info = @@ -213,7 +231,8 @@ Target_i386::got_section(const General_options* options, Symbol_table* symtab, this->got_ = new Output_data_got<32, false>(options); layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, - elfcpp::SHF_ALLOC, this->got_); + elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, + this->got_); // The old GNU linker creates a .got.plt section. We just // create another set of data in the .got section. Note that we @@ -221,16 +240,17 @@ Target_i386::got_section(const General_options* options, Symbol_table* symtab, // might be empty. this->got_plt_ = new Output_data_space(4); layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, - elfcpp::SHF_ALLOC, this->got_plt_); + elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, + this->got_plt_); // The first three entries are reserved. this->got_plt_->set_space_size(3 * 4); // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT. - symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", + symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL, this->got_plt_, 0, 0, elfcpp::STT_OBJECT, - elfcpp::STB_GLOBAL, + elfcpp::STB_LOCAL, elfcpp::STV_HIDDEN, 0, false, false); } @@ -238,6 +258,21 @@ Target_i386::got_section(const General_options* options, Symbol_table* symtab, return this->got_; } +// Get the dynamic reloc section, creating it if necessary. + +Target_i386::Reloc_section* +Target_i386::rel_dyn_section(Layout* layout) +{ + if (this->rel_dyn_ == NULL) + { + gold_assert(layout != NULL); + this->rel_dyn_ = new Reloc_section(); + layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, + elfcpp::SHF_ALLOC, this->rel_dyn_); + } + return this->rel_dyn_; +} + // A class to handle the PLT data. class Output_data_plt_i386 : public Output_section_data @@ -251,6 +286,15 @@ class Output_data_plt_i386 : public Output_section_data void add_entry(Symbol* gsym); + // Return the .rel.plt section data. + const Reloc_section* + rel_plt() const + { return this->rel_; } + + protected: + void + do_adjust_output_section(Output_section* os); + private: // The size of an entry in the PLT. static const int plt_entry_size = 16; @@ -300,6 +344,16 @@ Output_data_plt_i386::Output_data_plt_i386(Layout* layout, elfcpp::SHF_ALLOC, this->rel_); } +// For some reason + +void +Output_data_plt_i386::do_adjust_output_section(Output_section* os) +{ + // UnixWare sets the entsize of .plt to 4, and so does the old GNU + // linker, and so do we. + os->set_entsize(4); +} + // Add an entry to the PLT. void @@ -321,6 +375,7 @@ Output_data_plt_i386::add_entry(Symbol* gsym) this->got_plt_->set_space_size(got_offset + 4); // Every PLT entry needs a reloc. + gsym->set_needs_dynsym_entry(); this->rel_->add_global(gsym, elfcpp::R_386_JUMP_SLOT, this->got_plt_, got_offset); @@ -470,6 +525,10 @@ Target_i386::make_plt_entry(const General_options* options, this->plt_ = new Output_data_plt_i386(layout, this->got_plt_, options->is_shared()); + layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_EXECINSTR), + this->plt_); } this->plt_->add_entry(gsym); @@ -493,18 +552,71 @@ Target_i386::make_plt_entry(const General_options* options, void Target_i386::copy_reloc(const General_options* options, + Symbol_table* symtab, + Layout* layout, Sized_relobj<32, false>* object, unsigned int data_shndx, Symbol* gsym, - const elfcpp::Rel<32, false>&) + const elfcpp::Rel<32, false>& rel) { - if (!Relocate_functions<32, false>::need_copy_reloc(options, object, - data_shndx, gsym)) + Sized_symbol<32>* ssym; + ssym = symtab->get_sized_symbol SELECT_SIZE_NAME(32) (gsym + SELECT_SIZE(32)); + + if (!Copy_relocs<32, false>::need_copy_reloc(options, object, + data_shndx, ssym)) { // So far we do not need a COPY reloc. Save this relocation. - // If it turns out that we never a COPY reloc for this symbol, - // then we emit the relocation. + // If it turns out that we never need a COPY reloc for this + // 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); } + else + { + // Allocate space for this symbol in the .bss section. + + elfcpp::Elf_types<32>::Elf_WXword symsize = ssym->symsize(); + + // There is no defined way to determine the required alignment + // of the symbol. We pick the alignment based on the size. We + // set an arbitrary maximum of 256. + unsigned int align; + for (align = 1; align < 512; align <<= 1) + if ((symsize & align) != 0) + break; + if (this->dynbss_ == NULL) + { + this->dynbss_ = new Output_data_space(align); + layout->add_output_section_data(".bss", + elfcpp::SHT_NOBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + this->dynbss_); + } + + Output_data_space* dynbss = this->dynbss_; + + if (align > dynbss->addralign()) + dynbss->set_space_alignment(align); + + off_t dynbss_size = dynbss->data_size(); + dynbss_size = align_address(dynbss_size, align); + off_t offset = dynbss_size; + dynbss->set_space_size(dynbss_size + symsize); + + // Define the symbol in the .dynbss section. + symtab->define_in_output_data(this, ssym->name(), ssym->version(), + dynbss, offset, symsize, ssym->type(), + ssym->binding(), ssym->visibility(), + ssym->nonvis(), false, false); + + // Add the COPY reloc. + ssym->set_needs_dynsym_entry(); + Reloc_section* rel_dyn = this->rel_dyn_section(layout); + rel_dyn->add_global(ssym, elfcpp::R_386_COPY, dynbss, offset); + } } // Optimize the TLS relocation type based on what we know about the @@ -707,7 +819,7 @@ Target_i386::Scan::global(const General_options& options, // relocation in order to avoid a COPY relocation. gold_assert(!options.is_shared()); - if (gsym->is_defined_in_dynobj()) + if (gsym->is_from_dynobj()) { // This symbol is defined in a dynamic object. If it is a // function, we make a PLT entry. Otherwise we need to @@ -715,7 +827,8 @@ Target_i386::Scan::global(const General_options& options, if (gsym->type() == elfcpp::STT_FUNC) target->make_plt_entry(&options, symtab, layout, gsym); else - target->copy_reloc(&options, object, data_shndx, gsym, reloc); + target->copy_reloc(&options, symtab, layout, object, data_shndx, + gsym, reloc); } break; @@ -854,6 +967,57 @@ Target_i386::scan_relocs(const General_options& options, global_symbols); } +// Finalize the sections. + +void +Target_i386::do_finalize_sections(const General_options* options, + Layout* layout) +{ + // Fill in some more dynamic tags. + Output_data_dynamic* const odyn = layout->dynamic_data(); + if (odyn != NULL) + { + if (this->got_plt_ != NULL) + odyn->add_section_address(elfcpp::DT_PLTGOT, this->got_plt_); + + if (this->plt_ != NULL) + { + const Output_data* od = this->plt_->rel_plt(); + odyn->add_section_size(elfcpp::DT_PLTRELSZ, od); + odyn->add_section_address(elfcpp::DT_JMPREL, od); + odyn->add_constant(elfcpp::DT_PLTREL, elfcpp::DT_REL); + } + + if (this->rel_dyn_ != NULL) + { + const Output_data* od = this->rel_dyn_; + odyn->add_section_address(elfcpp::DT_REL, od); + odyn->add_section_size(elfcpp::DT_RELSZ, od); + odyn->add_constant(elfcpp::DT_RELENT, + elfcpp::Elf_sizes<32>::rel_size); + } + + if (!options->is_shared()) + { + // The value of the DT_DEBUG tag is filled in by the dynamic + // linker at run time, and used by the debugger. + odyn->add_constant(elfcpp::DT_DEBUG, 0); + } + } + + // Emit any relocs we saved in an attempt to avoid generating COPY + // relocs. + if (this->copy_relocs_ == NULL) + return; + if (this->copy_relocs_->any_to_emit()) + { + Reloc_section* rel_dyn = this->rel_dyn_section(layout); + this->copy_relocs_->emit(rel_dyn); + } + delete this->copy_relocs_; + this->copy_relocs_ = NULL; +} + // Perform a relocation. inline bool @@ -863,7 +1027,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, const elfcpp::Rel<32, false>& rel, unsigned int r_type, const Sized_symbol<32>* gsym, - elfcpp::Elf_types<32>::Elf_Addr value, + const Symbol_value<32>* psymval, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr address, off_t view_size) @@ -886,14 +1050,19 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, } // Pick the value to use for symbols defined in shared objects. - if (gsym != NULL && gsym->is_defined_in_dynobj()) + Symbol_value<32> symval; + if (gsym != NULL && gsym->is_from_dynobj()) { - if (gsym->has_plt_offset()) - address = target->plt_section()->address() + gsym->plt_offset(); - else + if (!gsym->has_plt_offset()) gold_unreachable(); + + symval.set_output_value(target->plt_section()->address() + + gsym->plt_offset()); + psymval = &symval; } + const Sized_relobj<32, false>* object = relinfo->object; + switch (r_type) { case elfcpp::R_386_NONE: @@ -902,51 +1071,57 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, break; case elfcpp::R_386_32: - Relocate_functions<32, false>::rel32(view, value); + Relocate_functions<32, false>::rel32(view, object, psymval); break; case elfcpp::R_386_PC32: - Relocate_functions<32, false>::pcrel32(view, value, address); + Relocate_functions<32, false>::pcrel32(view, object, psymval, address); break; case elfcpp::R_386_16: - Relocate_functions<32, false>::rel16(view, value); + Relocate_functions<32, false>::rel16(view, object, psymval); break; case elfcpp::R_386_PC16: - Relocate_functions<32, false>::pcrel16(view, value, address); + Relocate_functions<32, false>::pcrel16(view, object, psymval, address); break; case elfcpp::R_386_8: - Relocate_functions<32, false>::rel8(view, value); + Relocate_functions<32, false>::rel8(view, object, psymval); break; case elfcpp::R_386_PC8: - Relocate_functions<32, false>::pcrel8(view, value, address); + Relocate_functions<32, false>::pcrel8(view, object, psymval, address); break; case elfcpp::R_386_PLT32: gold_assert(gsym->has_plt_offset() || gsym->final_value_is_known(relinfo->options)); - Relocate_functions<32, false>::pcrel32(view, value, address); + Relocate_functions<32, false>::pcrel32(view, object, psymval, address); break; case elfcpp::R_386_GOT32: // Local GOT offsets not yet supported. gold_assert(gsym); gold_assert(gsym->has_got_offset()); - value = gsym->got_offset(); - Relocate_functions<32, false>::rel32(view, value); + Relocate_functions<32, false>::rel32(view, gsym->got_offset()); break; case elfcpp::R_386_GOTOFF: - value -= target->got_section(NULL, NULL, NULL)->address(); - Relocate_functions<32, false>::rel32(view, value); + { + elfcpp::Elf_types<32>::Elf_Addr value; + value = (psymval->value(object, 0) + - target->got_section(NULL, NULL, NULL)->address()); + Relocate_functions<32, false>::rel32(view, value); + } break; case elfcpp::R_386_GOTPC: - value = target->got_section(NULL, NULL, NULL)->address(); - Relocate_functions<32, false>::pcrel32(view, value, address); + { + elfcpp::Elf_types<32>::Elf_Addr value; + value = target->got_section(NULL, NULL, NULL)->address(); + Relocate_functions<32, false>::pcrel32(view, value, address); + } break; case elfcpp::R_386_COPY: @@ -975,7 +1150,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, case elfcpp::R_386_TLS_LE_32: case elfcpp::R_386_TLS_GOTDESC: case elfcpp::R_386_TLS_DESC_CALL: - this->relocate_tls(relinfo, relnum, rel, r_type, gsym, value, view, + this->relocate_tls(relinfo, relnum, rel, r_type, gsym, psymval, view, address, view_size); break; @@ -1009,7 +1184,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, const elfcpp::Rel<32, false>& rel, unsigned int r_type, const Sized_symbol<32>* gsym, - elfcpp::Elf_types<32>::Elf_Addr value, + const Symbol_value<32>* psymval, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr, off_t view_size) @@ -1023,6 +1198,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, gold_exit(false); } + elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(relinfo->object, 0); + const bool is_final = (gsym == NULL ? !relinfo->options->is_shared() : gsym->final_value_is_known(relinfo->options));