N32 uses ELFCLASS32, RELA relocs, and does not support the 3-in-1 reloc
encoding that N64 has.
Depends on D21131
Patch by: Daniel Sanders
Paths
| Differential D21292
[mips] Correct ELF format for N32. AbandonedPublic Authored by atanasyan on Jun 13 2016, 8:07 AM.
Details
Summary N32 uses ELFCLASS32, RELA relocs, and does not support the 3-in-1 reloc Depends on D21131 Patch by: Daniel Sanders
Diff Detail
Event Timelinedsanders updated this object. Herald added subscribers: sdardis, dsanders, srhines and 2 others. · View Herald TranscriptJun 13 2016, 8:07 AM Comment Actions Apologies for the very long lines in elf_header.s. I'm about to post a patch to FileCheck that helps with this. Comment Actions One last ping since I need to either commit this series next week or hand over to a colleague to continue it. Comment Actions Ping. Able to compile and run non-PIC n32 binaries for my project. However, lld still crashes when linking PIC n32 object files. I think the fixup_Mips_GPOFF_HI/LO in the ELF writer should also have demux logic to differentiate between n64 and n32, otherwise the 3-in-1 relocation entry may be written to n32 and crashes lld. Comment Actions
How do you create the n32 object file and run LLD? I would like to reproduce the crash. Comment Actions
Can be reproduced quite easily: clang -target mips64 -mcpu=mips4 -mabi=n32 -fPIC -mabicalls -integrated-as -c test.c -o test.o clang -target mips64 -mcpu=mips4 -mabi=n32 -fPIC -mabicalls -integrated-as -c test2.c -o test2.o ld.lld test.o test2.o -o test ld.lld: error: test.c:(function main): relocation R_MIPS_GPREL16 out of range The disassembly shows GPREL16 relocations inserted in the function prologues which I think caused the problem. test.c: extern void foo(); int main() { foo(); return 0; } test2.c: void foo() { volatile int i; i += 3; } Comment Actions After compiling the above test code with gcc, it seems mips gcc under n32 PIC keeps the 3-in-1 relocation "R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_LO16" in $gp function prologues, whereas clang n32 PIC does not write 3-in-1 relocation records and keeps only the "R_MIPS_GPREL16". It will then trigger the ld "out of range" error. Comment Actions After some out-of-band discussions with @Jerryxia32 we've discovered that the problem is that the Mips backend tries to write the 3-in-1 reloc format for N32, but the 32-bit ELF cannot store it all, so it only ends up with the R_MIPS_GPREL16, e.g. $ ../build/bin/clang -target mips64 -mabi=n32 -mcpu=mips4 -fpic -fPIC -mabicalls -integrated-as -c test.c -o -|../build/bin/llvm-readobj -r - File: <stdin> Format: ELF32-mips Arch: mips AddressSize: 32bit LoadName: Relocations [ Section (3) .rela.text { 0x14 R_MIPS_GPREL16 main 0x0 0x1C R_MIPS_GPREL16 main 0x0 0x24 R_MIPS_CALL16 foo 0x0 } Section (6) .rela.pdr { 0x0 R_MIPS_32 main 0x0 } ] N64 (Clang) $ ../build/bin/clang -target mips64 -mabi=n64 -mcpu=mips4 -fpic -fPIC -mabicalls -integrated-as -c test.c -o -|../build/bin/llvm-readobj -r - File: <stdin> Format: ELF64-mips Arch: mips64 AddressSize: 64bit LoadName: Relocations [ Section (3) .rela.text { 0x14 R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 main 0x0 0x1C R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_LO16 main 0x0 0x24 R_MIPS_CALL16/R_MIPS_NONE/R_MIPS_NONE foo 0x0 } Section (6) .rela.pdr { 0x0 R_MIPS_32/R_MIPS_NONE/R_MIPS_NONE main 0x0 } ] (for the test.c above) One solution would be to make MipsMCCodeEmitter.cpp emit multiple relocations, but the control flow there is set up to emit one, so it would need some reword to not be confusing, and not trip someone up in the future. @Jerryxia32 suggested detecting the 3-in-1 relocations when writing the ELF32, and split it. Attached hongyan-patch.diff3 KBDownload is the diff, with 45 lines of context so it makes more sense and can be read on its own. Perhaps this is better. (And also included here as it does not display attachments.)
diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index c8dd630..7da3ffa 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -1089,90 +1089,111 @@ void ELFObjectWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, WriteWord(EntrySize); // sh_entsize } void ELFObjectWriter::writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec) { std::vector<ELFRelocationEntry> &Relocs = Relocations[&Sec]; // We record relocations by pushing to the end of a vector. Reverse the vector // to get the relocations in the order they were created. // In most cases that is not important, but it can be for special sections // (.eh_frame) or specific relocations (TLS optimizations on SystemZ). std::reverse(Relocs.begin(), Relocs.end()); // Sort the relocation entries. MIPS needs this. TargetObjectWriter->sortRelocs(Asm, Relocs); for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { const ELFRelocationEntry &Entry = Relocs[e - i - 1]; unsigned Index = Entry.Symbol ? Entry.Symbol->getIndex() : 0; if (is64Bit()) { write(Entry.Offset); if (TargetObjectWriter->isN64()) { write(uint32_t(Index)); write(TargetObjectWriter->getRSsym(Entry.Type)); write(TargetObjectWriter->getRType3(Entry.Type)); write(TargetObjectWriter->getRType2(Entry.Type)); write(TargetObjectWriter->getRType(Entry.Type)); } else { struct ELF::Elf64_Rela ERE64; ERE64.setSymbolAndType(Index, Entry.Type); write(ERE64.r_info); } if (hasRelocationAddend()) write(Entry.Addend); } else { write(uint32_t(Entry.Offset)); struct ELF::Elf32_Rela ERE32; ERE32.setSymbolAndType(Index, Entry.Type); write(ERE32.r_info); if (hasRelocationAddend()) write(uint32_t(Entry.Addend)); + + uint32_t tempType = TargetObjectWriter->getRType2(Entry.Type); + if(tempType) { + write(uint32_t(Entry.Offset)); + + ERE32.setSymbolAndType(0, tempType); + write(ERE32.r_info); + + if (hasRelocationAddend()) + write(uint32_t(Entry.Addend)); + } + tempType = TargetObjectWriter->getRType3(Entry.Type); + if(tempType) { + write(uint32_t(Entry.Offset)); + + ERE32.setSymbolAndType(0, tempType); + write(ERE32.r_info); + + if (hasRelocationAddend()) + write(uint32_t(Entry.Addend)); + } } } } const MCSectionELF *ELFObjectWriter::createStringTable(MCContext &Ctx) { const MCSectionELF *StrtabSection = SectionTable[StringTableIndex - 1]; StrTabBuilder.write(getStream()); return StrtabSection; } void ELFObjectWriter::writeSection(const SectionIndexMapTy &SectionIndexMap, uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size, const MCSectionELF &Section) { uint64_t sh_link = 0; uint64_t sh_info = 0; switch(Section.getType()) { default: // Nothing to do. break; case ELF::SHT_DYNAMIC: llvm_unreachable("SHT_DYNAMIC in a relocatable object"); case ELF::SHT_REL: case ELF::SHT_RELA: { sh_link = SymbolTableIndex; assert(sh_link && ".symtab not found"); const MCSection *InfoSection = Section.getAssociatedSection(); sh_info = SectionIndexMap.lookup(cast<MCSectionELF>(InfoSection)); break; } case ELF::SHT_SYMTAB: case ELF::SHT_DYNSYM: sh_link = StringTableIndex; sh_info = LastLocalSymbolIndex; break; case ELF::SHT_SYMTAB_SHNDX: sh_link = SymbolTableIndex; break; case ELF::SHT_GROUP: sh_link = SymbolTableIndex; Comment Actions Now LLVM/Clang generates correct relocations for N32 ABI: $ clang -target mips64 -mabi=n32 -mcpu=mips4 -fpic -fPIC -mabicalls -integrated-as -c main.c -o -| llvm-readobj -r - File: <stdin> Format: ELF32-mips Arch: mips AddressSize: 32bit LoadName: Relocations [ Section (3) .rela.text { 0x14 R_MIPS_GPREL16 main 0x0 0x14 R_MIPS_SUB - 0x0 0x14 R_MIPS_HI16 - 0x0 0x1C R_MIPS_GPREL16 main 0x0 0x1C R_MIPS_SUB - 0x0 0x1C R_MIPS_LO16 - 0x0 0x30 R_MIPS_GOT_PAGE .rodata.cst8 0x0 0x34 R_MIPS_GOT_OFST .rodata.cst8 0x0 0x44 R_MIPS_GOT_PAGE .rodata.str1.1 0x0 0x48 R_MIPS_GOT_OFST .rodata.str1.1 0x0 0x50 R_MIPS_CALL16 printf 0x0 0x60 R_MIPS_JALR printf 0x0 } Section (7) .rela.pdr { 0x0 R_MIPS_32 main 0x0 } ]
Revision Contents
Diff 76842 lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h
lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h
lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
test/MC/Mips/cpsetup.s
test/MC/Mips/elf_eflags.s
test/MC/Mips/elf_header.s
test/MC/Mips/reloc-directive.s
|