From Cary Coutant: More support for -shared, including fixes to GOT

handling.
This commit is contained in:
Ian Lance Taylor 2007-11-01 00:19:30 +00:00
parent 823963270f
commit 96f2030e25
3 changed files with 205 additions and 79 deletions

View File

@ -97,6 +97,14 @@ class Target_i386 : public Sized_target<32, false>
std::string std::string
do_code_fill(off_t length); 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: private:
// The class which scans relocations. // The class which scans relocations.
struct Scan struct Scan
@ -215,6 +223,14 @@ class Target_i386 : public Sized_target<32, false>
Output_data_got<32, false>* Output_data_got<32, false>*
got_section(Symbol_table*, Layout*); 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. // Create a PLT entry for a global symbol.
void void
make_plt_entry(Symbol_table*, Layout*, Symbol*); make_plt_entry(Symbol_table*, Layout*, Symbol*);
@ -756,6 +772,9 @@ Target_i386::Scan::local(const General_options&,
// relocate it easily. // relocate it easily.
if (parameters->output_is_position_independent()) 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); Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx, rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx,
reloc.get_r_offset()); 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_PC16:
case elfcpp::R_386_8: case elfcpp::R_386_8:
case elfcpp::R_386_PC8: case elfcpp::R_386_PC8:
if (gsym->is_from_dynobj() {
|| (parameters->output_is_shared() bool is_pcrel = (r_type == elfcpp::R_386_PC32
&& gsym->is_preemptible())) || r_type == elfcpp::R_386_PC16
{ || r_type == elfcpp::R_386_PC8);
// (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);
// If this is not a PC relative reference, then we may if (gsym->is_from_dynobj()
// be taking the address of the function. In that case || (parameters->output_is_shared()
// we need to set the entry in the dynamic symbol table && gsym->is_preemptible()))
// to the address of the PLT entry. {
if (r_type != elfcpp::R_386_PC32 // (a) This symbol is defined in a dynamic object. If it is a
&& r_type != elfcpp::R_386_PC16 // function, we make a PLT entry. Otherwise we need to
&& r_type != elfcpp::R_386_PC8 // either generate a COPY reloc or copy this reloc.
&& gsym->is_from_dynobj()) // (b) We are building a shared object and this symbol is
gsym->set_needs_dynsym_value(); // preemptible. If it is a function, we make a PLT entry.
} // Otherwise, we copy the reloc.
else if (parameters->output_is_shared()) if (gsym->type() == elfcpp::STT_FUNC)
{ {
Reloc_section* rel_dyn = target->rel_dyn_section(layout); target->make_plt_entry(symtab, layout, gsym);
rel_dyn->add_global(gsym, r_type, object, data_shndx,
reloc.get_r_offset()); // If this is not a PC relative reference, then we may
} // be taking the address of the function. In that case
else // we need to set the entry in the dynamic symbol table
target->copy_reloc(&options, symtab, layout, object, data_shndx, // to the address of the PLT entry. We will also need to
gsym, reloc); // 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; break;
case elfcpp::R_386_GOT32: 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; const Sized_relobj<32, false>* object = relinfo->object;
// Get the GOT offset if needed. // 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; bool have_got_offset = false;
unsigned int got_offset = 0; unsigned int got_offset = 0;
switch (r_type) switch (r_type)
@ -1230,12 +1283,12 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
if (gsym != NULL) if (gsym != NULL)
{ {
gold_assert(gsym->has_got_offset()); gold_assert(gsym->has_got_offset());
got_offset = gsym->got_offset(); got_offset = gsym->got_offset() - target->got_size();
} }
else else
{ {
unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); 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; have_got_offset = true;
break; break;
@ -1291,7 +1344,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
{ {
elfcpp::Elf_types<32>::Elf_Addr value; elfcpp::Elf_types<32>::Elf_Addr value;
value = (psymval->value(object, 0) value = (psymval->value(object, 0)
- target->got_section(NULL, NULL)->address()); - target->got_plt_section()->address());
Relocate_functions<32, false>::rel32(view, value); Relocate_functions<32, false>::rel32(view, value);
} }
break; break;
@ -1299,7 +1352,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
case elfcpp::R_386_GOTPC: case elfcpp::R_386_GOTPC:
{ {
elfcpp::Elf_types<32>::Elf_Addr value; 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); Relocate_functions<32, false>::pcrel32(view, value, address);
} }
break; break;

View File

@ -591,7 +591,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
// Create the .interp section to hold the name of the // Create the .interp section to hold the name of the
// interpreter, and put it in a PT_INTERP segment. // 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 // Finish the .dynamic section to hold the dynamic data, and put
// it in a PT_DYNAMIC segment. // it in a PT_DYNAMIC segment.

View File

@ -110,6 +110,14 @@ class Target_x86_64 : public Sized_target<64, false>
std::string std::string
do_code_fill(off_t length); 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: private:
// The class which scans relocations. // The class which scans relocations.
struct Scan struct Scan
@ -215,6 +223,14 @@ class Target_x86_64 : public Sized_target<64, false>
Output_data_got<64, false>* Output_data_got<64, false>*
got_section(Symbol_table*, Layout*); 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. // Create a PLT entry for a global symbol.
void void
make_plt_entry(Symbol_table*, Layout*, Symbol*); 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_32S:
case elfcpp::R_X86_64_16: case elfcpp::R_X86_64_16:
case elfcpp::R_X86_64_8: case elfcpp::R_X86_64_8:
// FIXME: If we are generating a shared object we need to copy // If building a shared library (or a position-independent
// this relocation into the object. // executable), we need to create a dynamic relocation for
gold_assert(!parameters->output_is_shared()); // 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; break;
case elfcpp::R_X86_64_PC64: 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 // If we are generating a shared object, we need to add a
// dynamic RELATIVE relocation for this symbol. // 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); Reloc_section* rela_dyn = target->rela_dyn_section(layout);
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE,
data_shndx, reloc.get_r_offset(), 0); 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_PC16:
case elfcpp::R_X86_64_8: case elfcpp::R_X86_64_8:
case elfcpp::R_X86_64_PC8: 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 bool is_pcrel = (r_type == elfcpp::R_X86_64_PC64
// defined in a shared object, we may need to copy this || r_type == elfcpp::R_X86_64_PC32
// relocation in order to avoid a COPY relocation. || r_type == elfcpp::R_X86_64_PC16
gold_assert(!parameters->output_is_shared()); || r_type == elfcpp::R_X86_64_PC8);
if (gsym->is_from_dynobj()) if (gsym->is_from_dynobj()
{ || (parameters->output_is_shared()
// This symbol is defined in a dynamic object. If it is a && gsym->is_preemptible()))
// function, we make a PLT entry. Otherwise we need to {
// either generate a COPY reloc or copy this reloc. // (a) This symbol is defined in a dynamic object. If it is a
if (gsym->type() == elfcpp::STT_FUNC) // function, we make a PLT entry. Otherwise we need to
{ // either generate a COPY reloc or copy this reloc.
target->make_plt_entry(symtab, layout, gsym); // (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 // If this is not a PC relative reference, then we may
// be taking the address of the function. In that case // be taking the address of the function. In that case
// we need to set the entry in the dynamic symbol table // we need to set the entry in the dynamic symbol table
// to the address of the PLT entry. // to the address of the PLT entry. We will also need to
if (r_type != elfcpp::R_X86_64_PC64 // create a dynamic relocation.
&& r_type != elfcpp::R_X86_64_PC32 if (!is_pcrel)
&& r_type != elfcpp::R_X86_64_PC16 {
&& r_type != elfcpp::R_X86_64_PC8) if (gsym->is_from_dynobj())
gsym->set_needs_dynsym_value(); gsym->set_needs_dynsym_value();
} if (parameters->output_is_position_independent())
else {
target->copy_reloc(&options, symtab, layout, object, data_shndx, // FIXME: R_X86_64_RELATIVE assumes a 64-bit
gsym, reloc); // 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; break;
case elfcpp::R_X86_64_GOT64: 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. // Otherwise we need a PLT entry.
if (gsym->final_value_is_known()) if (gsym->final_value_is_known())
break; 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); target->make_plt_entry(symtab, layout, gsym);
break; 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. // Pick the value to use for symbols defined in shared objects.
Symbol_value<64> symval; 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() symval.set_output_value(target->plt_section()->address()
+ gsym->plt_offset()); + 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(); const elfcpp::Elf_Xword addend = rela.get_r_addend();
// Get the GOT offset if needed. // 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; bool have_got_offset = false;
unsigned int got_offset = 0; unsigned int got_offset = 0;
switch (r_type) switch (r_type)
@ -1179,12 +1251,12 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
if (gsym != NULL) if (gsym != NULL)
{ {
gold_assert(gsym->has_got_offset()); gold_assert(gsym->has_got_offset());
got_offset = gsym->got_offset(); got_offset = gsym->got_offset() - target->got_size();
} }
else else
{ {
unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info()); 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; have_got_offset = true;
break; break;
@ -1278,7 +1350,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
{ {
gold_assert(gsym); gold_assert(gsym);
elfcpp::Elf_types<64>::Elf_Addr value; 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); Relocate_functions<64, false>::pcrela32(view, value, addend, address);
} }
break; break;
@ -1295,7 +1367,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
{ {
gold_assert(gsym); gold_assert(gsym);
elfcpp::Elf_types<64>::Elf_Addr value; 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); Relocate_functions<64, false>::pcrela64(view, value, addend, address);
} }
break; break;
@ -1304,7 +1376,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
{ {
elfcpp::Elf_types<64>::Elf_Addr value; elfcpp::Elf_types<64>::Elf_Addr value;
value = (psymval->value(object, 0) value = (psymval->value(object, 0)
- target->got_section(NULL, NULL)->address()); - target->got_plt_section()->address());
Relocate_functions<64, false>::rela64(view, value, addend); Relocate_functions<64, false>::rela64(view, value, addend);
} }
break; break;
@ -1313,7 +1385,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
{ {
gold_assert(have_got_offset); gold_assert(have_got_offset);
elfcpp::Elf_types<64>::Elf_Addr value; 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); Relocate_functions<64, false>::pcrela32(view, value, addend, address);
} }
break; break;
@ -1322,7 +1394,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
{ {
gold_assert(have_got_offset); gold_assert(have_got_offset);
elfcpp::Elf_types<64>::Elf_Addr value; 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); Relocate_functions<64, false>::pcrela64(view, value, addend, address);
} }
break; 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); elfcpp::Elf_types<64>::Elf_Addr value = psymval->value(relinfo->object, 0);
const bool is_final = (gsym == NULL const bool is_final = (gsym == NULL
? !parameters->output_is_shared() ? !parameters->output_is_position_independent()
: gsym->final_value_is_known()); : gsym->final_value_is_known());
const tls::Tls_optimization optimized_type const tls::Tls_optimization optimized_type
= Target_x86_64::optimize_tls_reloc(is_final, r_type); = Target_x86_64::optimize_tls_reloc(is_final, r_type);