"git@repo.hca.bsc.es:rferrer/llvm-epi-0.8.git" did not exist on "c4f7bfa0812136149e76581a79820f585d3ff2cd"
Newer
Older
//===- yaml2elf - Convert YAML to a ELF object file -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief The ELF component of yaml2obj.
///
//===----------------------------------------------------------------------===//
#include "yaml2obj.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ELFYAML.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
// There is similar code in yaml2coff, but with some slight COFF-specific
// variations like different initial state. Might be able to deduplicate
// some day, but also want to make sure that the Mach-O use case is served.
//
// This class has a deliberately small interface, since a lot of
// implementation variation is possible.
//
// TODO: Use an ordered container with a suffix-based comparison in order
// to deduplicate suffixes. std::map<> with a custom comparator is likely
// to be the simplest implementation, but a suffix trie could be more
// suitable for the job.
class StringTableBuilder {
/// \brief Indices of strings currently present in `Buf`.
StringMap<unsigned> StringIndices;
/// \brief The contents of the string table as we build it.
std::string Buf;
public:
StringTableBuilder() {
Buf.push_back('\0');
}
/// \returns Index of string in string table.
unsigned addString(StringRef S) {
StringMapEntry<unsigned> &Entry = StringIndices.GetOrCreateValue(S);
unsigned &I = Entry.getValue();
if (I != 0)
return I;
I = Buf.size();
Buf.append(S.begin(), S.end());
Buf.push_back('\0');
return I;
}
size_t size() const {
return Buf.size();
}
void writeToStream(raw_ostream &OS) {
OS.write(Buf.data(), Buf.size());
}
};
} // end anonymous namespace
// This class is used to build up a contiguous binary blob while keeping
// track of an offset in the output (which notionally begins at
// `InitialOffset`).
class ContiguousBlobAccumulator {
const uint64_t InitialOffset;
raw_svector_ostream OS;
public:
ContiguousBlobAccumulator(uint64_t InitialOffset_, SmallVectorImpl<char> &Buf)
: InitialOffset(InitialOffset_), OS(Buf) {}
raw_ostream &getOS() { return OS; }
uint64_t currentOffset() const { return InitialOffset + OS.tell(); }
void writeBlobToStream(raw_ostream &Out) { Out << OS.str(); }
};
} // end anonymous namespace
// Used to keep track of section names, so that in the YAML file sections
// can be referenced by name instead of by index.
class SectionNameToIdxMap {
StringMap<int> Map;
public:
/// \returns true if name is already present in the map.
bool addName(StringRef SecName, unsigned i) {
StringMapEntry<int> &Entry = Map.GetOrCreateValue(SecName, -1);
if (Entry.getValue() != -1)
return true;
Entry.setValue((int)i);
return false;
}
/// \returns true if name is not present in the map
bool lookupSection(StringRef SecName, unsigned &Idx) const {
StringMap<int>::const_iterator I = Map.find(SecName);
if (I == Map.end())
return true;
Idx = I->getValue();
return false;
}
};
} // end anonymous namespace
template <class T>
static size_t vectorDataSize(const std::vector<T> &Vec) {
return Vec.size() * sizeof(T);
}
template <class T>
static void writeVectorData(raw_ostream &OS, const std::vector<T> &Vec) {
OS.write((const char *)Vec.data(), vectorDataSize(Vec));
}
template <class T>
static void zero(T &Obj) {
memset(&Obj, 0, sizeof(Obj));
}
/// \brief Create a string table in `SHeader`, which we assume is already
/// zero'd.
template <class Elf_Shdr>
static void createStringTableSectionHeader(Elf_Shdr &SHeader,
StringTableBuilder &STB,
ContiguousBlobAccumulator &CBA) {
SHeader.sh_type = ELF::SHT_STRTAB;
SHeader.sh_offset = CBA.currentOffset();
SHeader.sh_size = STB.size();
STB.writeToStream(CBA.getOS());
SHeader.sh_addralign = 1;
}
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// 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 <class ELFT>
static void handleSymtabSectionHeader(
const ELFYAML::Section &Sec,
const typename object::ELFObjectFile<ELFT>::Elf_Ehdr &Header,
typename object::ELFObjectFile<ELFT>::Elf_Shdr &SHeader,
StringTableBuilder &StrTab, ContiguousBlobAccumulator &CBA,
unsigned DotStrtabSecNo) {
typedef typename object::ELFObjectFile<ELFT>::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<Elf_Sym> 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);
}
static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) {
using namespace llvm::ELF;
using namespace llvm::object;
typedef typename ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr;
typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
const ELFYAML::FileHeader &Hdr = Doc.Header;
Elf_Ehdr Header;
zero(Header);
Header.e_ident[EI_MAG0] = 0x7f;
Header.e_ident[EI_MAG1] = 'E';
Header.e_ident[EI_MAG2] = 'L';
Header.e_ident[EI_MAG3] = 'F';
Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
bool IsLittleEndian = ELFT::TargetEndianness == support::little;
Header.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
Header.e_ident[EI_VERSION] = EV_CURRENT;
// TODO: Implement ELF_ELFOSABI enum.
Header.e_ident[EI_OSABI] = ELFOSABI_NONE;
// TODO: Implement ELF_ABIVERSION enum.
Header.e_ident[EI_ABIVERSION] = 0;
Header.e_type = Hdr.Type;
Header.e_machine = Hdr.Machine;
Header.e_version = EV_CURRENT;
Header.e_entry = Hdr.Entry;
Header.e_ehsize = sizeof(Elf_Ehdr);
// TODO: Flesh out section header support.
// TODO: Program headers.
Header.e_shentsize = sizeof(Elf_Shdr);
// Immediately following the ELF header.
Header.e_shoff = sizeof(Header);
std::vector<ELFYAML::Section> Sections = Doc.Sections;
if (Sections.empty() || Sections.front().Type != SHT_NULL) {
ELFYAML::Section S;
S.Type = SHT_NULL;
zero(S.Flags);
zero(S.Address);
zero(S.AddressAlign);
Sections.insert(Sections.begin(), S);
}
// "+ 2" for string table and section header string table.
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) {
StringRef Name = Sections[i].Name;
if (Name.empty())
continue;
if (SN2I.addName(Name, i)) {
errs() << "error: Repeated section name: '" << Name
<< "' at YAML section number " << i << ".\n";
StringTableBuilder SHStrTab;
SmallVector<char, 128> Buf;
// XXX: This offset is tightly coupled with the order that we write
// things to `OS`.
const size_t SectionContentBeginOffset =
Header.e_ehsize + Header.e_shentsize * Header.e_shnum;
ContiguousBlobAccumulator CBA(SectionContentBeginOffset, Buf);
StringTableBuilder DotStrTab;
for (unsigned i = 0, e = Sections.size(); i != e; ++i) {
const ELFYAML::Section &Sec = Sections[i];
Elf_Shdr SHeader;
zero(SHeader);
SHeader.sh_name = SHStrTab.addString(Sec.Name);
SHeader.sh_type = Sec.Type;
SHeader.sh_flags = Sec.Flags;
SHeader.sh_offset = CBA.currentOffset();
SHeader.sh_size = Sec.Content.binary_size();
Sec.Content.writeAsBinary(CBA.getOS());
if (!Sec.Link.empty()) {
unsigned Index;
if (SN2I.lookupSection(Sec.Link, Index)) {
errs() << "error: Unknown section referenced: '" << Sec.Link
<< "' at YAML section number " << i << ".\n";
}
SHeader.sh_link = Index;
}
SHeader.sh_addralign = Sec.AddressAlign;
// XXX: Really ugly right now. Need to put common state into a class.
if (Sec.Type == ELFYAML::ELF_SHT(SHT_SYMTAB))
handleSymtabSectionHeader<ELFT>(Sec, Header, SHeader, DotStrTab, CBA,
DotStrtabSecNo);
// .strtab string table header.
Elf_Shdr DotStrTabSHeader;
zero(DotStrTabSHeader);
DotStrTabSHeader.sh_name = SHStrTab.addString(StringRef(".strtab"));
createStringTableSectionHeader(DotStrTabSHeader, DotStrTab, CBA);
// Section header string table header.
Elf_Shdr SHStrTabSHeader;
zero(SHStrTabSHeader);
createStringTableSectionHeader(SHStrTabSHeader, SHStrTab, CBA);
OS.write((const char *)&Header, sizeof(Header));
OS.write((const char *)&DotStrTabSHeader, sizeof(DotStrTabSHeader));
OS.write((const char *)&SHStrTabSHeader, sizeof(SHStrTabSHeader));
CBA.writeBlobToStream(OS);
}
int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) {
yaml::Input YIn(Buf->getBuffer());
ELFYAML::Object Doc;
YIn >> Doc;
if (YIn.error()) {
errs() << "yaml2obj: Failed to parse YAML file!\n";
return 1;
}
if (Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64)) {
if (Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB))
return writeELF<object::ELFType<support::little, 8, true> >(outs(), Doc);
return writeELF<object::ELFType<support::big, 8, true> >(outs(), Doc);
} else {
if (Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB))
return writeELF<object::ELFType<support::little, 4, false> >(outs(), Doc);
return writeELF<object::ELFType<support::big, 4, false> >(outs(), Doc);