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, + RelocationOffsets, NoBits, Note, Hash, @@ -440,6 +441,17 @@ } }; +struct RelocationOffsetsSection : Section { + Optional> OffsetsAndBitmaps; + Optional Content; + + RelocationOffsetsSection() : Section(ChunkKind::RelocationOffsets) {} + + static bool classof(const Chunk *S) { + return S->Kind == ChunkKind::RelocationOffsets; + } +}; + 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; + using uintX_t = typename ELFT::uint; 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::RelocationOffsetsSection &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::RelocationOffsetsSection &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 (const llvm::yaml::Hex64 &Hex : *Section.OffsetsAndBitmaps) { + if (!ELFT::Is64Bits && Hex > UINT32_MAX) + reportError(Section.Name + ": the value is too large for 32-bits: 0x" + + Twine::utohexstr(Hex)); + support::endian::write(OS, Hex, ELFT::TargetEndianness); + } + + SHeader.sh_size = sizeof(uintX_t) * Section.OffsetsAndBitmaps->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::RelocationOffsetsSection &Section) { + commonSectionMapping(IO, Section); + IO.mapOptional("OffsetsAndBitmaps", Section.OffsetsAndBitmaps); + 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::RelocationOffsetsSection()); + 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 *ROS = dyn_cast(C.get())) { + if (ROS->OffsetsAndBitmaps && ROS->Content) + return "\"OffsetsAndBitmaps\" and \"Content\" can't be used together"; + return {}; + } + return {}; } Index: llvm/test/tools/yaml2obj/ELF/relr-section.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/ELF/relr-section.yaml @@ -0,0 +1,195 @@ +## This is a test to test how we create SHT_RELR sections. + +## Test how we create SHT_RELR sections for 64-bits LE targets. +## Test that sh_entsize is 8. +# 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 ] +## An arbitrary 32-bits values. + OffsetsAndBitmaps: [ 0x00000000AABBCCDD, 0x00000000EEFF1122, +## An arbitrary 64-bits values. + 0x1000000033445566, 0x10000000778899AA ] + +## Test how we create SHT_RELR sections for 64-bits BE targets. +# 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 ] +## An arbitrary 32-bits values. + OffsetsAndBitmaps: [ 0x00000000AABBCCDD, 0x00000000EEFF1122, +## An arbitrary 64-bits values. + 0x1000000033445566, 0x10000000778899AA ] + +## Test how we create SHT_RELR sections for 32-bit LE targets. +## Test that sh_entsize is 4. +# 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 ] + OffsetsAndBitmaps: [ 0xAABBCCDD, 0xEEFFAABB, + 0xEEFFAABB, 0xEEFFAABC ] + +## Test how we create SHT_RELR sections for 32-bit LE targets. +# 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 ] + OffsetsAndBitmaps: [ 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 + Flags: [ SHF_ALLOC ] + 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 + Flags: [ SHF_ALLOC ] + EntSize: 0x34 + Content: "12" + +## Test we can't use 64-bit offsets/bitmaps when creating a 32-bit object. +# RUN: not yaml2obj --docnum=7 %s 2>&1 | FileCheck %s --check-prefix=TOO-LARGE + +# TOO-LARGE: error: .relr.dyn: the value is too large for 32-bits: 0xaabbccddeeff0011 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 +Sections: + - Name: .relr.dyn + Type: SHT_RELR + Flags: [ SHF_ALLOC ] + OffsetsAndBitmaps: [ 0xAABBCCDDEEFF0011 ] + +## Test we can't specify "OffsetsAndBitmaps" and "Content" properties at the same time. +# RUN: not yaml2obj --docnum=8 %s 2>&1 | FileCheck %s --check-prefix=BOTH + +# BOTH: error: "OffsetsAndBitmaps" 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 + Flags: [ SHF_ALLOC ] + OffsetsAndBitmaps: [ 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,8 @@ dumpDependentLibrariesSection(const Elf_Shdr *Shdr); Expected dumpDynamicSection(const Elf_Shdr *Shdr); Expected dumpRelocSection(const Elf_Shdr *Shdr); + Expected + dumpRelocOffsetsSection(const Elf_Shdr *Shdr); Expected dumpContentSection(const Elf_Shdr *Shdr); Expected @@ -251,6 +254,14 @@ Y->Chunks.emplace_back(*SecOrErr); break; } + case ELF::SHT_RELR: { + Expected SecOrErr = + dumpRelocOffsetsSection(&Sec); + if (!SecOrErr) + return SecOrErr.takeError(); + Y->Chunks.emplace_back(*SecOrErr); + break; + } case ELF::SHT_GROUP: { Expected GroupOrErr = dumpGroup(&Sec); if (!GroupOrErr) @@ -723,6 +734,29 @@ return S.release(); } +template +Expected +ELFDumper::dumpRelocOffsetsSection(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->OffsetsAndBitmaps.emplace(); + for (Elf_Relr Rel : *Relrs) + S->OffsetsAndBitmaps->emplace_back(Rel); + return S.release(); + } else { + 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) {