Index: include/llvm/Object/ELFTypes.h =================================================================== --- include/llvm/Object/ELFTypes.h +++ include/llvm/Object/ELFTypes.h @@ -302,7 +302,10 @@ assert(!isMips64EL); return r_info; } - void setRInfo(uint32_t R) { r_info = R; } + void setRInfo(uint32_t R, bool IsMips64EL) { + assert(!IsMips64EL); + r_info = R; + } }; template @@ -321,9 +324,12 @@ 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; + void setRInfo(uint64_t R, bool IsMips64EL) { + if (IsMips64EL) + r_info = (R >> 32) | ((R & 0xff000000) << 8) | ((R & 0x00ff0000) << 24) | + ((R & 0x0000ff00) << 40) | ((R & 0x000000ff) << 56); + else + r_info = R; } }; @@ -338,7 +344,10 @@ assert(!isMips64EL); return r_info; } - void setRInfo(uint32_t R) { r_info = R; } + void setRInfo(uint32_t R, bool IsMips64EL) { + assert(!IsMips64EL); + r_info = R; + } }; template @@ -358,9 +367,12 @@ 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; + void setRInfo(uint64_t R, bool IsMips64EL) { + if (IsMips64EL) + r_info = (R >> 32) | ((R & 0xff000000) << 8) | ((R & 0x00ff0000) << 24) | + ((R & 0x0000ff00) << 40) | ((R & 0x000000ff) << 56); + else + r_info = R; } }; @@ -380,10 +392,14 @@ 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) { - this->setRInfo(((uint64_t)s << 32) + (t & 0xffffffffL)); + void setSymbol(uint32_t s, bool IsMips64EL) { + setSymbolAndType(s, getType(), IsMips64EL); + } + void setType(uint32_t t, bool IsMips64EL) { + setSymbolAndType(getSymbol(), t, IsMips64EL); + } + void setSymbolAndType(uint32_t s, uint32_t t, bool IsMips64EL) { + this->setRInfo(((uint64_t)s << 32) + (t & 0xffffffffL), IsMips64EL); } }; @@ -401,10 +417,14 @@ 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) { - this->setRInfo((s << 8) + t); + void setSymbol(uint32_t s, bool IsMips64EL) { + setSymbolAndType(s, getType(), IsMips64EL); + } + void setType(unsigned char t, bool IsMips64EL) { + setSymbolAndType(getSymbol(), t, IsMips64EL); + } + void setSymbolAndType(uint32_t s, unsigned char t, bool IsMips64EL) { + this->setRInfo((s << 8) + t, IsMips64EL); } }; Index: include/llvm/Object/ELFYAML.h =================================================================== --- include/llvm/Object/ELFYAML.h +++ include/llvm/Object/ELFYAML.h @@ -41,6 +41,7 @@ LLVM_YAML_STRONG_TYPEDEF(uint64_t, ELF_EF) LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_SHT) LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_REL) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_RSS) // Just use 64, since it can hold 32-bit values too. LLVM_YAML_STRONG_TYPEDEF(uint64_t, ELF_SHF) LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_STT) @@ -186,6 +187,11 @@ }; template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, ELFYAML::ELF_RSS &Value); +}; + +template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::FileHeader &FileHdr); }; Index: include/llvm/Support/ELF.h =================================================================== --- include/llvm/Support/ELF.h +++ include/llvm/Support/ELF.h @@ -796,6 +796,14 @@ STN_UNDEF = 0 }; +// Special relocation symbols used in the MIPS64 ELF relocation entries +enum { + RSS_UNDEF = 0, // None + RSS_GP = 1, // Value of gp + RSS_GP0 = 2, // Value of gp used to create object being relocated + RSS_LOC = 3 // Address of location being relocated +}; + // Relocation entry, without explicit addend. struct Elf32_Rel { Elf32_Addr r_offset; // Location (file byte offset, or program virtual addr) Index: lib/Object/ELFYAML.cpp =================================================================== --- lib/Object/ELFYAML.cpp +++ lib/Object/ELFYAML.cpp @@ -414,6 +414,16 @@ #undef BCaseMask } +void ScalarEnumerationTraits::enumeration( + IO &IO, ELFYAML::ELF_RSS &Value) { +#define ECase(X) IO.enumCase(Value, #X, ELF::X); + ECase(RSS_UNDEF) + ECase(RSS_GP) + ECase(RSS_GP0) + ECase(RSS_LOC) +#undef ECase +} + void ScalarEnumerationTraits::enumeration( IO &IO, ELFYAML::ELF_REL &Value) { const auto *Object = static_cast(IO.getContext()); @@ -539,11 +549,48 @@ return "Section size must be greater or equal to the content size"; } +namespace { +struct NormalizedMips64RelType { + NormalizedMips64RelType(IO &) + : Type(ELFYAML::ELF_REL(ELF::R_MIPS_NONE)), + Type2(ELFYAML::ELF_REL(ELF::R_MIPS_NONE)), + Type3(ELFYAML::ELF_REL(ELF::R_MIPS_NONE)), + SpecSym(ELFYAML::ELF_REL(ELF::RSS_UNDEF)) {} + NormalizedMips64RelType(IO &, ELFYAML::ELF_REL Original) + : Type(Original & 0xFF), Type2(Original >> 8 & 0xFF), + Type3(Original >> 16 & 0xFF), SpecSym(Original >> 24 & 0xFF) {} + + ELFYAML::ELF_REL denormalize(IO &) { + ELFYAML::ELF_REL Res = Type | Type2 << 8 | Type3 << 16 | SpecSym << 24; + return Res; + } + + ELFYAML::ELF_REL Type; + ELFYAML::ELF_REL Type2; + ELFYAML::ELF_REL Type3; + ELFYAML::ELF_RSS SpecSym; +}; +} + void MappingTraits::mapping(IO &IO, ELFYAML::Relocation &Rel) { + const auto *Object = static_cast(IO.getContext()); + assert(Object && "The IO context is not initialized"); + IO.mapRequired("Offset", Rel.Offset); IO.mapRequired("Symbol", Rel.Symbol); - IO.mapRequired("Type", Rel.Type); + + if (Object->Header.Machine == ELFYAML::ELF_EM(ELF::EM_MIPS) && + Object->Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64)) { + MappingNormalization Key( + IO, Rel.Type); + IO.mapRequired("Type", Key->Type); + IO.mapOptional("Type2", Key->Type2, ELFYAML::ELF_REL(ELF::R_MIPS_NONE)); + IO.mapOptional("Type3", Key->Type3, ELFYAML::ELF_REL(ELF::R_MIPS_NONE)); + IO.mapOptional("SpecSym", Key->SpecSym, ELFYAML::ELF_RSS(ELF::RSS_UNDEF)); + } else + IO.mapRequired("Type", Rel.Type); + IO.mapOptional("Addend", Rel.Addend); } Index: test/Object/Mips/elf-mips64-rel.yaml =================================================================== --- /dev/null +++ test/Object/Mips/elf-mips64-rel.yaml @@ -0,0 +1,113 @@ +# RUN: yaml2obj -format=elf %s > %t +# RUN: llvm-readobj -r %t | FileCheck -check-prefix=OBJ %s +# RUN: obj2yaml %t | FileCheck -check-prefix=YAML %s + +# OBJ: Relocations [ +# OBJ-NEXT: Section (2) .rela.text { +# OBJ-NEXT: 0x14 R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 main 0x4 +# OBJ-NEXT: 0x1C R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_LO16 main 0x8 +# OBJ-NEXT: 0x20 R_MIPS_GOT_PAGE/R_MIPS_NONE/R_MIPS_NONE .rodata 0x0 +# OBJ-NEXT: 0x24 R_MIPS_GOT_OFST/R_MIPS_NONE/R_MIPS_NONE .rodata 0x0 +# OBJ-NEXT: 0x28 R_MIPS_CALL16/R_MIPS_NONE/R_MIPS_NONE printf 0x0 +# OBJ-NEXT: 0x30 R_MIPS_GPREL16/R_MIPS_LO16/R_MIPS_NONE printf 0x0 +# OBJ-NEXT: } +# OBJ-NEXT: ] + +# YAML: Relocations: +# YAML-NEXT: - Offset: 0x0000000000000014 +# YAML-NEXT: Symbol: main +# YAML-NEXT: Type: R_MIPS_GPREL16 +# YAML-NEXT: Type2: R_MIPS_SUB +# YAML-NEXT: Type3: R_MIPS_HI16 +# YAML-NEXT: Addend: 4 +# YAML-NEXT: - Offset: 0x000000000000001C +# YAML-NEXT: Symbol: main +# YAML-NEXT: Type: R_MIPS_GPREL16 +# YAML-NEXT: Type2: R_MIPS_SUB +# YAML-NEXT: Type3: R_MIPS_LO16 +# YAML-NEXT: Addend: 8 +# YAML-NEXT: - Offset: 0x0000000000000020 +# YAML-NEXT: Symbol: .rodata +# YAML-NEXT: Type: R_MIPS_GOT_PAGE +# YAML-NEXT: Addend: 0 +# YAML-NEXT: - Offset: 0x0000000000000024 +# YAML-NEXT: Symbol: .rodata +# YAML-NEXT: Type: R_MIPS_GOT_OFST +# YAML-NEXT: Addend: 0 +# YAML-NEXT: - Offset: 0x0000000000000028 +# YAML-NEXT: Symbol: printf +# YAML-NEXT: Type: R_MIPS_CALL16 +# YAML-NEXT: Addend: 0 +# YAML-NEXT: - Offset: 0x0000000000000030 +# YAML-NEXT: Symbol: printf +# YAML-NEXT: Type: R_MIPS_GPREL16 +# YAML-NEXT: Type2: R_MIPS_LO16 +# YAML-NEXT: SpecSym: RSS_GP0 +# YAML-NEXT: Addend: 0 + +--- +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_PIC, EF_MIPS_CPIC, + EF_MIPS_NOREORDER, EF_MIPS_ARCH_64R2 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x10 + Size: 0x60 + - Name: .rela.text + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Info: .text + Relocations: + - Offset: 0x14 + Symbol: main + Type: R_MIPS_GPREL16 + Type2: R_MIPS_SUB + Type3: R_MIPS_HI16 + Addend: 4 + - Offset: 0x1C + Symbol: main + Type: R_MIPS_GPREL16 + Type2: R_MIPS_SUB + Type3: R_MIPS_LO16 + Addend: 8 + - Offset: 0x20 + Symbol: .rodata + Type: R_MIPS_GOT_PAGE + - Offset: 0x24 + Symbol: .rodata + Type: R_MIPS_GOT_OFST + - Offset: 0x28 + Symbol: printf + Type: R_MIPS_CALL16 + - Offset: 0x30 + Symbol: printf + Type: R_MIPS_GPREL16 + Type2: R_MIPS_LO16 + SpecSym: RSS_GP0 + - Name: .rodata + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + AddressAlign: 0x10 + Size: 0x0F + +Symbols: + Local: + - Name: .text + Type: STT_SECTION + Section: .text + - Name: .rodata + Type: STT_SECTION + Section: .rodata + Global: + - Name: main + Type: STT_FUNC + Section: .text + Size: 0x58 + - Name: printf +... Index: tools/yaml2obj/yaml2elf.cpp =================================================================== --- tools/yaml2obj/yaml2elf.cpp +++ tools/yaml2obj/yaml2elf.cpp @@ -90,6 +90,14 @@ memset(&Obj, 0, sizeof(Obj)); } +static bool is64Bit(const ELFYAML::Object &Doc) { + return Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); +} + +static bool isLittleEndian(const ELFYAML::Object &Doc) { + return Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); +} + namespace { /// \brief "Single point of truth" for the ELF file construction. /// TODO: This class still has a ways to go before it is truly a "single @@ -332,6 +340,8 @@ return false; } + bool IsMips64EL = Doc.Header.Machine == ELFYAML::ELF_EM(llvm::ELF::EM_MIPS) && + isLittleEndian(Doc) && is64Bit(Doc); bool IsRela = Section.Type == llvm::ELF::SHT_RELA; SHeader.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); SHeader.sh_size = SHeader.sh_entsize * Section.Relocations.size(); @@ -351,13 +361,13 @@ zero(REntry); REntry.r_offset = Rel.Offset; REntry.r_addend = Rel.Addend; - REntry.setSymbolAndType(SymIdx, Rel.Type); + REntry.setSymbolAndType(SymIdx, Rel.Type, IsMips64EL); OS.write((const char *)&REntry, sizeof(REntry)); } else { Elf_Rel REntry; zero(REntry); REntry.r_offset = Rel.Offset; - REntry.setSymbolAndType(SymIdx, Rel.Type); + REntry.setSymbolAndType(SymIdx, Rel.Type, IsMips64EL); OS.write((const char *)&REntry, sizeof(REntry)); } } @@ -456,14 +466,6 @@ return 0; } -static bool is64Bit(const ELFYAML::Object &Doc) { - return Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64); -} - -static bool isLittleEndian(const ELFYAML::Object &Doc) { - return Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); -} - int yaml2elf(yaml::Input &YIn, raw_ostream &Out) { ELFYAML::Object Doc; YIn >> Doc;