Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -111,7 +111,9 @@ struct DynamicEntry { ELF_DYNTAG Tag; - llvm::yaml::Hex64 Val; + Optional Val; + // Optional, used to specify string-based values. + Optional StrVal; }; struct Section { @@ -378,7 +380,8 @@ }; template <> struct MappingTraits { - static void mapping(IO &IO, ELFYAML::DynamicEntry &Rel); + static void mapping(IO &IO, ELFYAML::DynamicEntry &Dyn); + static StringRef validate(IO &IO, ELFYAML::DynamicEntry &Dyn); }; template <> struct MappingTraits { Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -663,8 +663,6 @@ void ScalarEnumerationTraits::enumeration( IO &IO, ELFYAML::ELF_DYNTAG &Value) { - assert(IO.getContext() && "The IO context is not initialized"); - // TODO: For simplicity we do not handle target specific flags. They are // still supported and will be shown as a raw numeric values in the output. #define MIPS_DYNAMIC_TAG(name, value) @@ -990,11 +988,20 @@ } // end anonymous namespace void MappingTraits::mapping(IO &IO, - ELFYAML::DynamicEntry &Rel) { - assert(IO.getContext() && "The IO context is not initialized"); + ELFYAML::DynamicEntry &Dyn) { + IO.mapRequired("Tag", Dyn.Tag); + IO.mapOptional("Value", Dyn.Val); + IO.mapOptional("String", Dyn.StrVal); +} - IO.mapRequired("Tag", Rel.Tag); - IO.mapRequired("Value", Rel.Val); +StringRef MappingTraits::validate( + IO &io, ELFYAML::DynamicEntry &Dyn) { + if (Dyn.Val.hasValue() && Dyn.StrVal.hasValue()) + return "Dynamic entry must have a `String` or a numeric `Value`"; + else if (!Dyn.Val.hasValue() && !Dyn.StrVal.hasValue()) + return "Dynamic cannot have both a `String` and numeric `Value`"; + + return StringRef(); } void MappingTraits::mapping(IO &IO, 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 + String: .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,19 @@ +# 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 ] + Entries: + - Tag: DT_STRSZ + Value: 17 + - Tag: DT_STRTAB + String: xxyyzz + +# CHECK: error: String is not a valid section name Index: llvm/tools/obj2yaml/elf2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/elf2yaml.cpp +++ llvm/tools/obj2yaml/elf2yaml.cpp @@ -51,7 +51,7 @@ template std::error_code dumpRelocation(const RelT *Rel, const Elf_Shdr *SymTab, ELFYAML::Relocation &R); - + ErrorOr dumpDynamicSection(const Elf_Shdr *Shdr); ErrorOr dumpRelocSection(const Elf_Shdr *Shdr); ErrorOr @@ -370,8 +370,12 @@ if (!DynTagsOrErr) return errorToErrorCode(DynTagsOrErr.takeError()); - for (const Elf_Dyn &Dyn : *DynTagsOrErr) - S->Entries.push_back({(ELFYAML::ELF_DYNTAG)Dyn.getTag(), Dyn.getVal()}); + for (const Elf_Dyn &Dyn : *DynTagsOrErr) { + ELFYAML::DynamicEntry Ent; + Ent.Tag = Dyn.getTag(); + Ent.Val = Dyn.getVal(); + S->Entries.push_back(Ent); + } return S.release(); } Index: llvm/tools/yaml2obj/yaml2elf.cpp =================================================================== --- llvm/tools/yaml2obj/yaml2elf.cpp +++ llvm/tools/yaml2obj/yaml2elf.cpp @@ -127,6 +127,12 @@ /// 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; + unsigned DynamicSectionIdx = 0; + NameToIdxMap SN2I; NameToIdxMap SymN2I; const ELFYAML::Object &Doc; @@ -143,6 +149,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, @@ -163,6 +173,7 @@ const ELFYAML::DynamicSection &Section, ContiguousBlobAccumulator &CBA); bool hasDynamicSymbols() const; + bool hasDynamicEntries() const; SmallVector implicitSectionNames() const; // - SHT_NULL entry (placed first, i.e. 0'th entry) @@ -171,6 +182,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"); } @@ -296,7 +308,9 @@ // so just to setup the section offset. CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); } else if (auto S = dyn_cast(Sec.get())) { - writeSectionContent(SHeader, *S, CBA); + YamlDynamicSection = S; + DynamicSectionIdx = SHeaders.size(); + initDynamicSectionHeader(SHeader); } else llvm_unreachable("Unknown section type"); @@ -360,6 +374,73 @@ SHeader.sh_addralign = 1; } +template +void ELFState::initDynamicSectionHeader(Elf_Shdr &SHeader) { + SHeader.sh_name = DotShStrtab.getOffset(YamlDynamicSection->Name); + SHeader.sh_type = ELF::SHT_DYNAMIC; + if (YamlDynamicSection->EntSize) + SHeader.sh_entsize = *YamlDynamicSection->EntSize; + else + SHeader.sh_entsize = sizeof(Elf_Dyn); + + if (SHeader.sh_addralign < sizeof(Elf_Dyn)/2) + 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->Entries) { + Elf_Dyn Ent; + Ent.d_tag = YamlEntry.Tag; + + // If a section name, use that section's sh_addr. + if (YamlEntry.StrVal.hasValue()) { + unsigned SectionIdx; + if (!SN2I.lookup(*YamlEntry.StrVal, SectionIdx)) { + Ent.d_un.d_val = AllShdrs[SectionIdx].sh_addr; + } else { + printYamlError(YamlEntry, + "String is not a valid section name"); + return false; + } + + // Otherwise, attempt to treat as a number. + } else if (YamlEntry.Val.hasValue()) { + Ent.d_un.d_val = *YamlEntry.Val; + } else { + printYamlError(YamlEntry, + "Value is not a number or valid section name"); + return false; + } + Dyn.push_back(Ent); + } + + // Ensure DT_NULL is present. + if (!Dyn.empty() && Dyn.back().getTag() != ELF::DT_NULL) { + 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) { @@ -579,29 +660,6 @@ return true; } -template -void ELFState::writeSectionContent(Elf_Shdr &SHeader, - const ELFYAML::DynamicSection &Section, - ContiguousBlobAccumulator &CBA) { - typedef typename ELFT::Addr Elf_Addr; - assert(Section.Type == llvm::ELF::SHT_DYNAMIC && - "Section type is not SHT_DYNAMIC"); - - SHeader.sh_size = 2 * sizeof(Elf_Addr) * Section.Entries.size(); - if (Section.EntSize) - SHeader.sh_entsize = *Section.EntSize; - else - SHeader.sh_entsize = sizeof(Elf_Dyn); - - auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); - for (const ELFYAML::DynamicEntry &DE : Section.Entries) { - Elf_Addr Tag = (Elf_Addr)DE.Tag; - OS.write((const char *)&Tag, sizeof(Elf_Addr)); - Elf_Addr Val = (Elf_Addr)DE.Val; - OS.write((const char *)&Val, sizeof(Elf_Addr)); - } -} - template bool ELFState::buildSectionIndex() { for (unsigned i = 0, e = Doc.Sections.size(); i != e; ++i) { StringRef Name = Doc.Sections[i]->Name; @@ -695,6 +753,13 @@ SHeaders[Index].sh_flags |= ELF::SHF_ALLOC; } + // Write .dynamic section header and contents. + if (State.hasDynamicEntries()) { + Elf_Shdr &DynamicHdr = SHeaders[State.DynamicSectionIdx]; + if (!State.finalizeDynamicSection(DynamicHdr, SHeaders, CBA)) + return 1; + } + // Now we can decide segment offsets State.setProgramHeaderLayout(PHeaders, SHeaders); @@ -711,6 +776,10 @@ Doc.DynamicSymbols.Local.size() > 0; } +template bool ELFState::hasDynamicEntries() const { + return YamlDynamicSection; +} + template SmallVector ELFState::implicitSectionNames() const { if (!hasDynamicSymbols())