Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -38,6 +38,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) @@ -88,6 +89,12 @@ std::vector Sections; }; +struct DynamicEntry { + ELF_DT Tag; + Optional Val; + Optional Ptr; +}; + struct Symbol { StringRef Name; ELF_STT Type; @@ -210,12 +217,14 @@ // being a single SHT_SYMTAB section are upheld. LocalGlobalWeakSymbols Symbols; LocalGlobalWeakSymbols DynamicSymbols; + std::vector Dynamic; }; } // end namespace ELFYAML } // 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) @@ -234,6 +243,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); @@ -341,6 +355,12 @@ static void mapping(IO &IO, ELFYAML::ProgramHeader &FileHdr); }; +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::DynamicEntry &Entry); + static StringRef validate(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 @@ -55,6 +55,118 @@ IO.enumFallback(Value); } +void ScalarEnumerationTraits::enumeration( + IO &IO, ELFYAML::ELF_DT &Value) { +#define ECase(X) IO.enumCase(Value, #X, ELF::X) + ECase(DT_NULL); + ECase(DT_NEEDED); + ECase(DT_PLTRELSZ); + ECase(DT_PLTGOT); + ECase(DT_HASH); + ECase(DT_STRTAB); + ECase(DT_SYMTAB); + ECase(DT_RELA); + ECase(DT_RELASZ); + ECase(DT_RELAENT); + ECase(DT_STRSZ); + ECase(DT_SYMENT); + ECase(DT_INIT); + ECase(DT_FINI); + ECase(DT_SONAME); + ECase(DT_RPATH); + ECase(DT_SYMBOLIC); + ECase(DT_REL); + ECase(DT_RELSZ); + ECase(DT_RELENT); + ECase(DT_PLTREL); + ECase(DT_DEBUG); + ECase(DT_TEXTREL); + ECase(DT_JMPREL); + ECase(DT_BIND_NOW); + ECase(DT_INIT_ARRAY); + ECase(DT_FINI_ARRAY); + ECase(DT_INIT_ARRAYSZ); + ECase(DT_FINI_ARRAYSZ); + ECase(DT_RUNPATH); + ECase(DT_FLAGS); + ECase(DT_ENCODING); + ECase(DT_PREINIT_ARRAY); + ECase(DT_PREINIT_ARRAYSZ); + ECase(DT_LOOS); + ECase(DT_HIOS); + ECase(DT_LOPROC); + ECase(DT_HIPROC); + ECase(DT_GNU_HASH); + ECase(DT_TLSDESC_PLT); + ECase(DT_TLSDESC_GOT); + ECase(DT_RELACOUNT); + ECase(DT_RELCOUNT); + ECase(DT_FLAGS_1); + ECase(DT_VERSYM); + ECase(DT_VERDEF); + ECase(DT_VERDEFNUM); + ECase(DT_VERNEED); + ECase(DT_VERNEEDNUM); + + // Hexagon specific dynamic table entries + ECase(DT_HEXAGON_SYMSZ); + ECase(DT_HEXAGON_VER); + ECase(DT_HEXAGON_PLT); + + // Mips specific dynamic table entry tags. + ECase(DT_MIPS_RLD_VERSION); + ECase(DT_MIPS_TIME_STAMP); + ECase(DT_MIPS_ICHECKSUM); + ECase(DT_MIPS_IVERSION); + ECase(DT_MIPS_FLAGS); + ECase(DT_MIPS_BASE_ADDRESS); + ECase(DT_MIPS_MSYM); + ECase(DT_MIPS_CONFLICT); + ECase(DT_MIPS_LIBLIST); + ECase(DT_MIPS_LOCAL_GOTNO); + ECase(DT_MIPS_CONFLICTNO); + ECase(DT_MIPS_LIBLISTNO); + ECase(DT_MIPS_SYMTABNO); + ECase(DT_MIPS_UNREFEXTNO); + ECase(DT_MIPS_GOTSYM); + ECase(DT_MIPS_HIPAGENO); + ECase(DT_MIPS_RLD_MAP); + ECase(DT_MIPS_DELTA_CLASS); + ECase(DT_MIPS_DELTA_CLASS_NO); + ECase(DT_MIPS_DELTA_INSTANCE); + ECase(DT_MIPS_DELTA_INSTANCE_NO); + ECase(DT_MIPS_DELTA_RELOC); + ECase(DT_MIPS_DELTA_RELOC_NO); + ECase(DT_MIPS_DELTA_SYM); + ECase(DT_MIPS_DELTA_SYM_NO); + ECase(DT_MIPS_DELTA_CLASSSYM); + ECase(DT_MIPS_DELTA_CLASSSYM_NO); + ECase(DT_MIPS_CXX_FLAGS); + ECase(DT_MIPS_PIXIE_INIT); + ECase(DT_MIPS_SYMBOL_LIB); + ECase(DT_MIPS_LOCALPAGE_GOTIDX); + ECase(DT_MIPS_LOCAL_GOTIDX); + ECase(DT_MIPS_HIDDEN_GOTIDX); + ECase(DT_MIPS_PROTECTED_GOTIDX); + ECase(DT_MIPS_OPTIONS); + ECase(DT_MIPS_INTERFACE); + ECase(DT_MIPS_DYNSTR_ALIGN); + ECase(DT_MIPS_INTERFACE_SIZE); + ECase(DT_MIPS_RLD_TEXT_RESOLVE_ADDR); + ECase(DT_MIPS_PERF_SUFFIX); + ECase(DT_MIPS_COMPACT_SIZE); + ECase(DT_MIPS_GP_VALUE); + ECase(DT_MIPS_AUX_DYNAMIC); + ECase(DT_MIPS_PLTGOT); + ECase(DT_MIPS_RWPLT); + ECase(DT_MIPS_RLD_MAP_REL); + + // Sun machine-independent extensions. + ECase(DT_AUXILIARY); + ECase(DT_FILTER); +#undef ECase +} + void ScalarEnumerationTraits::enumeration( IO &IO, ELFYAML::ELF_EM &Value) { #define ECase(X) IO.enumCase(Value, #X, ELF::X) @@ -770,6 +882,22 @@ IO.mapOptional("Align", Phdr.Align); } +void MappingTraits::mapping( + IO &IO, ELFYAML::DynamicEntry &Entry) { + IO.mapRequired("Tag", Entry.Tag); + IO.mapOptional("Value", Entry.Val); + IO.mapOptional("Pointer", Entry.Ptr); +} + +StringRef +MappingTraits::validate(IO &IO, + ELFYAML::DynamicEntry &Entry) { + if (Entry.Val.hasValue() == Entry.Ptr.hasValue()) + return "Dynamic entry must have either Value OR Pointer specified"; + + return StringRef(); +} + namespace { struct NormalizedOther { @@ -982,6 +1110,7 @@ IO.mapOptional("ProgramHeaders", Object.ProgramHeaders); IO.mapOptional("Sections", Object.Sections); IO.mapOptional("Symbols", Object.Symbols); + IO.mapOptional("DynamicEntries", Object.Dynamic); IO.mapOptional("DynamicSymbols", Object.DynamicSymbols); IO.setContext(nullptr); } Index: llvm/test/tools/yaml2obj/dynamic-entry-extra-val.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/dynamic-entry-extra-val.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 +DynamicEntries: + - Tag: DT_FLAGS + Value: 0xa + Pointer: 0xa + - Tag: DT_DEBUG + Pointer: 0x1000 + +# CHECK: Dynamic entry must have either Value OR Pointer specified Index: llvm/test/tools/yaml2obj/dynamic-entry-missing-val.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/dynamic-entry-missing-val.yaml @@ -0,0 +1,14 @@ +# RUN: not yaml2obj %s -o %t 2>&1 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +DynamicEntries: + - Tag: DT_FLAGS + - Tag: DT_DEBUG + Pointer: 0x1000 + +# CHECK: Dynamic entry must have either Value OR Pointer specified Index: llvm/test/tools/yaml2obj/dynamic-section.yaml =================================================================== --- llvm/test/tools/yaml2obj/dynamic-section.yaml +++ llvm/test/tools/yaml2obj/dynamic-section.yaml @@ -1,6 +1,6 @@ -# Ensures that dynamic section has sh_entsize correctly set # RUN: yaml2obj %s -o %t # RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=SECTION +# RUN: llvm-readobj -dynamic %t | FileCheck %s --check-prefix=DYNAMIC !ELF FileHeader: @@ -8,10 +8,29 @@ Data: ELFDATA2LSB Type: ET_DYN Machine: EM_X86_64 -Sections: - - Name: .dynamic - Type: SHT_DYNAMIC - Flags: [ SHF_ALLOC, SHF_WRITE ] +DynamicEntries: + - Tag: DT_FLAGS + Value: 0xa + - Tag: DT_DEBUG + Pointer: 0x1000 +# 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 -# SECTION: Name: .dynamic +# SECTION: Name: .dynamic # SECTION: EntrySize: 16 +# DYNAMIC: FLAGS SYMBOLIC BIND_NOW +# DYNAMIC: DEBUG 0x1000{{$}} Index: llvm/tools/yaml2obj/yaml2elf.cpp =================================================================== --- llvm/tools/yaml2obj/yaml2elf.cpp +++ llvm/tools/yaml2obj/yaml2elf.cpp @@ -144,6 +144,10 @@ void initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, StringTableBuilder &STB, ContiguousBlobAccumulator &CBA); + void initDynamicSectionHeader(Elf_Shdr &SHeader); + void finalizeDynamicSection(Elf_Shdr &DynamicHdr, + Elf_Shdr &DynStrHeader, + ContiguousBlobAccumulator &CBA); void setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders); void addSymbols(const std::vector &Symbols, @@ -161,6 +165,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) @@ -169,6 +174,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"); } @@ -355,6 +361,41 @@ 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_link = getDotDynStrSecNo(); + SHeader.sh_entsize = sizeof(Elf_Dyn); + SHeader.sh_addralign = 8; +} + +template +void ELFState::finalizeDynamicSection(Elf_Shdr &DynamicHdr, + Elf_Shdr &DynStrHeader, + ContiguousBlobAccumulator &CBA) { + std::vector Dyn; + for (const auto &YamlEntry : Doc.Dynamic) { + Elf_Dyn Ent; + Ent.d_tag = YamlEntry.Tag; + if (YamlEntry.Val.hasValue()) + Ent.d_un.d_val = *YamlEntry.Val; + else + Ent.d_un.d_ptr = *YamlEntry.Ptr; + Dyn.push_back(Ent); + } + { + // Ensure STN_UNDEF is present + Elf_Dyn NullEnt; + zero(NullEnt); + Dyn.push_back(NullEnt); + } + writeArrayData( + CBA.getOSAndAlignedOffset(DynamicHdr.sh_offset, DynamicHdr.sh_addralign), + makeArrayRef(Dyn)); + DynamicHdr.sh_size = arrayDataSize(makeArrayRef(Dyn)); +} + template void ELFState::setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders) { @@ -669,6 +710,16 @@ SHeaders[Index].sh_flags |= ELF::SHF_ALLOC; } + // Initialize .dynamic section header and write contents. + if (State.hasDynamicEntries()) { + auto DynamicIdx = State.SN2I.get(".dynamic"); + auto DynStrIdx = State.SN2I.get(".dynstr"); + State.initDynamicSectionHeader(SHeaders[DynamicIdx]); + State.finalizeDynamicSection(SHeaders[DynamicIdx], SHeaders[DynStrIdx], + CBA); + SHeaders[Index].sh_flags |= ELF::SHF_ALLOC; + } + // Now we can decide segment offsets State.setProgramHeaderLayout(PHeaders, SHeaders); @@ -685,11 +736,21 @@ Doc.DynamicSymbols.Local.size() > 0; } +template bool ELFState::hasDynamicEntries() const { + if (hasDynamicSymbols()) + return true; + + return Doc.Dynamic.size() > 0; +} + template SmallVector ELFState::implicitSectionNames() const { - if (!hasDynamicSymbols()) - return {".symtab", ".strtab", ".shstrtab"}; - return {".symtab", ".strtab", ".shstrtab", ".dynsym", ".dynstr"}; + if (hasDynamicSymbols()) + return {".symtab", ".strtab", ".shstrtab", + ".dynsym", ".dynstr", ".dynamic"}; + if (hasDynamicEntries()) + return {".symtab", ".strtab", ".shstrtab", ".dynstr", ".dynamic"}; + return {".symtab", ".strtab", ".shstrtab"}; } static bool is64Bit(const ELFYAML::Object &Doc) {