summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-11-01 00:19:30 +0000
committerIan Lance Taylor <iant@google.com>2007-11-01 00:19:30 +0000
commitb0119a0f17aeeeed73cb70ba9466abc508d0bac9 (patch)
treededbec62cd7ce4bf44129a83ce51427f41916b2c
parent3c32c379b843fd745602585e7d08172a79d50231 (diff)
downloadbinutils-redhat-b0119a0f17aeeeed73cb70ba9466abc508d0bac9.tar.gz
From Cary Coutant: More support for -shared, including fixes to GOT
handling.
-rw-r--r--gold/i386.cc131
-rw-r--r--gold/layout.cc3
-rw-r--r--gold/x86_64.cc156
3 files changed, 208 insertions, 82 deletions
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);
-
- // 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);
- }
+ {
+ bool is_pcrel = (r_type == elfcpp::R_386_PC32
+ || r_type == elfcpp::R_386_PC16
+ || r_type == 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.
+ 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());
-
- 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 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);
+ {
+ 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()
+ || (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: 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);