- }
-}
-
-class MachObjectWriter {
- // See <mach-o/loader.h>.
- enum {
- Header_Magic32 = 0xFEEDFACE,
- Header_Magic64 = 0xFEEDFACF
- };
-
- static const unsigned Header32Size = 28;
- static const unsigned Header64Size = 32;
- static const unsigned SegmentLoadCommand32Size = 56;
- static const unsigned Section32Size = 68;
- static const unsigned SymtabLoadCommandSize = 24;
- static const unsigned DysymtabLoadCommandSize = 80;
- static const unsigned Nlist32Size = 12;
- static const unsigned RelocationInfoSize = 8;
-
- enum HeaderFileType {
- HFT_Object = 0x1
- };
-
- enum HeaderFlags {
- HF_SubsectionsViaSymbols = 0x2000
- };
-
- enum LoadCommandType {
- LCT_Segment = 0x1,
- LCT_Symtab = 0x2,
- LCT_Dysymtab = 0xb
- };
-
- // See <mach-o/nlist.h>.
- enum SymbolTypeType {
- STT_Undefined = 0x00,
- STT_Absolute = 0x02,
- STT_Section = 0x0e
- };
-
- enum SymbolTypeFlags {
- // If any of these bits are set, then the entry is a stab entry number (see
- // <mach-o/stab.h>. Otherwise the other masks apply.
- STF_StabsEntryMask = 0xe0,
-
- STF_TypeMask = 0x0e,
- STF_External = 0x01,
- STF_PrivateExtern = 0x10
- };
-
- /// IndirectSymbolFlags - Flags for encoding special values in the indirect
- /// symbol entry.
- enum IndirectSymbolFlags {
- ISF_Local = 0x80000000,
- ISF_Absolute = 0x40000000
- };
-
- /// RelocationFlags - Special flags for addresses.
- enum RelocationFlags {
- RF_Scattered = 0x80000000
- };
-
- enum RelocationInfoType {
- RIT_Vanilla = 0,
- RIT_Pair = 1,
- RIT_Difference = 2,
- RIT_PreboundLazyPointer = 3,
- RIT_LocalDifference = 4
- };
-
- /// MachSymbolData - Helper struct for containing some precomputed information
- /// on symbols.
- struct MachSymbolData {
- MCSymbolData *SymbolData;
- uint64_t StringIndex;
- uint8_t SectionIndex;
-
- // Support lexicographic sorting.
- bool operator<(const MachSymbolData &RHS) const {
- const std::string &Name = SymbolData->getSymbol().getName();
- return Name < RHS.SymbolData->getSymbol().getName();
- }
- };
-
- raw_ostream &OS;
- bool IsLSB;
-
-public:
- MachObjectWriter(raw_ostream &_OS, bool _IsLSB = true)
- : OS(_OS), IsLSB(_IsLSB) {
- }
-
- /// @name Helper Methods
- /// @{
-
- void Write8(uint8_t Value) {
- OS << char(Value);
- }
-
- void Write16(uint16_t Value) {
- if (IsLSB) {
- Write8(uint8_t(Value >> 0));
- Write8(uint8_t(Value >> 8));
- } else {
- Write8(uint8_t(Value >> 8));
- Write8(uint8_t(Value >> 0));
- }
- }
-
- void Write32(uint32_t Value) {
- if (IsLSB) {
- Write16(uint16_t(Value >> 0));
- Write16(uint16_t(Value >> 16));
- } else {
- Write16(uint16_t(Value >> 16));
- Write16(uint16_t(Value >> 0));
- }
- }
-
- void Write64(uint64_t Value) {
- if (IsLSB) {
- Write32(uint32_t(Value >> 0));
- Write32(uint32_t(Value >> 32));
- } else {
- Write32(uint32_t(Value >> 32));
- Write32(uint32_t(Value >> 0));
- }
- }
-
- void WriteZeros(unsigned N) {
- const char Zeros[16] = { 0 };
-
- for (unsigned i = 0, e = N / 16; i != e; ++i)
- OS << StringRef(Zeros, 16);
-
- OS << StringRef(Zeros, N % 16);
- }
-
- void WriteString(StringRef Str, unsigned ZeroFillSize = 0) {
- OS << Str;
- if (ZeroFillSize)
- WriteZeros(ZeroFillSize - Str.size());
- }
-
- /// @}
-
- void WriteHeader32(unsigned NumLoadCommands, unsigned LoadCommandsSize,
- bool SubsectionsViaSymbols) {
- uint32_t Flags = 0;
-
- if (SubsectionsViaSymbols)
- Flags |= HF_SubsectionsViaSymbols;
-
- // struct mach_header (28 bytes)
-
- uint64_t Start = OS.tell();
- (void) Start;
-
- Write32(Header_Magic32);
-
- // FIXME: Support cputype.
- Write32(MachO::CPUTypeI386);
- // FIXME: Support cpusubtype.
- Write32(MachO::CPUSubType_I386_ALL);
- Write32(HFT_Object);
- Write32(NumLoadCommands); // Object files have a single load command, the
- // segment.
- Write32(LoadCommandsSize);
- Write32(Flags);
-
- assert(OS.tell() - Start == Header32Size);
- }
-
- /// WriteSegmentLoadCommand32 - Write a 32-bit segment load command.
- ///
- /// \arg NumSections - The number of sections in this segment.
- /// \arg SectionDataSize - The total size of the sections.
- void WriteSegmentLoadCommand32(unsigned NumSections,
- uint64_t VMSize,
- uint64_t SectionDataStartOffset,
- uint64_t SectionDataSize) {
- // struct segment_command (56 bytes)
-
- uint64_t Start = OS.tell();
- (void) Start;
-
- Write32(LCT_Segment);
- Write32(SegmentLoadCommand32Size + NumSections * Section32Size);
-
- WriteString("", 16);
- Write32(0); // vmaddr
- Write32(VMSize); // vmsize
- Write32(SectionDataStartOffset); // file offset
- Write32(SectionDataSize); // file size
- Write32(0x7); // maxprot
- Write32(0x7); // initprot
- Write32(NumSections);
- Write32(0); // flags
-
- assert(OS.tell() - Start == SegmentLoadCommand32Size);
- }
-
- void WriteSection32(const MCSectionData &SD, uint64_t FileOffset,
- uint64_t RelocationsStart, unsigned NumRelocations) {
- // The offset is unused for virtual sections.
- if (isVirtualSection(SD.getSection())) {
- assert(SD.getFileSize() == 0 && "Invalid file size!");
- FileOffset = 0;
- }
-
- // struct section (68 bytes)
-
- uint64_t Start = OS.tell();
- (void) Start;
-
- // FIXME: cast<> support!
- const MCSectionMachO &Section =
- static_cast<const MCSectionMachO&>(SD.getSection());
- WriteString(Section.getSectionName(), 16);
- WriteString(Section.getSegmentName(), 16);
- Write32(SD.getAddress()); // address
- Write32(SD.getSize()); // size
- Write32(FileOffset);
-
- unsigned Flags = Section.getTypeAndAttributes();
- if (SD.hasInstructions())
- Flags |= MCSectionMachO::S_ATTR_SOME_INSTRUCTIONS;
-
- assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!");
- Write32(Log2_32(SD.getAlignment()));
- Write32(NumRelocations ? RelocationsStart : 0);
- Write32(NumRelocations);
- Write32(Flags);
- Write32(0); // reserved1
- Write32(Section.getStubSize()); // reserved2
-
- assert(OS.tell() - Start == Section32Size);
- }
-
- void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols,
- uint32_t StringTableOffset,
- uint32_t StringTableSize) {
- // struct symtab_command (24 bytes)
-
- uint64_t Start = OS.tell();
- (void) Start;
-
- Write32(LCT_Symtab);
- Write32(SymtabLoadCommandSize);
- Write32(SymbolOffset);
- Write32(NumSymbols);
- Write32(StringTableOffset);
- Write32(StringTableSize);
-
- assert(OS.tell() - Start == SymtabLoadCommandSize);
- }
-
- void WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol,
- uint32_t NumLocalSymbols,
- uint32_t FirstExternalSymbol,
- uint32_t NumExternalSymbols,
- uint32_t FirstUndefinedSymbol,
- uint32_t NumUndefinedSymbols,
- uint32_t IndirectSymbolOffset,
- uint32_t NumIndirectSymbols) {
- // struct dysymtab_command (80 bytes)
-
- uint64_t Start = OS.tell();
- (void) Start;
-
- Write32(LCT_Dysymtab);
- Write32(DysymtabLoadCommandSize);
- Write32(FirstLocalSymbol);
- Write32(NumLocalSymbols);
- Write32(FirstExternalSymbol);
- Write32(NumExternalSymbols);
- Write32(FirstUndefinedSymbol);
- Write32(NumUndefinedSymbols);
- Write32(0); // tocoff
- Write32(0); // ntoc
- Write32(0); // modtaboff
- Write32(0); // nmodtab
- Write32(0); // extrefsymoff
- Write32(0); // nextrefsyms
- Write32(IndirectSymbolOffset);
- Write32(NumIndirectSymbols);
- Write32(0); // extreloff
- Write32(0); // nextrel
- Write32(0); // locreloff
- Write32(0); // nlocrel
-
- assert(OS.tell() - Start == DysymtabLoadCommandSize);
- }
-
- void WriteNlist32(MachSymbolData &MSD) {
- MCSymbolData &Data = *MSD.SymbolData;
- const MCSymbol &Symbol = Data.getSymbol();
- uint8_t Type = 0;
- uint16_t Flags = Data.getFlags();
- uint32_t Address = 0;
-
- // Set the N_TYPE bits. See <mach-o/nlist.h>.
- //
- // FIXME: Are the prebound or indirect fields possible here?
- if (Symbol.isUndefined())
- Type = STT_Undefined;
- else if (Symbol.isAbsolute())
- Type = STT_Absolute;
- else
- Type = STT_Section;
-
- // FIXME: Set STAB bits.
-
- if (Data.isPrivateExtern())
- Type |= STF_PrivateExtern;
-
- // Set external bit.
- if (Data.isExternal() || Symbol.isUndefined())
- Type |= STF_External;
-
- // Compute the symbol address.
- if (Symbol.isDefined()) {
- if (Symbol.isAbsolute()) {
- llvm_unreachable("FIXME: Not yet implemented!");
- } else {
- Address = Data.getFragment()->getAddress() + Data.getOffset();
- }
- } else if (Data.isCommon()) {
- // Common symbols are encoded with the size in the address
- // field, and their alignment in the flags.
- Address = Data.getCommonSize();
-
- // Common alignment is packed into the 'desc' bits.
- if (unsigned Align = Data.getCommonAlignment()) {
- unsigned Log2Size = Log2_32(Align);
- assert((1U << Log2Size) == Align && "Invalid 'common' alignment!");
- if (Log2Size > 15)
- llvm_report_error("invalid 'common' alignment '" +
- Twine(Align) + "'");
- // FIXME: Keep this mask with the SymbolFlags enumeration.
- Flags = (Flags & 0xF0FF) | (Log2Size << 8);
- }
- }
-
- // struct nlist (12 bytes)
-
- Write32(MSD.StringIndex);
- Write8(Type);
- Write8(MSD.SectionIndex);
-
- // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc'
- // value.
- Write16(Flags);
- Write32(Address);
- }
-
- struct MachRelocationEntry {
- uint32_t Word0;
- uint32_t Word1;
- };
- void ComputeScatteredRelocationInfo(MCAssembler &Asm, MCFragment &Fragment,
- MCAsmFixup &Fixup,
- const MCValue &Target,
- DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap,
- std::vector<MachRelocationEntry> &Relocs) {
- uint32_t Address = Fragment.getOffset() + Fixup.Offset;
- unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind);
- unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind);
- unsigned Type = RIT_Vanilla;
-
- // See <reloc.h>.
- const MCSymbol *A = Target.getSymA();
- MCSymbolData *A_SD = SymbolMap.lookup(A);
-
- if (!A_SD->getFragment())
- llvm_report_error("symbol '" + A->getName() +
- "' can not be undefined in a subtraction expression");
-
- uint32_t Value = A_SD->getFragment()->getAddress() + A_SD->getOffset();
- uint32_t Value2 = 0;
-
- if (const MCSymbol *B = Target.getSymB()) {
- MCSymbolData *B_SD = SymbolMap.lookup(B);
-
- if (!B_SD->getFragment())
- llvm_report_error("symbol '" + B->getName() +
- "' can not be undefined in a subtraction expression");
-
- // FIXME: This change of type based on the external bit doesn't make much
- // sense, it seems to be redundant with the other information in the
- // relocation entry.
- Type = A_SD->isExternal() ? RIT_Difference : RIT_LocalDifference;
- Value2 = B_SD->getFragment()->getAddress() + B_SD->getOffset();
- }