From 152c92b261fd9e4655688bef746ca32352f56bc4 Mon Sep 17 00:00:00 2001 From: Vladimir Radosavljevic Date: Wed, 15 Mar 2017 16:41:48 -0700 Subject: [PATCH] Mips: Add support for resolving multiple consecutive relocations. gold/ * mips.cc (Target_mips::Relocate::calculated_value_): New data member. (Target_mips::Relocate::calculate_only_): Likewise. (Target_mips::Relocate::relocate): Handle multiple consecutive relocations with the same offset. --- gold/ChangeLog | 8 ++ gold/mips.cc | 263 ++++++++++++++++++++++++++++++------------------- 2 files changed, 171 insertions(+), 100 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 2426b0afbe3..6532b9a68eb 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,11 @@ +2017-03-15 Vladimir Radosavljevic + + * mips.cc (Target_mips::Relocate::calculated_value_): New data + member. + (Target_mips::Relocate::calculate_only_): Likewise. + (Target_mips::Relocate::relocate): Handle multiple consecutive + relocations with the same offset. + 2017-03-15 Vladimir Radosavljevic * mips.cc (Target_mips::Relocate::relocate): Remove redundant diff --git a/gold/mips.cc b/gold/mips.cc index de43e1d3e56..426817600eb 100644 --- a/gold/mips.cc +++ b/gold/mips.cc @@ -3857,6 +3857,7 @@ class Target_mips : public Sized_target { public: Relocate() + : calculated_value_(0), calculate_only_(false) { } ~Relocate() @@ -3876,6 +3877,12 @@ class Target_mips : public Sized_target Target_mips*, Output_section*, size_t, const unsigned char*, const Sized_symbol*, const Symbol_value*, unsigned char*, Mips_address, section_size_type); + + private: + // Result of the relocation. + Valtype calculated_value_; + // Whether we have to calculate relocation instead of applying it. + bool calculate_only_; }; // This POD class holds the dynamic relocations that should be emitted instead @@ -11428,6 +11435,13 @@ Target_mips::Relocate::relocate( unsigned int r_type3; unsigned char r_ssym; typename elfcpp::Elf_types::Elf_Swxword r_addend; + // r_offset and r_type of the next relocation is needed for resolving multiple + // consecutive relocations with the same offset. + Mips_address next_r_offset = static_cast(0) - 1; + unsigned int next_r_type = elfcpp::R_MIPS_NONE; + + elfcpp::Shdr shdr(relinfo->reloc_shdr); + size_t reloc_count = shdr.get_sh_size() / shdr.get_sh_entsize(); if (rel_type == elfcpp::SHT_RELA) { @@ -11444,6 +11458,17 @@ Target_mips::Relocate::relocate( r_ssym = Mips_classify_reloc:: get_r_ssym(&rela); r_addend = rela.get_r_addend(); + // If this is not last relocation, get r_offset and r_type of the next + // relocation. + if (relnum + 1 < reloc_count) + { + const int reloc_size = elfcpp::Elf_sizes::rela_size; + const Relatype next_rela(preloc + reloc_size); + next_r_offset = next_rela.get_r_offset(); + next_r_type = + Mips_classify_reloc:: + get_r_type(&next_rela); + } } else { @@ -11454,9 +11479,19 @@ Target_mips::Relocate::relocate( r_type = Mips_classify_reloc:: get_r_type(&rel); r_ssym = 0; - r_type2 = 0; - r_type3 = 0; + r_type2 = elfcpp::R_MIPS_NONE; + r_type3 = elfcpp::R_MIPS_NONE; r_addend = 0; + // If this is not last relocation, get r_offset and r_type of the next + // relocation. + if (relnum + 1 < reloc_count) + { + const int reloc_size = elfcpp::Elf_sizes::rel_size; + const Reltype next_rel(preloc + reloc_size); + next_r_offset = next_rel.get_r_offset(); + next_r_type = Mips_classify_reloc:: + get_r_type(&next_rel); + } } typedef Mips_relocate_functions Reloc_funcs; @@ -11716,8 +11751,7 @@ Target_mips::Relocate::relocate( unsigned int got_offset = 0; int gp_offset = 0; - bool calculate_only = false; - Valtype calculated_value = 0; + // Whether we have to extract addend from instruction. bool extract_addend = rel_type == elfcpp::SHT_REL; unsigned int r_types[3] = { r_type, r_type2, r_type3 }; @@ -11740,10 +11774,23 @@ Target_mips::Relocate::relocate( if (r_types[i] == elfcpp::R_MIPS_NONE) break; - // TODO(Vladimir) - // Check if the next relocation is for the same instruction. - calculate_only = i == 2 ? false - : r_types[i+1] != elfcpp::R_MIPS_NONE; + // If we didn't apply previous relocation, use its result as addend + // for current. + if (this->calculate_only_) + { + r_addend = this->calculated_value_; + extract_addend = false; + } + + // In the N32 and 64-bit ABIs there may be multiple consecutive + // relocations for the same offset. In that case we are + // supposed to treat the output of each relocation as the addend + // for the next. For N64 ABI, we are checking offsets only in a + // third operation in a record (r_type3). + this->calculate_only_ = + (object->is_n64() && i < 2 + ? r_types[i+1] != elfcpp::R_MIPS_NONE + : (r_offset == next_r_offset) && (next_r_type != elfcpp::R_MIPS_NONE)); if (object->is_n64()) { @@ -11783,16 +11830,18 @@ Target_mips::Relocate::relocate( break; case elfcpp::R_MIPS_16: reloc_status = Reloc_funcs::rel16(view, object, psymval, r_addend, - extract_addend, calculate_only, - &calculated_value); + extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_32: if (should_apply_static_reloc(mips_sym, r_types[i], output_section, target)) reloc_status = Reloc_funcs::rel32(view, object, psymval, r_addend, - extract_addend, calculate_only, - &calculated_value); + extract_addend, + this->calculate_only_, + &this->calculated_value_); if (mips_sym != NULL && (mips_sym->is_mips16() || mips_sym->is_micromips()) && mips_sym->global_got_area() == GGA_RELOC_ONLY) @@ -11817,14 +11866,16 @@ Target_mips::Relocate::relocate( if (should_apply_static_reloc(mips_sym, r_types[i], output_section, target)) reloc_status = Reloc_funcs::rel64(view, object, psymval, r_addend, - extract_addend, calculate_only, - &calculated_value, false); + extract_addend, + this->calculate_only_, + &this->calculated_value_, false); else if (target->is_output_n64() && r_addend != 0) // Only apply the addend. The static relocation was RELA, but the // dynamic relocation is REL, so we need to apply the addend. reloc_status = Reloc_funcs::rel64(view, object, psymval, r_addend, - extract_addend, calculate_only, - &calculated_value, true); + extract_addend, + this->calculate_only_, + &this->calculated_value_, true); break; case elfcpp::R_MIPS_REL32: gold_unreachable(); @@ -11832,8 +11883,8 @@ Target_mips::Relocate::relocate( case elfcpp::R_MIPS_PC32: reloc_status = Reloc_funcs::relpc32(view, object, psymval, address, r_addend, extract_addend, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS16_26: @@ -11845,8 +11896,8 @@ Target_mips::Relocate::relocate( case elfcpp::R_MICROMIPS_26_S1: reloc_status = Reloc_funcs::rel26(view, object, psymval, address, gsym == NULL, r_addend, extract_addend, gsym, cross_mode_jump, - r_types[i], target->jal_to_bal(), calculate_only, - &calculated_value); + r_types[i], target->jal_to_bal(), this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_HI16: @@ -11857,8 +11908,9 @@ Target_mips::Relocate::relocate( r_addend, address, gp_disp, r_types[i], extract_addend, 0, - target, calculate_only, - &calculated_value); + target, + this->calculate_only_, + &this->calculated_value_); else if (rel_type == elfcpp::SHT_REL) reloc_status = Reloc_funcs::relhi16(view, object, psymval, r_addend, address, gp_disp, r_types[i], @@ -11874,8 +11926,8 @@ Target_mips::Relocate::relocate( reloc_status = Reloc_funcs::rello16(target, view, object, psymval, r_addend, extract_addend, address, gp_disp, r_types[i], r_sym, - rel_type, calculate_only, - &calculated_value); + rel_type, this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_LITERAL: @@ -11895,42 +11947,43 @@ Target_mips::Relocate::relocate( target->adjusted_gp_value(object), r_addend, extract_addend, gsym == NULL, r_types[i], - calculate_only, &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_PC16: reloc_status = Reloc_funcs::relpc16(view, object, psymval, address, r_addend, extract_addend, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_PC21_S2: reloc_status = Reloc_funcs::relpc21(view, object, psymval, address, r_addend, extract_addend, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_PC26_S2: reloc_status = Reloc_funcs::relpc26(view, object, psymval, address, r_addend, extract_addend, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_PC18_S3: reloc_status = Reloc_funcs::relpc18(view, object, psymval, address, r_addend, extract_addend, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_PC19_S2: reloc_status = Reloc_funcs::relpc19(view, object, psymval, address, r_addend, extract_addend, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_PCHI16: @@ -11938,8 +11991,8 @@ Target_mips::Relocate::relocate( reloc_status = Reloc_funcs::do_relpchi16(view, object, psymval, r_addend, address, extract_addend, 0, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); else if (rel_type == elfcpp::SHT_REL) reloc_status = Reloc_funcs::relpchi16(view, object, psymval, r_addend, address, r_sym, @@ -11951,36 +12004,36 @@ Target_mips::Relocate::relocate( case elfcpp::R_MIPS_PCLO16: reloc_status = Reloc_funcs::relpclo16(view, object, psymval, r_addend, extract_addend, address, r_sym, - rel_type, calculate_only, - &calculated_value); + rel_type, this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MICROMIPS_PC7_S1: reloc_status = Reloc_funcs::relmicromips_pc7_s1(view, object, psymval, - address, r_addend, - extract_addend, - calculate_only, - &calculated_value); + address, r_addend, + extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MICROMIPS_PC10_S1: reloc_status = Reloc_funcs::relmicromips_pc10_s1(view, object, - psymval, address, - r_addend, extract_addend, - calculate_only, - &calculated_value); + psymval, address, + r_addend, extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MICROMIPS_PC16_S1: reloc_status = Reloc_funcs::relmicromips_pc16_s1(view, object, - psymval, address, - r_addend, extract_addend, - calculate_only, - &calculated_value); + psymval, address, + r_addend, extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_GPREL32: reloc_status = Reloc_funcs::relgprel32(view, object, psymval, target->adjusted_gp_value(object), r_addend, extract_addend, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_GOT_HI16: case elfcpp::R_MIPS_CALL_HI16: @@ -11996,8 +12049,8 @@ Target_mips::Relocate::relocate( object, r_addend); gp_offset = target->got_section()->gp_offset(got_offset, object); reloc_status = Reloc_funcs::relgot_hi16(view, gp_offset, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); update_got_entry = changed_symbol_value; break; @@ -12015,8 +12068,8 @@ Target_mips::Relocate::relocate( object, r_addend); gp_offset = target->got_section()->gp_offset(got_offset, object); reloc_status = Reloc_funcs::relgot_lo16(view, gp_offset, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); update_got_entry = changed_symbol_value; break; @@ -12034,12 +12087,12 @@ Target_mips::Relocate::relocate( gp_offset = target->got_section()->gp_offset(got_offset, object); if (eh_reloc(r_types[i])) reloc_status = Reloc_funcs::releh(view, gp_offset, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); else reloc_status = Reloc_funcs::relgot(view, gp_offset, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_CALL16: case elfcpp::R_MIPS16_CALL16: @@ -12050,7 +12103,8 @@ Target_mips::Relocate::relocate( object); gp_offset = target->got_section()->gp_offset(got_offset, object); reloc_status = Reloc_funcs::relgot(view, gp_offset, - calculate_only, &calculated_value); + this->calculate_only_, + &this->calculated_value_); // TODO(sasa): We should also initialize update_got_entry // in other place swhere relgot is called. update_got_entry = changed_symbol_value; @@ -12066,18 +12120,18 @@ Target_mips::Relocate::relocate( object); gp_offset = target->got_section()->gp_offset(got_offset, object); reloc_status = Reloc_funcs::relgot(view, gp_offset, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); } else { if (rel_type == elfcpp::SHT_RELA) reloc_status = Reloc_funcs::do_relgot16_local(view, object, - psymval, r_addend, - extract_addend, 0, - target, - calculate_only, - &calculated_value); + psymval, r_addend, + extract_addend, 0, + target, + this->calculate_only_, + &this->calculated_value_); else if (rel_type == elfcpp::SHT_REL) reloc_status = Reloc_funcs::relgot16_local(view, object, psymval, r_addend, @@ -12101,8 +12155,9 @@ Target_mips::Relocate::relocate( GOT_TYPE_TLS_PAIR, object, r_addend); gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot(view, gp_offset, calculate_only, - &calculated_value); + reloc_status = Reloc_funcs::relgot(view, gp_offset, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_TLS_GOTTPREL: @@ -12117,8 +12172,9 @@ Target_mips::Relocate::relocate( GOT_TYPE_TLS_OFFSET, object, r_addend); gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot(view, gp_offset, calculate_only, - &calculated_value); + reloc_status = Reloc_funcs::relgot(view, gp_offset, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_TLS_LDM: @@ -12128,24 +12184,25 @@ Target_mips::Relocate::relocate( // the module index. got_offset = target->got_section()->tls_ldm_offset(object); gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot(view, gp_offset, calculate_only, - &calculated_value); + reloc_status = Reloc_funcs::relgot(view, gp_offset, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_GOT_PAGE: case elfcpp::R_MICROMIPS_GOT_PAGE: reloc_status = Reloc_funcs::relgotpage(target, view, object, psymval, r_addend, extract_addend, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_GOT_OFST: case elfcpp::R_MICROMIPS_GOT_OFST: reloc_status = Reloc_funcs::relgotofst(target, view, object, psymval, r_addend, extract_addend, - local, calculate_only, - &calculated_value); + local, this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_JALR: @@ -12160,8 +12217,8 @@ Target_mips::Relocate::relocate( cross_mode_jump, r_types[i], target->jalr_to_bal(), target->jr_to_b(), - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_TLS_DTPREL_HI16: @@ -12169,65 +12226,73 @@ Target_mips::Relocate::relocate( case elfcpp::R_MICROMIPS_TLS_DTPREL_HI16: reloc_status = Reloc_funcs::tlsrelhi16(view, object, psymval, elfcpp::DTP_OFFSET, r_addend, - extract_addend, calculate_only, - &calculated_value); + extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_TLS_DTPREL_LO16: case elfcpp::R_MIPS16_TLS_DTPREL_LO16: case elfcpp::R_MICROMIPS_TLS_DTPREL_LO16: reloc_status = Reloc_funcs::tlsrello16(view, object, psymval, elfcpp::DTP_OFFSET, r_addend, - extract_addend, calculate_only, - &calculated_value); + extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_TLS_DTPREL32: case elfcpp::R_MIPS_TLS_DTPREL64: reloc_status = Reloc_funcs::tlsrel32(view, object, psymval, elfcpp::DTP_OFFSET, r_addend, - extract_addend, calculate_only, - &calculated_value); + extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_TLS_TPREL_HI16: case elfcpp::R_MIPS16_TLS_TPREL_HI16: case elfcpp::R_MICROMIPS_TLS_TPREL_HI16: reloc_status = Reloc_funcs::tlsrelhi16(view, object, psymval, elfcpp::TP_OFFSET, r_addend, - extract_addend, calculate_only, - &calculated_value); + extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_TLS_TPREL_LO16: case elfcpp::R_MIPS16_TLS_TPREL_LO16: case elfcpp::R_MICROMIPS_TLS_TPREL_LO16: reloc_status = Reloc_funcs::tlsrello16(view, object, psymval, elfcpp::TP_OFFSET, r_addend, - extract_addend, calculate_only, - &calculated_value); + extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_TLS_TPREL32: case elfcpp::R_MIPS_TLS_TPREL64: reloc_status = Reloc_funcs::tlsrel32(view, object, psymval, elfcpp::TP_OFFSET, r_addend, - extract_addend, calculate_only, - &calculated_value); + extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_SUB: case elfcpp::R_MICROMIPS_SUB: reloc_status = Reloc_funcs::relsub(view, object, psymval, r_addend, extract_addend, - calculate_only, &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_HIGHER: case elfcpp::R_MICROMIPS_HIGHER: reloc_status = Reloc_funcs::relhigher(view, object, psymval, r_addend, - extract_addend, calculate_only, - &calculated_value); + extract_addend, + this->calculate_only_, + &this->calculated_value_); break; case elfcpp::R_MIPS_HIGHEST: case elfcpp::R_MICROMIPS_HIGHEST: reloc_status = Reloc_funcs::relhighest(view, object, psymval, r_addend, extract_addend, - calculate_only, - &calculated_value); + this->calculate_only_, + &this->calculated_value_); break; default: gold_error_at_location(relinfo, relnum, r_offset, @@ -12244,8 +12309,6 @@ Target_mips::Relocate::relocate( else got->update_got_entry(got_offset, psymval->value(object, 0)); } - - r_addend = calculated_value; } bool jal_shuffle = jal_reloc(r_type); -- 2.30.2