// sparc.cc -- sparc target support for gold.
-// Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
+// Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
// This file is part of gold.
{
public:
Relocate()
- : ignore_gd_add_(false)
+ : ignore_gd_add_(false), reloc_adjust_addr_(NULL)
{ }
~Relocate()
// Ignore the next relocation which should be R_SPARC_TLS_GD_ADD
bool ignore_gd_add_;
+
+ // If we hit a reloc at this view address, adjust it back by 4 bytes.
+ unsigned char *reloc_adjust_addr_;
};
// A class which returns the size required for a relocation type,
false, // has_resolve
false, // has_code_fill
true, // is_default_stack_executable
+ false, // can_icf_inline_merge_sections
'\0', // wrap_char
"/usr/lib/ld.so.1", // dynamic_linker
0x00010000, // default_text_segment_address
false, // has_resolve
false, // has_code_fill
true, // is_default_stack_executable
+ false, // can_icf_inline_merge_sections
'\0', // wrap_char
"/usr/lib/sparcv9/ld.so.1", // dynamic_linker
0x100000, // default_text_segment_address
rela_dyn->add_local_relative(object, r_sym, elfcpp::R_SPARC_RELATIVE,
output_section, data_shndx,
reloc.get_r_offset(),
- reloc.get_r_addend());
+ reloc.get_r_addend(), false);
}
break;
object->set_local_got_offset(r_sym, GOT_TYPE_STANDARD, off);
rela_dyn->add_local_relative(object, r_sym,
elfcpp::R_SPARC_RELATIVE,
- got, off, 0);
+ got, off, 0, false);
}
}
else
object->error(_("local symbol %u has bad shndx %u"),
r_sym, shndx);
else
- got->add_local_pair_with_rela(object, r_sym,
- lsym.get_st_shndx(),
- GOT_TYPE_TLS_PAIR,
- target->rela_dyn_section(layout),
- (size == 64
- ? elfcpp::R_SPARC_TLS_DTPMOD64
- : elfcpp::R_SPARC_TLS_DTPMOD32),
- 0);
+ got->add_local_pair_with_rel(object, r_sym,
+ lsym.get_st_shndx(),
+ GOT_TYPE_TLS_PAIR,
+ target->rela_dyn_section(layout),
+ (size == 64
+ ? elfcpp::R_SPARC_TLS_DTPMOD64
+ : elfcpp::R_SPARC_TLS_DTPMOD32),
+ 0);
if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
generate_tls_call(symtab, layout, target);
}
if (gsym->is_from_dynobj()
|| gsym->is_undefined()
|| gsym->is_preemptible())
- got->add_global_with_rela(gsym, GOT_TYPE_STANDARD, rela_dyn,
- elfcpp::R_SPARC_GLOB_DAT);
+ got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
+ elfcpp::R_SPARC_GLOB_DAT);
else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
{
unsigned int off = got->add_constant(0);
// dtv-relative offset.
Output_data_got<size, big_endian>* got
= target->got_section(symtab, layout);
- got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_PAIR,
- target->rela_dyn_section(layout),
- (size == 64 ?
- elfcpp::R_SPARC_TLS_DTPMOD64 :
- elfcpp::R_SPARC_TLS_DTPMOD32),
- (size == 64 ?
- elfcpp::R_SPARC_TLS_DTPOFF64 :
- elfcpp::R_SPARC_TLS_DTPOFF32));
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+ target->rela_dyn_section(layout),
+ (size == 64
+ ? elfcpp::R_SPARC_TLS_DTPMOD64
+ : elfcpp::R_SPARC_TLS_DTPMOD32),
+ (size == 64
+ ? elfcpp::R_SPARC_TLS_DTPOFF64
+ : elfcpp::R_SPARC_TLS_DTPOFF32));
// Emit R_SPARC_WPLT30 against "__tls_get_addr"
if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
// Create a GOT entry for the tp-relative offset.
Output_data_got<size, big_endian>* got
= target->got_section(symtab, layout);
- got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
- target->rela_dyn_section(layout),
- (size == 64 ?
- elfcpp::R_SPARC_TLS_TPOFF64 :
- elfcpp::R_SPARC_TLS_TPOFF32));
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ target->rela_dyn_section(layout),
+ (size == 64 ?
+ elfcpp::R_SPARC_TLS_TPOFF64 :
+ elfcpp::R_SPARC_TLS_TPOFF32));
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
// Create a GOT entry for the tp-relative offset.
Output_data_got<size, big_endian>* got
= target->got_section(symtab, layout);
- got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
- target->rela_dyn_section(layout),
- (size == 64 ?
- elfcpp::R_SPARC_TLS_TPOFF64 :
- elfcpp::R_SPARC_TLS_TPOFF32));
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ target->rela_dyn_section(layout),
+ (size == 64
+ ? elfcpp::R_SPARC_TLS_TPOFF64
+ : elfcpp::R_SPARC_TLS_TPOFF32));
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
return false;
}
}
+ if (this->reloc_adjust_addr_ == view)
+ view -= 4;
typedef Sparc_relocate_functions<size, big_endian> Reloc;
wv += 1;
this->ignore_gd_add_ = true;
}
-
+ else
+ {
+ // Even if the delay slot isn't the TLS_GD_ADD
+ // instruction, we still have to handle the case
+ // where it sets up %o0 in some other way.
+ elfcpp::Swap<32, true>::writeval(wv, val);
+ wv += 1;
+ this->reloc_adjust_addr_ = view + 4;
+ }
// call __tls_get_addr --> add %g7, %o0, %o0
elfcpp::Swap<32, true>::writeval(wv, 0x9001c008);
break;
public:
Target_selector_sparc()
: Target_selector(elfcpp::EM_NONE, size, big_endian,
- (size == 64 ? "elf64-sparc" : "elf32-sparc"))
+ (size == 64 ? "elf64-sparc" : "elf32-sparc"),
+ (size == 64 ? "elf64_sparc" : "elf32_sparc"))
{ }
Target* do_recognize(int machine, int, int)