From 0da6fa6c5b5a2b4fc5b64fbae25ccd9509210860 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 13 Feb 2010 00:01:20 +0000 Subject: * output.h (Output_reloc::Output_reloc): Add is_symbolless parameter. (Output_reloc::is_symbolless): New. (Output_reloc::is_symbolless_): New. (Output_reloc::type_): Decrease to 29 bits. (Output_reloc::Output_reloc): Add is_symbolless parameter. (Output_reloc::is_symbolless): New. (Output_data_reloc::add_global): Handle is_symbolless. (Output_data_reloc::add_global_relative): Likewise. (Output_data_reloc::add_local): Likewise. (Output_data_reloc::add_local_relative): Likewise. (Output_data_reloc::add_symbolless_global_addend): New. (Output_data_reloc::add_symbolless_local_addend): New. * output.cc (Output_reloc::Output_reloc): Handle is_symbolless. (Output_reloc::set_needs_dynsym_index): Test ->is_symbolless_ instead of ->is_relative_ (Output_reloc::write): Likewise. (Output_reloc::get_symbol_index): Return 0 when ->is_symbolless_ (Output_reloc::write_rel): Simplify. * sparc.cc (Target_sparc::Scan::local): Use ->add_symbolless_local_addend as needed. (Target_sparc::Scan::global): Use ->add_symbolless_global_addend as needed. Also, emit appropriate unaligned vs. aligned dynamic reloc based upon relocation offset. --- gold/ChangeLog | 29 ++++++++++ gold/output.cc | 48 +++++++++++------ gold/output.h | 167 +++++++++++++++++++++++++++++++++++++++++++++------------ gold/sparc.cc | 94 +++++++++++++++++++++----------- 4 files changed, 258 insertions(+), 80 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 0b50ead..936d0b9 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,32 @@ +2010-02-12 David S. Miller + + * output.h (Output_reloc::Output_reloc): Add + is_symbolless parameter. + (Output_reloc::is_symbolless): New. + (Output_reloc::is_symbolless_): New. + (Output_reloc::type_): Decrease to 29 bits. + (Output_reloc::Output_reloc): Add is_symbolless parameter. + (Output_reloc::is_symbolless): New. + (Output_data_reloc::add_global): Handle is_symbolless. + (Output_data_reloc::add_global_relative): Likewise. + (Output_data_reloc::add_local): Likewise. + (Output_data_reloc::add_local_relative): Likewise. + (Output_data_reloc::add_symbolless_global_addend): New. + (Output_data_reloc::add_symbolless_local_addend): New. + * output.cc (Output_reloc::Output_reloc): Handle + is_symbolless. + (Output_reloc::set_needs_dynsym_index): Test ->is_symbolless_ + instead of ->is_relative_ + (Output_reloc::write): Likewise. + (Output_reloc::get_symbol_index): Return 0 when ->is_symbolless_ + (Output_reloc::write_rel): Simplify. + + * sparc.cc (Target_sparc::Scan::local): Use + ->add_symbolless_local_addend as needed. + (Target_sparc::Scan::global): Use ->add_symbolless_global_addend as + needed. Also, emit appropriate unaligned vs. aligned dynamic reloc + based upon relocation offset. + 2010-02-11 Doug Kwan * arm.cc (Target_arm::Scan::local): Fix bugs in relocation handling. diff --git a/gold/output.cc b/gold/output.cc index 4b34b8b..1c2533c 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -638,9 +638,11 @@ Output_reloc::Output_reloc( unsigned int type, Output_data* od, Address address, - bool is_relative) + bool is_relative, + bool is_symbolless) : address_(address), local_sym_index_(GSYM_CODE), type_(type), - is_relative_(is_relative), is_section_symbol_(false), shndx_(INVALID_CODE) + is_relative_(is_relative), is_symbolless_(is_symbolless), + is_section_symbol_(false), shndx_(INVALID_CODE) { // this->type_ is a bitfield; make sure TYPE fits. gold_assert(this->type_ == type); @@ -657,9 +659,11 @@ Output_reloc::Output_reloc( Sized_relobj* relobj, unsigned int shndx, Address address, - bool is_relative) + bool is_relative, + bool is_symbolless) : address_(address), local_sym_index_(GSYM_CODE), type_(type), - is_relative_(is_relative), is_section_symbol_(false), shndx_(shndx) + is_relative_(is_relative), is_symbolless_(is_symbolless), + is_section_symbol_(false), shndx_(shndx) { gold_assert(shndx != INVALID_CODE); // this->type_ is a bitfield; make sure TYPE fits. @@ -680,10 +684,11 @@ Output_reloc::Output_reloc( Output_data* od, Address address, bool is_relative, + bool is_symbolless, bool is_section_symbol) : address_(address), local_sym_index_(local_sym_index), type_(type), - is_relative_(is_relative), is_section_symbol_(is_section_symbol), - shndx_(INVALID_CODE) + is_relative_(is_relative), is_symbolless_(is_symbolless), + is_section_symbol_(is_section_symbol), shndx_(INVALID_CODE) { gold_assert(local_sym_index != GSYM_CODE && local_sym_index != INVALID_CODE); @@ -703,10 +708,11 @@ Output_reloc::Output_reloc( unsigned int shndx, Address address, bool is_relative, + bool is_symbolless, bool is_section_symbol) : address_(address), local_sym_index_(local_sym_index), type_(type), - is_relative_(is_relative), is_section_symbol_(is_section_symbol), - shndx_(shndx) + is_relative_(is_relative), is_symbolless_(is_symbolless), + is_section_symbol_(is_section_symbol), shndx_(shndx) { gold_assert(local_sym_index != GSYM_CODE && local_sym_index != INVALID_CODE); @@ -728,7 +734,8 @@ Output_reloc::Output_reloc( Output_data* od, Address address) : address_(address), local_sym_index_(SECTION_CODE), type_(type), - is_relative_(false), is_section_symbol_(true), shndx_(INVALID_CODE) + is_relative_(false), is_symbolless_(false), + is_section_symbol_(true), shndx_(INVALID_CODE) { // this->type_ is a bitfield; make sure TYPE fits. gold_assert(this->type_ == type); @@ -748,7 +755,8 @@ Output_reloc::Output_reloc( unsigned int shndx, Address address) : address_(address), local_sym_index_(SECTION_CODE), type_(type), - is_relative_(false), is_section_symbol_(true), shndx_(shndx) + is_relative_(false), is_symbolless_(false), + is_section_symbol_(true), shndx_(shndx) { gold_assert(shndx != INVALID_CODE); // this->type_ is a bitfield; make sure TYPE fits. @@ -769,7 +777,8 @@ Output_reloc::Output_reloc( Output_data* od, Address address) : address_(address), local_sym_index_(0), type_(type), - is_relative_(false), is_section_symbol_(false), shndx_(INVALID_CODE) + is_relative_(false), is_symbolless_(false), + is_section_symbol_(false), shndx_(INVALID_CODE) { // this->type_ is a bitfield; make sure TYPE fits. gold_assert(this->type_ == type); @@ -784,7 +793,8 @@ Output_reloc::Output_reloc( unsigned int shndx, Address address) : address_(address), local_sym_index_(0), type_(type), - is_relative_(false), is_section_symbol_(false), shndx_(shndx) + is_relative_(false), is_symbolless_(false), + is_section_symbol_(false), shndx_(shndx) { gold_assert(shndx != INVALID_CODE); // this->type_ is a bitfield; make sure TYPE fits. @@ -802,7 +812,8 @@ Output_reloc::Output_reloc( Output_data* od, Address address) : address_(address), local_sym_index_(TARGET_CODE), type_(type), - is_relative_(false), is_section_symbol_(false), shndx_(INVALID_CODE) + is_relative_(false), is_symbolless_(false), + is_section_symbol_(false), shndx_(INVALID_CODE) { // this->type_ is a bitfield; make sure TYPE fits. gold_assert(this->type_ == type); @@ -818,7 +829,8 @@ Output_reloc::Output_reloc( unsigned int shndx, Address address) : address_(address), local_sym_index_(TARGET_CODE), type_(type), - is_relative_(false), is_section_symbol_(false), shndx_(shndx) + is_relative_(false), is_symbolless_(false), + is_section_symbol_(false), shndx_(shndx) { gold_assert(shndx != INVALID_CODE); // this->type_ is a bitfield; make sure TYPE fits. @@ -834,7 +846,7 @@ void Output_reloc:: set_needs_dynsym_index() { - if (this->is_relative_) + if (this->is_symbolless_) return; switch (this->local_sym_index_) { @@ -876,6 +888,8 @@ Output_reloc::get_symbol_index() const { unsigned int index; + if (this->is_symbolless_) + return 0; switch (this->local_sym_index_) { case INVALID_CODE: @@ -995,7 +1009,7 @@ Output_reloc::write_rel( Write_rel* wr) const { wr->put_r_offset(this->get_address()); - unsigned int sym_index = this->is_relative_ ? 0 : this->get_symbol_index(); + unsigned int sym_index = this->get_symbol_index(); wr->put_r_info(elfcpp::elf_r_info(sym_index, this->type_)); } @@ -1097,7 +1111,7 @@ Output_reloc::write( if (this->rel_.is_target_specific()) addend = parameters->target().reloc_addend(this->rel_.target_arg(), this->rel_.type(), addend); - else if (this->rel_.is_relative()) + else if (this->rel_.is_symbolless()) addend = this->rel_.symbol_value(addend); else if (this->rel_.is_local_section_symbol()) addend = this->rel_.local_section_offset(addend); diff --git a/gold/output.h b/gold/output.h index a549b74..9008bdd 100644 --- a/gold/output.h +++ b/gold/output.h @@ -974,23 +974,24 @@ class Output_reloc // A reloc against a global symbol. Output_reloc(Symbol* gsym, unsigned int type, Output_data* od, - Address address, bool is_relative); + Address address, bool is_relative, bool is_symbolless); Output_reloc(Symbol* gsym, unsigned int type, Sized_relobj* relobj, - unsigned int shndx, Address address, bool is_relative); + unsigned int shndx, Address address, bool is_relative, + bool is_symbolless); // A reloc against a local symbol or local section symbol. Output_reloc(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, Output_data* od, Address address, bool is_relative, - bool is_section_symbol); + bool is_symbolless, bool is_section_symbol); Output_reloc(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, unsigned int shndx, Address address, bool is_relative, - bool is_section_symbol); + bool is_symbolless, bool is_section_symbol); // A reloc against the STT_SECTION symbol of an output section. @@ -1029,6 +1030,12 @@ class Output_reloc is_relative() const { return this->is_relative_; } + // Return whether this is a relocation which should not use + // a symbol, but which obtains its addend from a symbol. + bool + is_symbolless() const + { return this->is_symbolless_; } + // Return whether this is against a local section symbol. bool is_local_section_symbol() const @@ -1152,9 +1159,12 @@ class Output_reloc // input file. unsigned int local_sym_index_; // The reloc type--a processor specific code. - unsigned int type_ : 30; + unsigned int type_ : 29; // True if the relocation is a RELATIVE relocation. bool is_relative_ : 1; + // True if the relocation is one which should not use + // a symbol, but which obtains its addend from a symbol. + bool is_symbolless_ : 1; // True if the relocation is against a section symbol. bool is_section_symbol_ : 1; // If the reloc address is an input section in an object, the @@ -1181,15 +1191,18 @@ class Output_reloc // A reloc against a global symbol. Output_reloc(Symbol* gsym, unsigned int type, Output_data* od, - Address address, Addend addend, bool is_relative) - : rel_(gsym, type, od, address, is_relative), addend_(addend) + Address address, Addend addend, bool is_relative, + bool is_symbolless) + : rel_(gsym, type, od, address, is_relative, is_symbolless), + addend_(addend) { } Output_reloc(Symbol* gsym, unsigned int type, Sized_relobj* relobj, unsigned int shndx, Address address, Addend addend, - bool is_relative) - : rel_(gsym, type, relobj, shndx, address, is_relative), addend_(addend) + bool is_relative, bool is_symbolless) + : rel_(gsym, type, relobj, shndx, address, is_relative, + is_symbolless), addend_(addend) { } // A reloc against a local symbol. @@ -1197,18 +1210,20 @@ class Output_reloc Output_reloc(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, Output_data* od, Address address, - Addend addend, bool is_relative, bool is_section_symbol) + Addend addend, bool is_relative, + bool is_symbolless, bool is_section_symbol) : rel_(relobj, local_sym_index, type, od, address, is_relative, - is_section_symbol), + is_symbolless, is_section_symbol), addend_(addend) { } Output_reloc(Sized_relobj* relobj, unsigned int local_sym_index, unsigned int type, unsigned int shndx, Address address, - Addend addend, bool is_relative, bool is_section_symbol) + Addend addend, bool is_relative, + bool is_symbolless, bool is_section_symbol) : rel_(relobj, local_sym_index, type, shndx, address, is_relative, - is_section_symbol), + is_symbolless, is_section_symbol), addend_(addend) { } @@ -1257,6 +1272,12 @@ class Output_reloc is_relative() const { return this->rel_.is_relative(); } + // Return whether this is a relocation which should not use + // a symbol, but which obtains its addend from a symbol. + bool + is_symbolless() const + { return this->rel_.is_symbolless(); } + // Write the reloc entry to an output view. void write(unsigned char* pov) const; @@ -1413,14 +1434,14 @@ class Output_data_reloc void add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address) - { this->add(od, Output_reloc_type(gsym, type, od, address, false)); } + { this->add(od, Output_reloc_type(gsym, type, od, address, false, false)); } void add_global(Symbol* gsym, unsigned int type, Output_data* od, Sized_relobj* relobj, unsigned int shndx, Address address) { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - false)); } + false, false)); } // These are to simplify the Copy_relocs class. @@ -1447,7 +1468,7 @@ class Output_data_reloc void add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, Address address) - { this->add(od, Output_reloc_type(gsym, type, od, address, true)); } + { this->add(od, Output_reloc_type(gsym, type, od, address, true, true)); } void add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, @@ -1455,7 +1476,25 @@ class Output_data_reloc unsigned int shndx, Address address) { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - true)); + true, true)); + } + + // Add a global relocation which does not use a symbol for the relocation, + // but which gets its addend from a symbol. + + void + add_symbolless_global_addend(Symbol* gsym, unsigned int type, + Output_data* od, Address address) + { this->add(od, Output_reloc_type(gsym, type, od, address, false, true)); } + + void + add_symbolless_global_addend(Symbol* gsym, unsigned int type, + Output_data* od, + Sized_relobj* relobj, + unsigned int shndx, Address address) + { + this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, + false, true)); } // Add a reloc against a local symbol. @@ -1466,7 +1505,7 @@ class Output_data_reloc Output_data* od, Address address) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, - address, false, false)); + address, false, false, false)); } void @@ -1475,7 +1514,7 @@ class Output_data_reloc Output_data* od, unsigned int shndx, Address address) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, - address, false, false)); + address, false, false, false)); } // Add a RELATIVE reloc against a local symbol. @@ -1486,7 +1525,7 @@ class Output_data_reloc Output_data* od, Address address) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, - address, true, false)); + address, true, true, false)); } void @@ -1495,7 +1534,29 @@ class Output_data_reloc Output_data* od, unsigned int shndx, Address address) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, - address, true, false)); + address, true, true, false)); + } + + // Add a local relocation which does not use a symbol for the relocation, + // but which gets its addend from a symbol. + + void + add_symbolless_local_addend(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + Output_data* od, Address address) + { + this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, + address, false, true, false)); + } + + void + add_symbolless_local_addend(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + Output_data* od, unsigned int shndx, + Address address) + { + this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, + address, false, true, false)); } // Add a reloc against a local section symbol. This will be @@ -1508,7 +1569,7 @@ class Output_data_reloc Output_data* od, Address address) { this->add(od, Output_reloc_type(relobj, input_shndx, type, od, - address, false, true)); + address, false, false, true)); } void @@ -1517,7 +1578,7 @@ class Output_data_reloc Output_data* od, unsigned int shndx, Address address) { this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx, - address, false, true)); + address, false, false, true)); } // A reloc against the STT_SECTION symbol of an output section. @@ -1587,7 +1648,7 @@ class Output_data_reloc add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address, Addend addend) { this->add(od, Output_reloc_type(gsym, type, od, address, addend, - false)); } + false, false)); } void add_global(Symbol* gsym, unsigned int type, Output_data* od, @@ -1595,7 +1656,7 @@ class Output_data_reloc unsigned int shndx, Address address, Addend addend) { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - addend, false)); } + addend, false, false)); } // Add a RELATIVE reloc against a global symbol. The final output // relocation will not reference the symbol, but we must keep the symbol @@ -1605,14 +1666,32 @@ class Output_data_reloc void add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, Address address, Addend addend) - { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true)); } + { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true, + true)); } void add_global_relative(Symbol* gsym, unsigned int type, Output_data* od, Sized_relobj* relobj, unsigned int shndx, Address address, Addend addend) { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, - addend, true)); } + addend, true, true)); } + + // Add a global relocation which does not use a symbol for the relocation, + // but which gets its addend from a symbol. + + void + add_symbolless_global_addend(Symbol* gsym, unsigned int type, Output_data* od, + Address address, Addend addend) + { this->add(od, Output_reloc_type(gsym, type, od, address, addend, + false, true)); } + + void + add_symbolless_global_addend(Symbol* gsym, unsigned int type, + Output_data* od, + Sized_relobj* relobj, + unsigned int shndx, Address address, Addend addend) + { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, + addend, false, true)); } // Add a reloc against a local symbol. @@ -1622,7 +1701,7 @@ class Output_data_reloc Output_data* od, Address address, Addend addend) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address, - addend, false, false)); + addend, false, false, false)); } void @@ -1632,7 +1711,7 @@ class Output_data_reloc Addend addend) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, - address, addend, false, false)); + address, addend, false, false, false)); } // Add a RELATIVE reloc against a local symbol. @@ -1643,7 +1722,7 @@ class Output_data_reloc Output_data* od, Address address, Addend addend) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address, - addend, true, false)); + addend, true, true, false)); } void @@ -1653,7 +1732,29 @@ class Output_data_reloc Addend addend) { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, - address, addend, true, false)); + address, addend, true, true, false)); + } + + // Add a local relocation which does not use a symbol for the relocation, + // but which gets it's addend from a symbol. + + void + add_symbolless_local_addend(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + Output_data* od, Address address, Addend addend) + { + this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address, + addend, false, true, false)); + } + + void + add_symbolless_local_addend(Sized_relobj* relobj, + unsigned int local_sym_index, unsigned int type, + Output_data* od, unsigned int shndx, + Address address, Addend addend) + { + this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, + address, addend, false, true, false)); } // Add a reloc against a local section symbol. This will be @@ -1666,7 +1767,7 @@ class Output_data_reloc Output_data* od, Address address, Addend addend) { this->add(od, Output_reloc_type(relobj, input_shndx, type, od, address, - addend, false, true)); + addend, false, false, true)); } void @@ -1676,7 +1777,7 @@ class Output_data_reloc Addend addend) { this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx, - address, addend, false, true)); + address, addend, false, false, true)); } // A reloc against the STT_SECTION symbol of an output section. diff --git a/gold/sparc.cc b/gold/sparc.cc index 234c5f5..ab25203 100644 --- a/gold/sparc.cc +++ b/gold/sparc.cc @@ -1686,20 +1686,11 @@ Target_sparc::Scan::local( } else { - unsigned int shndx = lsym.get_st_shndx(); - bool is_ordinary; - gold_assert(lsym.get_st_value() == 0); - 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 - rela_dyn->add_local_section(object, shndx, - r_type, output_section, - data_shndx, reloc.get_r_offset(), - reloc.get_r_addend()); + rela_dyn->add_symbolless_local_addend(object, r_sym, orig_r_type, + output_section, data_shndx, + reloc.get_r_offset(), + reloc.get_r_addend()); } } break; @@ -1847,13 +1838,15 @@ Target_sparc::Scan::local( if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_OFFSET)) { Reloc_section* rela_dyn = target->rela_dyn_section(layout); + unsigned int off = got->add_constant(0); + + object->set_local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET, off); - got->add_local_with_rela(object, r_sym, - GOT_TYPE_TLS_OFFSET, - rela_dyn, - (size == 64 ? - elfcpp::R_SPARC_TLS_TPOFF64 : - elfcpp::R_SPARC_TLS_TPOFF32)); + rela_dyn->add_symbolless_local_addend(object, r_sym, + (size == 64 ? + elfcpp::R_SPARC_TLS_TPOFF64 : + elfcpp::R_SPARC_TLS_TPOFF32), + got, off, 0); } } else if (optimized_type != tls::TLSOPT_TO_LE) @@ -1869,9 +1862,9 @@ Target_sparc::Scan::local( gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION); unsigned int r_sym = elfcpp::elf_r_sym(reloc.get_r_info()); Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_local(object, r_sym, r_type, - output_section, data_shndx, - reloc.get_r_offset(), 0); + rela_dyn->add_symbolless_local_addend(object, r_sym, r_type, + output_section, data_shndx, + reloc.get_r_offset(), 0); } break; } @@ -2046,6 +2039,38 @@ Target_sparc::Scan::global( // Make a dynamic relocation if necessary. if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF)) { + unsigned int r_off = reloc.get_r_offset(); + + // The assembler can sometimes emit unaligned relocations + // for dwarf2 cfi directives. + switch (r_type) + { + case elfcpp::R_SPARC_16: + if (r_off & 0x1) + orig_r_type = r_type = elfcpp::R_SPARC_UA16; + break; + case elfcpp::R_SPARC_32: + if (r_off & 0x3) + orig_r_type = r_type = elfcpp::R_SPARC_UA32; + break; + case elfcpp::R_SPARC_64: + if (r_off & 0x7) + orig_r_type = r_type = elfcpp::R_SPARC_UA64; + break; + case elfcpp::R_SPARC_UA16: + if (!(r_off & 0x1)) + orig_r_type = r_type = elfcpp::R_SPARC_16; + break; + case elfcpp::R_SPARC_UA32: + if (!(r_off & 0x3)) + orig_r_type = r_type = elfcpp::R_SPARC_32; + break; + case elfcpp::R_SPARC_UA64: + if (!(r_off & 0x7)) + orig_r_type = r_type = elfcpp::R_SPARC_64; + break; + } + if (gsym->may_need_copy_reloc()) { target->copy_reloc(symtab, layout, object, @@ -2066,10 +2091,19 @@ Target_sparc::Scan::global( Reloc_section* rela_dyn = target->rela_dyn_section(layout); check_non_pic(object, r_type); - rela_dyn->add_global(gsym, orig_r_type, output_section, - object, data_shndx, - reloc.get_r_offset(), - reloc.get_r_addend()); + if (gsym->is_from_dynobj() + || gsym->is_undefined() + || gsym->is_preemptible()) + rela_dyn->add_global(gsym, orig_r_type, output_section, + object, data_shndx, + reloc.get_r_offset(), + reloc.get_r_addend()); + else + rela_dyn->add_symbolless_global_addend(gsym, orig_r_type, + output_section, + object, data_shndx, + reloc.get_r_offset(), + reloc.get_r_addend()); } } } @@ -2201,10 +2235,10 @@ Target_sparc::Scan::global( if (parameters->options().shared()) { Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_global(gsym, orig_r_type, - output_section, object, - data_shndx, reloc.get_r_offset(), - 0); + rela_dyn->add_symbolless_global_addend(gsym, orig_r_type, + output_section, object, + data_shndx, reloc.get_r_offset(), + 0); } break; -- cgit v1.1