File indexing completed on 2026-05-10 08:43:53
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_EXECUTIONENGINE_ORC_MACHOBUILDER_H
0014 #define LLVM_EXECUTIONENGINE_ORC_MACHOBUILDER_H
0015
0016 #include "llvm/BinaryFormat/MachO.h"
0017 #include "llvm/Support/Endian.h"
0018 #include "llvm/Support/MathExtras.h"
0019
0020 #include <list>
0021 #include <map>
0022 #include <vector>
0023
0024 namespace llvm {
0025 namespace orc {
0026
0027 template <typename MachOStruct>
0028 size_t writeMachOStruct(MutableArrayRef<char> Buf, size_t Offset, MachOStruct S,
0029 bool SwapStruct) {
0030 if (SwapStruct)
0031 MachO::swapStruct(S);
0032 assert(Offset + sizeof(MachOStruct) <= Buf.size() && "Buffer overflow");
0033 memcpy(&Buf[Offset], reinterpret_cast<const char *>(&S), sizeof(MachOStruct));
0034 return Offset + sizeof(MachOStruct);
0035 }
0036
0037
0038 struct MachOBuilderLoadCommandBase {
0039 virtual ~MachOBuilderLoadCommandBase() {}
0040 virtual size_t size() const = 0;
0041 virtual size_t write(MutableArrayRef<char> Buf, size_t Offset,
0042 bool SwapStruct) = 0;
0043 };
0044
0045
0046 template <MachO::LoadCommandType LCType> struct MachOBuilderLoadCommandImplBase;
0047
0048 #define HANDLE_LOAD_COMMAND(Name, Value, LCStruct) \
0049 template <> \
0050 struct MachOBuilderLoadCommandImplBase<MachO::Name> \
0051 : public MachO::LCStruct, public MachOBuilderLoadCommandBase { \
0052 using CmdStruct = LCStruct; \
0053 MachOBuilderLoadCommandImplBase() { \
0054 memset(&rawStruct(), 0, sizeof(CmdStruct)); \
0055 cmd = Value; \
0056 cmdsize = sizeof(CmdStruct); \
0057 } \
0058 template <typename... ArgTs> \
0059 MachOBuilderLoadCommandImplBase(ArgTs &&...Args) \
0060 : CmdStruct{Value, sizeof(CmdStruct), std::forward<ArgTs>(Args)...} {} \
0061 CmdStruct &rawStruct() { return static_cast<CmdStruct &>(*this); } \
0062 size_t size() const override { return cmdsize; } \
0063 size_t write(MutableArrayRef<char> Buf, size_t Offset, \
0064 bool SwapStruct) override { \
0065 return writeMachOStruct(Buf, Offset, rawStruct(), SwapStruct); \
0066 } \
0067 };
0068
0069 #include "llvm/BinaryFormat/MachO.def"
0070
0071 #undef HANDLE_LOAD_COMMAND
0072
0073 template <MachO::LoadCommandType LCType>
0074 struct MachOBuilderLoadCommand
0075 : public MachOBuilderLoadCommandImplBase<LCType> {
0076 public:
0077 MachOBuilderLoadCommand() = default;
0078
0079 template <typename... ArgTs>
0080 MachOBuilderLoadCommand(ArgTs &&...Args)
0081 : MachOBuilderLoadCommandImplBase<LCType>(std::forward<ArgTs>(Args)...) {}
0082 };
0083
0084 template <>
0085 struct MachOBuilderLoadCommand<MachO::LC_ID_DYLIB>
0086 : public MachOBuilderLoadCommandImplBase<MachO::LC_ID_DYLIB> {
0087
0088 MachOBuilderLoadCommand(std::string Name, uint32_t Timestamp,
0089 uint32_t CurrentVersion,
0090 uint32_t CompatibilityVersion)
0091 : MachOBuilderLoadCommandImplBase(
0092 MachO::dylib{24, Timestamp, CurrentVersion, CompatibilityVersion}),
0093 Name(std::move(Name)) {
0094 cmdsize += (this->Name.size() + 1 + 3) & ~0x3;
0095 }
0096
0097 size_t write(MutableArrayRef<char> Buf, size_t Offset,
0098 bool SwapStruct) override {
0099 Offset = writeMachOStruct(Buf, Offset, rawStruct(), SwapStruct);
0100 strcpy(Buf.data() + Offset, Name.data());
0101 return Offset + ((Name.size() + 1 + 3) & ~0x3);
0102 }
0103
0104 std::string Name;
0105 };
0106
0107 template <>
0108 struct MachOBuilderLoadCommand<MachO::LC_LOAD_DYLIB>
0109 : public MachOBuilderLoadCommandImplBase<MachO::LC_LOAD_DYLIB> {
0110
0111 MachOBuilderLoadCommand(std::string Name, uint32_t Timestamp,
0112 uint32_t CurrentVersion,
0113 uint32_t CompatibilityVersion)
0114 : MachOBuilderLoadCommandImplBase(
0115 MachO::dylib{24, Timestamp, CurrentVersion, CompatibilityVersion}),
0116 Name(std::move(Name)) {
0117 cmdsize += (this->Name.size() + 1 + 3) & ~0x3;
0118 }
0119
0120 size_t write(MutableArrayRef<char> Buf, size_t Offset,
0121 bool SwapStruct) override {
0122 Offset = writeMachOStruct(Buf, Offset, rawStruct(), SwapStruct);
0123 strcpy(Buf.data() + Offset, Name.data());
0124 return Offset + ((Name.size() + 1 + 3) & ~0x3);
0125 }
0126
0127 std::string Name;
0128 };
0129
0130 template <>
0131 struct MachOBuilderLoadCommand<MachO::LC_RPATH>
0132 : public MachOBuilderLoadCommandImplBase<MachO::LC_RPATH> {
0133 MachOBuilderLoadCommand(std::string Path)
0134 : MachOBuilderLoadCommandImplBase(12u), Path(std::move(Path)) {
0135 cmdsize += (this->Path.size() + 1 + 3) & ~0x3;
0136 }
0137
0138 size_t write(MutableArrayRef<char> Buf, size_t Offset,
0139 bool SwapStruct) override {
0140 Offset = writeMachOStruct(Buf, Offset, rawStruct(), SwapStruct);
0141 strcpy(Buf.data() + Offset, Path.data());
0142 return Offset + ((Path.size() + 1 + 3) & ~0x3);
0143 }
0144
0145 std::string Path;
0146 };
0147
0148
0149 template <typename MachOTraits> class MachOBuilder {
0150 private:
0151 struct SymbolContainer {
0152 size_t SymbolIndexBase = 0;
0153 std::vector<typename MachOTraits::NList> Symbols;
0154 };
0155
0156 struct StringTableEntry {
0157 StringRef S;
0158 size_t Offset;
0159 };
0160
0161 using StringTable = std::vector<StringTableEntry>;
0162
0163 static bool swapStruct() {
0164 return MachOTraits::Endianness != llvm::endianness::native;
0165 }
0166
0167 public:
0168 using StringId = size_t;
0169
0170 struct Section;
0171
0172
0173
0174 class RelocTarget {
0175 public:
0176 RelocTarget(const Section &S) : S(&S), Idx(~0U) {}
0177 RelocTarget(SymbolContainer &SC, size_t Idx) : SC(&SC), Idx(Idx) {}
0178
0179 bool isSymbol() { return Idx != ~0U; }
0180
0181 uint32_t getSymbolNum() {
0182 assert(isSymbol() && "Target is not a symbol");
0183 return SC->SymbolIndexBase + Idx;
0184 }
0185
0186 uint32_t getSectionId() {
0187 assert(!isSymbol() && "Target is not a section");
0188 return S->SectionNumber;
0189 }
0190
0191 typename MachOTraits::NList &nlist() {
0192 assert(isSymbol() && "Target is not a symbol");
0193 return SC->Symbols[Idx];
0194 }
0195
0196 private:
0197 union {
0198 const Section *S;
0199 SymbolContainer *SC;
0200 };
0201 size_t Idx;
0202 };
0203
0204 struct Reloc : public MachO::relocation_info {
0205 RelocTarget Target;
0206
0207 Reloc(int32_t Offset, RelocTarget Target, bool PCRel, unsigned Length,
0208 unsigned Type)
0209 : Target(Target) {
0210 assert(Type < 16 && "Relocation type out of range");
0211 r_address = Offset;
0212 r_symbolnum = 0;
0213 r_pcrel = PCRel;
0214 r_length = Length;
0215 r_extern = Target.isSymbol();
0216 r_type = Type;
0217 }
0218
0219 MachO::relocation_info &rawStruct() {
0220 return static_cast<MachO::relocation_info &>(*this);
0221 }
0222 };
0223
0224 struct SectionContent {
0225 const char *Data = nullptr;
0226 size_t Size = 0;
0227 };
0228
0229 struct Section : public MachOTraits::Section, public RelocTarget {
0230 MachOBuilder &Builder;
0231 SectionContent Content;
0232 size_t SectionNumber = 0;
0233 SymbolContainer SC;
0234 std::vector<Reloc> Relocs;
0235
0236 Section(MachOBuilder &Builder, StringRef SecName, StringRef SegName)
0237 : RelocTarget(*this), Builder(Builder) {
0238 memset(&rawStruct(), 0, sizeof(typename MachOTraits::Section));
0239 assert(SecName.size() <= 16 && "SecName too long");
0240 assert(SegName.size() <= 16 && "SegName too long");
0241 memcpy(this->sectname, SecName.data(), SecName.size());
0242 memcpy(this->segname, SegName.data(), SegName.size());
0243 }
0244
0245 RelocTarget addSymbol(int32_t Offset, StringRef Name, uint8_t Type,
0246 uint16_t Desc) {
0247 StringId SI = Builder.addString(Name);
0248 typename MachOTraits::NList Sym;
0249 Sym.n_strx = SI;
0250 Sym.n_type = Type | MachO::N_SECT;
0251 Sym.n_sect = MachO::NO_SECT;
0252 Sym.n_desc = Desc;
0253 Sym.n_value = Offset;
0254 SC.Symbols.push_back(Sym);
0255 return {SC, SC.Symbols.size() - 1};
0256 }
0257
0258 void addReloc(int32_t Offset, RelocTarget Target, bool PCRel,
0259 unsigned Length, unsigned Type) {
0260 Relocs.push_back({Offset, Target, PCRel, Length, Type});
0261 }
0262
0263 auto &rawStruct() {
0264 return static_cast<typename MachOTraits::Section &>(*this);
0265 }
0266 };
0267
0268 struct Segment : public MachOBuilderLoadCommand<MachOTraits::SegmentCmd> {
0269 MachOBuilder &Builder;
0270 std::vector<std::unique_ptr<Section>> Sections;
0271
0272 Segment(MachOBuilder &Builder, StringRef SegName)
0273 : MachOBuilderLoadCommand<MachOTraits::SegmentCmd>(), Builder(Builder) {
0274 assert(SegName.size() <= 16 && "SegName too long");
0275 memcpy(this->segname, SegName.data(), SegName.size());
0276 this->maxprot =
0277 MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
0278 this->initprot = this->maxprot;
0279 }
0280
0281 Section &addSection(StringRef SecName, StringRef SegName) {
0282 Sections.push_back(std::make_unique<Section>(Builder, SecName, SegName));
0283 return *Sections.back();
0284 }
0285
0286 size_t write(MutableArrayRef<char> Buf, size_t Offset,
0287 bool SwapStruct) override {
0288 Offset = MachOBuilderLoadCommand<MachOTraits::SegmentCmd>::write(
0289 Buf, Offset, SwapStruct);
0290 for (auto &Sec : Sections)
0291 Offset = writeMachOStruct(Buf, Offset, Sec->rawStruct(), SwapStruct);
0292 return Offset;
0293 }
0294 };
0295
0296 MachOBuilder(size_t PageSize) : PageSize(PageSize) {
0297 memset((char *)&Header, 0, sizeof(Header));
0298 Header.magic = MachOTraits::Magic;
0299 }
0300
0301 template <MachO::LoadCommandType LCType, typename... ArgTs>
0302 MachOBuilderLoadCommand<LCType> &addLoadCommand(ArgTs &&...Args) {
0303 static_assert(LCType != MachOTraits::SegmentCmd,
0304 "Use addSegment to add segment load command");
0305 auto LC = std::make_unique<MachOBuilderLoadCommand<LCType>>(
0306 std::forward<ArgTs>(Args)...);
0307 auto &Tmp = *LC;
0308 LoadCommands.push_back(std::move(LC));
0309 return Tmp;
0310 }
0311
0312 StringId addString(StringRef Str) {
0313 if (Strings.empty() && !Str.empty())
0314 addString("");
0315 return Strings.insert(std::make_pair(Str, Strings.size())).first->second;
0316 }
0317
0318 Segment &addSegment(StringRef SegName) {
0319 Segments.push_back(Segment(*this, SegName));
0320 return Segments.back();
0321 }
0322
0323 RelocTarget addSymbol(StringRef Name, uint8_t Type, uint8_t Sect,
0324 uint16_t Desc, typename MachOTraits::UIntPtr Value) {
0325 StringId SI = addString(Name);
0326 typename MachOTraits::NList Sym;
0327 Sym.n_strx = SI;
0328 Sym.n_type = Type;
0329 Sym.n_sect = Sect;
0330 Sym.n_desc = Desc;
0331 Sym.n_value = Value;
0332 SC.Symbols.push_back(Sym);
0333 return {SC, SC.Symbols.size() - 1};
0334 }
0335
0336
0337
0338
0339
0340 size_t layout() {
0341
0342
0343 makeStringTable();
0344 MachOBuilderLoadCommand<MachOTraits::SymTabCmd> *SymTabLC = nullptr;
0345 if (!StrTab.empty())
0346 SymTabLC = &addLoadCommand<MachOTraits::SymTabCmd>();
0347
0348
0349 size_t Offset = sizeof(Header);
0350 for (auto &Seg : Segments) {
0351 Seg.cmdsize +=
0352 Seg.Sections.size() * sizeof(typename MachOTraits::Section);
0353 Seg.nsects = Seg.Sections.size();
0354 Offset += Seg.cmdsize;
0355 }
0356 for (auto &LC : LoadCommands)
0357 Offset += LC->size();
0358
0359 Header.sizeofcmds = Offset - sizeof(Header);
0360
0361
0362 size_t SegVMAddr = 0;
0363 for (auto &Seg : Segments) {
0364 Seg.vmaddr = SegVMAddr;
0365 Seg.fileoff = Offset;
0366 for (auto &Sec : Seg.Sections) {
0367 Offset = alignTo(Offset, 1ULL << Sec->align);
0368 if (Sec->Content.Size)
0369 Sec->offset = Offset;
0370 Sec->size = Sec->Content.Size;
0371 Sec->addr = SegVMAddr + Sec->offset - Seg.fileoff;
0372 Offset += Sec->Content.Size;
0373 }
0374 size_t SegContentSize = Offset - Seg.fileoff;
0375 Seg.filesize = SegContentSize;
0376 Seg.vmsize = Header.filetype == MachO::MH_OBJECT
0377 ? SegContentSize
0378 : alignTo(SegContentSize, PageSize);
0379 SegVMAddr += Seg.vmsize;
0380 }
0381
0382
0383 for (auto &Sym : SC.Symbols)
0384 Sym.n_strx = StrTab[Sym.n_strx].Offset;
0385
0386
0387
0388 size_t NumSymbols = SC.Symbols.size();
0389 size_t SectionNumber = 0;
0390 for (auto &Seg : Segments) {
0391 for (auto &Sec : Seg.Sections) {
0392 ++SectionNumber;
0393 Sec->SectionNumber = SectionNumber;
0394 Sec->SC.SymbolIndexBase = NumSymbols;
0395 NumSymbols += Sec->SC.Symbols.size();
0396 for (auto &Sym : Sec->SC.Symbols) {
0397 Sym.n_sect = SectionNumber;
0398 Sym.n_strx = StrTab[Sym.n_strx].Offset;
0399 Sym.n_value += Sec->addr;
0400 }
0401 }
0402 }
0403
0404
0405 bool OffsetAlignedForRelocs = false;
0406 for (auto &Seg : Segments) {
0407 for (auto &Sec : Seg.Sections) {
0408 if (!Sec->Relocs.empty()) {
0409 if (!OffsetAlignedForRelocs) {
0410 Offset = alignTo(Offset, sizeof(MachO::relocation_info));
0411 OffsetAlignedForRelocs = true;
0412 }
0413 Sec->reloff = Offset;
0414 Sec->nreloc = Sec->Relocs.size();
0415 Offset += Sec->Relocs.size() * sizeof(MachO::relocation_info);
0416 for (auto &R : Sec->Relocs)
0417 R.r_symbolnum = R.Target.isSymbol() ? R.Target.getSymbolNum()
0418 : R.Target.getSectionId();
0419 }
0420 }
0421 }
0422
0423
0424 if (NumSymbols > 0) {
0425 Offset = alignTo(Offset, sizeof(typename MachOTraits::NList));
0426 SymTabLC->symoff = Offset;
0427 SymTabLC->nsyms = NumSymbols;
0428
0429
0430 if (!StrTab.empty()) {
0431 Offset += NumSymbols * sizeof(typename MachOTraits::NList);
0432 size_t StringTableSize =
0433 StrTab.back().Offset + StrTab.back().S.size() + 1;
0434
0435 SymTabLC->stroff = Offset;
0436 SymTabLC->strsize = StringTableSize;
0437 Offset += StringTableSize;
0438 }
0439 }
0440
0441 return Offset;
0442 }
0443
0444 void write(MutableArrayRef<char> Buffer) {
0445 size_t Offset = 0;
0446 Offset = writeHeader(Buffer, Offset);
0447 Offset = writeSegments(Buffer, Offset);
0448 Offset = writeLoadCommands(Buffer, Offset);
0449 Offset = writeSectionContent(Buffer, Offset);
0450 Offset = writeRelocations(Buffer, Offset);
0451 Offset = writeSymbols(Buffer, Offset);
0452 Offset = writeStrings(Buffer, Offset);
0453 }
0454
0455 typename MachOTraits::Header Header;
0456
0457 private:
0458 void makeStringTable() {
0459 if (Strings.empty())
0460 return;
0461
0462 StrTab.resize(Strings.size());
0463 for (auto &[Str, Idx] : Strings)
0464 StrTab[Idx] = {Str, 0};
0465 size_t Offset = 0;
0466 for (auto &Elem : StrTab) {
0467 Elem.Offset = Offset;
0468 Offset += Elem.S.size() + 1;
0469 }
0470 }
0471
0472 size_t writeHeader(MutableArrayRef<char> Buf, size_t Offset) {
0473 Header.ncmds = Segments.size() + LoadCommands.size();
0474 return writeMachOStruct(Buf, Offset, Header, swapStruct());
0475 }
0476
0477 size_t writeSegments(MutableArrayRef<char> Buf, size_t Offset) {
0478 for (auto &Seg : Segments)
0479 Offset = Seg.write(Buf, Offset, swapStruct());
0480 return Offset;
0481 }
0482
0483 size_t writeLoadCommands(MutableArrayRef<char> Buf, size_t Offset) {
0484 for (auto &LC : LoadCommands)
0485 Offset = LC->write(Buf, Offset, swapStruct());
0486 return Offset;
0487 }
0488
0489 size_t writeSectionContent(MutableArrayRef<char> Buf, size_t Offset) {
0490 for (auto &Seg : Segments) {
0491 for (auto &Sec : Seg.Sections) {
0492 if (!Sec->Content.Data) {
0493 assert(Sec->Relocs.empty() &&
0494 "Cant' have relocs for zero-fill segment");
0495 continue;
0496 }
0497 while (Offset != Sec->offset)
0498 Buf[Offset++] = '\0';
0499
0500 assert(Offset + Sec->Content.Size <= Buf.size() && "Buffer overflow");
0501 memcpy(&Buf[Offset], Sec->Content.Data, Sec->Content.Size);
0502 Offset += Sec->Content.Size;
0503 }
0504 }
0505 return Offset;
0506 }
0507
0508 size_t writeRelocations(MutableArrayRef<char> Buf, size_t Offset) {
0509 for (auto &Seg : Segments) {
0510 for (auto &Sec : Seg.Sections) {
0511 if (!Sec->Relocs.empty()) {
0512 while (Offset % sizeof(MachO::relocation_info))
0513 Buf[Offset++] = '\0';
0514 }
0515 for (auto &R : Sec->Relocs) {
0516 assert(Offset + sizeof(MachO::relocation_info) <= Buf.size() &&
0517 "Buffer overflow");
0518 memcpy(&Buf[Offset], reinterpret_cast<const char *>(&R.rawStruct()),
0519 sizeof(MachO::relocation_info));
0520 Offset += sizeof(MachO::relocation_info);
0521 }
0522 }
0523 }
0524 return Offset;
0525 }
0526
0527 size_t writeSymbols(MutableArrayRef<char> Buf, size_t Offset) {
0528
0529
0530 size_t NumSymbols = SC.Symbols.size();
0531 for (auto &Seg : Segments)
0532 for (auto &Sec : Seg.Sections)
0533 NumSymbols += Sec->SC.Symbols.size();
0534
0535
0536 if (NumSymbols == 0)
0537 return Offset;
0538
0539
0540 while (Offset % sizeof(typename MachOTraits::NList))
0541 Buf[Offset++] = '\0';
0542
0543
0544 for (auto &Sym : SC.Symbols)
0545 Offset = writeMachOStruct(Buf, Offset, Sym, swapStruct());
0546
0547
0548 for (auto &Seg : Segments) {
0549 for (auto &Sec : Seg.Sections) {
0550 for (auto &Sym : Sec->SC.Symbols) {
0551 Offset = writeMachOStruct(Buf, Offset, Sym, swapStruct());
0552 }
0553 }
0554 }
0555 return Offset;
0556 }
0557
0558 size_t writeStrings(MutableArrayRef<char> Buf, size_t Offset) {
0559 for (auto &Elem : StrTab) {
0560 assert(Offset + Elem.S.size() + 1 <= Buf.size() && "Buffer overflow");
0561 memcpy(&Buf[Offset], Elem.S.data(), Elem.S.size());
0562 Offset += Elem.S.size();
0563 Buf[Offset++] = '\0';
0564 }
0565 return Offset;
0566 }
0567
0568 size_t PageSize;
0569 std::list<Segment> Segments;
0570 std::vector<std::unique_ptr<MachOBuilderLoadCommandBase>> LoadCommands;
0571 SymbolContainer SC;
0572
0573
0574 std::map<StringRef, size_t> Strings;
0575 StringTable StrTab;
0576 };
0577
0578 struct MachO64LE {
0579 using UIntPtr = uint64_t;
0580 using Header = MachO::mach_header_64;
0581 using Section = MachO::section_64;
0582 using NList = MachO::nlist_64;
0583 using Relocation = MachO::relocation_info;
0584
0585 static constexpr llvm::endianness Endianness = llvm::endianness::little;
0586 static constexpr uint32_t Magic = MachO::MH_MAGIC_64;
0587 static constexpr MachO::LoadCommandType SegmentCmd = MachO::LC_SEGMENT_64;
0588 static constexpr MachO::LoadCommandType SymTabCmd = MachO::LC_SYMTAB;
0589 };
0590
0591 }
0592 }
0593
0594 #endif