Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -55,9 +55,12 @@ void resolveSystemZRelocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend); - void resolveMIPS64Relocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend, - uint64_t SymOffset, SID SectionID); + void resolveMIPSN32Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, + uint64_t SymOffset, SID SectionID); + void resolveMIPSN64Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, + uint64_t SymOffset, SID SectionID); int64_t evaluateMIPS64Relocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -585,22 +585,33 @@ if (Arch == Triple::UnknownArch || !StringRef(Triple::getArchTypePrefix(Arch)).equals("mips")) { IsMipsO32ABI = false; + IsMipsN32ABI = false; IsMipsN64ABI = false; return; } unsigned AbiVariant; Obj.getPlatformFlags(AbiVariant); IsMipsO32ABI = AbiVariant & ELF::EF_MIPS_ABI_O32; + IsMipsN32ABI = AbiVariant & ELF::EF_MIPS_ABI2; IsMipsN64ABI = Obj.getFileFormatName().equals("ELF64-mips"); - if (AbiVariant & ELF::EF_MIPS_ABI2) - llvm_unreachable("Mips N32 ABI is not supported yet"); } -void RuntimeDyldELF::resolveMIPS64Relocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type, int64_t Addend, - uint64_t SymOffset, - SID SectionID) { +void RuntimeDyldELF::resolveMIPSN32Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, + uint64_t SymOffset, + SID SectionID) { + int64_t CalculatedValue = evaluateMIPS64Relocation( + Section, Offset, Value, Type, Addend, SymOffset, SectionID); + applyMIPS64Relocation(Section.getAddressWithOffset(Offset), CalculatedValue, + Type); +} + +void RuntimeDyldELF::resolveMIPSN64Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, + uint64_t SymOffset, + SID SectionID) { uint32_t r_type = Type & 0xff; uint32_t r_type2 = (Type >> 8) & 0xff; uint32_t r_type3 = (Type >> 16) & 0xff; @@ -669,7 +680,7 @@ case ELF::R_MIPS_GOT_PAGE: { uint8_t *LocalGOTAddr = getSectionAddress(SectionToGOTMap[SectionID]) + SymOffset; - uint64_t GOTEntry = readBytesUnaligned(LocalGOTAddr, 8); + uint64_t GOTEntry = readBytesUnaligned(LocalGOTAddr, getGOTEntrySize()); Value += Addend; if (Type == ELF::R_MIPS_GOT_PAGE) @@ -679,7 +690,7 @@ assert(GOTEntry == Value && "GOT entry has two different addresses."); else - writeBytesUnaligned(Value, LocalGOTAddr, 8); + writeBytesUnaligned(Value, LocalGOTAddr, getGOTEntrySize()); return (SymOffset - 0x7ff0) & 0xffff; } @@ -1131,9 +1142,12 @@ if (IsMipsO32ABI) resolveMIPSRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, (uint32_t)(Addend & 0xffffffffL)); + else if (IsMipsN32ABI) + resolveMIPSN32Relocation(Section, Offset, Value, Type, Addend, SymOffset, + SectionID); else if (IsMipsN64ABI) - resolveMIPS64Relocation(Section, Offset, Value, Type, Addend, SymOffset, - SectionID); + resolveMIPSN64Relocation(Section, Offset, Value, Type, Addend, SymOffset, + SectionID); else llvm_unreachable("Mips ABI not handled"); break; @@ -1469,7 +1483,7 @@ Value.Addend += SignExtend32<28>((Opcode & 0x03ffffff) << 2); processSimpleRelocation(SectionID, Offset, RelType, Value); } - } else if (IsMipsN64ABI) { + } else if (IsMipsN32ABI || IsMipsN64ABI) { uint32_t r_type = RelType & 0xff; RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); if (r_type == ELF::R_MIPS_CALL16 || r_type == ELF::R_MIPS_GOT_PAGE @@ -1806,7 +1820,7 @@ case Triple::mipsel: case Triple::mips64: case Triple::mips64el: - if (IsMipsO32ABI) + if (IsMipsO32ABI || IsMipsN32ABI) Result = sizeof(uint32_t); else if (IsMipsN64ABI) Result = sizeof(uint64_t); @@ -1871,7 +1885,7 @@ // For now, initialize all GOT entries to zero. We'll fill them in as // needed when GOT-based relocations are applied. memset(Addr, 0, TotalSize); - if (IsMipsN64ABI) { + if (IsMipsN32ABI || IsMipsN64ABI) { // To correctly resolve Mips GOT relocations, we need a mapping from // object's sections to GOTs. for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -275,6 +275,7 @@ Triple::ArchType Arch; bool IsTargetLittleEndian; bool IsMipsO32ABI; + bool IsMipsN32ABI; bool IsMipsN64ABI; // True if all sections should be passed to the memory manager, false if only @@ -338,6 +339,7 @@ virtual void setMipsABI(const ObjectFile &Obj) { IsMipsO32ABI = false; + IsMipsN32ABI = false; IsMipsN64ABI = false; } Index: test/ExecutionEngine/RuntimeDyld/Mips/ELF_N32_relocations.s =================================================================== --- /dev/null +++ test/ExecutionEngine/RuntimeDyld/Mips/ELF_N32_relocations.s @@ -0,0 +1,156 @@ +# RUN: llvm-mc -triple=mips64el-unknown-linux -target-abi n32 -code-model=small -filetype=obj -o %T/test_ELF_N32.o %s +# RUN: llc -mtriple=mips64el-unknown-linux -target-abi n32 -filetype=obj -o %T/test_ELF_ExternalFunction_N32.o %S/Inputs/ExternalFunction.ll +# RUN: llvm-rtdyld -triple=mips64el-unknown-linux -verify -map-section test_ELF_N32.o,.text=0x1000 -map-section test_ELF_ExternalFunction_N32.o,.text=0x10000 -check=%s %/T/test_ELF_N32.o %T/test_ELF_ExternalFunction_N32.o + +# RUN: llvm-mc -triple=mips64-unknown-linux -target-abi n32 -code-model=small -filetype=obj -o %T/test_ELF_N32.o %s +# RUN: llc -mtriple=mips64-unknown-linux -target-abi n32 -filetype=obj -o %T/test_ELF_ExternalFunction_N32.o %S/Inputs/ExternalFunction.ll +# RUN: llvm-rtdyld -triple=mips64-unknown-linux -verify -map-section test_ELF_N32.o,.text=0x1000 -map-section test_ELF_ExternalFunction_N32.o,.text=0x10000 -check=%s %/T/test_ELF_N32.o %T/test_ELF_ExternalFunction_N32.o + + .data +# Test R_MIPS_PC32 relocation. +# rtdyld-check: *{4}(R_MIPS_PC32) = (foo - R_MIPS_PC32)[31:0] +R_MIPS_PC32: + .word foo-. +# rtdyld-check: *{4}(R_MIPS_PC32 + 4) = (foo - tmp1)[31:0] +tmp1: + .4byte foo-tmp1 + + .text + .abicalls + .section .mdebug.abi64,"",@progbits + .nan legacy + .file "ELF_N32_PIC_relocations.ll" + .text + .globl bar + .align 3 + .type bar,@function + .set nomicromips + .set nomips16 + .ent bar +bar: + .frame $fp,40,$ra + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + .set noat + daddiu $sp, $sp, -40 + sd $ra, 32($sp) + sd $fp, 24($sp) + move $fp, $sp + sd $4, 16($fp) + lb $2, 0($4) + sd $4, 8($fp) + +# Test R_MIPS_26 relocation. +# rtdyld-check: decode_operand(insn1, 0)[27:0] = foo[27:0] +insn1: + .option pic0 + jal foo + .option pic2 + nop + +# Test R_MIPS_PC16 relocation. +# rtdyld-check: decode_operand(insn2, 1)[17:0] = (foo - insn2)[17:0] +insn2: + bal foo + nop + + move $sp, $fp + ld $ra, 32($sp) + ld $fp, 24($sp) + daddiu $sp, $sp, 32 + jr $ra + nop + .set at + .set macro + .set reorder + .end bar +$func_end0: + .size bar, ($func_end0)-bar + + .globl main + .align 3 + .type main,@function + .set nomicromips + .set nomips16 + .ent main +main: + .frame $fp,32,$ra + .mask 0x00000000,0 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + .set noat + daddiu $sp, $sp, -32 + sd $ra, 24($sp) + sd $fp, 16($sp) + sd $gp, 8($sp) + move $fp, $sp + +# $gp register contains address of the .got section + 0x7FF0. 0x7FF0 is +# the offset of $gp from the beginning of the .got section. Check that we are +# loading address of the page pointer from correct offset. In this case +# the page pointer is the first entry in the .got section, so offset will be +# 0 - 0x7FF0. +# rtdyld-check: decode_operand(insn5, 2)[15:0] = 0x8010 +# +# Check that the global offset table contains the page pointer. +# rtdyld-check: *{4}(section_addr(test_ELF_N32.o, .got)) = (_str + 0x8000) & 0xffff0000 +insn5: + ld $25, %got_page(_str)($1) + +# Check the offset of _str from the page pointer. +# rtdyld-check: decode_operand(insn6, 2)[15:0] = _str[15:0] +insn6: + daddiu $25, $25, %got_ofst(_str) + +# Check that we are loading address of var from correct offset. In this case +# var is the second entry in the .got section, so offset will be 4 - 0x7FF0. +# rtdyld-check: decode_operand(insn7, 2)[15:0] = 0x8014 +# +# Check that the global offset table contains the address of the var. +# rtdyld-check: *{4}(section_addr(test_ELF_N32.o, .got) + 4) = var +insn7: + ld $2, %got_disp(var)($1) + sd $25, 0($2) + +# Check that we are loading address of bar from correct offset. In this case +# bar is the third entry in the .got section, so offset will be 8 - 0x7FF0. +# rtdyld-check: decode_operand(insn8, 2)[15:0] = 0x8018 +# +# Check that the global offset table contains the address of the bar. +# rtdyld-check: *{4}(section_addr(test_ELF_N32.o, .got) + 8) = bar +insn8: + ld $2, %call16(bar)($1) + + move $4, $25 + move $gp, $1 + move $25, $2 + jalr $25 + nop + move $sp, $fp + ld $gp, 8($sp) + ld $fp, 16($sp) + ld $ra, 24($sp) + daddiu $sp, $sp, 32 + jr $ra + nop + .set at + .set macro + .set reorder + .end main +$func_end1: + .size main, ($func_end1)-main + + .type _str,@object + .section .rodata.str1.1,"aMS",@progbits,1 +_str: + .asciz "test" + .size _str, 5 + + .type var,@object + .comm var,8,8 + + .section ".note.GNU-stack","",@progbits + .text