summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Target.cpp20
-rw-r--r--lld/test/ELF/mips-higher-highest.s21
2 files changed, 41 insertions, 0 deletions
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index f18789af940..3f97079d5f9 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -1967,6 +1967,20 @@ static void writeMipsHi16(uint8_t *Loc, uint64_t V) {
}
template <endianness E>
+static void writeMipsHigher(uint8_t *Loc, uint64_t V) {
+ uint32_t Instr = read32<E>(Loc);
+ uint16_t Res = ((V + 0x80008000) >> 32) & 0xffff;
+ write32<E>(Loc, (Instr & 0xffff0000) | Res);
+}
+
+template <endianness E>
+static void writeMipsHighest(uint8_t *Loc, uint64_t V) {
+ uint32_t Instr = read32<E>(Loc);
+ uint16_t Res = ((V + 0x800080008000) >> 48) & 0xffff;
+ write32<E>(Loc, (Instr & 0xffff0000) | Res);
+}
+
+template <endianness E>
static void writeMipsLo16(uint8_t *Loc, uint64_t V) {
uint32_t Instr = read32<E>(Loc);
write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
@@ -2150,6 +2164,12 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
case R_MIPS_TLS_TPREL_HI16:
writeMipsHi16<E>(Loc, Val);
break;
+ case R_MIPS_HIGHER:
+ writeMipsHigher<E>(Loc, Val);
+ break;
+ case R_MIPS_HIGHEST:
+ writeMipsHighest<E>(Loc, Val);
+ break;
case R_MIPS_JALR:
// Ignore this optimization relocation for now
break;
diff --git a/lld/test/ELF/mips-higher-highest.s b/lld/test/ELF/mips-higher-highest.s
new file mode 100644
index 00000000000..123b51a65ad
--- /dev/null
+++ b/lld/test/ELF/mips-higher-highest.s
@@ -0,0 +1,21 @@
+# Check R_MIPS_HIGHER / R_MIPS_HIGHEST relocations calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN: %S/Inputs/mips-dynamic.s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+ .global __start
+__start:
+ lui $6, %highest(_foo+0x300047FFF7FF7)
+ daddiu $6, $6, %higher(_foo+0x300047FFF7FF7)
+ lui $7, %highest(_foo+0x300047FFF7FF8)
+ ld $7, %higher (_foo+0x300047FFF7FF8)($7)
+
+# CHECK: 20000: 3c 06 00 03 lui $6, 3
+# CHECK-NEXT: 20004: 64 c6 00 05 daddiu $6, $6, 5
+# CHECK-NEXT: 20008: 3c 07 00 03 lui $7, 3
+# CHECK-NEXT: 2000c: dc e7 00 05 ld $7, 5($7)
OpenPOWER on IntegriCloud