diff --git a/include/llvm/Object/ELFYAML.h b/include/llvm/Object/ELFYAML.h index 04ba0a66225..d6ce525248c 100644 --- a/include/llvm/Object/ELFYAML.h +++ b/include/llvm/Object/ELFYAML.h @@ -49,6 +49,9 @@ struct FileHeader { ELF_EM Machine; llvm::yaml::Hex64 Entry; }; +struct Symbol { + StringRef Name; +}; struct Section { StringRef Name; ELF_SHT Type; @@ -57,6 +60,8 @@ struct Section { object::yaml::BinaryRef Content; StringRef Link; llvm::yaml::Hex64 AddressAlign; + // For SHT_SYMTAB; should be empty otherwise. + std::vector Symbols; }; struct Object { FileHeader Header; @@ -67,6 +72,7 @@ struct Object { } // end namespace llvm LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Section) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol) namespace llvm { namespace yaml { @@ -106,6 +112,11 @@ struct MappingTraits { static void mapping(IO &IO, ELFYAML::FileHeader &FileHdr); }; +template <> +struct MappingTraits { + static void mapping(IO &IO, ELFYAML::Symbol &Symbol); +}; + template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::Section &Section); diff --git a/lib/Object/ELFYAML.cpp b/lib/Object/ELFYAML.cpp index e0e95bee934..32a759dc0b3 100644 --- a/lib/Object/ELFYAML.cpp +++ b/lib/Object/ELFYAML.cpp @@ -260,6 +260,10 @@ void MappingTraits::mapping(IO &IO, IO.mapOptional("Entry", FileHdr.Entry, Hex64(0)); } +void MappingTraits::mapping(IO &IO, ELFYAML::Symbol &Symbol) { + IO.mapOptional("Name", Symbol.Name, StringRef()); +} + void MappingTraits::mapping(IO &IO, ELFYAML::Section &Section) { IO.mapOptional("Name", Section.Name, StringRef()); @@ -269,6 +273,12 @@ void MappingTraits::mapping(IO &IO, IO.mapOptional("Content", Section.Content); IO.mapOptional("Link", Section.Link); IO.mapOptional("AddressAlign", Section.AddressAlign, Hex64(0)); + // TODO: Error if `Type` is SHT_SYMTAB and this is not present, or if + // `Type` is *not* SHT_SYMTAB and this *is* present. (By SHT_SYMTAB I + // also mean SHT_DYNSYM, but for simplicity right now we just do + // SHT_SYMTAB). Want to be able to share the predicate with consumers of + // this structure. + IO.mapOptional("Symbols", Section.Symbols); } void MappingTraits::mapping(IO &IO, ELFYAML::Object &Object) { diff --git a/test/Object/yaml2obj-elf-symbol-basic.yaml b/test/Object/yaml2obj-elf-symbol-basic.yaml new file mode 100644 index 00000000000..c33d3853041 --- /dev/null +++ b/test/Object/yaml2obj-elf-symbol-basic.yaml @@ -0,0 +1,22 @@ +# RUN: yaml2obj -format=elf %s | llvm-readobj -symbols - | FileCheck %s +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + - Name: .symtab + Type: SHT_SYMTAB + Symbols: + - Name: "" # TODO: Add STN_UNDEF automatically. + - Name: main + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: (0) +# CHECK: Symbol { +# CHECK-NEXT: Name: main diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index b83dd1d1a35..bebcbde256f 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -133,6 +133,42 @@ static void createStringTableSectionHeader(Elf_Shdr &SHeader, SHeader.sh_addralign = 1; } +// FIXME: This function is hideous. Between the sheer number of parameters +// and the hideous ELF typenames, it's just a travesty. Factor the ELF +// output into a class (templated on ELFT) and share some typedefs. +template +static void handleSymtabSectionHeader( + const ELFYAML::Section &Sec, + const typename object::ELFObjectFile::Elf_Ehdr &Header, + typename object::ELFObjectFile::Elf_Shdr &SHeader, + StringTableBuilder &StrTab, ContiguousBlobAccumulator &CBA, + unsigned DotStrtabSecNo) { + + typedef typename object::ELFObjectFile::Elf_Sym Elf_Sym; + // TODO: Ensure that a manually specified `Link` field is diagnosed as an + // error for SHT_SYMTAB. + SHeader.sh_link = DotStrtabSecNo; + // TODO: Once we handle symbol binding, this should be one greater than + // symbol table index of the last local symbol. + SHeader.sh_info = 0; + SHeader.sh_entsize = sizeof(Elf_Sym); + + std::vector Syms; + // FIXME: Ensure STN_UNDEF entry is present. + for (unsigned i = 0, e = Sec.Symbols.size(); i != e; ++i) { + const ELFYAML::Symbol &Sym = Sec.Symbols[i]; + Elf_Sym Symbol; + zero(Symbol); + if (!Sym.Name.empty()) + Symbol.st_name = StrTab.addString(Sym.Name); + Syms.push_back(Symbol); + } + + SHeader.sh_offset = CBA.currentOffset(); + SHeader.sh_size = vectorDataSize(Syms); + writeVectorData(CBA.getOS(), Syms); +} + template static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { using namespace llvm::ELF; @@ -181,6 +217,7 @@ static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { Header.e_shnum = Sections.size() + 2; // Place section header string table last. Header.e_shstrndx = Sections.size() + 1; + const unsigned DotStrtabSecNo = Sections.size(); SectionNameToIdxMap SN2I; for (unsigned i = 0, e = Sections.size(); i != e; ++i) { @@ -202,6 +239,7 @@ static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { Header.e_ehsize + Header.e_shentsize * Header.e_shnum; ContiguousBlobAccumulator CBA(SectionContentBeginOffset, Buf); std::vector SHeaders; + StringTableBuilder DotStrTab; for (unsigned i = 0, e = Sections.size(); i != e; ++i) { const ELFYAML::Section &Sec = Sections[i]; Elf_Shdr SHeader; @@ -227,11 +265,14 @@ static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { SHeader.sh_info = 0; SHeader.sh_addralign = Sec.AddressAlign; SHeader.sh_entsize = 0; + // XXX: Really ugly right now. Need to put common state into a class. + if (Sec.Type == ELFYAML::ELF_SHT(SHT_SYMTAB)) + handleSymtabSectionHeader(Sec, Header, SHeader, DotStrTab, CBA, + DotStrtabSecNo); SHeaders.push_back(SHeader); } - // .strtab string table header. Currently emitted empty. - StringTableBuilder DotStrTab; + // .strtab string table header. Elf_Shdr DotStrTabSHeader; zero(DotStrTabSHeader); DotStrTabSHeader.sh_name = SHStrTab.addString(StringRef(".strtab"));