diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index ac6f386032e4..8ea5e46e09e8 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -330,6 +330,14 @@ struct Elf_Rel_Base, false> { MaxAlign LLVM_ELF_COMMA false>) Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Word r_info; // Symbol table index and type of relocation to apply + + uint32_t getRInfo(bool isMips64EL) const { + assert(!isMips64EL); + return r_info; + } + void setRInfo(uint32_t R) { + r_info = R; + } }; template class ELFT, @@ -339,6 +347,22 @@ struct Elf_Rel_Base, false> { MaxAlign LLVM_ELF_COMMA true>) Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Xword r_info; // Symbol table index and type of relocation to apply + + uint64_t getRInfo(bool isMips64EL) const { + uint64_t t = r_info; + if (!isMips64EL) + return t; + // Mip64 little endian has a "special" encoding of r_info. Instead of one + // 64 bit little endian number, it is a little ending 32 bit number followed + // by a 32 bit big endian number. + return (t << 32) | ((t >> 8) & 0xff000000) | ((t >> 24) & 0x00ff0000) | + ((t >> 40) & 0x0000ff00) | ((t >> 56) & 0x000000ff); + return r_info; + } + void setRInfo(uint64_t R) { + // FIXME: Add mips64el support. + r_info = R; + } }; template class ELFT, @@ -349,6 +373,14 @@ struct Elf_Rel_Base, true> { Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Word r_info; // Symbol table index and type of relocation to apply Elf_Sword r_addend; // Compute value for relocatable field by adding this + + uint32_t getRInfo(bool isMips64EL) const { + assert(!isMips64EL); + return r_info; + } + void setRInfo(uint32_t R) { + r_info = R; + } }; template class ELFT, @@ -359,6 +391,21 @@ struct Elf_Rel_Base, true> { Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Xword r_info; // Symbol table index and type of relocation to apply Elf_Sxword r_addend; // Compute value for relocatable field by adding this. + + uint64_t getRInfo(bool isMips64EL) const { + // Mip64 little endian has a "special" encoding of r_info. Instead of one + // 64 bit little endian number, it is a little ending 32 bit number followed + // by a 32 bit big endian number. + uint64_t t = r_info; + if (!isMips64EL) + return t; + return (t << 32) | ((t >> 8) & 0xff000000) | ((t >> 24) & 0x00ff0000) | + ((t >> 40) & 0x0000ff00) | ((t >> 56) & 0x000000ff); + } + void setRInfo(uint64_t R) { + // FIXME: Add mips64el support. + r_info = R; + } }; template @@ -368,20 +415,21 @@ template class ELFT, endianness TargetEndianness, std::size_t MaxAlign, bool isRela> struct Elf_Rel_Impl, isRela> : Elf_Rel_Base, isRela> { - using Elf_Rel_Base, isRela>::r_info; LLVM_ELF_IMPORT_TYPES(ELFT) // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE, // and ELF64_R_INFO macros defined in the ELF specification: - uint32_t getSymbol() const { return (uint32_t) (r_info >> 32); } - uint32_t getType() const { - return (uint32_t) (r_info & 0xffffffffL); + uint32_t getSymbol(bool isMips64EL) const { + return (uint32_t) (this->getRInfo(isMips64EL) >> 32); + } + uint32_t getType(bool isMips64EL) const { + return (uint32_t) (this->getRInfo(isMips64EL) & 0xffffffffL); } void setSymbol(uint32_t s) { setSymbolAndType(s, getType()); } void setType(uint32_t t) { setSymbolAndType(getSymbol(), t); } void setSymbolAndType(uint32_t s, uint32_t t) { - r_info = ((uint64_t)s << 32) + (t&0xffffffffL); + this->setRInfo(((uint64_t)s << 32) + (t&0xffffffffL)); } }; @@ -389,18 +437,21 @@ template class ELFT, endianness TargetEndianness, std::size_t MaxAlign, bool isRela> struct Elf_Rel_Impl, isRela> : Elf_Rel_Base, isRela> { - using Elf_Rel_Base, isRela>::r_info; LLVM_ELF_IMPORT_TYPES(ELFT) // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE, // and ELF32_R_INFO macros defined in the ELF specification: - uint32_t getSymbol() const { return (r_info >> 8); } - unsigned char getType() const { return (unsigned char) (r_info & 0x0ff); } + uint32_t getSymbol(bool isMips64EL) const { + return this->getRInfo(isMips64EL) >> 8; + } + unsigned char getType(bool isMips64EL) const { + return (unsigned char) (this->getRInfo(isMips64EL) & 0x0ff); + } void setSymbol(uint32_t s) { setSymbolAndType(s, getType()); } void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); } void setSymbolAndType(uint32_t s, unsigned char t) { - r_info = (s << 8) + t; + this->setRInfo((s << 8) + t); } }; @@ -703,6 +754,13 @@ protected: public: ELFObjectFile(MemoryBuffer *Object, error_code &ec); + + bool isMips64EL() const { + return Header->e_machine == ELF::EM_MIPS && + Header->getFileClass() == ELF::ELFCLASS64 && + Header->getDataEncoding() == ELF::ELFDATA2LSB; + } + virtual symbol_iterator begin_symbols() const; virtual symbol_iterator end_symbols() const; @@ -1467,11 +1525,11 @@ error_code ELFObjectFile::getRelocationSymbol(DataRefImpl Rel, default : report_fatal_error("Invalid section type in Rel!"); case ELF::SHT_REL : { - symbolIdx = getRel(Rel)->getSymbol(); + symbolIdx = getRel(Rel)->getSymbol(isMips64EL()); break; } case ELF::SHT_RELA : { - symbolIdx = getRela(Rel)->getSymbol(); + symbolIdx = getRela(Rel)->getSymbol(isMips64EL()); break; } } @@ -1537,11 +1595,11 @@ error_code ELFObjectFile::getRelocationType(DataRefImpl Rel, default : report_fatal_error("Invalid section type in Rel!"); case ELF::SHT_REL : { - Result = getRel(Rel)->getType(); + Result = getRel(Rel)->getType(isMips64EL()); break; } case ELF::SHT_RELA : { - Result = getRela(Rel)->getType(); + Result = getRela(Rel)->getType(isMips64EL()); break; } } @@ -1561,11 +1619,11 @@ error_code ELFObjectFile::getRelocationTypeName( default : return object_error::parse_failed; case ELF::SHT_REL : { - type = getRel(Rel)->getType(); + type = getRel(Rel)->getType(isMips64EL()); break; } case ELF::SHT_RELA : { - type = getRela(Rel)->getType(); + type = getRela(Rel)->getType(isMips64EL()); break; } } @@ -2059,14 +2117,14 @@ error_code ELFObjectFile::getRelocationValueString( default: return object_error::parse_failed; case ELF::SHT_REL: { - type = getRel(Rel)->getType(); - symbol_index = getRel(Rel)->getSymbol(); + type = getRel(Rel)->getType(isMips64EL()); + symbol_index = getRel(Rel)->getSymbol(isMips64EL()); // TODO: Read implicit addend from section data. break; } case ELF::SHT_RELA: { - type = getRela(Rel)->getType(); - symbol_index = getRela(Rel)->getSymbol(); + type = getRela(Rel)->getType(isMips64EL()); + symbol_index = getRela(Rel)->getSymbol(isMips64EL()); addend = getRela(Rel)->r_addend; break; } diff --git a/llvm/test/MC/Mips/eh-frame.s b/llvm/test/MC/Mips/eh-frame.s index 67df21365d3e..93ff0b8bd277 100644 --- a/llvm/test/MC/Mips/eh-frame.s +++ b/llvm/test/MC/Mips/eh-frame.s @@ -130,7 +130,7 @@ func: // MIPS64EL: RELOCATION RECORDS FOR [.eh_frame]: -// FIXME: llvm-objdump currently misprints the relocations for mips64el +// MIPS64EL-NEXT: R_MIPS_64 // MIPS64EL: Contents of section .eh_frame: // MIPS64EL-NEXT: 0000 diff --git a/llvm/test/Object/Inputs/trivial-object-test.elf-mips64el b/llvm/test/Object/Inputs/trivial-object-test.elf-mips64el new file mode 100644 index 000000000000..5ad9ba3a0bc0 Binary files /dev/null and b/llvm/test/Object/Inputs/trivial-object-test.elf-mips64el differ diff --git a/llvm/test/Object/objdump-relocations.test b/llvm/test/Object/objdump-relocations.test index 6d35a2651d7a..95c4c4dcaedf 100644 --- a/llvm/test/Object/objdump-relocations.test +++ b/llvm/test/Object/objdump-relocations.test @@ -8,6 +8,8 @@ RUN: llvm-objdump -r %p/Inputs/trivial-object-test.elf-x86-64 \ RUN: | FileCheck %s -check-prefix ELF-x86-64 RUN: llvm-objdump -r %p/Inputs/trivial-object-test.elf-hexagon \ RUN: | FileCheck %s -check-prefix ELF-hexagon +RUN: llvm-objdump -r %p/Inputs/trivial-object-test.elf-mips64el \ +RUN: | FileCheck %s -check-prefix ELF-MIPS64EL RUN: llvm-objdump -r %p/Inputs/relocations.elf-x86-64 \ RUN: | FileCheck %s -check-prefix ELF-complex-x86-64 @@ -40,6 +42,11 @@ ELF-hexagon: R_HEX_LO16 puts ELF-hexagon: R_HEX_B15_PCREL testf ELF-hexagon: R_HEX_B22_PCREL puts +// Note: this file was produced with gas to make sure we don't end up in a +// situation where LLVM produces and accepts a broken file. +ELF-MIPS64EL: .data +ELF-MIPS64EL: R_MIPS_64 + ELF-complex-x86-64: .text ELF-complex-x86-64-NEXT: R_X86_64_8 .data-4 ELF-complex-x86-64-NEXT: R_X86_64_16 .data-4