Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -138,6 +138,7 @@ Group, RawContent, Relocation, + Relr, NoBits, Note, Hash, @@ -440,6 +441,17 @@ } }; +struct RelrSection : Section { + Optional> Entries; + Optional Content; + + RelrSection() : Section(ChunkKind::Relr) {} + + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::Relr; + } +}; + struct SymtabShndxSection : Section { std::vector Entries; Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -110,6 +110,7 @@ typedef typename ELFT::Rela Elf_Rela; typedef typename ELFT::Relr Elf_Relr; typedef typename ELFT::Dyn Elf_Dyn; + typedef typename ELFT::uint uintX_t; enum class SymtabType { Static, Dynamic }; @@ -165,6 +166,9 @@ void writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::RelocationSection &Section, ContiguousBlobAccumulator &CBA); + void writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::RelrSection &Section, + ContiguousBlobAccumulator &CBA); void writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::Group &Group, ContiguousBlobAccumulator &CBA); void writeSectionContent(Elf_Shdr &SHeader, @@ -454,6 +458,8 @@ writeSectionContent(SHeader, *S, CBA); } else if (auto S = dyn_cast(Sec)) { writeSectionContent(SHeader, *S, CBA); + } else if (auto S = dyn_cast(Sec)) { + writeSectionContent(SHeader, *S, CBA); } else if (auto S = dyn_cast(Sec)) { writeSectionContent(SHeader, *S, CBA); } else if (auto S = dyn_cast(Sec)) { @@ -770,10 +776,6 @@ if (Section.EntSize) SHeader.sh_entsize = *Section.EntSize; - else if (Section.Type == llvm::ELF::SHT_RELR) - SHeader.sh_entsize = sizeof(Elf_Relr); - else - SHeader.sh_entsize = 0; if (Section.Info) SHeader.sh_info = *Section.Info; @@ -827,6 +829,30 @@ } } +template +void ELFState::writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::RelrSection &Section, + ContiguousBlobAccumulator &CBA) { + raw_ostream &OS = + CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + SHeader.sh_entsize = + Section.EntSize ? uint64_t(*Section.EntSize) : sizeof(Elf_Relr); + + if (Section.Content) { + SHeader.sh_size = writeContent(OS, Section.Content, None); + return; + } + + for (llvm::yaml::Hex64 E : *Section.Entries) { + if (!ELFT::Is64Bits && E > UINT32_MAX) + reportError(Section.Name + ": the value is too large for 32-bits: 0x" + + Twine::utohexstr(E)); + support::endian::write(OS, E, ELFT::TargetEndianness); + } + + SHeader.sh_size = sizeof(uintX_t) * Section.Entries->size(); +} + template void ELFState::writeSectionContent( Elf_Shdr &SHeader, const ELFYAML::SymtabShndxSection &Shndx, @@ -889,7 +915,6 @@ void ELFState::writeSectionContent( Elf_Shdr &SHeader, const ELFYAML::StackSizesSection &Section, ContiguousBlobAccumulator &CBA) { - using uintX_t = typename ELFT::uint; raw_ostream &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); @@ -1115,8 +1140,6 @@ void ELFState::writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::DynamicSection &Section, ContiguousBlobAccumulator &CBA) { - typedef typename ELFT::uint uintX_t; - assert(Section.Type == llvm::ELF::SHT_DYNAMIC && "Section type is not SHT_DYNAMIC"); Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1101,6 +1101,12 @@ IO.mapOptional("Relocations", Section.Relocations); } +static void sectionMapping(IO &IO, ELFYAML::RelrSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("Entries", Section.Entries); + IO.mapOptional("Content", Section.Content); +} + static void groupSectionMapping(IO &IO, ELFYAML::Group &Group) { commonSectionMapping(IO, Group); IO.mapOptional("Info", Group.Signature); @@ -1200,6 +1206,11 @@ Section.reset(new ELFYAML::RelocationSection()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_RELR: + if (!IO.outputting()) + Section.reset(new ELFYAML::RelrSection()); + sectionMapping(IO, *cast(Section.get())); + break; case ELF::SHT_GROUP: if (!IO.outputting()) Section.reset(new ELFYAML::Group()); @@ -1441,6 +1452,12 @@ return {}; } + if (const auto *RS = dyn_cast(C.get())) { + if (RS->Entries && RS->Content) + return "\"Entries\" and \"Content\" can't be used together"; + return {}; + } + return {}; } Index: llvm/test/tools/obj2yaml/relr-section.yaml =================================================================== --- /dev/null +++ llvm/test/tools/obj2yaml/relr-section.yaml @@ -0,0 +1,102 @@ +## Test how we dump SHT_RELR sections for 32 and 64-bits targets. + +## Test we use the "Entries" property when it is possible do +## dump values correctly. + +# RUN: yaml2obj --docnum=1 %s -o %t.64le +# RUN: obj2yaml %t.64le | FileCheck %s --check-prefix=ELF64LE +# RUN: yaml2obj --docnum=2 %s -o %t.32le +# RUN: obj2yaml %t.32le | FileCheck %s --check-prefix=ELF32LE +# RUN: yaml2obj --docnum=3 %s -o %t.64be +# RUN: obj2yaml %t.64be | FileCheck %s --check-prefix=ELF64BE +# RUN: yaml2obj --docnum=4 %s -o %t.32be +# RUN: obj2yaml %t.32be | FileCheck %s --check-prefix=ELF32BE + +# ELF64LE: Sections: +# ELF64LE-NEXT: - Name: .relr.dyn +# ELF64LE-NEXT: Type: SHT_RELR +# ELF64LE-NEXT: EntSize: 0x0000000000000008 +# ELF64LE-NEXT: Entries: [ 0x8877665544332211 ] + +# ELF32LE: Sections: +# ELF32LE-NEXT: - Name: .relr.dyn +# ELF32LE-NEXT: Type: SHT_RELR +# ELF32LE-NEXT: EntSize: 0x0000000000000004 +# ELF32LE-NEXT: Entries: [ 0x0000000044332211, 0x0000000088776655 ] + +# ELF64BE: Sections: +# ELF64BE-NEXT: - Name: .relr.dyn +# ELF64BE-NEXT: Type: SHT_RELR +# ELF64BE-NEXT: EntSize: 0x0000000000000008 +# ELF64BE-NEXT: Entries: [ 0x1122334455667788 ] + +# ELF32BE: Sections: +# ELF32BE-NEXT: - Name: .relr.dyn +# ELF32BE-NEXT: Type: SHT_RELR +# ELF32BE-NEXT: EntSize: 0x0000000000000004 +# ELF32BE-NEXT: Entries: [ 0x0000000011223344, 0x0000000055667788 ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Content: "1122334455667788" + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Content: "1122334455667788" + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Content: "1122334455667788" + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2MSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Content: "1122334455667788" + +## Test we use the "Content" property when a SHT_RELR section is truncated. + +# RUN: yaml2obj --docnum=5 %s -o %t.content +# RUN: obj2yaml %t.content | FileCheck %s --check-prefix=CONTENT + +# CONTENT: - Name: .relr.dyn +# CONTENT-NEXT: Type: SHT_RELR +# CONTENT-NEXT: EntSize: 0x0000000000000008 +# CONTENT-NEXT: Content: '11223344556677' + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Content: "11223344556677" Index: llvm/test/tools/yaml2obj/ELF/relr-section.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/ELF/relr-section.yaml @@ -0,0 +1,203 @@ +## Test how we create SHT_RELR sections. + +## Test that the content of SHT_RELR sections for 64-bits little endian targets is correct. +# RUN: yaml2obj --docnum=1 %s -o %t.le64 +# RUN: llvm-readobj --sections --section-data %t.le64 | FileCheck %s --check-prefix=LE64 + +# LE64: Name: .relr.dyn +# LE64-NEXT: Type: SHT_RELR +# LE64-NEXT: Flags [ +# LE64-NEXT: SHF_ALLOC +# LE64-NEXT: ] +# LE64-NEXT: Address: 0x0 +# LE64-NEXT: Offset: 0x40 +# LE64-NEXT: Size: 32 +# LE64-NEXT: Link: 0 +# LE64-NEXT: Info: 0 +# LE64-NEXT: AddressAlignment: 0 +# LE64-NEXT: EntrySize: 8 +# LE64-NEXT: SectionData ( +# LE64-NEXT: 0000: DDCCBBAA 00000000 2211FFEE 00000000 +# LE64-NEXT: 0010: 66554433 00000010 AA998877 00000010 +# LE64-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Flags: [ SHF_ALLOC ] + Entries: [ 0x00000000AABBCCDD, 0x00000000EEFF1122, + 0x1000000033445566, 0x10000000778899AA ] + +## Test that the content of SHT_RELR sections for 64-bits big endian targets is correct. +# RUN: yaml2obj --docnum=2 %s -o %t.be64 +# RUN: llvm-readobj --sections --section-data %t.be64 | FileCheck %s --check-prefix=BE64 + +# BE64: Name: .relr.dyn +# BE64: SectionData ( +# BE64-NEXT: 0000: 00000000 AABBCCDD 00000000 EEFF1122 +# BE64-NEXT: 0010: 10000000 33445566 10000000 778899AA +# BE64-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Flags: [ SHF_ALLOC ] + Entries: [ 0x00000000AABBCCDD, 0x00000000EEFF1122, + 0x1000000033445566, 0x10000000778899AA ] + +## Test that the content of SHT_RELR sections for 32-bits little endian targets is correct. +# RUN: yaml2obj --docnum=3 %s -o %t.le32 +# RUN: llvm-readobj --sections --section-data %t.le32 | FileCheck %s --check-prefix=LE32 + +# LE32: Name: .relr.dyn +# LE32-NEXT: Type: SHT_RELR +# LE32-NEXT: Flags [ +# LE32-NEXT: SHF_ALLOC +# LE32-NEXT: ] +# LE32-NEXT: Address: 0x0 +# LE32-NEXT: Offset: 0x34 +# LE32-NEXT: Size: 16 +# LE32-NEXT: Link: 0 +# LE32-NEXT: Info: 0 +# LE32-NEXT: AddressAlignment: 0 +# LE32-NEXT: EntrySize: 4 +# LE32-NEXT: SectionData ( +# LE32-NEXT: 0000: DDCCBBAA BBAAFFEE BBAAFFEE BCAAFFEE +# LE32-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Flags: [ SHF_ALLOC ] + Entries: [ 0xAABBCCDD, 0xEEFFAABB, + 0xEEFFAABB, 0xEEFFAABC ] + +## Test that the content of SHT_RELR sections for 32-bits big endian targets is correct. +# RUN: yaml2obj --docnum=4 %s -o %t.be32 +# RUN: llvm-readobj --sections --section-data %t.be32 | FileCheck %s --check-prefix=BE32 + +# BE32: Name: .relr.dyn +# BE32: SectionData ( +# BE32-NEXT: 0000: AABBCCDD EEFFAABB EEFFAABB EEFFAABC | +# BE32-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2MSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Flags: [ SHF_ALLOC ] + Entries: [ 0xAABBCCDD, 0xEEFFAABB, + 0xEEFFAABB, 0xEEFFAABC ] + +## Test we can use "Content" to describe SHT_RELR section. +# RUN: yaml2obj --docnum=5 %s -o %t.content +# RUN: llvm-readobj --sections --section-data %t.content | FileCheck %s --check-prefix=CONTENT + +# CONTENT: Name: .relr.dyn +# CONTENT: SectionData ( +# CONTENT-NEXT: 0000: 112233 | +# CONTENT-NEXT: ) + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Content: "112233" + +## Check we are able to set an arbitrary sh_entsize. +# RUN: yaml2obj --docnum=6 %s -o %t.entsize +# RUN: llvm-readelf --sections %t.entsize | FileCheck %s --check-prefix=ENTSIZE + +# ENTSIZE: [Nr] Name Type Address Off Size ES +# ENTSIZE: [ 1] .relr.dyn RELR 00000000 000034 000001 34 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + EntSize: 0x34 + Content: "12" + +## Test we can't use 64-bit offsets/bitmaps when creating a 32-bit object. +# RUN: yaml2obj --docnum=7 %s -o %t.nottoolarge +# RUN: llvm-readobj --sections --section-data %t.nottoolarge | FileCheck %s --check-prefix=NOT-TOO-LARGE + +# NOT-TOO-LARGE: Name: .relr.dyn +# NOT-TOO-LARGE: SectionData ( +# NOT-TOO-LARGE-NEXT: 0000: FFFFFFFF +# NOT-TOO-LARGE-NEXT: ) + +# RUN: not yaml2obj --docnum=8 %s 2>&1 | FileCheck %s --check-prefix=TOO-LARGE +# TOO-LARGE: error: .relr.dyn: the value is too large for 32-bits: 0x100000000 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Entries: [ 0x00000000FFFFFFFF ] + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Entries: [ 0x0000000100000000 ] + +## Test we can't specify "Entries" and "Content" properties at the same time. +# RUN: not yaml2obj --docnum=9 %s 2>&1 | FileCheck %s --check-prefix=BOTH + +# BOTH: error: "Entries" and "Content" can't be used together + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Entries: [ 0x0 ] + Content: "00" Index: llvm/tools/obj2yaml/elf2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/elf2yaml.cpp +++ llvm/tools/obj2yaml/elf2yaml.cpp @@ -27,6 +27,7 @@ typedef typename ELFT::Word Elf_Word; typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; + using Elf_Relr = typename ELFT::Relr; using Elf_Nhdr = typename ELFT::Nhdr; using Elf_Note = typename ELFT::Note; @@ -66,6 +67,7 @@ dumpDependentLibrariesSection(const Elf_Shdr *Shdr); Expected dumpDynamicSection(const Elf_Shdr *Shdr); Expected dumpRelocSection(const Elf_Shdr *Shdr); + Expected dumpRelrSection(const Elf_Shdr *Shdr); Expected dumpContentSection(const Elf_Shdr *Shdr); Expected @@ -251,6 +253,13 @@ Y->Chunks.emplace_back(*SecOrErr); break; } + case ELF::SHT_RELR: { + Expected SecOrErr = dumpRelrSection(&Sec); + if (!SecOrErr) + return SecOrErr.takeError(); + Y->Chunks.emplace_back(*SecOrErr); + break; + } case ELF::SHT_GROUP: { Expected GroupOrErr = dumpGroup(&Sec); if (!GroupOrErr) @@ -723,6 +732,30 @@ return S.release(); } +template +Expected +ELFDumper::dumpRelrSection(const Elf_Shdr *Shdr) { + auto S = std::make_unique(); + if (auto E = dumpCommonSection(Shdr, *S)) + return std::move(E); + + if (Expected> Relrs = Obj.relrs(Shdr)) { + S->Entries.emplace(); + for (Elf_Relr Rel : *Relrs) + S->Entries->emplace_back(Rel); + return S.release(); + } else { + // Ignore. We are going to dump the data as raw content below. + consumeError(Relrs.takeError()); + } + + Expected> ContentOrErr = Obj.getSectionContents(Shdr); + if (!ContentOrErr) + return ContentOrErr.takeError(); + S->Content = *ContentOrErr; + return S.release(); +} + template Expected ELFDumper::dumpContentSection(const Elf_Shdr *Shdr) {