2 changes: 1 addition & 1 deletion lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P,
// formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
uint64_t V = InX::MipsGot->getGp() + A - P;
if (Type == R_MIPS_LO16)
if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16)
V += 4;
return V;
}
Expand Down
10 changes: 8 additions & 2 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,12 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
// relocation types occupy eight bit. In case of N64 ABI we extract first
// relocation from 3-in-1 packet because only the first relocation can
// be against a real symbol.
if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16)
return false;
if (Config->EMachine == EM_MIPS) {
Type &= 0xff;
if (Type == R_MIPS_GPREL16 || Type == R_MICROMIPS_GPREL16 ||
Type == R_MICROMIPS_GPREL7_S2)
return false;
}
return Body.isPreemptible();
}

Expand Down Expand Up @@ -301,6 +305,8 @@ static uint32_t getMipsPairType(uint32_t Type, const SymbolBody &Sym) {
return R_MIPS_LO16;
case R_MIPS_GOT16:
return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE;
case R_MICROMIPS_GOT16:
return Sym.isLocal() ? R_MICROMIPS_LO16 : R_MIPS_NONE;
case R_MIPS_PCHI16:
return R_MIPS_PCLO16;
case R_MICROMIPS_HI16:
Expand Down
12 changes: 12 additions & 0 deletions lld/test/ELF/Inputs/mips-micro.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.text
.set micromips
.global foo
.type foo,@function
foo:
nop

.set nomicromips
.global bar
.type bar,@function
bar:
nop
46 changes: 46 additions & 0 deletions lld/test/ELF/mips-micro-got.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Check microMIPS GOT relocations for O32 ABI.

# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mattr=micromips \
# RUN: %s -o %t1.o
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mattr=micromips \
# RUN: %S/Inputs/mips-dynamic.s -o %t2.o
# RUN: ld.lld %t2.o -shared -o %t.so
# RUN: ld.lld %t1.o %t.so -o %t.exe
# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s

# REQUIRES: mips

# CHECK: Local entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Access: -32744
# CHECK-NEXT: Initial: 0x30000
# CHECK-NEXT: }
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Access: -32740
# CHECK-NEXT: Initial: 0x40000
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: Global entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Access: -32736
# CHECK-NEXT: Initial: 0x0
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Type: Function
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: Name: foo0
# CHECK-NEXT: }
# CHECK-NEXT: ]

.text
.global __start
__start:
lw $4, %got(data)($28)
addiu $4, $4, %lo(data)
lw $25, %call16(foo0)($28)

.data
data:
.word 0
48 changes: 48 additions & 0 deletions lld/test/ELF/mips-micro-got64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Check microMIPS GOT relocations for N64 ABI.

# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -mattr=micromips \
# RUN: %s -o %t1.o
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -mattr=micromips \
# RUN: %S/Inputs/mips-dynamic.s -o %t2.o
# RUN: ld.lld %t2.o -shared -o %t.so
# RUN: ld.lld %t1.o %t.so -o %t.exe
# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s

# REQUIRES: mips

# CHECK: Local entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Access: -32736
# CHECK-NEXT: Initial: 0x30000
# CHECK-NEXT: }
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Access: -32728
# CHECK-NEXT: Initial: 0x40000
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: Global entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Access: -32720
# CHECK-NEXT: Initial: 0x0
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Type: Function
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: Name: foo0
# CHECK-NEXT: }
# CHECK-NEXT: ]

.text
.global __start
__start:
lui $28, %hi(%neg(%gp_rel(foo0)))
addiu $28, $28, %lo(%neg(%gp_rel(foo0)))
lw $4, %got_page(data)($28)
addiu $4, $4, %got_ofst(data)
lw $25, %call16(foo0)($28)

.data
data:
.word 0
125 changes: 125 additions & 0 deletions lld/test/ELF/mips-micro-jal.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Check PLT creation for microMIPS to microMIPS calls.

# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
# RUN: -mattr=micromips %S/Inputs/mips-micro.s -o %t1eb.o
# RUN: ld.lld -shared -o %teb.so %t1eb.o
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
# RUN: -mattr=micromips %s -o %t2eb.o
# RUN: ld.lld -o %teb.exe %t2eb.o %teb.so
# RUN: llvm-objdump -d -mattr=micromips %teb.exe | FileCheck --check-prefix=EB %s
# RUN: llvm-readobj -mips-plt-got %teb.exe | FileCheck --check-prefix=PLT %s

# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
# RUN: -mattr=micromips %S/Inputs/mips-micro.s -o %t1el.o
# RUN: ld.lld -shared -o %tel.so %t1el.o
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
# RUN: -mattr=micromips %s -o %t2el.o
# RUN: ld.lld -o %tel.exe %t2el.o %tel.so
# RUN: llvm-objdump -d -mattr=micromips %tel.exe | FileCheck --check-prefix=EL %s
# RUN: llvm-readobj -mips-plt-got %tel.exe | FileCheck --check-prefix=PLT %s

# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
# RUN: -mattr=micromips -mcpu=mips32r6 %S/Inputs/mips-micro.s -o %t1eb.o
# RUN: ld.lld -shared -o %teb.so %t1eb.o
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
# RUN: -mattr=micromips -mcpu=mips32r6 %s -o %t2eb.o
# RUN: ld.lld -o %teb.exe %t2eb.o %teb.so
# RUN: llvm-objdump -d -mattr=micromips %teb.exe | FileCheck --check-prefix=EBR6 %s

# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
# RUN: -mattr=micromips -mcpu=mips32r6 %S/Inputs/mips-micro.s -o %t1el.o
# RUN: ld.lld -shared -o %tel.so %t1el.o
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
# RUN: -mattr=micromips -mcpu=mips32r6 %s -o %t2el.o
# RUN: ld.lld -o %tel.exe %t2el.o %tel.so
# RUN: llvm-objdump -d -mattr=micromips %tel.exe | FileCheck --check-prefix=ELR6 %s

# REQUIRES: mips

# EB: Disassembly of section .plt:
# EB-NEXT: .plt:
# EB-NEXT: 20010: 79 80 3f fd addiupc $3, 65524
# EB-NEXT: 20014: ff 23 00 00 lw $25, 0($3)
# EB-NEXT: 20018: 05 35 subu16 $2, $2, $3
# EB-NEXT: 2001a: 25 25 srl16 $2, $2, 2
# EB-NEXT: 2001c: 33 02 ff fe addiu $24, $2, -2
# EB-NEXT: 20020: 0d ff move $15, $ra
# EB-NEXT: 20022: 45 f9 jalrs16 $25
# EB-NEXT: 20024: 0f 83 move $gp, $3
# EB-NEXT: 20026: 0c 00 nop
# EB-NEXT: 20028: 00 00 00 00 nop
# EB-NEXT: 2002c: 00 00 00 00 nop

# EB-NEXT: 20030: 79 00 3f f7 addiupc $2, 65500
# EB-NEXT: 20034: ff 22 00 00 lw $25, 0($2)
# EB-NEXT: 20038: 45 99 jr16 $25
# EB-NEXT: 2003a: 0f 02 move $24, $2

# EL: Disassembly of section .plt:
# EL-NEXT: .plt:
# EL-NEXT: 20010: 80 79 fd 3f addiupc $3, 65524
# EL-NEXT: 20014: 23 ff 00 00 lw $25, 0($3)
# EL-NEXT: 20018: 35 05 subu16 $2, $2, $3
# EL-NEXT: 2001a: 25 25 srl16 $2, $2, 2
# EL-NEXT: 2001c: 02 33 fe ff addiu $24, $2, -2
# EL-NEXT: 20020: ff 0d move $15, $ra
# EL-NEXT: 20022: f9 45 jalrs16 $25
# EL-NEXT: 20024: 83 0f move $gp, $3
# EL-NEXT: 20026: 00 0c nop
# EL-NEXT: 20028: 00 00 00 00 nop
# EL-NEXT: 2002c: 00 00 00 00 nop

# EL-NEXT: 20030: 00 79 f7 3f addiupc $2, 65500
# EL-NEXT: 20034: 22 ff 00 00 lw $25, 0($2)
# EL-NEXT: 20038: 99 45 jr16 $25
# EL-NEXT: 2003a: 02 0f move $24, $2

# EBR6: Disassembly of section .plt:
# EBR6-NEXT: .plt:
# EBR6-NEXT: 20010: 78 60 3f fd lapc $3, 65524
# EBR6-NEXT: 20014: ff 23 00 00 lw $25, 0($3)
# EBR6-NEXT: 20018: 05 35 subu16 $2, $2, $3
# EBR6-NEXT: 2001a: 25 25 srl16 $2, $2, 2
# EBR6-NEXT: 2001c: 33 02 ff fe addiu $24, $2, -2
# EBR6-NEXT: 20020: 0d ff move16 $15, $ra
# EBR6-NEXT: 20022: 0f 83 move16 $gp, $3
# EBR6-NEXT: 20024: 47 2b jalr $25

# EBR6: 20030: 78 40 3f f7 lapc $2, 65500
# EBR6-NEXT: 20034: ff 22 00 00 lw $25, 0($2)
# EBR6-NEXT: 20038: 0f 02 move16 $24, $2
# EBR6-NEXT: 2003a: 47 23 jrc16 $25

# ELR6: Disassembly of section .plt:
# ELR6-NEXT: .plt:
# ELR6-NEXT: 20010: 60 78 fd 3f lapc $3, 65524
# ELR6-NEXT: 20014: 23 ff 00 00 lw $25, 0($3)
# ELR6-NEXT: 20018: 35 05 subu16 $2, $2, $3
# ELR6-NEXT: 2001a: 25 25 srl16 $2, $2, 2
# ELR6-NEXT: 2001c: 02 33 fe ff addiu $24, $2, -2
# ELR6-NEXT: 20020: ff 0d move16 $15, $ra
# ELR6-NEXT: 20022: 83 0f move16 $gp, $3
# ELR6-NEXT: 20024: 2b 47 jalr $25

# ELR6: 20030: 40 78 f7 3f lapc $2, 65500
# ELR6-NEXT: 20034: 22 ff 00 00 lw $25, 0($2)
# ELR6-NEXT: 20038: 02 0f move16 $24, $2
# ELR6-NEXT: 2003a: 23 47 jrc16 $25

# PLT: Entries [
# PLT-NEXT: Entry {
# PLT-NEXT: Address: 0x3000C
# ^ 0x20030 + 65500
# PLT-NEXT: Initial:
# PLT-NEXT: Value: 0x0
# PLT-NEXT: Type: Function
# PLT-NEXT: Section: Undefined
# PLT-NEXT: Name: foo
# PLT-NEXT: }
# PLT-NEXT: ]

.text
.set micromips
.global __start
__start:
jal foo
59 changes: 59 additions & 0 deletions lld/test/ELF/mips-micro-relocs.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Check handling of microMIPS relocations.

# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
# RUN: -mattr=micromips %S/Inputs/mips-micro.s -o %t1eb.o
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
# RUN: -mattr=micromips %s -o %t2eb.o
# RUN: ld.lld -o %teb.exe %t1eb.o %t2eb.o
# RUN: llvm-objdump -d -t -mattr=micromips %teb.exe \
# RUN: | FileCheck --check-prefixes=EB,SYM %s

# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
# RUN: -mattr=micromips %S/Inputs/mips-micro.s -o %t1el.o
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
# RUN: -mattr=micromips %s -o %t2el.o
# RUN: ld.lld -o %tel.exe %t1el.o %t2el.o
# RUN: llvm-objdump -d -t -mattr=micromips %tel.exe \
# RUN: | FileCheck --check-prefixes=EL,SYM %s

# REQUIRES: mips

# EB: __start:
# EB-NEXT: 20010: 41 a3 00 01 lui $3, 1
# EB-NEXT: 20014: 30 63 7f e0 addiu $3, $3, 32736
# EB-NEXT: 20018: fc 7c 80 18 lw $3, -32744($gp)
# EB-NEXT: 2001c: fc 63 80 18 lw $3, -32744($3)
# EB-NEXT: 20020: 8f 70 beqz16 $6, -32
# EB-NEXT: 20022: 00 7e 00 00 sll $3, $fp, 0
# EB-NEXT: 20026: cf ec b16 -40
# EB-NEXT: 20028: 00 00 00 00 nop
# EB-NEXT: 2002c: 94 00 ff e8 b -44

# EL: __start:
# EL-NEXT: 20010: a3 41 01 00 lui $3, 1
# EL-NEXT: 20014: 63 30 e0 7f addiu $3, $3, 32736
# EL-NEXT: 20018: 7c fc 18 80 lw $3, -32744($gp)
# EL-NEXT: 2001c: 63 fc 18 80 lw $3, -32744($3)
# EL-NEXT: 20020: 70 8f beqz16 $6, -32
# EL-NEXT: 20022: 7e 00 00 00 sll $3, $fp, 0
# EL-NEXT: 20026: ec cf b16 -40
# EL-NEXT: 20028: 00 00 00 00 nop
# EL-NEXT: 2002c: 00 94 e8 ff b -44

# SYM: 00037ff0 *ABS* 00000000 .hidden _gp
# SYM: 00020000 g F .text 00000000 foo
# SYM: 00020010 .text 00000000 __start

.text
.set micromips
.global __start
__start:
lui $3, %hi(_gp_disp) # R_MICROMIPS_HI16
addiu $3, $3, %lo(_gp_disp) # R_MICROMIPS_LO16

lw $3, %call16(foo)($gp) # R_MICROMIPS_CALL16
lw $3, %got(foo)($3) # R_MICROMIPS_GOT16

beqz16 $6, foo # R_MICROMIPS_PC7_S1
b16 foo # R_MICROMIPS_PC10_S1
b foo # R_MICROMIPS_PC16_S1