Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -37,6 +37,7 @@ // class's with appropriate fixed underlying type. LLVM_YAML_STRONG_TYPEDEF(uint16_t, ELF_ET) LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_PT) +LLVM_YAML_STRONG_TYPEDEF(int64_t, ELF_DT) LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_EM) LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFCLASS) LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFDATA) @@ -87,6 +88,11 @@ std::vector Sections; }; +struct DynamicEntry { + ELF_DT Tag; + StringRef Val; +}; + struct Symbol { StringRef Name; ELF_STT Type; @@ -112,6 +118,7 @@ Group, RawContent, Relocation, + Dynamic, NoBits, MipsABIFlags }; @@ -128,6 +135,7 @@ Section(SectionKind Kind) : Kind(Kind) {} virtual ~Section(); }; + struct RawContentSection : Section { yaml::BinaryRef Content; llvm::yaml::Hex64 Size; @@ -135,7 +143,21 @@ RawContentSection() : Section(SectionKind::RawContent) {} static bool classof(const Section *S) { - return S->Kind == SectionKind::RawContent; + return S->Kind == SectionKind::RawContent || + S->Kind == SectionKind::Dynamic; + } + +protected: + RawContentSection(SectionKind Kind) : Section(Kind) {} +}; + +struct DynamicSection : RawContentSection { + std::vector DynamicEntries; + + DynamicSection() : RawContentSection(SectionKind::Dynamic) {} + + static bool classof(const Section *S) { + return S->Kind == SectionKind::Dynamic; } }; @@ -215,6 +237,7 @@ } // end namespace llvm LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation) @@ -233,6 +256,11 @@ static void enumeration(IO &IO, ELFYAML::ELF_PT &Value); }; +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, ELFYAML::ELF_DT &Value); +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, ELFYAML::ELF_EM &Value); @@ -340,6 +368,11 @@ static void mapping(IO &IO, ELFYAML::ProgramHeader &FileHdr); }; +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::DynamicEntry &Entry); +}; + template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::Symbol &Symbol); Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -54,6 +54,27 @@ IO.enumFallback(Value); } +void ScalarEnumerationTraits::enumeration( + IO &IO, ELFYAML::ELF_DT &Value) { +#define DYNAMIC_TAG(Name, Value) ECase(DT_##Name) +#define HEXAGON_DYNAMIC_TAG(Name, Value) ECase(DT_##Name) +#define MIPS_DYNAMIC_TAG(Name, Value) ECase(DT_##Name) +#define PPC64_DYNAMIC_TAG(Name, Value) ECase(DT_##Name) +// Ignore marker tags. +#define DT_TAG_MARKER(Name, Value) + +// Add tags. +#define ECase(X) IO.enumCase(Value, #X, ELF::X); +#include "llvm/BinaryFormat/DynamicTags.def" + +#undef ECase +#undef DT_TAG_MARKER +#undef PPC64_DYNAMIC_TAG +#undef MIPS_DYNAMIC_TAG +#undef HEXAGON_DYNAMIC_TAG +#undef DYNAMIC_TAG +} + void ScalarEnumerationTraits::enumeration( IO &IO, ELFYAML::ELF_EM &Value) { #define ECase(X) IO.enumCase(Value, #X, ELF::X) @@ -770,6 +791,12 @@ IO.mapOptional("Align", Phdr.Align); } +void MappingTraits::mapping( + IO &IO, ELFYAML::DynamicEntry &Entry) { + IO.mapRequired("Tag", Entry.Tag); + IO.mapRequired("Value", Entry.Val); +} + namespace { struct NormalizedOther { @@ -837,6 +864,13 @@ IO.mapOptional("Size", Section.Size, Hex64(Section.Content.binary_size())); } +static void sectionMapping(IO &IO, ELFYAML::DynamicSection &Section) { + // commonSectionMapping() is implicitly called in RawContentSection's + // sectionMapping(). + sectionMapping(IO, (ELFYAML::RawContentSection &)Section); + IO.mapOptional("Entries", Section.DynamicEntries); +} + static void sectionMapping(IO &IO, ELFYAML::NoBitsSection &Section) { commonSectionMapping(IO, Section); IO.mapOptional("Size", Section.Size, Hex64(0)); @@ -897,6 +931,11 @@ Section.reset(new ELFYAML::RelocationSection()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_DYNAMIC: + if (!IO.outputting()) + Section.reset(new ELFYAML::DynamicSection()); + sectionMapping(IO, *cast(Section.get())); + break; case ELF::SHT_GROUP: if (!IO.outputting()) Section.reset(new ELFYAML::Group()); @@ -921,10 +960,17 @@ StringRef MappingTraits>::validate( IO &io, std::unique_ptr &Section) { - const auto *RawSection = dyn_cast(Section.get()); - if (!RawSection || RawSection->Size >= RawSection->Content.binary_size()) - return StringRef(); - return "Section size must be greater or equal to the content size"; + if (const auto *Dyn = dyn_cast(Section.get())) { + if (Dyn->DynamicEntries.size() > 0 && Dyn->Content.binary_size() > 0) + return "Dynamic section can't have Entries and Content simultaneously"; + } + if (const auto *RawSection = + dyn_cast(Section.get())) { + if ((uint64_t)RawSection->Size < + (uint64_t)RawSection->Content.binary_size()) + return "Section size must be greater or equal to the content size"; + } + return StringRef(); } namespace { Index: llvm/test/tools/yaml2obj/dynamic-entries-and-content.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/dynamic-entries-and-content.yaml @@ -0,0 +1,27 @@ +# RUN: not yaml2obj %s -o %t 2>&1 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .somestrings + Type: SHT_STRTAB + Flags: [ SHF_ALLOC, SHF_WRITE ] + # "\0libsomething.so\0" + Content: "006c6962736f6d657468696e672e736f00" + Address: 0x1000 + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC, SHF_WRITE ] + Link: .somestrings + Content: "0a00000000000000110000000000000005000000000000000010000000000000" + Entries: + - Tag: DT_STRSZ + Value: 17 + - Tag: DT_STRTAB + Value: .somestrings + +# CHECK: error: Dynamic section can't have Entries and Content simultaneously Index: llvm/test/tools/yaml2obj/dynamic-entries-invalid-name.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/dynamic-entries-invalid-name.yaml @@ -0,0 +1,26 @@ +# RUN: not yaml2obj %s -o %t 2>&1 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .somestrings + Type: SHT_STRTAB + Flags: [ SHF_ALLOC, SHF_WRITE ] + # "\0libsomething.so\0" + Content: "006c6962736f6d657468696e672e736f00" + Address: 0x1000 + - Name: .mydynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC, SHF_WRITE ] + Link: .somestrings + Entries: + - Tag: DT_STRSZ + Value: 17 + - Tag: DT_STRTAB + Value: .somestrings + +# CHECK: error: Dynamic section must be named `.dynamic` when using Entries to populate the section Index: llvm/test/tools/yaml2obj/dynamic-entries.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/dynamic-entries.yaml @@ -0,0 +1,52 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-readobj -dynamic %t | FileCheck %s --check-prefix=DYNAMIC + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .somestrings + Type: SHT_STRTAB + Flags: [ SHF_ALLOC, SHF_WRITE ] + # "\0libsomething.so\0" + Content: "006c6962736f6d657468696e672e736f00" + Address: 0x1000 + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC, SHF_WRITE ] + Link: .somestrings + Entries: + - Tag: DT_STRSZ + Value: 17 + - Tag: DT_STRTAB + Value: .somestrings +# llvm-readobj requires some program headers to read .dynamic entries. +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R ] + VAddr: 0x0000 + PAddr: 0x0000 + Align: 8 + Sections: + - Section: .dynamic + - Section: .dynstr + - Type: PT_DYNAMIC + Flags: [ PF_X, PF_R ] + VAddr: 0x0000 + PAddr: 0x0000 + Sections: + - Section: .dynamic + - Type: PT_LOAD + Flags: [ PF_R ] + VAddr: 0x1000 + PAddr: 0x1000 + Align: 8 + Sections: + - Section: .somestrings + +# DYNAMIC: STRSZ 17 (bytes) +# DYNAMIC: STRTAB 0x1000{{$}} +# DYNAMIC: NULL 0x0{{$}} Index: llvm/test/tools/yaml2obj/dynamic-entry-invalid-val.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/dynamic-entry-invalid-val.yaml @@ -0,0 +1,26 @@ +# RUN: not yaml2obj %s -o %t 2>&1 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .somestrings + Type: SHT_STRTAB + Flags: [ SHF_ALLOC, SHF_WRITE ] + # "\0libsomething.so\0" + Content: "006c6962736f6d657468696e672e736f00" + Address: 0x1000 + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC, SHF_WRITE ] + Link: .somestrings + Entries: + - Tag: DT_STRSZ + Value: 17 + - Tag: DT_STRTAB + Value: xxyyzz + +# CHECK: error: Value is not a number or valid section name Index: llvm/test/tools/yaml2obj/dynamic-raw-invalid-size.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/dynamic-raw-invalid-size.yaml @@ -0,0 +1,16 @@ +# RUN: not yaml2obj %s -o %t 2>&1 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC, SHF_WRITE ] + Content: "0000000000000000000000000000000000000000000000000000000000000000" + Size: 16 + +# CHECK: error: Section size must be greater or equal to the content size Index: llvm/tools/yaml2obj/yaml2elf.cpp =================================================================== --- llvm/tools/yaml2obj/yaml2elf.cpp +++ llvm/tools/yaml2obj/yaml2elf.cpp @@ -127,6 +127,11 @@ /// The future ".dynstr" section. StringTableBuilder DotDynstr{StringTableBuilder::ELF}; + /// Retain a pointer to the ELFYAML::DynamicSection as state. + /// This is required as the .dynamic section isn't written until after the + /// .dynstr section. + ELFYAML::DynamicSection *YamlDynamicSection = nullptr; + NameToIdxMap SN2I; NameToIdxMap SymN2I; const ELFYAML::Object &Doc; @@ -143,6 +148,10 @@ void initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, StringTableBuilder &STB, ContiguousBlobAccumulator &CBA); + void initDynamicSectionHeader(Elf_Shdr &SHeader); + bool finalizeDynamicSection(Elf_Shdr &DynamicHdr, + std::vector &AllShdrs, + ContiguousBlobAccumulator &CBA); void setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders); void addSymbols(const std::vector &Symbols, @@ -160,6 +169,7 @@ const ELFYAML::MipsABIFlags &Section, ContiguousBlobAccumulator &CBA); bool hasDynamicSymbols() const; + bool hasDynamicEntries() const; SmallVector implicitSectionNames() const; // - SHT_NULL entry (placed first, i.e. 0'th entry) @@ -168,6 +178,7 @@ // - section header string table (.shstrtab) (defaults to after .strtab) // - dynamic symbol table (.dynsym) (defaults to after .shstrtab) // - dynamic string table (.dynstr) (defaults to after .dynsym) + // - dynamic section (.dynamic) (defaults to after .dynstr) unsigned getDotSymTabSecNo() const { return SN2I.get(".symtab"); } unsigned getDotStrTabSecNo() const { return SN2I.get(".strtab"); } unsigned getDotShStrTabSecNo() const { return SN2I.get(".shstrtab"); } @@ -259,9 +270,24 @@ SHeader.sh_link = Index; } - if (auto S = dyn_cast(Sec.get())) + if (auto S = dyn_cast(Sec.get())) { + // Determine whether to use `Entries` or older raw `Contents`. + if (S->DynamicEntries.empty()) { + ELFYAML::RawContentSection *RawSec = + dyn_cast(S); + writeSectionContent(SHeader, *RawSec, CBA); + } else { + // To use DynamicEntries, the section name must be `.dynamic` + if (S->Name != ".dynamic") { + WithColor::error() << "Dynamic section must be named `.dynamic` " + "when using Entries to populate the section\n"; + return false; + } + YamlDynamicSection = S; + } + } else if (auto S = dyn_cast(Sec.get())) { writeSectionContent(SHeader, *S, CBA); - else if (auto S = dyn_cast(Sec.get())) { + } else if (auto S = dyn_cast(Sec.get())) { if (S->Link.empty()) // For relocation section set link to .symtab by default. SHeader.sh_link = getDotSymTabSecNo(); @@ -354,6 +380,61 @@ SHeader.sh_addralign = 1; } +template +void ELFState::initDynamicSectionHeader(Elf_Shdr &SHeader) { + SHeader.sh_name = DotShStrtab.getOffset(".dynamic"); + SHeader.sh_type = ELF::SHT_DYNAMIC; + SHeader.sh_entsize = sizeof(Elf_Dyn); + SHeader.sh_addralign = sizeof(Elf_Dyn)/2; + // TODO: Link .dynamic to .dynstr by default. +} + +template +bool ELFState::finalizeDynamicSection(Elf_Shdr &DynamicHdr, + std::vector &AllShdrs, + ContiguousBlobAccumulator &CBA) { + std::vector Dyn; + auto printYamlError = [](ELFYAML::DynamicEntry YamlObj, StringRef After) { + yaml::Output Yout(errs()); + Yout << YamlObj; + WithColor::error() << After << "\n"; + }; + + for (const auto &YamlEntry : YamlDynamicSection->DynamicEntries) { + Elf_Dyn Ent; + Ent.d_tag = YamlEntry.Tag; + uint64_t Value; + unsigned SectionIdx; + + // If a section name, use that section's sh_addr. + if (!SN2I.lookup(YamlEntry.Val, SectionIdx)) { + Value = AllShdrs[SectionIdx].sh_addr; + + // Otherwise, attempt to treat as a number. + } else if (!to_integer(YamlEntry.Val, Value)) { + printYamlError(YamlEntry, + "Value is not a number or valid section name"); + return false; + } + Ent.d_un.d_val = Value; + Dyn.push_back(Ent); + } + + // Ensure DT_NULL is present. + // TODO: Check if DT_NULL already present instead of always adding. + Elf_Dyn NullEnt; + NullEnt.d_tag = ELF::DT_NULL; + NullEnt.d_un.d_val = 0; + Dyn.push_back(NullEnt); + + writeArrayData( + CBA.getOSAndAlignedOffset(DynamicHdr.sh_offset, DynamicHdr.sh_addralign), + makeArrayRef(Dyn)); + DynamicHdr.sh_size = arrayDataSize(makeArrayRef(Dyn)); + + return true; +} + template void ELFState::setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders) { @@ -668,6 +749,13 @@ SHeaders[Index].sh_flags |= ELF::SHF_ALLOC; } + // Write .dynamic section header and contents. + if (State.hasDynamicEntries()) { + Index = State.SN2I.get(".dynamic"); + if (!State.finalizeDynamicSection(SHeaders[Index], SHeaders, CBA)) + return 1; + } + // Now we can decide segment offsets State.setProgramHeaderLayout(PHeaders, SHeaders); @@ -684,6 +772,10 @@ Doc.DynamicSymbols.Local.size() > 0; } +template bool ELFState::hasDynamicEntries() const { + return YamlDynamicSection; +} + template SmallVector ELFState::implicitSectionNames() const { if (!hasDynamicSymbols())