Index: include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- include/llvm/ObjectYAML/ELFYAML.h +++ include/llvm/ObjectYAML/ELFYAML.h @@ -113,6 +113,8 @@ RawContent, Relocation, NoBits, + VersionDef, + VersionNeed, MipsABIFlags }; SectionKind Kind; @@ -128,6 +130,7 @@ Section(SectionKind Kind) : Kind(Kind) {} virtual ~Section(); }; + struct RawContentSection : Section { yaml::BinaryRef Content; llvm::yaml::Hex64 Size; @@ -178,6 +181,54 @@ } }; +struct VersionDefParent { + llvm::yaml::Hex64 Name; +}; + +struct VersionDef { + int32_t Revision; + llvm::yaml::Hex32 Flags; + llvm::yaml::Hex32 Index; + llvm::yaml::Hex64 Hash; + llvm::yaml::Hex64 Name; + std::vector Parents; +}; + +// Represents .gnu.version_d +struct VersionDefSection : Section { + std::vector VersionDefs; + + VersionDefSection() : Section(SectionKind::VersionDef) {} + + static bool classof(const Section *S) { + return S->Kind == SectionKind::VersionDef; + } +}; + +struct VersionNeedAux { + llvm::yaml::Hex64 Hash; + llvm::yaml::Hex32 Flags; + llvm::yaml::Hex32 Other; + llvm::yaml::Hex64 Name; +}; + +struct VersionNeed { + int32_t Version; + llvm::yaml::Hex64 File; + std::vector Auxiliaries; +}; + +// Represents .gnu.version_r section +struct VersionNeedSection : Section { + std::vector VersionNeeds; + + VersionNeedSection() : Section(SectionKind::VersionNeed) {} + + static bool classof(const Section *S) { + return S->Kind == SectionKind::VersionNeed; + } +}; + // Represents .MIPS.abiflags section struct MipsABIFlags : Section { llvm::yaml::Hex16 Version; @@ -220,6 +271,10 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionOrType) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionName) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VersionDef) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VersionDefParent) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VersionNeed) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VersionNeedAux) namespace llvm { namespace yaml { @@ -374,6 +429,26 @@ static void mapping(IO &IO, ELFYAML::SectionName §ionName); }; +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::VersionDef &VDef); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::VersionDefParent &VDefParent); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::VersionNeed &VNeed); +}; + +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::VersionNeedAux &VNeedAux); +}; + } // end namespace yaml } // end namespace llvm Index: lib/ObjectYAML/ELFYAML.cpp =================================================================== --- lib/ObjectYAML/ELFYAML.cpp +++ lib/ObjectYAML/ELFYAML.cpp @@ -861,6 +861,16 @@ IO.mapRequired("Section", sectionName.Section); } +static void sectionMapping(IO &IO, ELFYAML::VersionDefSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("VersionDefs", Section.VersionDefs); +} + +static void sectionMapping(IO &IO, ELFYAML::VersionNeedSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("VersionNeeds", Section.VersionNeeds); +} + static void sectionMapping(IO &IO, ELFYAML::MipsABIFlags &Section) { commonSectionMapping(IO, Section); IO.mapOptional("Version", Section.Version, Hex16(0)); @@ -906,6 +916,16 @@ Section.reset(new ELFYAML::NoBitsSection()); sectionMapping(IO, *cast(Section.get())); break; + case ELF::SHT_GNU_verdef: + if (!IO.outputting()) + Section.reset(new ELFYAML::VersionDefSection()); + sectionMapping(IO, *cast(Section.get())); + break; + case ELF::SHT_GNU_verneed: + if (!IO.outputting()) + Section.reset(new ELFYAML::VersionNeedSection()); + sectionMapping(IO, *cast(Section.get())); + break; case ELF::SHT_MIPS_ABIFLAGS: if (!IO.outputting()) Section.reset(new ELFYAML::MipsABIFlags()); @@ -973,6 +993,40 @@ IO.mapOptional("Addend", Rel.Addend, (int64_t)0); } +void MappingTraits::mapping(IO &IO, + ELFYAML::VersionDef &VDef) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapRequired("Revision", VDef.Revision); + IO.mapRequired("Flags", VDef.Flags); + IO.mapRequired("Index", VDef.Index); + IO.mapRequired("Hash", VDef.Hash); + IO.mapRequired("Name", VDef.Name); + IO.mapOptional("Parents", VDef.Parents); +} + +void MappingTraits::mapping( + IO &IO, ELFYAML::VersionDefParent &VDefParent) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapRequired("Name", VDefParent.Name); +} + +void MappingTraits::mapping(IO &IO, + ELFYAML::VersionNeed &VNeed) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapRequired("Version", VNeed.Version); + IO.mapRequired("File", VNeed.File); + IO.mapRequired("Auxiliaries", VNeed.Auxiliaries); +} + +void MappingTraits::mapping( + IO &IO, ELFYAML::VersionNeedAux &VNeedAux) { + assert(IO.getContext() && "The IO context is not initialized"); + IO.mapRequired("Hash", VNeedAux.Hash); + IO.mapRequired("Flags", VNeedAux.Flags); + IO.mapRequired("Other", VNeedAux.Other); + IO.mapRequired("Name", VNeedAux.Name); +} + void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { assert(!IO.getContext() && "The IO context is initialized already"); IO.setContext(&Object); Index: test/tools/yaml2obj/symbol-version-section.yaml =================================================================== --- /dev/null +++ test/tools/yaml2obj/symbol-version-section.yaml @@ -0,0 +1,118 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-readobj -V %t | FileCheck %s + +# CHECK: SHT_GNU_verdef { +# CHECK-NEXT: Definition { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Flags: Base (0x1) +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Hash: 4660 +# CHECK-NEXT: Name: foo +# CHECK-NEXT: Predecessor: VERSION1 +# CHECK-NEXT: } +# CHECK-NEXT: Definition { +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Flags: 0x0 +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Hash: 17185 +# CHECK-NEXT: Name: bar +# CHECK-NEXT: } +# CHECK-NEXT: } + +# CHECK: SHT_GNU_verneed { +# CHECK-NEXT: Dependency { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Count: 1 +# CHECK-NEXT: FileName: libfoo.so.0 +# CHECK-NEXT: Entry { +# CHECK-NEXT: Hash: 6 +# CHECK-NEXT: Flags: 0x0 +# CHECK-NEXT: Index: 0 +# CHECK-NEXT: Name: GLIBFOO_0.0.0 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: Dependency { +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Count: 2 +# CHECK-NEXT: FileName: libbar.so.0 +# CHECK-NEXT: Entry { +# CHECK-NEXT: Hash: 74565 +# CHECK-NEXT: Flags: Base (0x1) +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Name: GLIBBAR_0.0.0 +# CHECK-NEXT: } +# CHECK-NEXT: Entry { +# CHECK-NEXT: Hash: 344865 +# CHECK-NEXT: Flags: Weak (0x2) +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: GLIBFOO_0.0.0 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: } + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Content: 006c6962666f6f2e736f2e30006c69626261722e736f2e3000474c4942464f4f5f302e302e3000474c49424241525f302e302e300056455253494f4e3100666f6f0062617200 + # Content: "libfoo.so.0 libbar.so.0 GLIBFOO_0.0.0 GLIBBAR_0.0.0 VERSION1 foo bar" + # Offset: 0x01 0x0d 0x19 0x27 0x35 0x3e 0x42 + - Name: .gnu.version_d + Type: SHT_GNU_verdef + Flags: [ SHF_ALLOC ] + Link: .dynstr + VersionDefs: + - Revision: 2 + Flags: 0x01 + Index: 0x02 + Hash: 0x1234 + Name: 0x3e + Parents: + - Name: 0x35 + - Revision: 1 + Flags: 0x00 + Index: 0x03 + Hash: 0x4321 + Name: 0x42 + - Name: .gnu.version_r + Type: SHT_GNU_verneed + Flags: [ SHF_ALLOC ] + Link: .dynstr + AddressAlign: 0x0510 + VersionNeeds: + - Version: 2 + File: 0x01 # libfoo.so.0 + Auxiliaries: + - Hash: 0x06 + Name: 0x19 # GLIBFOO_0.0.0 + Flags: 0x00 + Other: 0x00 + - Version: 1 + File: 0x0d # libbar.so.0 + Auxiliaries: + - Hash: 0x012345 + Name: 0x27 # GLIBBAR_0.0.0 + Flags: 0x01 + Other: 0x01 + - Hash: 0x054321 + Name: 0x19 # GLIBFOO_0.0.0 + Flags: 0x02 + Other: 0x02 + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_WRITE, SHF_ALLOC ] + Link: .dynstr + Content: 0100000000000000010000000000000001000000000000000d000000000000000C00000000000000A0060000000000000D000000000000002409000000000000FDFFFF6F000000000200000000000000FFFFFF6F000000000200000000000000FEFFFF6F0000000010050000000000000000000000000000000000000000000000000000000000000000000000000000 +ProgramHeaders: + - Type: PT_DYNAMIC + Flags: [ PF_W, PF_R ] + VAddr: 0xAAAA1000 + PAddr: 0xFFFF1000 + Sections: + - Section: .dynamic Index: tools/yaml2obj/yaml2elf.cpp =================================================================== --- tools/yaml2obj/yaml2elf.cpp +++ tools/yaml2obj/yaml2elf.cpp @@ -158,6 +158,12 @@ bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::Group &Group, ContiguousBlobAccumulator &CBA); bool writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::VersionDefSection &Section, + ContiguousBlobAccumulator &CBA); + bool writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::VersionNeedSection &Section, + ContiguousBlobAccumulator &CBA); + bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::MipsABIFlags &Section, ContiguousBlobAccumulator &CBA); bool hasDynamicSymbols() const; @@ -226,6 +232,16 @@ } } +static bool checkSectionIndex(NameToIdxMap &SX2I, StringRef SecName, + StringRef SecField, unsigned &Index) { + if (SX2I.lookup(SecField, Index) && !to_integer(SecField, Index)) { + WithColor::error() << "Unknown section referenced: '" << SecField + << "' at YAML section '" << SecName << "'.\n"; + return false; + } + return true; +} + template bool ELFState::initSectionHeaders(std::vector &SHeaders, ContiguousBlobAccumulator &CBA) { @@ -245,38 +261,27 @@ if (!Sec->Link.empty()) { unsigned Index; - if (SN2I.lookup(Sec->Link, Index) && !to_integer(Sec->Link, Index)) { - WithColor::error() << "Unknown section referenced: '" << Sec->Link - << "' at YAML section '" << Sec->Name << "'.\n"; + if (!checkSectionIndex(SN2I, Sec->Name, Sec->Link, Index)) return false; - } SHeader.sh_link = Index; } - if (auto S = dyn_cast(Sec.get())) + 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(); - unsigned Index; - if (SN2I.lookup(S->Info, Index) && !to_integer(S->Info, Index)) { - WithColor::error() << "Unknown section referenced: '" << S->Info - << "' at YAML section '" << S->Name << "'.\n"; + if (!checkSectionIndex(SN2I, S->Name, S->Info, Index)) return false; - } SHeader.sh_info = Index; - if (!writeSectionContent(SHeader, *S, CBA)) return false; } else if (auto S = dyn_cast(Sec.get())) { unsigned SymIdx; - if (SymN2I.lookup(S->Info, SymIdx) && !to_integer(S->Info, SymIdx)) { - WithColor::error() << "Unknown symbol referenced: '" << S->Info - << "' at YAML section '" << S->Name << "'.\n"; + if (!checkSectionIndex(SymN2I, S->Name, S->Info, SymIdx)) return false; - } SHeader.sh_info = SymIdx; if (!writeSectionContent(SHeader, *S, CBA)) return false; @@ -289,6 +294,12 @@ // SHT_NOBITS section does not have content // so just to setup the section offset. CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + } else if (auto S = dyn_cast(Sec.get())) { + if (!writeSectionContent(SHeader, *S, CBA)) + return false; + } else if (auto S = dyn_cast(Sec.get())) { + if (!writeSectionContent(SHeader, *S, CBA)) + return false; } else llvm_unreachable("Unknown section type"); @@ -535,20 +546,119 @@ unsigned int sectionIndex = 0; if (member.sectionNameOrType == "GRP_COMDAT") sectionIndex = llvm::ELF::GRP_COMDAT; - else if (SN2I.lookup(member.sectionNameOrType, sectionIndex) && - !to_integer(member.sectionNameOrType, sectionIndex)) { - WithColor::error() << "Unknown section referenced: '" - << member.sectionNameOrType << "' at YAML section' " - << Section.Name << "\n"; + else if (!checkSectionIndex(SN2I, Section.Name, member.sectionNameOrType, + sectionIndex)) return false; - } SIdx = sectionIndex; + OS.write((const char *)&SIdx, sizeof(SIdx)); } return true; } template +bool ELFState::writeSectionContent( + Elf_Shdr &SHeader, const ELFYAML::VersionDefSection &Section, + ContiguousBlobAccumulator &CBA) { + assert(Section.Type == llvm::ELF::SHT_GNU_verdef && + "Section type is not SHT_GNU_verdef"); + + typedef typename ELFT::Verdef Elf_Verdef; + typedef typename ELFT::Verdaux Elf_Verdaux; + + uint64_t BlobSize = 0; + SHeader.sh_info = Section.VersionDefs.size(); + auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + + for (auto VDefIt = Section.VersionDefs.begin(); + VDefIt != Section.VersionDefs.end(); ++VDefIt) { + Elf_Verdef VDef; + zero(VDef); + + VDef.vd_version = VDefIt->Revision; + VDef.vd_flags = VDefIt->Flags; + VDef.vd_ndx = VDefIt->Index; + VDef.vd_hash = VDefIt->Hash; + VDef.vd_aux = sizeof(Elf_Verdef); + VDef.vd_cnt = 1 + VDefIt->Parents.size(); + VDef.vd_next = (VDefIt != Section.VersionDefs.end() - 1) + ? sizeof(Elf_Verdef) + VDef.vd_cnt * sizeof(Elf_Verdaux) + : 0; + BlobSize += sizeof(Elf_Verdef); + OS.write((const char *)&VDef, sizeof(Elf_Verdef)); + + Elf_Verdaux VDefName; + zero(VDefName); + VDefName.vda_name = VDefIt->Name; + VDefName.vda_next = (VDefIt->Parents.size() != 0) ? sizeof(Elf_Verdaux) : 0; + BlobSize += sizeof(Elf_Verdaux); + OS.write((const char *)&VDefName, sizeof(Elf_Verdaux)); + + for (auto VDefAuxIt = VDefIt->Parents.begin(); + VDefAuxIt != VDefIt->Parents.end(); ++VDefAuxIt) { + Elf_Verdaux VDefAux; + zero(VDefAux); + VDefAux.vda_name = VDefAuxIt->Name; + VDefAux.vda_next = + (VDefAuxIt != VDefIt->Parents.end() - 1) ? sizeof(Elf_Verdaux) : 0; + BlobSize += sizeof(Elf_Verdaux); + OS.write((const char *)&VDefAux, sizeof(Elf_Verdaux)); + } + } + SHeader.sh_size = BlobSize; + return true; +} + +template +bool ELFState::writeSectionContent( + Elf_Shdr &SHeader, const ELFYAML::VersionNeedSection &Section, + ContiguousBlobAccumulator &CBA) { + assert(Section.Type == llvm::ELF::SHT_GNU_verneed && + "Section type is not SHT_GNU_verneed"); + + typedef typename ELFT::Verneed Elf_Verneed; + typedef typename ELFT::Vernaux Elf_Vernaux; + + uint64_t BlobSize = 0; + SHeader.sh_info = Section.VersionNeeds.size(); + auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); + + for (auto VNeedIt = Section.VersionNeeds.begin(); + VNeedIt != Section.VersionNeeds.end(); ++VNeedIt) { + Elf_Verneed VNeed; + zero(VNeed); + + VNeed.vn_version = VNeedIt->Version; + VNeed.vn_cnt = VNeedIt->Auxiliaries.size(); + VNeed.vn_file = VNeedIt->File; + VNeed.vn_aux = sizeof(Elf_Verneed); + VNeed.vn_next = + (VNeedIt != Section.VersionNeeds.end() - 1) + ? sizeof(Elf_Verneed) + VNeed.vn_cnt * sizeof(Elf_Vernaux) + : 0; + BlobSize += sizeof(Elf_Verneed); + OS.write((const char *)&VNeed, sizeof(VNeed)); + + for (auto VNeedAuxIt = VNeedIt->Auxiliaries.begin(); + VNeedAuxIt != VNeedIt->Auxiliaries.end(); ++VNeedAuxIt) { + Elf_Vernaux VNeedAux; + zero(VNeedAux); + VNeedAux.vna_hash = VNeedAuxIt->Hash; + VNeedAux.vna_flags = VNeedAuxIt->Flags; + VNeedAux.vna_other = VNeedAuxIt->Other; + VNeedAux.vna_name = VNeedAuxIt->Name; + VNeedAux.vna_next = (VNeedAuxIt != VNeedIt->Auxiliaries.end() - 1) + ? sizeof(Elf_Vernaux) + : 0; + BlobSize += sizeof(Elf_Vernaux); + OS.write((const char *)&VNeedAux, sizeof(Elf_Vernaux)); + } + } + SHeader.sh_size = BlobSize; + return true; +} + +template bool ELFState::writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::MipsABIFlags &Section, ContiguousBlobAccumulator &CBA) {