llvm-project/lld/ELF/ELFCreator.cpp

127 lines
3.8 KiB
C++

//===- ELFCreator.cpp -----------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a class to create an ELF file in memory. This is
// supposed to be used for "-format binary" option.
//
//===----------------------------------------------------------------------===//
#include "ELFCreator.h"
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace lld;
using namespace lld::elf;
template <class ELFT>
ELFCreator<ELFT>::ELFCreator(std::uint16_t Type, std::uint16_t Machine) {
std::memcpy(Header.e_ident, "\177ELF", 4);
Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
Header.e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
? ELFDATA2LSB
: ELFDATA2MSB;
Header.e_ident[EI_VERSION] = EV_CURRENT;
Header.e_ident[EI_OSABI] = 0;
Header.e_type = Type;
Header.e_machine = Machine;
Header.e_version = EV_CURRENT;
Header.e_entry = 0;
Header.e_phoff = 0;
Header.e_flags = 0;
Header.e_ehsize = sizeof(Elf_Ehdr);
Header.e_phnum = 0;
Header.e_shentsize = sizeof(Elf_Shdr);
Header.e_shstrndx = 1;
ShStrTab = addSection(".shstrtab").Header;
ShStrTab->sh_type = SHT_STRTAB;
ShStrTab->sh_addralign = 1;
StrTab = addSection(".strtab").Header;
StrTab->sh_type = SHT_STRTAB;
StrTab->sh_addralign = 1;
SymTab = addSection(".symtab").Header;
SymTab->sh_type = SHT_SYMTAB;
SymTab->sh_link = 2;
SymTab->sh_info = 1;
SymTab->sh_addralign = sizeof(uintX_t);
SymTab->sh_entsize = sizeof(Elf_Sym);
}
template <class ELFT>
typename ELFCreator<ELFT>::Section
ELFCreator<ELFT>::addSection(StringRef Name) {
std::size_t NameOff = SecHdrStrTabBuilder.add(Name);
auto Shdr = new (Alloc) Elf_Shdr{};
Shdr->sh_name = NameOff;
Sections.push_back(Shdr);
return {Shdr, Sections.size()};
}
template <class ELFT>
typename ELFCreator<ELFT>::Symbol ELFCreator<ELFT>::addSymbol(StringRef Name) {
std::size_t NameOff = StrTabBuilder.add(Name);
auto Sym = new (Alloc) Elf_Sym{};
Sym->st_name = NameOff;
StaticSymbols.push_back(Sym);
return {Sym, StaticSymbols.size()};
}
template <class ELFT> std::size_t ELFCreator<ELFT>::layout() {
SecHdrStrTabBuilder.finalizeInOrder();
ShStrTab->sh_size = SecHdrStrTabBuilder.getSize();
StrTabBuilder.finalizeInOrder();
StrTab->sh_size = StrTabBuilder.getSize();
SymTab->sh_size = (StaticSymbols.size() + 1) * sizeof(Elf_Sym);
uintX_t Offset = sizeof(Elf_Ehdr);
for (Elf_Shdr *Sec : Sections) {
Offset = alignTo(Offset, Sec->sh_addralign);
Sec->sh_offset = Offset;
Offset += Sec->sh_size;
}
Offset = alignTo(Offset, sizeof(uintX_t));
Header.e_shoff = Offset;
Offset += (Sections.size() + 1) * sizeof(Elf_Shdr);
Header.e_shnum = Sections.size() + 1;
return Offset;
}
template <class ELFT> void ELFCreator<ELFT>::write(uint8_t *Out) {
std::memcpy(Out, &Header, sizeof(Elf_Ehdr));
std::copy(SecHdrStrTabBuilder.data().begin(),
SecHdrStrTabBuilder.data().end(), Out + ShStrTab->sh_offset);
std::copy(StrTabBuilder.data().begin(), StrTabBuilder.data().end(),
Out + StrTab->sh_offset);
Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Out + SymTab->sh_offset);
// Skip null.
++Sym;
for (Elf_Sym *S : StaticSymbols)
*Sym++ = *S;
Elf_Shdr *Shdr = reinterpret_cast<Elf_Shdr *>(Out + Header.e_shoff);
// Skip null.
++Shdr;
for (Elf_Shdr *S : Sections)
*Shdr++ = *S;
}
template class elf::ELFCreator<ELF32LE>;
template class elf::ELFCreator<ELF32BE>;
template class elf::ELFCreator<ELF64LE>;
template class elf::ELFCreator<ELF64BE>;