diff --git a/gold/i386.cc b/gold/i386.cc index cfa10ad2fb..052b7d3fe8 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -97,6 +97,14 @@ class Target_i386 : public Sized_target<32, false> std::string do_code_fill(off_t length); + // Return the size of the GOT section. + off_t + got_size() + { + gold_assert(this->got_ != NULL); + return this->got_->data_size(); + } + private: // The class which scans relocations. struct Scan @@ -215,6 +223,14 @@ class Target_i386 : public Sized_target<32, false> Output_data_got<32, false>* got_section(Symbol_table*, Layout*); + // Get the GOT PLT section. + Output_data_space* + got_plt_section() const + { + gold_assert(this->got_plt_ != NULL); + return this->got_plt_; + } + // Create a PLT entry for a global symbol. void make_plt_entry(Symbol_table*, Layout*, Symbol*); @@ -756,6 +772,9 @@ Target_i386::Scan::local(const General_options&, // relocate it easily. if (parameters->output_is_position_independent()) { + // FIXME: R_386_RELATIVE only works for a 32-bit relocation. + gold_assert(r_type != elfcpp::R_386_16 && r_type != elfcpp::R_386_8); + 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()); @@ -924,42 +943,73 @@ Target_i386::Scan::global(const General_options& options, case elfcpp::R_386_PC16: case elfcpp::R_386_8: case elfcpp::R_386_PC8: - if (gsym->is_from_dynobj() - || (parameters->output_is_shared() - && gsym->is_preemptible())) - { - // (a) This symbol is defined in a dynamic object. If it is a - // function, we make a PLT entry. Otherwise we need to - // either generate a COPY reloc or copy this reloc. - // (b) We are building a shared object and this symbol is - // preemptible. If it is a function, we make a PLT entry. - // Otherwise, we copy the reloc. We do not make COPY relocs - // in shared objects. - if (gsym->type() == elfcpp::STT_FUNC) - { - target->make_plt_entry(symtab, layout, gsym); + { + bool is_pcrel = (r_type == elfcpp::R_386_PC32 + || r_type == elfcpp::R_386_PC16 + || r_type == elfcpp::R_386_PC8); - // If this is not a PC relative reference, then we may - // be taking the address of the function. In that case - // we need to set the entry in the dynamic symbol table - // to the address of the PLT entry. - if (r_type != elfcpp::R_386_PC32 - && r_type != elfcpp::R_386_PC16 - && r_type != elfcpp::R_386_PC8 - && gsym->is_from_dynobj()) - gsym->set_needs_dynsym_value(); - } - else if (parameters->output_is_shared()) - { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - rel_dyn->add_global(gsym, r_type, object, data_shndx, - reloc.get_r_offset()); - } - else - target->copy_reloc(&options, symtab, layout, object, data_shndx, - gsym, reloc); - } + if (gsym->is_from_dynobj() + || (parameters->output_is_shared() + && gsym->is_preemptible())) + { + // (a) This symbol is defined in a dynamic object. If it is a + // function, we make a PLT entry. Otherwise we need to + // either generate a COPY reloc or copy this reloc. + // (b) We are building a shared object and this symbol is + // preemptible. If it is a function, we make a PLT entry. + // Otherwise, we copy the reloc. + if (gsym->type() == elfcpp::STT_FUNC) + { + target->make_plt_entry(symtab, layout, gsym); + + // If this is not a PC relative reference, then we may + // be taking the address of the function. In that case + // we need to set the entry in the dynamic symbol table + // to the address of the PLT entry. We will also need to + // create a dynamic relocation. + if (!is_pcrel) + { + if (gsym->is_from_dynobj()) + gsym->set_needs_dynsym_value(); + if (parameters->output_is_position_independent()) + { + // FIXME: If this is an 8-bit or 16-bit + // relocation, R_386_RELATIVE won't work. + gold_assert(r_type != elfcpp::R_386_16 + && r_type != elfcpp::R_386_8); + 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()); + } + } + } + else if (parameters->output_is_shared()) + { + // We do not make COPY relocs in shared objects. + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_global(gsym, r_type, object, data_shndx, + reloc.get_r_offset()); + } + else + target->copy_reloc(&options, symtab, layout, object, data_shndx, + gsym, reloc); + } + else if (!is_pcrel && parameters->output_is_position_independent()) + { + // FIXME: If this is an 8-bit or 16-bit relocation, + // R_386_RELATIVE won't work. + gold_assert(r_type != elfcpp::R_386_16 + && r_type != elfcpp::R_386_8); + + // This is not a PC-relative reference, so we need to generate + // a dynamic relocation. + 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()); + } + } break; case elfcpp::R_386_GOT32: @@ -1222,6 +1272,9 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, const Sized_relobj<32, false>* object = relinfo->object; // 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) @@ -1230,12 +1283,12 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, if (gsym != NULL) { gold_assert(gsym->has_got_offset()); - got_offset = gsym->got_offset(); + got_offset = gsym->got_offset() - target->got_size(); } else { unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); - got_offset = object->local_got_offset(r_sym); + got_offset = object->local_got_offset(r_sym) - target->got_size(); } have_got_offset = true; break; @@ -1291,7 +1344,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, { elfcpp::Elf_types<32>::Elf_Addr value; value = (psymval->value(object, 0) - - target->got_section(NULL, NULL)->address()); + - target->got_plt_section()->address()); Relocate_functions<32, false>::rel32(view, value); } break; @@ -1299,7 +1352,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, case elfcpp::R_386_GOTPC: { elfcpp::Elf_types<32>::Elf_Addr value; - value = target->got_section(NULL, NULL)->address(); + value = target->got_plt_section()->address(); Relocate_functions<32, false>::pcrel32(view, value, address); } break; diff --git a/gold/layout.cc b/gold/layout.cc index 488ca6de55..d9593904f3 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -591,7 +591,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) // Create the .interp section to hold the name of the // interpreter, and put it in a PT_INTERP segment. - this->create_interp(target); + if (!parameters->output_is_shared()) + this->create_interp(target); // Finish the .dynamic section to hold the dynamic data, and put // it in a PT_DYNAMIC segment. diff --git a/gold/x86_64.cc b/gold/x86_64.cc index a90f8f46bf..5597d599bb 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -110,6 +110,14 @@ class Target_x86_64 : public Sized_target<64, false> std::string do_code_fill(off_t length); + // Return the size of the GOT section. + off_t + got_size() + { + gold_assert(this->got_ != NULL); + return this->got_->data_size(); + } + private: // The class which scans relocations. struct Scan @@ -215,6 +223,14 @@ class Target_x86_64 : public Sized_target<64, false> Output_data_got<64, false>* got_section(Symbol_table*, Layout*); + // Get the GOT PLT section. + Output_data_space* + got_plt_section() const + { + gold_assert(this->got_plt_ != NULL); + return this->got_plt_; + } + // Create a PLT entry for a global symbol. void make_plt_entry(Symbol_table*, Layout*, Symbol*); @@ -719,9 +735,21 @@ Target_x86_64::Scan::local(const General_options&, case elfcpp::R_X86_64_32S: case elfcpp::R_X86_64_16: case elfcpp::R_X86_64_8: - // FIXME: If we are generating a shared object we need to copy - // this relocation into the object. - gold_assert(!parameters->output_is_shared()); + // If building a shared library (or a position-independent + // executable), we need to create a dynamic relocation for + // this location. The relocation applied at link time will + // apply the link-time value, so we flag the location with + // an R_386_RELATIVE relocation so the dynamic loader can + // relocate it easily. + if (parameters->output_is_position_independent()) + { + // FIXME: R_X86_64_RELATIVE assumes a 64-bit relocation. + gold_assert(r_type == elfcpp::R_X86_64_64); + + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, + data_shndx, reloc.get_r_offset(), 0); + } break; case elfcpp::R_X86_64_PC64: @@ -758,8 +786,11 @@ Target_x86_64::Scan::local(const General_options&, { // If we are generating a shared object, we need to add a // dynamic RELATIVE relocation for this symbol. - if (parameters->output_is_shared()) + if (parameters->output_is_position_independent()) { + // FIXME: R_X86_64_RELATIVE assumes a 64-bit relocation. + gold_assert(r_type != elfcpp::R_X86_64_GOT32); + Reloc_section* rela_dyn = target->rela_dyn_section(layout); rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, data_shndx, reloc.get_r_offset(), 0); @@ -884,36 +915,63 @@ Target_x86_64::Scan::global(const General_options& options, case elfcpp::R_X86_64_PC16: case elfcpp::R_X86_64_8: case elfcpp::R_X86_64_PC8: - // FIXME: If we are generating a shared object we may need to - // copy this relocation into the object. If this symbol is - // defined in a shared object, we may need to copy this - // relocation in order to avoid a COPY relocation. - gold_assert(!parameters->output_is_shared()); + { + bool is_pcrel = (r_type == elfcpp::R_X86_64_PC64 + || r_type == elfcpp::R_X86_64_PC32 + || r_type == elfcpp::R_X86_64_PC16 + || r_type == elfcpp::R_X86_64_PC8); - 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 - // either generate a COPY reloc or copy this reloc. - if (gsym->type() == elfcpp::STT_FUNC) - { - target->make_plt_entry(symtab, layout, gsym); + if (gsym->is_from_dynobj() + || (parameters->output_is_shared() + && gsym->is_preemptible())) + { + // (a) This symbol is defined in a dynamic object. If it is a + // function, we make a PLT entry. Otherwise we need to + // either generate a COPY reloc or copy this reloc. + // (b) We are building a shared object and this symbol is + // preemptible. If it is a function, we make a PLT entry. + // Otherwise, we copy the reloc. + if (gsym->type() == elfcpp::STT_FUNC) + { + target->make_plt_entry(symtab, layout, gsym); - // If this is not a PC relative reference, then we may - // be taking the address of the function. In that case - // we need to set the entry in the dynamic symbol table - // to the address of the PLT entry. - if (r_type != elfcpp::R_X86_64_PC64 - && r_type != elfcpp::R_X86_64_PC32 - && r_type != elfcpp::R_X86_64_PC16 - && r_type != elfcpp::R_X86_64_PC8) - gsym->set_needs_dynsym_value(); - } - else - target->copy_reloc(&options, symtab, layout, object, data_shndx, - gsym, reloc); + // If this is not a PC relative reference, then we may + // be taking the address of the function. In that case + // we need to set the entry in the dynamic symbol table + // to the address of the PLT entry. We will also need to + // create a dynamic relocation. + if (!is_pcrel) + { + if (gsym->is_from_dynobj()) + gsym->set_needs_dynsym_value(); + if (parameters->output_is_position_independent()) + { + // FIXME: R_X86_64_RELATIVE assumes a 64-bit + // relocation. + gold_assert(r_type == elfcpp::R_X86_64_64); + + Reloc_section* rela_dyn = + target->rela_dyn_section(layout); + rela_dyn->add_local(object, 0, + elfcpp::R_X86_64_RELATIVE, + data_shndx, + reloc.get_r_offset(), 0); + } + } + } + else if (parameters->output_is_shared()) + { + // We do not make COPY relocs in shared objects. + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + rela_dyn->add_global(gsym, r_type, object, data_shndx, + reloc.get_r_offset(), + reloc.get_r_addend()); + } + else + target->copy_reloc(&options, symtab, layout, object, data_shndx, + gsym, reloc); + } } - break; case elfcpp::R_X86_64_GOT64: @@ -948,6 +1006,13 @@ Target_x86_64::Scan::global(const General_options& options, // Otherwise we need a PLT entry. if (gsym->final_value_is_known()) break; + // If building a shared library, we can also skip the PLT entry + // if the symbol is defined in the output file and is protected + // or hidden. + if (gsym->is_defined() + && !gsym->is_from_dynobj() + && !gsym->is_preemptible()) + break; target->make_plt_entry(symtab, layout, gsym); break; @@ -1156,7 +1221,11 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, // Pick the value to use for symbols defined in shared objects. Symbol_value<64> symval; - if (gsym != NULL && gsym->is_from_dynobj() && gsym->has_plt_offset()) + if (gsym != NULL + && (gsym->is_from_dynobj() + || (parameters->output_is_shared() + && gsym->is_preemptible())) + && gsym->has_plt_offset()) { symval.set_output_value(target->plt_section()->address() + gsym->plt_offset()); @@ -1167,6 +1236,9 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, const elfcpp::Elf_Xword addend = rela.get_r_addend(); // 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) @@ -1179,12 +1251,12 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, if (gsym != NULL) { gold_assert(gsym->has_got_offset()); - got_offset = gsym->got_offset(); + got_offset = gsym->got_offset() - target->got_size(); } else { unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info()); - got_offset = object->local_got_offset(r_sym); + got_offset = object->local_got_offset(r_sym) - target->got_size(); } have_got_offset = true; break; @@ -1278,7 +1350,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, { gold_assert(gsym); elfcpp::Elf_types<64>::Elf_Addr value; - value = target->got_section(NULL, NULL)->address(); + value = target->got_plt_section()->address(); Relocate_functions<64, false>::pcrela32(view, value, addend, address); } break; @@ -1295,7 +1367,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, { gold_assert(gsym); elfcpp::Elf_types<64>::Elf_Addr value; - value = target->got_section(NULL, NULL)->address(); + value = target->got_plt_section()->address(); Relocate_functions<64, false>::pcrela64(view, value, addend, address); } break; @@ -1304,7 +1376,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, { elfcpp::Elf_types<64>::Elf_Addr value; value = (psymval->value(object, 0) - - target->got_section(NULL, NULL)->address()); + - target->got_plt_section()->address()); Relocate_functions<64, false>::rela64(view, value, addend); } break; @@ -1313,7 +1385,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, { gold_assert(have_got_offset); elfcpp::Elf_types<64>::Elf_Addr value; - value = target->got_section(NULL, NULL)->address() + got_offset; + value = target->got_plt_section()->address() + got_offset; Relocate_functions<64, false>::pcrela32(view, value, addend, address); } break; @@ -1322,7 +1394,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, { gold_assert(have_got_offset); elfcpp::Elf_types<64>::Elf_Addr value; - value = target->got_section(NULL, NULL)->address() + got_offset; + value = target->got_plt_section()->address() + got_offset; Relocate_functions<64, false>::pcrela64(view, value, addend, address); } break; @@ -1389,7 +1461,7 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, elfcpp::Elf_types<64>::Elf_Addr value = psymval->value(relinfo->object, 0); const bool is_final = (gsym == NULL - ? !parameters->output_is_shared() + ? !parameters->output_is_position_independent() : gsym->final_value_is_known()); const tls::Tls_optimization optimized_type = Target_x86_64::optimize_tls_reloc(is_final, r_type);