From 9af798f5e46a45178af33175800312393770a1d9 Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Mon, 9 Mar 2015 10:53:15 +0000 Subject: [PATCH] [Mips] Fix incorrect handling of cross mode jumps We should not take in account a type of "source" symbol. Cross mode jump adjustment is requred when target symbol and relocation belong to different (regular/microMIPS) instruction sets. llvm-svn: 231639 --- .../ELF/Mips/MipsRelocationHandler.cpp | 62 +++++++++++++--------- lld/test/elf/Mips/la25-stub-micro.test | 2 + lld/test/elf/Mips/r26-1-micro.test | 6 +-- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp index 7b479ec..7719fe0 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp @@ -17,6 +17,14 @@ using namespace elf; using namespace llvm::ELF; using namespace llvm::support; +namespace { +enum class CrossJumpMode { + None, // Not a jump or non-isa-cross jump + ToRegular, // cross isa jump to regular symbol + ToMicro // cross isa jump to microMips symbol +}; +} + static inline void applyReloc(uint32_t &ins, uint32_t result, uint32_t mask) { ins = (ins & ~mask) | (result & mask); } @@ -140,12 +148,16 @@ static void reloc32hi16(uint32_t &ins, uint64_t S, int64_t A) { applyReloc(ins, (S + A + 0x8000) & 0xffff0000, 0xffffffff); } -static void fixJumpOpCode(uint32_t &ins, uint64_t tgt, bool isMicro) { - uint32_t opNative = isMicro ? 0x3d : 0x03; - uint32_t opCross = isMicro ? 0x3c : 0x1d; +static void adjustJumpOpCode(uint32_t &ins, uint64_t tgt, CrossJumpMode mode) { + if (mode == CrossJumpMode::None) + return; + + bool toMicro = mode == CrossJumpMode::ToMicro; + uint32_t opNative = toMicro ? 0x03 : 0x3d; + uint32_t opCross = toMicro ? 0x1d : 0x3c; // FIXME (simon): Convert this into the regular fatal error. - if ((tgt & 1) == isMicro) + if ((tgt & 1) != toMicro) llvm_unreachable("Incorrect bit 0 for the jalx target"); if (tgt & 2) @@ -167,6 +179,22 @@ static bool isMicroMipsAtom(const Atom *a) { return false; } +static CrossJumpMode getCrossJumpMode(const Reference &ref) { + if (!isa(ref.target())) + return CrossJumpMode::None; + bool isTgtMicro = isMicroMipsAtom(ref.target()); + switch (ref.kindValue()) { + case R_MIPS_26: + case LLD_R_MIPS_GLOBAL_26: + return isTgtMicro ? CrossJumpMode::ToMicro : CrossJumpMode::None; + case R_MICROMIPS_26_S1: + case LLD_R_MICROMIPS_GLOBAL_26_S1: + return isTgtMicro ? CrossJumpMode::None : CrossJumpMode::ToRegular; + default: + return CrossJumpMode::None; + } +} + static bool needMicroShuffle(const Reference &ref) { if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF) return false; @@ -241,26 +269,11 @@ std::error_code RelocationHandler::applyRelocation( if (shuffle) ins = microShuffle(ins); - bool isSrcMicroMips = isMicroMipsAtom(atom._atom); - bool isTgtMicroMips = isMicroMipsAtom(ref.target()); - bool isCrossJump = isSrcMicroMips != isTgtMicroMips; - - if (isTgtMicroMips) + if (isMicroMipsAtom(ref.target())) targetVAddress |= 1; - if (isCrossJump) - switch (ref.kindValue()) { - case R_MIPS_26: - case LLD_R_MIPS_GLOBAL_26: - fixJumpOpCode(ins, targetVAddress, false); - break; - case R_MICROMIPS_26_S1: - case LLD_R_MICROMIPS_GLOBAL_26_S1: - fixJumpOpCode(ins, targetVAddress, true); - break; - default: - break; // Do nothing. - } + CrossJumpMode crossJump = getCrossJumpMode(ref); + adjustJumpOpCode(ins, targetVAddress, crossJump); switch (ref.kindValue()) { case R_MIPS_NONE: @@ -273,7 +286,7 @@ std::error_code RelocationHandler::applyRelocation( break; case R_MICROMIPS_26_S1: reloc26loc(ins, relocVAddress, targetVAddress, ref.addend(), - isCrossJump ? 2 : 1); + crossJump != CrossJumpMode::None ? 2 : 1); break; case R_MIPS_HI16: relocHi16(ins, relocVAddress, targetVAddress, ref.addend(), isGpDisp); @@ -361,7 +374,8 @@ std::error_code RelocationHandler::applyRelocation( reloc26ext(ins, targetVAddress, ref.addend(), 2); break; case LLD_R_MICROMIPS_GLOBAL_26_S1: - reloc26ext(ins, targetVAddress, ref.addend(), isCrossJump ? 2 : 1); + reloc26ext(ins, targetVAddress, ref.addend(), + crossJump != CrossJumpMode::None ? 2 : 1); break; case LLD_R_MIPS_HI16: relocHi16(ins, 0, targetVAddress, 0, false); diff --git a/lld/test/elf/Mips/la25-stub-micro.test b/lld/test/elf/Mips/la25-stub-micro.test index cdf68d0..d41297a 100644 --- a/lld/test/elf/Mips/la25-stub-micro.test +++ b/lld/test/elf/Mips/la25-stub-micro.test @@ -125,6 +125,7 @@ Symbols: - Name: loc Section: .text Value: 0x10 + Size: 0x18 Other: [ STO_MIPS_MICROMIPS ] - Name: .text Type: STT_SECTION @@ -132,6 +133,7 @@ Symbols: Global: - Name: glob Section: .text + Size: 0x10 Other: [ STO_MIPS_MICROMIPS ] - Name: T1 - Name: T1N diff --git a/lld/test/elf/Mips/r26-1-micro.test b/lld/test/elf/Mips/r26-1-micro.test index 72caa71..629754f 100644 --- a/lld/test/elf/Mips/r26-1-micro.test +++ b/lld/test/elf/Mips/r26-1-micro.test @@ -19,7 +19,7 @@ # Object file has three R_MICROMIPS_26_S1 relocations # OBJ-REL: Relocations [ # OBJ-REL-NEXT: Section (2) .rel.text { -# OBJ-REL-NEXT: 0x8 R_MICROMIPS_26_S1 .text 0x0 +# OBJ-REL-NEXT: 0x8 R_MICROMIPS_26_S1 loc 0x0 # OBJ-REL-NEXT: 0x10 R_MICROMIPS_26_S1 glob 0x0 # OBJ-REL-NEXT: 0x18 R_MICROMIPS_26_S1 T1 0x0 # OBJ-REL-NEXT: } @@ -55,7 +55,7 @@ # DIS-NEXT: 400182: 02 0f move $24, $2 # DIS: Contents of section .text: -# DIS-NEXT: 400184 09f82003 00000000 12006106 00000000 .. .......a..... +# DIS-NEXT: 400184 09f82003 00000000 2400ca0c 00000000 .. .....$....... # DIS-NEXT: 400194 2000c20c 00000000 2000bc0c 00000000 ....... ....... # so.o @@ -105,7 +105,7 @@ Sections: Info: .text Relocations: - Offset: 0x08 - Symbol: .text + Symbol: loc Type: R_MICROMIPS_26_S1 - Offset: 0x10 Symbol: glob -- 2.7.4