clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
595 lines
19 KiB
C++
595 lines
19 KiB
C++
//===------------ MachOBuilder.h -- Build MachO Objects ---------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Build MachO object files for interaction with the ObjC runtime and debugger.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_EXECUTIONENGINE_ORC_MACHOBUILDER_H
|
|
#define LLVM_EXECUTIONENGINE_ORC_MACHOBUILDER_H
|
|
|
|
#include "llvm/BinaryFormat/MachO.h"
|
|
#include "llvm/Support/Endian.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
#include <list>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
namespace llvm {
|
|
namespace orc {
|
|
|
|
template <typename MachOStruct>
|
|
size_t writeMachOStruct(MutableArrayRef<char> Buf, size_t Offset, MachOStruct S,
|
|
bool SwapStruct) {
|
|
if (SwapStruct)
|
|
MachO::swapStruct(S);
|
|
assert(Offset + sizeof(MachOStruct) <= Buf.size() && "Buffer overflow");
|
|
memcpy(&Buf[Offset], reinterpret_cast<const char *>(&S), sizeof(MachOStruct));
|
|
return Offset + sizeof(MachOStruct);
|
|
}
|
|
|
|
/// Base type for MachOBuilder load command wrappers.
|
|
struct MachOBuilderLoadCommandBase {
|
|
virtual ~MachOBuilderLoadCommandBase() {}
|
|
virtual size_t size() const = 0;
|
|
virtual size_t write(MutableArrayRef<char> Buf, size_t Offset,
|
|
bool SwapStruct) = 0;
|
|
};
|
|
|
|
/// MachOBuilder load command wrapper type.
|
|
template <MachO::LoadCommandType LCType> struct MachOBuilderLoadCommandImplBase;
|
|
|
|
#define HANDLE_LOAD_COMMAND(Name, Value, LCStruct) \
|
|
template <> \
|
|
struct MachOBuilderLoadCommandImplBase<MachO::Name> \
|
|
: public MachO::LCStruct, public MachOBuilderLoadCommandBase { \
|
|
using CmdStruct = LCStruct; \
|
|
MachOBuilderLoadCommandImplBase() { \
|
|
memset(&rawStruct(), 0, sizeof(CmdStruct)); \
|
|
cmd = Value; \
|
|
cmdsize = sizeof(CmdStruct); \
|
|
} \
|
|
template <typename... ArgTs> \
|
|
MachOBuilderLoadCommandImplBase(ArgTs &&...Args) \
|
|
: CmdStruct{Value, sizeof(CmdStruct), std::forward<ArgTs>(Args)...} {} \
|
|
CmdStruct &rawStruct() { return static_cast<CmdStruct &>(*this); } \
|
|
size_t size() const override { return cmdsize; } \
|
|
size_t write(MutableArrayRef<char> Buf, size_t Offset, \
|
|
bool SwapStruct) override { \
|
|
return writeMachOStruct(Buf, Offset, rawStruct(), SwapStruct); \
|
|
} \
|
|
};
|
|
|
|
#include "llvm/BinaryFormat/MachO.def"
|
|
|
|
#undef HANDLE_LOAD_COMMAND
|
|
|
|
template <MachO::LoadCommandType LCType>
|
|
struct MachOBuilderLoadCommand
|
|
: public MachOBuilderLoadCommandImplBase<LCType> {
|
|
public:
|
|
MachOBuilderLoadCommand() = default;
|
|
|
|
template <typename... ArgTs>
|
|
MachOBuilderLoadCommand(ArgTs &&...Args)
|
|
: MachOBuilderLoadCommandImplBase<LCType>(std::forward<ArgTs>(Args)...) {}
|
|
};
|
|
|
|
template <>
|
|
struct MachOBuilderLoadCommand<MachO::LC_ID_DYLIB>
|
|
: public MachOBuilderLoadCommandImplBase<MachO::LC_ID_DYLIB> {
|
|
|
|
MachOBuilderLoadCommand(std::string Name, uint32_t Timestamp,
|
|
uint32_t CurrentVersion,
|
|
uint32_t CompatibilityVersion)
|
|
: MachOBuilderLoadCommandImplBase(
|
|
MachO::dylib{24, Timestamp, CurrentVersion, CompatibilityVersion}),
|
|
Name(std::move(Name)) {
|
|
cmdsize += (this->Name.size() + 1 + 3) & ~0x3;
|
|
}
|
|
|
|
size_t write(MutableArrayRef<char> Buf, size_t Offset,
|
|
bool SwapStruct) override {
|
|
Offset = writeMachOStruct(Buf, Offset, rawStruct(), SwapStruct);
|
|
strcpy(Buf.data() + Offset, Name.data());
|
|
return Offset + ((Name.size() + 1 + 3) & ~0x3);
|
|
}
|
|
|
|
std::string Name;
|
|
};
|
|
|
|
template <>
|
|
struct MachOBuilderLoadCommand<MachO::LC_LOAD_DYLIB>
|
|
: public MachOBuilderLoadCommandImplBase<MachO::LC_LOAD_DYLIB> {
|
|
|
|
MachOBuilderLoadCommand(std::string Name, uint32_t Timestamp,
|
|
uint32_t CurrentVersion,
|
|
uint32_t CompatibilityVersion)
|
|
: MachOBuilderLoadCommandImplBase(
|
|
MachO::dylib{24, Timestamp, CurrentVersion, CompatibilityVersion}),
|
|
Name(std::move(Name)) {
|
|
cmdsize += (this->Name.size() + 1 + 3) & ~0x3;
|
|
}
|
|
|
|
size_t write(MutableArrayRef<char> Buf, size_t Offset,
|
|
bool SwapStruct) override {
|
|
Offset = writeMachOStruct(Buf, Offset, rawStruct(), SwapStruct);
|
|
strcpy(Buf.data() + Offset, Name.data());
|
|
return Offset + ((Name.size() + 1 + 3) & ~0x3);
|
|
}
|
|
|
|
std::string Name;
|
|
};
|
|
|
|
template <>
|
|
struct MachOBuilderLoadCommand<MachO::LC_RPATH>
|
|
: public MachOBuilderLoadCommandImplBase<MachO::LC_RPATH> {
|
|
MachOBuilderLoadCommand(std::string Path)
|
|
: MachOBuilderLoadCommandImplBase(12u), Path(std::move(Path)) {
|
|
cmdsize += (this->Path.size() + 1 + 3) & ~0x3;
|
|
}
|
|
|
|
size_t write(MutableArrayRef<char> Buf, size_t Offset,
|
|
bool SwapStruct) override {
|
|
Offset = writeMachOStruct(Buf, Offset, rawStruct(), SwapStruct);
|
|
strcpy(Buf.data() + Offset, Path.data());
|
|
return Offset + ((Path.size() + 1 + 3) & ~0x3);
|
|
}
|
|
|
|
std::string Path;
|
|
};
|
|
|
|
// Builds MachO objects.
|
|
template <typename MachOTraits> class MachOBuilder {
|
|
private:
|
|
struct SymbolContainer {
|
|
size_t SymbolIndexBase = 0;
|
|
std::vector<typename MachOTraits::NList> Symbols;
|
|
};
|
|
|
|
struct StringTableEntry {
|
|
StringRef S;
|
|
size_t Offset;
|
|
};
|
|
|
|
using StringTable = std::vector<StringTableEntry>;
|
|
|
|
static bool swapStruct() {
|
|
return MachOTraits::Endianness != llvm::endianness::native;
|
|
}
|
|
|
|
public:
|
|
using StringId = size_t;
|
|
|
|
struct Section;
|
|
|
|
// Points to either an nlist entry (as a (symbol-container, index) pair), or
|
|
// a section.
|
|
class RelocTarget {
|
|
public:
|
|
RelocTarget(const Section &S) : S(&S), Idx(~0U) {}
|
|
RelocTarget(SymbolContainer &SC, size_t Idx) : SC(&SC), Idx(Idx) {}
|
|
|
|
bool isSymbol() { return Idx != ~0U; }
|
|
|
|
uint32_t getSymbolNum() {
|
|
assert(isSymbol() && "Target is not a symbol");
|
|
return SC->SymbolIndexBase + Idx;
|
|
}
|
|
|
|
uint32_t getSectionId() {
|
|
assert(!isSymbol() && "Target is not a section");
|
|
return S->SectionNumber;
|
|
}
|
|
|
|
typename MachOTraits::NList &nlist() {
|
|
assert(isSymbol() && "Target is not a symbol");
|
|
return SC->Symbols[Idx];
|
|
}
|
|
|
|
private:
|
|
union {
|
|
const Section *S;
|
|
SymbolContainer *SC;
|
|
};
|
|
size_t Idx;
|
|
};
|
|
|
|
struct Reloc : public MachO::relocation_info {
|
|
RelocTarget Target;
|
|
|
|
Reloc(int32_t Offset, RelocTarget Target, bool PCRel, unsigned Length,
|
|
unsigned Type)
|
|
: Target(Target) {
|
|
assert(Type < 16 && "Relocation type out of range");
|
|
r_address = Offset; // Will slide to account for sec addr during layout
|
|
r_symbolnum = 0;
|
|
r_pcrel = PCRel;
|
|
r_length = Length;
|
|
r_extern = Target.isSymbol();
|
|
r_type = Type;
|
|
}
|
|
|
|
MachO::relocation_info &rawStruct() {
|
|
return static_cast<MachO::relocation_info &>(*this);
|
|
}
|
|
};
|
|
|
|
struct SectionContent {
|
|
const char *Data = nullptr;
|
|
size_t Size = 0;
|
|
};
|
|
|
|
struct Section : public MachOTraits::Section, public RelocTarget {
|
|
MachOBuilder &Builder;
|
|
SectionContent Content;
|
|
size_t SectionNumber = 0;
|
|
SymbolContainer SC;
|
|
std::vector<Reloc> Relocs;
|
|
|
|
Section(MachOBuilder &Builder, StringRef SecName, StringRef SegName)
|
|
: RelocTarget(*this), Builder(Builder) {
|
|
memset(&rawStruct(), 0, sizeof(typename MachOTraits::Section));
|
|
assert(SecName.size() <= 16 && "SecName too long");
|
|
assert(SegName.size() <= 16 && "SegName too long");
|
|
memcpy(this->sectname, SecName.data(), SecName.size());
|
|
memcpy(this->segname, SegName.data(), SegName.size());
|
|
}
|
|
|
|
RelocTarget addSymbol(int32_t Offset, StringRef Name, uint8_t Type,
|
|
uint16_t Desc) {
|
|
StringId SI = Builder.addString(Name);
|
|
typename MachOTraits::NList Sym;
|
|
Sym.n_strx = SI;
|
|
Sym.n_type = Type | MachO::N_SECT;
|
|
Sym.n_sect = MachO::NO_SECT; // Will be filled in later.
|
|
Sym.n_desc = Desc;
|
|
Sym.n_value = Offset;
|
|
SC.Symbols.push_back(Sym);
|
|
return {SC, SC.Symbols.size() - 1};
|
|
}
|
|
|
|
void addReloc(int32_t Offset, RelocTarget Target, bool PCRel,
|
|
unsigned Length, unsigned Type) {
|
|
Relocs.push_back({Offset, Target, PCRel, Length, Type});
|
|
}
|
|
|
|
auto &rawStruct() {
|
|
return static_cast<typename MachOTraits::Section &>(*this);
|
|
}
|
|
};
|
|
|
|
struct Segment : public MachOBuilderLoadCommand<MachOTraits::SegmentCmd> {
|
|
MachOBuilder &Builder;
|
|
std::vector<std::unique_ptr<Section>> Sections;
|
|
|
|
Segment(MachOBuilder &Builder, StringRef SegName)
|
|
: MachOBuilderLoadCommand<MachOTraits::SegmentCmd>(), Builder(Builder) {
|
|
assert(SegName.size() <= 16 && "SegName too long");
|
|
memcpy(this->segname, SegName.data(), SegName.size());
|
|
this->maxprot =
|
|
MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
|
|
this->initprot = this->maxprot;
|
|
}
|
|
|
|
Section &addSection(StringRef SecName, StringRef SegName) {
|
|
Sections.push_back(std::make_unique<Section>(Builder, SecName, SegName));
|
|
return *Sections.back();
|
|
}
|
|
|
|
size_t write(MutableArrayRef<char> Buf, size_t Offset,
|
|
bool SwapStruct) override {
|
|
Offset = MachOBuilderLoadCommand<MachOTraits::SegmentCmd>::write(
|
|
Buf, Offset, SwapStruct);
|
|
for (auto &Sec : Sections)
|
|
Offset = writeMachOStruct(Buf, Offset, Sec->rawStruct(), SwapStruct);
|
|
return Offset;
|
|
}
|
|
};
|
|
|
|
MachOBuilder(size_t PageSize) : PageSize(PageSize) {
|
|
memset((char *)&Header, 0, sizeof(Header));
|
|
Header.magic = MachOTraits::Magic;
|
|
}
|
|
|
|
template <MachO::LoadCommandType LCType, typename... ArgTs>
|
|
MachOBuilderLoadCommand<LCType> &addLoadCommand(ArgTs &&...Args) {
|
|
static_assert(LCType != MachOTraits::SegmentCmd,
|
|
"Use addSegment to add segment load command");
|
|
auto LC = std::make_unique<MachOBuilderLoadCommand<LCType>>(
|
|
std::forward<ArgTs>(Args)...);
|
|
auto &Tmp = *LC;
|
|
LoadCommands.push_back(std::move(LC));
|
|
return Tmp;
|
|
}
|
|
|
|
StringId addString(StringRef Str) {
|
|
if (Strings.empty() && !Str.empty())
|
|
addString("");
|
|
return Strings.insert(std::make_pair(Str, Strings.size())).first->second;
|
|
}
|
|
|
|
Segment &addSegment(StringRef SegName) {
|
|
Segments.push_back(Segment(*this, SegName));
|
|
return Segments.back();
|
|
}
|
|
|
|
RelocTarget addSymbol(StringRef Name, uint8_t Type, uint8_t Sect,
|
|
uint16_t Desc, typename MachOTraits::UIntPtr Value) {
|
|
StringId SI = addString(Name);
|
|
typename MachOTraits::NList Sym;
|
|
Sym.n_strx = SI;
|
|
Sym.n_type = Type;
|
|
Sym.n_sect = Sect;
|
|
Sym.n_desc = Desc;
|
|
Sym.n_value = Value;
|
|
SC.Symbols.push_back(Sym);
|
|
return {SC, SC.Symbols.size() - 1};
|
|
}
|
|
|
|
// Call to perform layout on the MachO. Returns the total size of the
|
|
// resulting file.
|
|
// This method will automatically insert some load commands (e.g.
|
|
// LC_SYMTAB) and fill in load command fields.
|
|
size_t layout() {
|
|
|
|
// Build symbol table and add LC_SYMTAB command.
|
|
makeStringTable();
|
|
MachOBuilderLoadCommand<MachOTraits::SymTabCmd> *SymTabLC = nullptr;
|
|
if (!StrTab.empty())
|
|
SymTabLC = &addLoadCommand<MachOTraits::SymTabCmd>();
|
|
|
|
// Lay out header, segment load command, and other load commands.
|
|
size_t Offset = sizeof(Header);
|
|
for (auto &Seg : Segments) {
|
|
Seg.cmdsize +=
|
|
Seg.Sections.size() * sizeof(typename MachOTraits::Section);
|
|
Seg.nsects = Seg.Sections.size();
|
|
Offset += Seg.cmdsize;
|
|
}
|
|
for (auto &LC : LoadCommands)
|
|
Offset += LC->size();
|
|
|
|
Header.sizeofcmds = Offset - sizeof(Header);
|
|
|
|
// Lay out content, set segment / section addrs and offsets.
|
|
size_t SegVMAddr = 0;
|
|
for (auto &Seg : Segments) {
|
|
Seg.vmaddr = SegVMAddr;
|
|
Seg.fileoff = Offset;
|
|
for (auto &Sec : Seg.Sections) {
|
|
Offset = alignTo(Offset, 1ULL << Sec->align);
|
|
if (Sec->Content.Size)
|
|
Sec->offset = Offset;
|
|
Sec->size = Sec->Content.Size;
|
|
Sec->addr = SegVMAddr + Sec->offset - Seg.fileoff;
|
|
Offset += Sec->Content.Size;
|
|
}
|
|
size_t SegContentSize = Offset - Seg.fileoff;
|
|
Seg.filesize = SegContentSize;
|
|
Seg.vmsize = Header.filetype == MachO::MH_OBJECT
|
|
? SegContentSize
|
|
: alignTo(SegContentSize, PageSize);
|
|
SegVMAddr += Seg.vmsize;
|
|
}
|
|
|
|
// Set string table offsets for non-section symbols.
|
|
for (auto &Sym : SC.Symbols)
|
|
Sym.n_strx = StrTab[Sym.n_strx].Offset;
|
|
|
|
// Number sections, set symbol section numbers and string table offsets,
|
|
// count relocations.
|
|
size_t NumSymbols = SC.Symbols.size();
|
|
size_t SectionNumber = 0;
|
|
for (auto &Seg : Segments) {
|
|
for (auto &Sec : Seg.Sections) {
|
|
++SectionNumber;
|
|
Sec->SectionNumber = SectionNumber;
|
|
Sec->SC.SymbolIndexBase = NumSymbols;
|
|
NumSymbols += Sec->SC.Symbols.size();
|
|
for (auto &Sym : Sec->SC.Symbols) {
|
|
Sym.n_sect = SectionNumber;
|
|
Sym.n_strx = StrTab[Sym.n_strx].Offset;
|
|
Sym.n_value += Sec->addr;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle relocations
|
|
bool OffsetAlignedForRelocs = false;
|
|
for (auto &Seg : Segments) {
|
|
for (auto &Sec : Seg.Sections) {
|
|
if (!Sec->Relocs.empty()) {
|
|
if (!OffsetAlignedForRelocs) {
|
|
Offset = alignTo(Offset, sizeof(MachO::relocation_info));
|
|
OffsetAlignedForRelocs = true;
|
|
}
|
|
Sec->reloff = Offset;
|
|
Sec->nreloc = Sec->Relocs.size();
|
|
Offset += Sec->Relocs.size() * sizeof(MachO::relocation_info);
|
|
for (auto &R : Sec->Relocs)
|
|
R.r_symbolnum = R.Target.isSymbol() ? R.Target.getSymbolNum()
|
|
: R.Target.getSectionId();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calculate offset to start of nlist and update symtab command.
|
|
if (NumSymbols > 0) {
|
|
Offset = alignTo(Offset, sizeof(typename MachOTraits::NList));
|
|
SymTabLC->symoff = Offset;
|
|
SymTabLC->nsyms = NumSymbols;
|
|
|
|
// Calculate string table bounds and update symtab command.
|
|
if (!StrTab.empty()) {
|
|
Offset += NumSymbols * sizeof(typename MachOTraits::NList);
|
|
size_t StringTableSize =
|
|
StrTab.back().Offset + StrTab.back().S.size() + 1;
|
|
|
|
SymTabLC->stroff = Offset;
|
|
SymTabLC->strsize = StringTableSize;
|
|
Offset += StringTableSize;
|
|
}
|
|
}
|
|
|
|
return Offset;
|
|
}
|
|
|
|
void write(MutableArrayRef<char> Buffer) {
|
|
size_t Offset = 0;
|
|
Offset = writeHeader(Buffer, Offset);
|
|
Offset = writeSegments(Buffer, Offset);
|
|
Offset = writeLoadCommands(Buffer, Offset);
|
|
Offset = writeSectionContent(Buffer, Offset);
|
|
Offset = writeRelocations(Buffer, Offset);
|
|
Offset = writeSymbols(Buffer, Offset);
|
|
Offset = writeStrings(Buffer, Offset);
|
|
}
|
|
|
|
typename MachOTraits::Header Header;
|
|
|
|
private:
|
|
void makeStringTable() {
|
|
if (Strings.empty())
|
|
return;
|
|
|
|
StrTab.resize(Strings.size());
|
|
for (auto &KV : Strings)
|
|
StrTab[KV.second] = {KV.first, 0};
|
|
size_t Offset = 0;
|
|
for (auto &Elem : StrTab) {
|
|
Elem.Offset = Offset;
|
|
Offset += Elem.S.size() + 1;
|
|
}
|
|
}
|
|
|
|
size_t writeHeader(MutableArrayRef<char> Buf, size_t Offset) {
|
|
Header.ncmds = Segments.size() + LoadCommands.size();
|
|
return writeMachOStruct(Buf, Offset, Header, swapStruct());
|
|
}
|
|
|
|
size_t writeSegments(MutableArrayRef<char> Buf, size_t Offset) {
|
|
for (auto &Seg : Segments)
|
|
Offset = Seg.write(Buf, Offset, swapStruct());
|
|
return Offset;
|
|
}
|
|
|
|
size_t writeLoadCommands(MutableArrayRef<char> Buf, size_t Offset) {
|
|
for (auto &LC : LoadCommands)
|
|
Offset = LC->write(Buf, Offset, swapStruct());
|
|
return Offset;
|
|
}
|
|
|
|
size_t writeSectionContent(MutableArrayRef<char> Buf, size_t Offset) {
|
|
for (auto &Seg : Segments) {
|
|
for (auto &Sec : Seg.Sections) {
|
|
if (!Sec->Content.Data) {
|
|
assert(Sec->Relocs.empty() &&
|
|
"Cant' have relocs for zero-fill segment");
|
|
continue;
|
|
}
|
|
while (Offset != Sec->offset)
|
|
Buf[Offset++] = '\0';
|
|
|
|
assert(Offset + Sec->Content.Size <= Buf.size() && "Buffer overflow");
|
|
memcpy(&Buf[Offset], Sec->Content.Data, Sec->Content.Size);
|
|
Offset += Sec->Content.Size;
|
|
}
|
|
}
|
|
return Offset;
|
|
}
|
|
|
|
size_t writeRelocations(MutableArrayRef<char> Buf, size_t Offset) {
|
|
for (auto &Seg : Segments) {
|
|
for (auto &Sec : Seg.Sections) {
|
|
if (!Sec->Relocs.empty()) {
|
|
while (Offset % sizeof(MachO::relocation_info))
|
|
Buf[Offset++] = '\0';
|
|
}
|
|
for (auto &R : Sec->Relocs) {
|
|
assert(Offset + sizeof(MachO::relocation_info) <= Buf.size() &&
|
|
"Buffer overflow");
|
|
memcpy(&Buf[Offset], reinterpret_cast<const char *>(&R.rawStruct()),
|
|
sizeof(MachO::relocation_info));
|
|
Offset += sizeof(MachO::relocation_info);
|
|
}
|
|
}
|
|
}
|
|
return Offset;
|
|
}
|
|
|
|
size_t writeSymbols(MutableArrayRef<char> Buf, size_t Offset) {
|
|
|
|
// Count symbols.
|
|
size_t NumSymbols = SC.Symbols.size();
|
|
for (auto &Seg : Segments)
|
|
for (auto &Sec : Seg.Sections)
|
|
NumSymbols += Sec->SC.Symbols.size();
|
|
|
|
// If none then return.
|
|
if (NumSymbols == 0)
|
|
return Offset;
|
|
|
|
// Align to nlist entry size.
|
|
while (Offset % sizeof(typename MachOTraits::NList))
|
|
Buf[Offset++] = '\0';
|
|
|
|
// Write non-section symbols.
|
|
for (auto &Sym : SC.Symbols)
|
|
Offset = writeMachOStruct(Buf, Offset, Sym, swapStruct());
|
|
|
|
// Write section symbols.
|
|
for (auto &Seg : Segments) {
|
|
for (auto &Sec : Seg.Sections) {
|
|
for (auto &Sym : Sec->SC.Symbols) {
|
|
Offset = writeMachOStruct(Buf, Offset, Sym, swapStruct());
|
|
}
|
|
}
|
|
}
|
|
return Offset;
|
|
}
|
|
|
|
size_t writeStrings(MutableArrayRef<char> Buf, size_t Offset) {
|
|
for (auto &Elem : StrTab) {
|
|
assert(Offset + Elem.S.size() + 1 <= Buf.size() && "Buffer overflow");
|
|
memcpy(&Buf[Offset], Elem.S.data(), Elem.S.size());
|
|
Offset += Elem.S.size();
|
|
Buf[Offset++] = '\0';
|
|
}
|
|
return Offset;
|
|
}
|
|
|
|
size_t PageSize;
|
|
std::list<Segment> Segments;
|
|
std::vector<std::unique_ptr<MachOBuilderLoadCommandBase>> LoadCommands;
|
|
SymbolContainer SC;
|
|
|
|
// Maps strings to their "id" (addition order).
|
|
std::map<StringRef, size_t> Strings;
|
|
StringTable StrTab;
|
|
};
|
|
|
|
struct MachO64LE {
|
|
using UIntPtr = uint64_t;
|
|
using Header = MachO::mach_header_64;
|
|
using Section = MachO::section_64;
|
|
using NList = MachO::nlist_64;
|
|
using Relocation = MachO::relocation_info;
|
|
|
|
static constexpr llvm::endianness Endianness = llvm::endianness::little;
|
|
static constexpr uint32_t Magic = MachO::MH_MAGIC_64;
|
|
static constexpr MachO::LoadCommandType SegmentCmd = MachO::LC_SEGMENT_64;
|
|
static constexpr MachO::LoadCommandType SymTabCmd = MachO::LC_SYMTAB;
|
|
};
|
|
|
|
} // namespace orc
|
|
} // namespace llvm
|
|
|
|
#endif // LLVM_EXECUTIONENGINE_ORC_MACHOBUILDER_H
|