X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fi386.cc;h=3a8735f3a7164569731ca697955204c5301f0f6e;hb=de54374205650be71237ce51ef7981d30ddd78dc;hp=3715e5eaf857f1af6181dcc247653a74ebca7ca5;hpb=8a8880cb673893c479b473f598905c0490897817;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/i386.cc b/gold/i386.cc index 3715e5eaf8..3a8735f3a7 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -1,6 +1,6 @@ // i386.cc -- i386 target support for gold. -// Copyright (C) 2006-2016 Free Software Foundation, Inc. +// Copyright (C) 2006-2020 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -500,7 +500,8 @@ class Target_i386 : public Sized_target<32, false> // Return whether SYM is call to a non-split function. bool - do_is_call_to_non_split(const Symbol* sym, const unsigned char*) const; + do_is_call_to_non_split(const Symbol* sym, const unsigned char*, + const unsigned char*, section_size_type) const; // Adjust -fsplit-stack code which calls non-split-stack code. void @@ -743,11 +744,10 @@ class Target_i386 : public Sized_target<32, false> public gold::Default_classify_reloc { public: - typedef typename Reloc_types::Reloc - Reltype; + typedef Reloc_types::Reloc Reltype; // Return the explicit addend of the relocation (return 0 for SHT_REL). - static typename elfcpp::Elf_types<32>::Elf_Swxword + static elfcpp::Elf_types<32>::Elf_Swxword get_r_addend(const Reltype*) { return 0; } @@ -925,6 +925,7 @@ const Target::Target_info Target_i386::i386_info = NULL, // attributes_vendor "_start", // entry_symbol_name 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; // Get the GOT section, creating it if necessary. @@ -1565,6 +1566,8 @@ Target_i386::plt_entry_count() const unsigned int Target_i386::first_plt_entry_offset() const { + if (this->plt_ == NULL) + return 0; return this->plt_->first_plt_entry_offset(); } @@ -1573,6 +1576,8 @@ Target_i386::first_plt_entry_offset() const unsigned int Target_i386::plt_entry_size() const { + if (this->plt_ == NULL) + return 0; return this->plt_->get_plt_entry_size(); } @@ -2394,6 +2399,23 @@ Target_i386::Scan::global(Symbol_table* symtab, break; case elfcpp::R_386_GOTOFF: + // A GOT-relative reference must resolve locally. + if (!gsym->is_defined()) + gold_error(_("%s: relocation R_386_GOTOFF against undefined symbol %s" + " cannot be used when making a shared object"), + object->name().c_str(), gsym->name()); + else if (gsym->is_from_dynobj()) + gold_error(_("%s: relocation R_386_GOTOFF against external symbol %s" + " cannot be used when making a shared object"), + object->name().c_str(), gsym->name()); + else if (gsym->is_preemptible()) + gold_error(_("%s: relocation R_386_GOTOFF against preemptible symbol %s" + " cannot be used when making a shared object"), + object->name().c_str(), gsym->name()); + // We need a GOT section. + target->got_section(symtab, layout); + break; + case elfcpp::R_386_GOTPC: // We need a GOT section. target->got_section(symtab, layout); @@ -2769,11 +2791,15 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, if (this->skip_call_tls_get_addr_) { if ((r_type != elfcpp::R_386_PLT32 + && r_type != elfcpp::R_386_GOT32X && r_type != elfcpp::R_386_PC32) || gsym == NULL || strcmp(gsym->name(), "___tls_get_addr") != 0) - gold_error_at_location(relinfo, relnum, rel.get_r_offset(), - _("missing expected TLS relocation")); + { + gold_error_at_location(relinfo, relnum, rel.get_r_offset(), + _("missing expected TLS relocation")); + this->skip_call_tls_get_addr_ = false; + } else { this->skip_call_tls_get_addr_ = false; @@ -2931,10 +2957,9 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, case elfcpp::R_386_GOTOFF: { - elfcpp::Elf_types<32>::Elf_Addr value; - value = (psymval->value(object, 0) - - target->got_plt_section()->address()); - Relocate_functions<32, false>::rel32(view, value); + elfcpp::Elf_types<32>::Elf_Addr reladdr; + reladdr = target->got_plt_section()->address(); + Relocate_functions<32, false>::pcrel32(view, object, psymval, reladdr); } break; @@ -3297,9 +3322,11 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, unsigned char* view, section_size_type view_size) { - // leal foo(,%reg,1),%eax; call ___tls_get_addr + // leal foo(,%ebx,1),%eax; call ___tls_get_addr@PLT // ==> movl %gs:0,%eax; subl $foo@tpoff,%eax - // leal foo(%reg),%eax; call ___tls_get_addr + // leal foo(%ebx),%eax; call ___tls_get_addr@PLT + // ==> movl %gs:0,%eax; subl $foo@tpoff,%eax + // leal foo(%reg),%eax; call *___tls_get_addr@GOT(%reg) // ==> movl %gs:0,%eax; subl $foo@tpoff,%eax tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); @@ -3307,10 +3334,12 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, unsigned char op1 = view[-1]; unsigned char op2 = view[-2]; + unsigned char op3 = view[4]; 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); + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + op3 == 0xe8 || op3 == 0xff); int roff = 5; @@ -3324,12 +3353,18 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, } else { + unsigned char reg = op1 & 7; 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) + ((op1 & 0xf8) == 0x80 + && reg != 4 + && reg != 0 + && (op3 == 0xe8 || (view[5] & 0x7) == reg))); + if (op3 == 0xff + || (rel.get_r_offset() + 9 < view_size + && view[9] == 0x90)) { - // There is a trailing nop. Use the size byte subl. + // There is an indirect call or 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; } @@ -3360,20 +3395,24 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo, unsigned char* view, section_size_type view_size) { - // leal foo(,%ebx,1),%eax; call ___tls_get_addr + // leal foo(,%ebx,1),%eax; call ___tls_get_addr@PLT // ==> movl %gs:0,%eax; addl foo@gotntpoff(%ebx),%eax - // leal foo(%ebx),%eax; call ___tls_get_addr; nop + // leal foo(%ebx),%eax; call ___tls_get_addr@PLT; nop // ==> movl %gs:0,%eax; addl foo@gotntpoff(%ebx),%eax + // leal foo(%reg),%eax; call *___tls_get_addr@GOT(%reg) + // ==> movl %gs:0,%eax; addl foo@gotntpoff(%reg),%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]; + unsigned char op3 = view[4]; 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); + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + op3 == 0xe8 || op3 == 0xff); int roff; @@ -3387,10 +3426,14 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo, } else { + unsigned char reg = op1 & 7; tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 10); tls::check_tls(relinfo, relnum, rel.get_r_offset(), - (op1 & 0xf8) == 0x80 && (op1 & 7) != 4); - tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[9] == 0x90); + ((op1 & 0xf8) == 0x80 + && reg != 4 + && reg != 0 + && ((op3 == 0xe8 && view[9] == 0x90) + || (view[5] & 0x7) == reg))); roff = 6; } @@ -3491,19 +3534,36 @@ Target_i386::Relocate::tls_ld_to_le(const Relocate_info<32, false>* relinfo, unsigned char* view, section_size_type view_size) { - // leal foo(%reg), %eax; call ___tls_get_addr + // leal foo(%ebx), %eax; call ___tls_get_addr@PLT // ==> movl %gs:0,%eax; nop; leal 0(%esi,1),%esi + // leal foo(%reg), %eax; call call *___tls_get_addr@GOT(%reg) + // ==> movl %gs:0,%eax; leal (%esi),%esi tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); - tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 9); - // FIXME: Does this test really always pass? + unsigned char op1 = view[-1]; + unsigned char op2 = view[-2]; + unsigned char op3 = view[4]; + tls::check_tls(relinfo, relnum, rel.get_r_offset(), - view[-2] == 0x8d && view[-1] == 0x83); + op3 == 0xe8 || op3 == 0xff); + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, + op3 == 0xe8 ? 9 : 10); + + // FIXME: Does this test really always pass? + tls::check_tls(relinfo, relnum, rel.get_r_offset(), op2 == 0x8d); - tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[4] == 0xe8); + unsigned char reg = op1 & 7; + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + ((op1 & 0xf8) == 0x80 + && reg != 4 + && reg != 0 + && (op3 == 0xe8 || (view[5] & 0x7) == reg))); - memcpy(view - 2, "\x65\xa1\0\0\0\0\x90\x8d\x74\x26\0", 11); + if (op3 == 0xe8) + memcpy(view - 2, "\x65\xa1\0\0\0\0\x90\x8d\x74\x26\0", 11); + else + memcpy(view - 2, "\x65\xa1\0\0\0\0\x8d\xb6\0\0\0\0", 12); // The next reloc should be a PLT32 reloc against __tls_get_addr. // We can skip it. @@ -3917,7 +3977,9 @@ Target_i386::do_ehframe_datarel_base() const bool Target_i386::do_is_call_to_non_split(const Symbol* sym, - const unsigned char*) const + const unsigned char*, + const unsigned char*, + section_size_type) const { return (sym->type() == elfcpp::STT_FUNC && !is_prefix_of("__i686.get_pc_thunk.", sym->name())); @@ -4141,6 +4203,7 @@ const Target::Target_info Target_i386_nacl::i386_nacl_info = NULL, // attributes_vendor "_start", // entry_symbol_name 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; #define NACLMASK 0xe0 // 32-byte alignment mask @@ -4378,6 +4441,7 @@ const Target::Target_info Target_iamcu::iamcu_info = NULL, // attributes_vendor "_start", // entry_symbol_name 32, // hash_entry_size + elfcpp::SHT_PROGBITS, // unwind_section_type }; class Target_selector_iamcu : public Target_selector