#include "symtab.h"
#include "layout.h"
#include "output.h"
+#include "copy-relocs.h"
#include "target.h"
#include "target-reloc.h"
#include "target-select.h"
Target_i386()
: Sized_target<32, false>(&i386_info),
got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
- copy_relocs_(NULL), dynbss_(NULL), got_mod_index_offset_(-1U)
+ copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
+ got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
{ }
// Scan the relocations to look for symbol adjustments.
unsigned char* view,
section_size_type view_size);
+ // Do a TLS_GOTDESC or TLS_DESC_CALL General-Dynamic to Initial-Exec
+ // transition.
+ inline void
+ tls_desc_gd_to_ie(const Relocate_info<32, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rel<32, false>&, unsigned int r_type,
+ elfcpp::Elf_types<32>::Elf_Addr value,
+ unsigned char* view,
+ section_size_type view_size);
+
+ // Do a TLS_GOTDESC or TLS_DESC_CALL General-Dynamic to Local-Exec
+ // transition.
+ inline void
+ tls_desc_gd_to_le(const Relocate_info<32, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rel<32, false>&, unsigned int r_type,
+ elfcpp::Elf_types<32>::Elf_Addr value,
+ unsigned char* view,
+ section_size_type view_size);
+
// Do a TLS Local-Dynamic to Local-Exec transition.
inline void
tls_ld_to_le(const Relocate_info<32, false>*, size_t relnum,
void
make_plt_entry(Symbol_table*, Layout*, Symbol*);
+ // Define the _TLS_MODULE_BASE_ symbol at the end of the TLS segment.
+ void
+ define_tls_base_symbol(Symbol_table*, Layout*);
+
// Create a GOT entry for the TLS module index.
unsigned int
got_mod_index_entry(Symbol_table* symtab, Layout* layout,
&& gsym->type() != elfcpp::STT_FUNC);
}
- // Copy a relocation against a global symbol.
+ // Add a potential copy relocation.
void
- copy_reloc(const General_options*, Symbol_table*, Layout*,
- Sized_relobj<32, false>*, unsigned int,
- Output_section*, Symbol*, const elfcpp::Rel<32, false>&);
+ copy_reloc(Symbol_table* symtab, Layout* layout,
+ Sized_relobj<32, false>* object,
+ unsigned int shndx, Output_section* output_section,
+ Symbol* sym, const elfcpp::Rel<32, false>& reloc)
+ {
+ this->copy_relocs_.copy_reloc(symtab, layout,
+ symtab->get_sized_symbol<32>(sym),
+ object, shndx, output_section, reloc,
+ this->rel_dyn_section(layout));
+ }
// Information about this specific target which we pass to the
// general Target structure.
enum Got_type
{
GOT_TYPE_STANDARD = 0, // GOT entry for a regular symbol
- GOT_TYPE_TLS_OFFSET = 1, // GOT entry for TLS offset
- GOT_TYPE_TLS_PAIR = 2, // GOT entry for TLS module/offset pair
- GOT_TYPE_TLS_DESC = 3 // GOT entry for TLS_DESC pair
+ GOT_TYPE_TLS_NOFFSET = 1, // GOT entry for negative TLS offset
+ GOT_TYPE_TLS_OFFSET = 2, // GOT entry for positive TLS offset
+ GOT_TYPE_TLS_PAIR = 3, // GOT entry for TLS module/offset pair
+ GOT_TYPE_TLS_DESC = 4 // GOT entry for TLS_DESC pair
};
// The GOT section.
// The dynamic reloc section.
Reloc_section* rel_dyn_;
// Relocs saved to avoid a COPY reloc.
- Copy_relocs<32, false>* copy_relocs_;
+ Copy_relocs<elfcpp::SHT_REL, 32, false> copy_relocs_;
// Space for variables copied with a COPY reloc.
Output_data_space* dynbss_;
- // Offset of the GOT entry for the TLS module index;
+ // Offset of the GOT entry for the TLS module index.
unsigned int got_mod_index_offset_;
+ // True if the _TLS_MODULE_BASE_ symbol has been defined.
+ bool tls_base_symbol_defined_;
};
const Target::Target_info Target_i386::i386_info =
false, // has_resolve
true, // has_code_fill
true, // is_default_stack_executable
+ '\0', // wrap_char
"/usr/lib/libc.so.1", // dynamic_linker
0x08048000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
this->got_ = new Output_data_got<32, false>();
- layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
- this->got_);
+ Output_section* os;
+ os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_);
+ os->set_is_relro();
// The old GNU linker creates a .got.plt section. We just
// create another set of data in the .got section. Note that we
// always create a PLT if we create a GOT, although the PLT
// might be empty.
- this->got_plt_ = new Output_data_space(4);
- layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
- this->got_plt_);
+ this->got_plt_ = new Output_data_space(4, "** GOT PLT");
+ os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_plt_);
+ os->set_is_relro();
// The first three entries are reserved.
this->got_plt_->set_current_data_size(3 * 4);
if (this->rel_dyn_ == NULL)
{
gold_assert(layout != NULL);
- this->rel_dyn_ = new Reloc_section();
+ this->rel_dyn_ = new Reloc_section(parameters->options().combreloc());
layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
elfcpp::SHF_ALLOC, this->rel_dyn_);
}
void
do_adjust_output_section(Output_section* os);
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** PLT")); }
+
private:
// The size of an entry in the PLT.
static const int plt_entry_size = 16;
Output_data_space* got_plt)
: Output_section_data(4), got_plt_(got_plt), count_(0)
{
- this->rel_ = new Reloc_section();
+ this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
elfcpp::SHF_ALLOC, this->rel_);
}
this->plt_->add_entry(gsym);
}
+// Define the _TLS_MODULE_BASE_ symbol at the end of the TLS segment.
+
+void
+Target_i386::define_tls_base_symbol(Symbol_table* symtab, Layout* layout)
+{
+ if (this->tls_base_symbol_defined_)
+ return;
+
+ Output_segment* tls_segment = layout->tls_segment();
+ if (tls_segment != NULL)
+ {
+ symtab->define_in_output_segment("_TLS_MODULE_BASE_", NULL,
+ tls_segment, 0, 0,
+ elfcpp::STT_TLS,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ Symbol::SEGMENT_END, true);
+ }
+ this->tls_base_symbol_defined_ = true;
+}
+
// Create a GOT entry for the TLS module index.
unsigned int
return this->got_mod_index_offset_;
}
-// Handle a relocation against a non-function symbol defined in a
-// dynamic object. The traditional way to handle this is to generate
-// a COPY relocation to copy the variable at runtime from the shared
-// object into the executable's data segment. However, this is
-// undesirable in general, as if the size of the object changes in the
-// dynamic object, the executable will no longer work correctly. If
-// this relocation is in a writable section, then we can create a
-// dynamic reloc and the dynamic linker will resolve it to the correct
-// address at runtime. However, we do not want do that if the
-// relocation is in a read-only section, as it would prevent the
-// readonly segment from being shared. And if we have to eventually
-// generate a COPY reloc, then any dynamic relocations will be
-// useless. So this means that if this is a writable section, we need
-// to save the relocation until we see whether we have to create a
-// COPY relocation for this symbol for any other relocation.
-
-void
-Target_i386::copy_reloc(const General_options* options,
- Symbol_table* symtab,
- Layout* layout,
- Sized_relobj<32, false>* object,
- unsigned int data_shndx,
- Output_section* output_section,
- Symbol* gsym,
- const elfcpp::Rel<32, false>& rel)
-{
- Sized_symbol<32>* ssym = symtab->get_sized_symbol<32>(gsym);
-
- 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 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, output_section, 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);
-
- section_size_type dynbss_size =
- convert_to_section_size_type(dynbss->current_data_size());
- dynbss_size = align_address(dynbss_size, align);
- section_size_type offset = dynbss_size;
- dynbss->set_current_data_size(dynbss_size + symsize);
-
- symtab->define_with_copy_reloc(ssym, dynbss, offset);
-
- // Add the COPY reloc.
- 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
// symbol. IS_FINAL is true if the final address of this symbol is
// known at link time.
if (parameters->options().output_is_position_independent())
{
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
if (lsym.get_st_type() != elfcpp::STT_SECTION)
- {
- unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- rel_dyn->add_local(object, r_sym, r_type, output_section,
- data_shndx, reloc.get_r_offset());
- }
+ rel_dyn->add_local(object, r_sym, r_type, output_section,
+ data_shndx, reloc.get_r_offset());
else
{
gold_assert(lsym.get_st_value() == 0);
- rel_dyn->add_local_section(object, lsym.get_st_shndx(),
- r_type, output_section,
- data_shndx, reloc.get_r_offset());
+ unsigned int shndx = lsym.get_st_shndx();
+ bool is_ordinary;
+ shndx = object->adjust_sym_shndx(r_sym, shndx,
+ &is_ordinary);
+ if (!is_ordinary)
+ object->error(_("section symbol %u has bad shndx %u"),
+ r_sym, shndx);
+ else
+ rel_dyn->add_local_section(object, shndx,
+ r_type, output_section,
+ data_shndx, reloc.get_r_offset());
}
}
break;
Output_data_got<32, false>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- got->add_local_pair_with_rel(object, r_sym,
- lsym.get_st_shndx(),
- GOT_TYPE_TLS_PAIR,
- target->rel_dyn_section(layout),
- elfcpp::R_386_TLS_DTPMOD32, 0);
+ unsigned int shndx = lsym.get_st_shndx();
+ bool is_ordinary;
+ shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+ if (!is_ordinary)
+ object->error(_("local symbol %u has bad shndx %u"),
+ r_sym, shndx);
+ else
+ got->add_local_pair_with_rel(object, r_sym, shndx,
+ GOT_TYPE_TLS_PAIR,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_DTPMOD32, 0);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
break;
case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva)
- case elfcpp::R_386_TLS_DESC_CALL:
- // FIXME: If not relaxing to LE, we need to generate
- // a GOT entry with an R_386_TLS_DESC reloc.
- if (optimized_type != tls::TLSOPT_TO_LE)
+ target->define_tls_base_symbol(symtab, layout);
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a double GOT entry with an R_386_TLS_DESC reloc.
+ Output_data_got<32, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ unsigned int shndx = lsym.get_st_shndx();
+ bool is_ordinary;
+ shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+ if (!is_ordinary)
+ object->error(_("local symbol %u has bad shndx %u"),
+ r_sym, shndx);
+ else
+ got->add_local_pair_with_rel(object, r_sym, shndx,
+ GOT_TYPE_TLS_DESC,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_DESC, 0);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
break;
+ case elfcpp::R_386_TLS_DESC_CALL:
+ break;
+
case elfcpp::R_386_TLS_LDM: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
? elfcpp::R_386_TLS_TPOFF32
: elfcpp::R_386_TLS_TPOFF);
- got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
+ unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_NOFFSET);
+ got->add_local_with_rel(object, r_sym, got_type,
target->rel_dyn_section(layout),
dyn_r_type);
}
// Scan a relocation for a global symbol.
inline void
-Target_i386::Scan::global(const General_options& options,
+Target_i386::Scan::global(const General_options&,
Symbol_table* symtab,
Layout* layout,
Target_i386* target,
{
if (target->may_need_copy_reloc(gsym))
{
- target->copy_reloc(&options, symtab, layout, object,
+ target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
}
else if (r_type == elfcpp::R_386_32
{
if (target->may_need_copy_reloc(gsym))
{
- target->copy_reloc(&options, symtab, layout, object,
+ target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
}
else
// Create a GOT entry for the tp-relative offset.
Output_data_got<32, false>* got
= target->got_section(symtab, layout);
- got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_NOFFSET,
target->rel_dyn_section(layout),
- elfcpp::R_386_TLS_TPOFF32);
+ elfcpp::R_386_TLS_TPOFF);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
break;
case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (~oliva url)
- case elfcpp::R_386_TLS_DESC_CALL:
- // FIXME: If not relaxing to LE, we need to generate
- // a GOT entry with an R_386_TLS_DESC reloc.
- if (optimized_type != tls::TLSOPT_TO_LE)
+ target->define_tls_base_symbol(symtab, layout);
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a double GOT entry with an R_386_TLS_DESC reloc.
+ Output_data_got<32, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_DESC, 0);
+ }
+ else if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<32, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_NOFFSET,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_TPOFF);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
- unsupported_reloc_global(object, r_type, gsym);
+ break;
+
+ case elfcpp::R_386_TLS_DESC_CALL:
break;
case elfcpp::R_386_TLS_LDM: // Local-dynamic
unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
? elfcpp::R_386_TLS_TPOFF32
: elfcpp::R_386_TLS_TPOFF);
- got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_NOFFSET);
+ got->add_global_with_rel(gsym, got_type,
target->rel_dyn_section(layout),
dyn_r_type);
}
// 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;
+ if (this->copy_relocs_.any_saved_relocs())
+ this->copy_relocs_.emit(this->rel_dyn_section(layout));
}
// Return whether a direct absolute static relocation needs to be applied.
if (gsym != NULL && gsym->type() == elfcpp::STT_FUNC)
ref_flags |= Symbol::FUNCTION_CALL;
if (should_apply_static_reloc(gsym, ref_flags, false))
- Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
+ Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
}
break;
if (gsym != NULL && gsym->type() == elfcpp::STT_FUNC)
ref_flags |= Symbol::FUNCTION_CALL;
if (should_apply_static_reloc(gsym, ref_flags, false))
- Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
+ Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
}
break;
}
else
{
+ unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+ ? GOT_TYPE_TLS_NOFFSET
+ : GOT_TYPE_TLS_PAIR);
unsigned int got_offset;
if (gsym != NULL)
{
- gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_PAIR));
- got_offset = (gsym->got_offset(GOT_TYPE_TLS_PAIR)
- - target->got_size());
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type) - target->got_size();
}
else
{
unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym,
- GOT_TYPE_TLS_PAIR));
- got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_PAIR)
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset = (object->local_got_offset(r_sym, got_type)
- target->got_size());
}
if (optimized_type == tls::TLSOPT_TO_IE)
case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url)
case elfcpp::R_386_TLS_DESC_CALL:
+ this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU;
+ if (optimized_type == tls::TLSOPT_TO_LE)
+ {
+ gold_assert(tls_segment != NULL);
+ this->tls_desc_gd_to_le(relinfo, relnum, tls_segment,
+ rel, r_type, value, view,
+ view_size);
+ break;
+ }
+ else
+ {
+ unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+ ? GOT_TYPE_TLS_NOFFSET
+ : GOT_TYPE_TLS_DESC);
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type) - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset = (object->local_got_offset(r_sym, got_type)
+ - target->got_size());
+ }
+ if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ gold_assert(tls_segment != NULL);
+ this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type,
+ got_offset, view, view_size);
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ if (r_type == elfcpp::R_386_TLS_GOTDESC)
+ {
+ // Relocate the field with the offset of the pair of GOT
+ // entries.
+ Relocate_functions<32, false>::rel32(view, got_offset);
+ }
+ break;
+ }
+ }
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
_("unsupported reloc %u"),
r_type);
// This reloc can appear in debugging sections, in which case we
// won't see the TLS_LDM reloc. The local_dynamic_type field
// tells us this.
- if (optimized_type == tls::TLSOPT_TO_LE)
+ if (optimized_type == tls::TLSOPT_TO_LE
+ && this->local_dynamic_type_ != LOCAL_DYNAMIC_NONE)
{
gold_assert(tls_segment != NULL);
value -= tls_segment->memsz();
{
// Relocate the field with the offset of the GOT entry for
// the tp-relative offset of the symbol.
+ unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_NOFFSET);
unsigned int got_offset;
if (gsym != NULL)
{
- gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
- got_offset = gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type);
}
else
{
unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym,
- GOT_TYPE_TLS_OFFSET));
- got_offset = object->local_got_offset(r_sym,
- GOT_TYPE_TLS_OFFSET);
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset = object->local_got_offset(r_sym, got_type);
}
// For the R_386_TLS_IE relocation, we need to apply the
// absolute address of the GOT entry.
inline void
Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo,
size_t relnum,
- Output_segment* tls_segment,
+ Output_segment*,
const elfcpp::Rel<32, false>& rel,
unsigned int,
elfcpp::Elf_types<32>::Elf_Addr value,
int roff = 5;
- // FIXME: For now, support only one form.
- tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- op1 == 0x8d && op2 == 0x04);
+ // FIXME: For now, support only the first (SIB) form.
+ tls::check_tls(relinfo, relnum, rel.get_r_offset(), op2 == 0x04);
if (op2 == 0x04)
{
}
}
- value = tls_segment->memsz() - value;
Relocate_functions<32, false>::rel32(view + roff, value);
// The next reloc should be a PLT32 reloc against __tls_get_addr.
this->skip_call_tls_get_addr_ = true;
}
+// Do a relocation in which we convert a TLS_GOTDESC or TLS_DESC_CALL
+// General-Dynamic to a Local-Exec.
+
+inline void
+Target_i386::Relocate::tls_desc_gd_to_le(
+ const Relocate_info<32, false>* relinfo,
+ size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rel<32, false>& rel,
+ unsigned int r_type,
+ elfcpp::Elf_types<32>::Elf_Addr value,
+ unsigned char* view,
+ section_size_type view_size)
+{
+ if (r_type == elfcpp::R_386_TLS_GOTDESC)
+ {
+ // leal foo@TLSDESC(%ebx), %eax
+ // ==> leal foo@NTPOFF, %eax
+ tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
+ tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4);
+ tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+ view[-2] == 0x8d && view[-1] == 0x83);
+ view[-1] = 0x05;
+ value -= tls_segment->memsz();
+ Relocate_functions<32, false>::rel32(view, value);
+ }
+ else
+ {
+ // call *foo@TLSCALL(%eax)
+ // ==> nop; nop
+ gold_assert(r_type == elfcpp::R_386_TLS_DESC_CALL);
+ tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 2);
+ tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+ view[0] == 0xff && view[1] == 0x10);
+ view[0] = 0x66;
+ view[1] = 0x90;
+ }
+}
+
+// Do a relocation in which we convert a TLS_GOTDESC or TLS_DESC_CALL
+// General-Dynamic to an Initial-Exec.
+
+inline void
+Target_i386::Relocate::tls_desc_gd_to_ie(
+ const Relocate_info<32, false>* relinfo,
+ size_t relnum,
+ Output_segment*,
+ const elfcpp::Rel<32, false>& rel,
+ unsigned int r_type,
+ elfcpp::Elf_types<32>::Elf_Addr value,
+ unsigned char* view,
+ section_size_type view_size)
+{
+ if (r_type == elfcpp::R_386_TLS_GOTDESC)
+ {
+ // leal foo@TLSDESC(%ebx), %eax
+ // ==> movl foo@GOTNTPOFF(%ebx), %eax
+ tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
+ tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4);
+ tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+ view[-2] == 0x8d && view[-1] == 0x83);
+ view[-2] = 0x8b;
+ Relocate_functions<32, false>::rel32(view, value);
+ }
+ else
+ {
+ // call *foo@TLSCALL(%eax)
+ // ==> nop; nop
+ gold_assert(r_type == elfcpp::R_386_TLS_DESC_CALL);
+ tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 2);
+ tls::check_tls(relinfo, relnum, rel.get_r_offset(),
+ view[0] == 0xff && view[1] == 0x10);
+ view[0] = 0x66;
+ view[1] = 0x90;
+ }
+}
+
// Do a relocation in which we convert a TLS Local-Dynamic to a
// Local-Exec.