//===- lib/MC/MachObjectWriter.cpp - Mach-O File Writer -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/MC/MachObjectWriter.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MachO.h"
#include "llvm/Target/TargetAsmBackend.h"
// FIXME: Gross.
#include "../Target/X86/X86FixupKinds.h"
#include <vector>
using namespace llvm;
static unsigned getFixupKindLog2Size(unsigned Kind) {
switch (Kind) {
default: llvm_unreachable("invalid fixup kind!");
case X86::reloc_pcrel_1byte:
case FK_Data_1: return 0;
case FK_Data_2: return 1;
case X86::reloc_pcrel_4byte:
case X86::reloc_riprel_4byte:
case FK_Data_4: return 2;
case FK_Data_8: return 3;
}
}
static bool isFixupKindPCRel(unsigned Kind) {
switch (Kind) {
default:
return false;
case X86::reloc_pcrel_1byte:
case X86::reloc_pcrel_4byte:
case X86::reloc_riprel_4byte:
return true;
}
}
namespace {
class MachObjectWriterImpl {
// See <mach-o/loader.h>.
enum {
Header_Magic32 = 0xFEEDFACE,
Header_Magic64 = 0xFEEDFACF
};
enum {
Header32Size = 28,
Header64Size = 32,
SegmentLoadCommand32Size = 56,
SegmentLoadCommand64Size = 72,
Section32Size = 68,
Section64Size = 80,
SymtabLoadCommandSize = 24,
DysymtabLoadCommandSize = 80,
Nlist32Size = 12,
Nlist64Size = 16,
RelocationInfoSize = 8
};
enum HeaderFileType {
HFT_Object = 0x1
};
enum HeaderFlags {
HF_SubsectionsViaSymbols = 0x2000
};
enum LoadCommandType {
LCT_Segment = 0x1,
LCT_Symtab = 0x2,
LCT_Dysymtab = 0xb,
LCT_Segment64 = 0x19
};
// 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();
}
};
/// @name Relocation Data
/// @{
struct MachRelocationEntry {
uint32_t Word0;
uint32_t Word1;
};
llvm::DenseMap<const MCSectionData*,
std::vector<MachRelocationEntry> > Relocations;
/// @}
/// @name Symbol Table Data
/// @{
SmallString<256> StringTable;
std::vector<MachSymbolData> LocalSymbolData;
std::vector<MachSymbolData> ExternalSymbolData;
std::vector<MachSymbolData> UndefinedSymbolData;
/// @}
MachObjectWriter *Writer;
raw_ostream &OS;
unsigned Is64Bit : 1;
public:
MachObjectWriterImpl(MachObjectWriter *_Writer, bool _Is64Bit)
: Writer(_Writer), OS(Writer->getStream()), Is64Bit(_Is64Bit) {
}
void Write8(uint8_t Value) { Writer->Write8(Value); }
void Write16(uint16_t Value) { Writer->Write16(Value); }
void Write32(uint32_t Value) { Writer->Write32(Value); }
void Write64(uint64_t Value) { Writer->Write64(Value); }
void WriteZeros(unsigned N) { Writer->WriteZeros(N); }
void WriteBytes(StringRef Str, unsigned ZeroFillSize = 0) {
Writer->WriteBytes(Str, ZeroFillSize);
}
void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize,
bool SubsectionsViaSymbols) {
uint32_t Flags = 0;
if (SubsectionsViaSymbols)
Flags |= HF_Subsect