aboutsummaryrefslogtreecommitdiff
path: root/lib/MC
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2010-03-21 10:49:05 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2010-03-21 10:49:05 +0000
commit2f12f10af369d468b14617276446166383d692ed (patch)
tree2caca31db4facdc95c23930c0c745c8ef0dee97d /lib/MC
parentc69102774f9739c81ae1285ed9ae62405071c63c (diff)
downloadsrc-2f12f10af369d468b14617276446166383d692ed.tar.gz
src-2f12f10af369d468b14617276446166383d692ed.zip
Update LLVM to r99115.
Notes
Notes: svn path=/vendor/llvm/dist/; revision=205407
Diffstat (limited to 'lib/MC')
-rw-r--r--lib/MC/CMakeLists.txt2
-rw-r--r--lib/MC/MCAsmStreamer.cpp3
-rw-r--r--lib/MC/MCAssembler.cpp1234
-rw-r--r--lib/MC/MCCodeEmitter.cpp8
-rw-r--r--lib/MC/MCContext.cpp11
-rw-r--r--lib/MC/MCExpr.cpp44
-rw-r--r--lib/MC/MCMachOStreamer.cpp8
-rw-r--r--lib/MC/MCObjectWriter.cpp15
-rw-r--r--lib/MC/MCValue.cpp9
-rw-r--r--lib/MC/MachObjectWriter.cpp1109
-rw-r--r--lib/MC/TargetAsmBackend.cpp5
11 files changed, 1413 insertions, 1035 deletions
diff --git a/lib/MC/CMakeLists.txt b/lib/MC/CMakeLists.txt
index 4cf71dcabee0..dba0e1435651 100644
--- a/lib/MC/CMakeLists.txt
+++ b/lib/MC/CMakeLists.txt
@@ -12,11 +12,13 @@ add_llvm_library(LLVMMC
MCInstPrinter.cpp
MCMachOStreamer.cpp
MCNullStreamer.cpp
+ MCObjectWriter.cpp
MCSection.cpp
MCSectionELF.cpp
MCSectionMachO.cpp
MCStreamer.cpp
MCSymbol.cpp
MCValue.cpp
+ MachObjectWriter.cpp
TargetAsmBackend.cpp
)
diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index 7f3947114fe4..2025463a80be 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/lib/MC/MCAsmStreamer.cpp
@@ -16,6 +16,7 @@
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/ErrorHandling.h"
@@ -29,7 +30,7 @@ namespace {
class MCAsmStreamer : public MCStreamer {
formatted_raw_ostream &OS;
const MCAsmInfo &MAI;
- MCInstPrinter *InstPrinter;
+ OwningPtr<MCInstPrinter> InstPrinter;
MCCodeEmitter *Emitter;
SmallString<128> CommentToEmit;
diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp
index 4cf8b7e522b3..beecf7e6b858 100644
--- a/lib/MC/MCAssembler.cpp
+++ b/lib/MC/MCAssembler.cpp
@@ -10,18 +10,16 @@
#define DEBUG_TYPE "assembler"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCExpr.h"
-#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MachO.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetRegistry.h"
@@ -33,8 +31,6 @@
#include <vector>
using namespace llvm;
-class MachObjectWriter;
-
STATISTIC(EmittedFragments, "Number of emitted assembler fragments");
// FIXME FIXME FIXME: There are number of places in this file where we convert
@@ -42,917 +38,6 @@ STATISTIC(EmittedFragments, "Number of emitted assembler fragments");
// object file, which may truncate it. We should detect that truncation where
// invalid and report errors back.
-static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
- MachObjectWriter &MOW);
-
-static uint64_t WriteNopData(uint64_t Count, MachObjectWriter &MOW);
-
-/// isVirtualSection - Check if this is a section which does not actually exist
-/// in the object file.
-static bool isVirtualSection(const MCSection &Section) {
- // FIXME: Lame.
- const MCSectionMachO &SMO = static_cast<const MCSectionMachO&>(Section);
- return (SMO.getType() == MCSectionMachO::S_ZEROFILL);
-}
-
-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;
- }
-}
-
-class MachObjectWriter {
- // 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();
- }
- };
-
- raw_ostream &OS;
- unsigned Is64Bit : 1;
- unsigned IsLSB : 1;
-
-public:
- MachObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool _IsLSB = true)
- : OS(_OS), Is64Bit(_Is64Bit), 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 WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize,
- bool SubsectionsViaSymbols) {
- uint32_t Flags = 0;
-
- if (SubsectionsViaSymbols)
- Flags |= HF_SubsectionsViaSymbols;
-
- // struct mach_header (28 bytes) or
- // struct mach_header_64 (32 bytes)
-
- uint64_t Start = OS.tell();
- (void) Start;
-
- Write32(Is64Bit ? Header_Magic64 : Header_Magic32);
-
- // FIXME: Support cputype.
- Write32(Is64Bit ? MachO::CPUTypeX86_64 : 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);
- if (Is64Bit)
- Write32(0); // reserved
-
- assert(OS.tell() - Start == Is64Bit ? Header64Size : Header32Size);
- }
-
- /// WriteSegmentLoadCommand - Write a segment load command.
- ///
- /// \arg NumSections - The number of sections in this segment.
- /// \arg SectionDataSize - The total size of the sections.
- void WriteSegmentLoadCommand(unsigned NumSections,
- uint64_t VMSize,
- uint64_t SectionDataStartOffset,
- uint64_t SectionDataSize) {
- // struct segment_command (56 bytes) or
- // struct segment_command_64 (72 bytes)
-
- uint64_t Start = OS.tell();
- (void) Start;
-
- unsigned SegmentLoadCommandSize = Is64Bit ? SegmentLoadCommand64Size :
- SegmentLoadCommand32Size;
- Write32(Is64Bit ? LCT_Segment64 : LCT_Segment);
- Write32(SegmentLoadCommandSize +
- NumSections * (Is64Bit ? Section64Size : Section32Size));
-
- WriteString("", 16);
- if (Is64Bit) {
- Write64(0); // vmaddr
- Write64(VMSize); // vmsize
- Write64(SectionDataStartOffset); // file offset
- Write64(SectionDataSize); // file size
- } else {
- 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 == SegmentLoadCommandSize);
- }
-
- void WriteSection(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) or
- // struct section_64 (80 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);
- if (Is64Bit) {
- Write64(SD.getAddress()); // address
- Write64(SD.getSize()); // size
- } else {
- 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
- if (Is64Bit)
- Write32(0); // reserved3
-
- assert(OS.tell() - Start == Is64Bit ? Section64Size : 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 WriteNlist(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.getAddress();
- }
- } 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);
- if (Is64Bit)
- Write64(Address);
- else
- Write32(Address);
- }
-
- struct MachRelocationEntry {
- uint32_t Word0;
- uint32_t Word1;
- };
- void ComputeScatteredRelocationInfo(MCAssembler &Asm, MCFragment &Fragment,
- MCAsmFixup &Fixup,
- const MCValue &Target,
- 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 = &Asm.getSymbolData(*A);
-
- if (!A_SD->getFragment())
- llvm_report_error("symbol '" + A->getName() +
- "' can not be undefined in a subtraction expression");
-
- uint32_t Value = A_SD->getAddress();
- uint32_t Value2 = 0;
-
- if (const MCSymbol *B = Target.getSymB()) {
- MCSymbolData *B_SD = &Asm.getSymbolData(*B);
-
- if (!B_SD->getFragment())
- llvm_report_error("symbol '" + B->getName() +
- "' can not be undefined in a subtraction expression");
-
- // Select the appropriate difference relocation type.
- //
- // Note that there is no longer any semantic difference between these two
- // relocation types from the linkers point of view, this is done solely
- // for pedantic compatibility with 'as'.
- Type = A_SD->isExternal() ? RIT_Difference : RIT_LocalDifference;
- Value2 = B_SD->getAddress();
- }
-
- MachRelocationEntry MRE;
- MRE.Word0 = ((Address << 0) |
- (Type << 24) |
- (Log2Size << 28) |
- (IsPCRel << 30) |
- RF_Scattered);
- MRE.Word1 = Value;
- Relocs.push_back(MRE);
-
- if (Type == RIT_Difference || Type == RIT_LocalDifference) {
- MachRelocationEntry MRE;
- MRE.Word0 = ((0 << 0) |
- (RIT_Pair << 24) |
- (Log2Size << 28) |
- (IsPCRel << 30) |
- RF_Scattered);
- MRE.Word1 = Value2;
- Relocs.push_back(MRE);
- }
- }
-
- void ComputeRelocationInfo(MCAssembler &Asm, MCDataFragment &Fragment,
- MCAsmFixup &Fixup,
- std::vector<MachRelocationEntry> &Relocs) {
- unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind);
- unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind);
-
- // FIXME: Share layout object.
- MCAsmLayout Layout(Asm);
-
- // Evaluate the fixup; if the value was resolved, no relocation is needed.
- MCValue Target;
- if (Asm.EvaluateFixup(Layout, Fixup, &Fragment, Target, Fixup.FixedValue))
- return;
-
- // If this is a difference or a defined symbol plus an offset, then we need
- // a scattered relocation entry.
- uint32_t Offset = Target.getConstant();
- if (IsPCRel)
- Offset += 1 << Log2Size;
- if (Target.getSymB() ||
- (Target.getSymA() && !Target.getSymA()->isUndefined() &&
- Offset))
- return ComputeScatteredRelocationInfo(Asm, Fragment, Fixup, Target,
- Relocs);
-
- // See <reloc.h>.
- uint32_t Address = Fragment.getOffset() + Fixup.Offset;
- uint32_t Value = 0;
- unsigned Index = 0;
- unsigned IsExtern = 0;
- unsigned Type = 0;
-
- if (Target.isAbsolute()) { // constant
- // SymbolNum of 0 indicates the absolute section.
- //
- // FIXME: Currently, these are never generated (see code below). I cannot
- // find a case where they are actually emitted.
- Type = RIT_Vanilla;
- Value = 0;
- } else {
- const MCSymbol *Symbol = Target.getSymA();
- MCSymbolData *SD = &Asm.getSymbolData(*Symbol);
-
- if (Symbol->isUndefined()) {
- IsExtern = 1;
- Index = SD->getIndex();
- Value = 0;
- } else {
- // The index is the section ordinal.
- //
- // FIXME: O(N)
- Index = 1;
- MCAssembler::iterator it = Asm.begin(), ie = Asm.end();
- for (; it != ie; ++it, ++Index)
- if (&*it == SD->getFragment()->getParent())
- break;
- assert(it != ie && "Unable to find section index!");
- Value = SD->getAddress();
- }
-
- Type = RIT_Vanilla;
- }
-
- // struct relocation_info (8 bytes)
- MachRelocationEntry MRE;
- MRE.Word0 = Address;
- MRE.Word1 = ((Index << 0) |
- (IsPCRel << 24) |
- (Log2Size << 25) |
- (IsExtern << 27) |
- (Type << 28));
- Relocs.push_back(MRE);
- }
-
- void BindIndirectSymbols(MCAssembler &Asm) {
- // This is the point where 'as' creates actual symbols for indirect symbols
- // (in the following two passes). It would be easier for us to do this
- // sooner when we see the attribute, but that makes getting the order in the
- // symbol table much more complicated than it is worth.
- //
- // FIXME: Revisit this when the dust settles.
-
- // Bind non lazy symbol pointers first.
- for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
- ie = Asm.indirect_symbol_end(); it != ie; ++it) {
- // FIXME: cast<> support!
- const MCSectionMachO &Section =
- static_cast<const MCSectionMachO&>(it->SectionData->getSection());
-
- if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS)
- continue;
-
- Asm.getOrCreateSymbolData(*it->Symbol);
- }
-
- // Then lazy symbol pointers and symbol stubs.
- for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
- ie = Asm.indirect_symbol_end(); it != ie; ++it) {
- // FIXME: cast<> support!
- const MCSectionMachO &Section =
- static_cast<const MCSectionMachO&>(it->SectionData->getSection());
-
- if (Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS &&
- Section.getType() != MCSectionMachO::S_SYMBOL_STUBS)
- continue;
-
- // Set the symbol type to undefined lazy, but only on construction.
- //
- // FIXME: Do not hardcode.
- bool Created;
- MCSymbolData &Entry = Asm.getOrCreateSymbolData(*it->Symbol, &Created);
- if (Created)
- Entry.setFlags(Entry.getFlags() | 0x0001);
- }
- }
-
- /// ComputeSymbolTable - Compute the symbol table data
- ///
- /// \param StringTable [out] - The string table data.
- /// \param StringIndexMap [out] - Map from symbol names to offsets in the
- /// string table.
- void ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable,
- std::vector<MachSymbolData> &LocalSymbolData,
- std::vector<MachSymbolData> &ExternalSymbolData,
- std::vector<MachSymbolData> &UndefinedSymbolData) {
- // Build section lookup table.
- DenseMap<const MCSection*, uint8_t> SectionIndexMap;
- unsigned Index = 1;
- for (MCAssembler::iterator it = Asm.begin(),
- ie = Asm.end(); it != ie; ++it, ++Index)
- SectionIndexMap[&it->getSection()] = Index;
- assert(Index <= 256 && "Too many sections!");
-
- // Index 0 is always the empty string.
- StringMap<uint64_t> StringIndexMap;
- StringTable += '\x00';
-
- // Build the symbol arrays and the string table, but only for non-local
- // symbols.
- //
- // The particular order that we collect the symbols and create the string
- // table, then sort the symbols is chosen to match 'as'. Even though it
- // doesn't matter for correctness, this is important for letting us diff .o
- // files.
- for (MCAssembler::symbol_iterator it = Asm.symbol_begin(),
- ie = Asm.symbol_end(); it != ie; ++it) {
- const MCSymbol &Symbol = it->getSymbol();
-
- // Ignore assembler temporaries.
- if (it->getSymbol().isTemporary() &&
- (!it->getFragment() ||
- !Asm.getBackend().doesSectionRequireSymbols(
- it->getFragment()->getParent()->getSection())))
- continue;
-
- if (!it->isExternal() && !Symbol.isUndefined())
- continue;
-
- uint64_t &Entry = StringIndexMap[Symbol.getName()];
- if (!Entry) {
- Entry = StringTable.size();
- StringTable += Symbol.getName();
- StringTable += '\x00';
- }
-
- MachSymbolData MSD;
- MSD.SymbolData = it;
- MSD.StringIndex = Entry;
-
- if (Symbol.isUndefined()) {
- MSD.SectionIndex = 0;
- UndefinedSymbolData.push_back(MSD);
- } else if (Symbol.isAbsolute()) {
- MSD.SectionIndex = 0;
- ExternalSymbolData.push_back(MSD);
- } else {
- MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection());
- assert(MSD.SectionIndex && "Invalid section index!");
- ExternalSymbolData.push_back(MSD);
- }
- }
-
- // Now add the data for local symbols.
- for (MCAssembler::symbol_iterator it = Asm.symbol_begin(),
- ie = Asm.symbol_end(); it != ie; ++it) {
- const MCSymbol &Symbol = it->getSymbol();
-
- // Ignore assembler temporaries.
- if (it->getSymbol().isTemporary() &&
- (!it->getFragment() ||
- !Asm.getBackend().doesSectionRequireSymbols(
- it->getFragment()->getParent()->getSection())))
- continue;
-
- if (it->isExternal() || Symbol.isUndefined())
- continue;
-
- uint64_t &Entry = StringIndexMap[Symbol.getName()];
- if (!Entry) {
- Entry = StringTable.size();
- StringTable += Symbol.getName();
- StringTable += '\x00';
- }
-
- MachSymbolData MSD;
- MSD.SymbolData = it;
- MSD.StringIndex = Entry;
-
- if (Symbol.isAbsolute()) {
- MSD.SectionIndex = 0;
- LocalSymbolData.push_back(MSD);
- } else {
- MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection());
- assert(MSD.SectionIndex && "Invalid section index!");
- LocalSymbolData.push_back(MSD);
- }
- }
-
- // External and undefined symbols are required to be in lexicographic order.
- std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end());
- std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end());
-
- // Set the symbol indices.
- Index = 0;
- for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i)
- LocalSymbolData[i].SymbolData->setIndex(Index++);
- for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i)
- ExternalSymbolData[i].SymbolData->setIndex(Index++);
- for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i)
- UndefinedSymbolData[i].SymbolData->setIndex(Index++);
-
- // The string table is padded to a multiple of 4.
- while (StringTable.size() % 4)
- StringTable += '\x00';
- }
-
- void WriteObject(MCAssembler &Asm) {
- unsigned NumSections = Asm.size();
-
- // Create symbol data for any indirect symbols.
- BindIndirectSymbols(Asm);
-
- // Compute symbol table information.
- SmallString<256> StringTable;
- std::vector<MachSymbolData> LocalSymbolData;
- std::vector<MachSymbolData> ExternalSymbolData;
- std::vector<MachSymbolData> UndefinedSymbolData;
- unsigned NumSymbols = Asm.symbol_size();
-
- // No symbol table command is written if there are no symbols.
- if (NumSymbols)
- ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData,
- UndefinedSymbolData);
-
- // The section data starts after the header, the segment load command (and
- // section headers) and the symbol table.
- unsigned NumLoadCommands = 1;
- uint64_t LoadCommandsSize = Is64Bit ?
- SegmentLoadCommand64Size + NumSections * Section64Size :
- SegmentLoadCommand32Size + NumSections * Section32Size;
-
- // Add the symbol table load command sizes, if used.
- if (NumSymbols) {
- NumLoadCommands += 2;
- LoadCommandsSize += SymtabLoadCommandSize + DysymtabLoadCommandSize;
- }
-
- // Compute the total size of the section data, as well as its file size and
- // vm size.
- uint64_t SectionDataStart = (Is64Bit ? Header64Size : Header32Size)
- + LoadCommandsSize;
- uint64_t SectionDataSize = 0;
- uint64_t SectionDataFileSize = 0;
- uint64_t VMSize = 0;
- for (MCAssembler::iterator it = Asm.begin(),
- ie = Asm.end(); it != ie; ++it) {
- MCSectionData &SD = *it;
-
- VMSize = std::max(VMSize, SD.getAddress() + SD.getSize());
-
- if (isVirtualSection(SD.getSection()))
- continue;
-
- SectionDataSize = std::max(SectionDataSize,
- SD.getAddress() + SD.getSize());
- SectionDataFileSize = std::max(SectionDataFileSize,
- SD.getAddress() + SD.getFileSize());
- }
-
- // The section data is padded to 4 bytes.
- //
- // FIXME: Is this machine dependent?
- unsigned SectionDataPadding = OffsetToAlignment(SectionDataFileSize, 4);
- SectionDataFileSize += SectionDataPadding;
-
- // Write the prolog, starting with the header and load command...
- WriteHeader(NumLoadCommands, LoadCommandsSize,
- Asm.getSubsectionsViaSymbols());
- WriteSegmentLoadCommand(NumSections, VMSize,
- SectionDataStart, SectionDataSize);
-
- // ... and then the section headers.
- //
- // We also compute the section relocations while we do this. Note that
- // computing relocation info will also update the fixup to have the correct
- // value; this will overwrite the appropriate data in the fragment when it
- // is written.
- std::vector<MachRelocationEntry> RelocInfos;
- uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize;
- for (MCAssembler::iterator it = Asm.begin(),
- ie = Asm.end(); it != ie; ++it) {
- MCSectionData &SD = *it;
-
- // The assembler writes relocations in the reverse order they were seen.
- //
- // FIXME: It is probably more complicated than this.
- unsigned NumRelocsStart = RelocInfos.size();
- for (MCSectionData::reverse_iterator it2 = SD.rbegin(),
- ie2 = SD.rend(); it2 != ie2; ++it2)
- if (MCDataFragment *DF = dyn_cast<MCDataFragment>(&*it2))
- for (unsigned i = 0, e = DF->fixup_size(); i != e; ++i)
- ComputeRelocationInfo(Asm, *DF, DF->getFixups()[e - i - 1],
- RelocInfos);
-
- unsigned NumRelocs = RelocInfos.size() - NumRelocsStart;
- uint64_t SectionStart = SectionDataStart + SD.getAddress();
- WriteSection(SD, SectionStart, RelocTableEnd, NumRelocs);
- RelocTableEnd += NumRelocs * RelocationInfoSize;
- }
-
- // Write the symbol table load command, if used.
- if (NumSymbols) {
- unsigned FirstLocalSymbol = 0;
- unsigned NumLocalSymbols = LocalSymbolData.size();
- unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols;
- unsigned NumExternalSymbols = ExternalSymbolData.size();
- unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols;
- unsigned NumUndefinedSymbols = UndefinedSymbolData.size();
- unsigned NumIndirectSymbols = Asm.indirect_symbol_size();
- unsigned NumSymTabSymbols =
- NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols;
- uint64_t IndirectSymbolSize = NumIndirectSymbols * 4;
- uint64_t IndirectSymbolOffset = 0;
-
- // If used, the indirect symbols are written after the section data.
- if (NumIndirectSymbols)
- IndirectSymbolOffset = RelocTableEnd;
-
- // The symbol table is written after the indirect symbol data.
- uint64_t SymbolTableOffset = RelocTableEnd + IndirectSymbolSize;
-
- // The string table is written after symbol table.
- uint64_t StringTableOffset =
- SymbolTableOffset + NumSymTabSymbols * (Is64Bit ? Nlist64Size :
- Nlist32Size);
- WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols,
- StringTableOffset, StringTable.size());
-
- WriteDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols,
- FirstExternalSymbol, NumExternalSymbols,
- FirstUndefinedSymbol, NumUndefinedSymbols,
- IndirectSymbolOffset, NumIndirectSymbols);
- }
-
- // Write the actual section data.
- for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it)
- WriteFileData(OS, *it, *this);
-
- // Write the extra padding.
- WriteZeros(SectionDataPadding);
-
- // Write the relocation entries.
- for (unsigned i = 0, e = RelocInfos.size(); i != e; ++i) {
- Write32(RelocInfos[i].Word0);
- Write32(RelocInfos[i].Word1);
- }
-
- // Write the symbol table data, if used.
- if (NumSymbols) {
- // Write the indirect symbol entries.
- for (MCAssembler::indirect_symbol_iterator
- it = Asm.indirect_symbol_begin(),
- ie = Asm.indirect_symbol_end(); it != ie; ++it) {
- // Indirect symbols in the non lazy symbol pointer section have some
- // special handling.
- const MCSectionMachO &Section =
- static_cast<const MCSectionMachO&>(it->SectionData->getSection());
- if (Section.getType() == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) {
- // If this symbol is defined and internal, mark it as such.
- if (it->Symbol->isDefined() &&
- !Asm.getSymbolData(*it->Symbol).isExternal()) {
- uint32_t Flags = ISF_Local;
- if (it->Symbol->isAbsolute())
- Flags |= ISF_Absolute;
- Write32(Flags);
- continue;
- }
- }
-
- Write32(Asm.getSymbolData(*it->Symbol).getIndex());
- }
-
- // FIXME: Check that offsets match computed ones.
-
- // Write the symbol table entries.
- for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i)
- WriteNlist(LocalSymbolData[i]);
- for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i)
- WriteNlist(ExternalSymbolData[i]);
- for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i)
- WriteNlist(UndefinedSymbolData[i]);
-
- // Write the string table.
- OS << StringTable.str();
- }
- }
-
- void ApplyFixup(const MCAsmFixup &Fixup, MCDataFragment &DF) {
- unsigned Size = 1 << getFixupKindLog2Size(Fixup.Kind);
-
- // FIXME: Endianness assumption.
- assert(Fixup.Offset + Size <= DF.getContents().size() &&
- "Invalid fixup offset!");
- for (unsigned i = 0; i != Size; ++i)
- DF.getContents()[Fixup.Offset + i] = uint8_t(Fixup.FixedValue >> (i * 8));
- }
-};
-
/* *** */
MCFragment::MCFragment() : Kind(FragmentType(~0)) {
@@ -1008,14 +93,149 @@ MCSymbolData::MCSymbolData(const MCSymbol &_Symbol, MCFragment *_Fragment,
/* *** */
MCAssembler::MCAssembler(MCContext &_Context, TargetAsmBackend &_Backend,
- raw_ostream &_OS)
- : Context(_Context), Backend(_Backend), OS(_OS), SubsectionsViaSymbols(false)
+ MCCodeEmitter &_Emitter, raw_ostream &_OS)
+ : Context(_Context), Backend(_Backend), Emitter(_Emitter),
+ OS(_OS), SubsectionsViaSymbols(false)
{
}
MCAssembler::~MCAssembler() {
}
+static bool isScatteredFixupFullyResolvedSimple(const MCAssembler &Asm,
+ const MCAsmFixup &Fixup,
+ const MCDataFragment *DF,
+ const MCValue Target,
+ const MCSection *BaseSection) {
+ // The effective fixup address is
+ // addr(atom(A)) + offset(A)
+ // - addr(atom(B)) - offset(B)
+ // - addr(<base symbol>) + <fixup offset from base symbol>
+ // and the offsets are not relocatable, so the fixup is fully resolved when
+ // addr(atom(A)) - addr(atom(B)) - addr(<base symbol>)) == 0.
+ //
+ // The simple (Darwin, except on x86_64) way of dealing with this was to
+ // assume that any reference to a temporary symbol *must* be a temporary
+ // symbol in the same atom, unless the sections differ. Therefore, any PCrel
+ // relocation to a temporary symbol (in the same section) is fully
+ // resolved. This also works in conjunction with absolutized .set, which
+ // requires the compiler to use .set to absolutize the differences between
+ // symbols which the compiler knows to be assembly time constants, so we don't
+ // need to worry about consider symbol differences fully resolved.
+
+ // Non-relative fixups are only resolved if constant.
+ if (!BaseSection)
+ return Target.isAbsolute();
+
+ // Otherwise, relative fixups are only resolved if not a difference and the
+ // target is a temporary in the same section.
+ if (Target.isAbsolute() || Target.getSymB())
+ return false;
+
+ const MCSymbol *A = &Target.getSymA()->getSymbol();
+ if (!A->isTemporary() || !A->isInSection() ||
+ &A->getSection() != BaseSection)
+ return false;
+
+ return true;
+}
+
+static bool isScatteredFixupFullyResolved(const MCAssembler &Asm,
+ const MCAsmFixup &Fixup,
+ const MCDataFragment *DF,
+ const MCValue Target,
+ const MCSymbolData *BaseSymbol) {
+ // The effective fixup address is
+ // addr(atom(A)) + offset(A)
+ // - addr(atom(B)) - offset(B)
+ // - addr(BaseSymbol) + <fixup offset from base symbol>
+ // and the offsets are not relocatable, so the fixup is fully resolved when
+ // addr(atom(A)) - addr(atom(B)) - addr(BaseSymbol) == 0.
+ //
+ // Note that "false" is almost always conservatively correct (it means we emit
+ // a relocation which is unnecessary), except when it would force us to emit a
+ // relocation which the target cannot encode.
+
+ const MCSymbolData *A_Base = 0, *B_Base = 0;
+ if (const MCSymbolRefExpr *A = Target.getSymA()) {
+ // Modified symbol references cannot be resolved.
+ if (A->getKind() != MCSymbolRefExpr::VK_None)
+ return false;
+
+ A_Base = Asm.getAtom(&Asm.getSymbolData(A->getSymbol()));
+ if (!A_Base)
+ return false;
+ }
+
+ if (const MCSymbolRefExpr *B = Target.getSymB()) {
+ // Modified symbol references cannot be resolved.
+ if (B->getKind() != MCSymbolRefExpr::VK_None)
+ return false;
+
+ B_Base = Asm.getAtom(&Asm.getSymbolData(B->getSymbol()));
+ if (!B_Base)
+ return false;
+ }
+
+ // If there is no base, A and B have to be the same atom for this fixup to be
+ // fully resolved.
+ if (!BaseSymbol)
+ return A_Base == B_Base;
+
+ // Otherwise, B must be missing and A must be the base.
+ return !B_Base && BaseSymbol == A_Base;
+}
+
+bool MCAssembler::isSymbolLinkerVisible(const MCSymbolData *SD) const {
+ // Non-temporary labels should always be visible to the linker.
+ if (!SD->getSymbol().isTemporary())
+ return true;
+
+ // Absolute temporary labels are never visible.
+ if (!SD->getFragment())
+ return false;
+
+ // Otherwise, check if the section requires symbols even for temporary labels.
+ return getBackend().doesSectionRequireSymbols(
+ SD->getFragment()->getParent()->getSection());
+}
+
+const MCSymbolData *MCAssembler::getAtomForAddress(const MCSectionData *Section,
+ uint64_t Address) const {
+ const MCSymbolData *Best = 0;
+ for (MCAssembler::const_symbol_iterator it = symbol_begin(),
+ ie = symbol_end(); it != ie; ++it) {
+ // Ignore non-linker visible symbols.
+ if (!isSymbolLinkerVisible(it))
+ continue;
+
+ // Ignore symbols not in the same section.
+ if (!it->getFragment() || it->getFragment()->getParent() != Section)
+ continue;
+
+ // Otherwise, find the closest symbol preceding this address (ties are
+ // resolved in favor of the last defined symbol).
+ if (it->getAddress() <= Address &&
+ (!Best || it->getAddress() >= Best->getAddress()))
+ Best = it;
+ }
+
+ return Best;
+}
+
+const MCSymbolData *MCAssembler::getAtom(const MCSymbolData *SD) const {
+ // Linker visible symbols define atoms.
+ if (isSymbolLinkerVisible(SD))
+ return SD;
+
+ // Absolute and undefined symbols have no defining atom.
+ if (!SD->getFragment())
+ return 0;
+
+ // Otherwise, search by address.
+ return getAtomForAddress(SD->getFragment()->getParent(), SD->getAddress());
+}
+
bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout, MCAsmFixup &Fixup,
MCDataFragment *DF,
MCValue &Target, uint64_t &Value) const {
@@ -1028,34 +248,47 @@ bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout, MCAsmFixup &Fixup,
Value = Target.getConstant();
- // FIXME: This "resolved" check isn't quite right. The assumption is that if
- // we have a PCrel access to a temporary, then that temporary is in the same
- // atom, and so the value is resolved. We need explicit atom's to implement
- // this more precisely.
- bool IsResolved = true, IsPCRel = isFixupKindPCRel(Fixup.Kind);
- if (const MCSymbol *Symbol = Target.getSymA()) {
- if (Symbol->isDefined())
- Value += getSymbolData(*Symbol).getAddress();
+ bool IsPCRel =
+ Emitter.getFixupKindInfo(Fixup.Kind).Flags & MCFixupKindInfo::FKF_IsPCRel;
+ bool IsResolved = true;
+ if (const MCSymbolRefExpr *A = Target.getSymA()) {
+ if (A->getSymbol().isDefined())
+ Value += getSymbolData(A->getSymbol()).getAddress();
else
IsResolved = false;
-
- // With scattered symbols, we assume anything that isn't a PCrel temporary
- // access can have an arbitrary value.
- if (getBackend().hasScatteredSymbols() &&
- (!IsPCRel || !Symbol->isTemporary()))
- IsResolved = false;
}
- if (const MCSymbol *Symbol = Target.getSymB()) {
- if (Symbol->isDefined())
- Value -= getSymbolData(*Symbol).getAddress();
+ if (const MCSymbolRefExpr *B = Target.getSymB()) {
+ if (B->getSymbol().isDefined())
+ Value -= getSymbolData(B->getSymbol()).getAddress();
else
IsResolved = false;
+ }
- // With scattered symbols, we assume anything that isn't a PCrel temporary
- // access can have an arbitrary value.
- if (getBackend().hasScatteredSymbols() &&
- (!IsPCRel || !Symbol->isTemporary()))
- IsResolved = false;
+ // If we are using scattered symbols, determine whether this value is actually
+ // resolved; scattering may cause atoms to move.
+ if (IsResolved && getBackend().hasScatteredSymbols()) {
+ if (getBackend().hasReliableSymbolDifference()) {
+ // If this is a PCrel relocation, find the base atom (identified by its
+ // symbol) that the fixup value is relative to.
+ const MCSymbolData *BaseSymbol = 0;
+ if (IsPCRel) {
+ BaseSymbol = getAtomForAddress(
+ DF->getParent(), DF->getAddress() + Fixup.Offset);
+ if (!BaseSymbol)
+ IsResolved = false;
+ }
+
+ if (IsResolved)
+ IsResolved = isScatteredFixupFullyResolved(*this, Fixup, DF, Target,
+ BaseSymbol);
+ } else {
+ const MCSection *BaseSection = 0;
+ if (IsPCRel)
+ BaseSection = &DF->getParent()->getSection();
+
+ IsResolved = isScatteredFixupFullyResolvedSimple(*this, Fixup, DF, Target,
+ BaseSection);
+ }
}
if (IsPCRel)
@@ -1127,7 +360,7 @@ void MCAssembler::LayoutSection(MCSectionData &SD) {
// Set the section sizes.
SD.setSize(Address - SD.getAddress());
- if (isVirtualSection(SD.getSection()))
+ if (getBackend().isVirtualSection(SD.getSection()))
SD.setFileSize(0);
else
SD.setFileSize(Address - SD.getAddress());
@@ -1138,7 +371,7 @@ void MCAssembler::LayoutSection(MCSectionData &SD) {
/// the \arg Count is more than the maximum optimal nops.
///
/// FIXME this is X86 32-bit specific and should move to a better place.
-static uint64_t WriteNopData(uint64_t Count, MachObjectWriter &MOW) {
+static uint64_t WriteNopData(uint64_t Count, MCObjectWriter *OW) {
static const uint8_t Nops[16][16] = {
// nop
{0x90},
@@ -1186,15 +419,14 @@ static uint64_t WriteNopData(uint64_t Count, MachObjectWriter &MOW) {
return 0;
for (uint64_t i = 0; i < Count; i++)
- MOW.Write8 (uint8_t(Nops[Count - 1][i]));
+ OW->Write8(uint8_t(Nops[Count - 1][i]));
return Count;
}
-/// WriteFileData - Write the \arg F data to the output file.
-static void WriteFileData(raw_ostream &OS, const MCFragment &F,
- MachObjectWriter &MOW) {
- uint64_t Start = OS.tell();
+/// WriteFragmentData - Write the \arg F data to the output file.
+static void WriteFragmentData(const MCFragment &F, MCObjectWriter *OW) {
+ uint64_t Start = OW->getStream().tell();
(void) Start;
++EmittedFragments;
@@ -1218,7 +450,7 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F,
// the Count bytes. Then if that did not fill any bytes or there are any
// bytes left to fill use the the Value and ValueSize to fill the rest.
if (AF.getEmitNops()) {
- uint64_t NopByteCount = WriteNopData(Count, MOW);
+ uint64_t NopByteCount = WriteNopData(Count, OW);
Count -= NopByteCount;
}
@@ -1226,26 +458,17 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F,
switch (AF.getValueSize()) {
default:
assert(0 && "Invalid size!");
- case 1: MOW.Write8 (uint8_t (AF.getValue())); break;
- case 2: MOW.Write16(uint16_t(AF.getValue())); break;
- case 4: MOW.Write32(uint32_t(AF.getValue())); break;
- case 8: MOW.Write64(uint64_t(AF.getValue())); break;
+ case 1: OW->Write8 (uint8_t (AF.getValue())); break;
+ case 2: OW->Write16(uint16_t(AF.getValue())); break;
+ case 4: OW->Write32(uint32_t(AF.getValue())); break;
+ case 8: OW->Write64(uint64_t(AF.getValue())); break;
}
}
break;
}
case MCFragment::FT_Data: {
- MCDataFragment &DF = cast<MCDataFragment>(F);
-
- // Apply the fixups.
- //
- // FIXME: Move elsewhere.
- for (MCDataFragment::const_fixup_iterator it = DF.fixup_begin(),
- ie = DF.fixup_end(); it != ie; ++it)
- MOW.ApplyFixup(*it, DF);
-
- OS << cast<MCDataFragment>(F).getContents().str();
+ OW->WriteBytes(cast<MCDataFragment>(F).getContents().str());
break;
}
@@ -1255,10 +478,10 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F,
switch (FF.getValueSize()) {
default:
assert(0 && "Invalid size!");
- case 1: MOW.Write8 (uint8_t (FF.getValue())); break;
- case 2: MOW.Write16(uint16_t(FF.getValue())); break;
- case 4: MOW.Write32(uint32_t(FF.getValue())); break;
- case 8: MOW.Write64(uint64_t(FF.getValue())); break;
+ case 1: OW->Write8 (uint8_t (FF.getValue())); break;
+ case 2: OW->Write16(uint16_t(FF.getValue())); break;
+ case 4: OW->Write32(uint32_t(FF.getValue())); break;
+ case 8: OW->Write64(uint64_t(FF.getValue())); break;
}
}
break;
@@ -1268,7 +491,7 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F,
MCOrgFragment &OF = cast<MCOrgFragment>(F);
for (uint64_t i = 0, e = OF.getFileSize(); i != e; ++i)
- MOW.Write8(uint8_t(OF.getValue()));
+ OW->Write8(uint8_t(OF.getValue()));
break;
}
@@ -1279,30 +502,29 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F,
}
}
- assert(OS.tell() - Start == F.getFileSize());
+ assert(OW->getStream().tell() - Start == F.getFileSize());
}
-/// WriteFileData - Write the \arg SD data to the output file.
-static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
- MachObjectWriter &MOW) {
+void MCAssembler::WriteSectionData(const MCSectionData *SD,
+ MCObjectWriter *OW) const {
// Ignore virtual sections.
- if (isVirtualSection(SD.getSection())) {
- assert(SD.getFileSize() == 0);
+ if (getBackend().isVirtualSection(SD->getSection())) {
+ assert(SD->getFileSize() == 0);
return;
}
- uint64_t Start = OS.tell();
+ uint64_t Start = OW->getStream().tell();
(void) Start;
- for (MCSectionData::const_iterator it = SD.begin(),
- ie = SD.end(); it != ie; ++it)
- WriteFileData(OS, *it, MOW);
+ for (MCSectionData::const_iterator it = SD->begin(),
+ ie = SD->end(); it != ie; ++it)
+ WriteFragmentData(*it, OW);
// Add section padding.
- assert(SD.getFileSize() >= SD.getSize() && "Invalid section sizes!");
- MOW.WriteZeros(SD.getFileSize() - SD.getSize());
+ assert(SD->getFileSize() >= SD->getSize() && "Invalid section sizes!");
+ OW->WriteZeros(SD->getFileSize() - SD->getSize());
- assert(OS.tell() - Start == SD.getFileSize());
+ assert(OW->getStream().tell() - Start == SD->getFileSize());
}
void MCAssembler::Finish() {
@@ -1318,13 +540,47 @@ void MCAssembler::Finish() {
llvm::errs() << "assembler backend - post-layout\n--\n";
dump(); });
- // Write the object file.
- //
// FIXME: Factor out MCObjectWriter.
- bool Is64Bit = StringRef(getBackend().getTarget().getName()) == "x86-64";
- MachObjectWriter MOW(OS, Is64Bit);
- MOW.WriteObject(*this);
+ llvm::OwningPtr<MCObjectWriter> Writer(getBackend().createObjectWriter(OS));
+ if (!Writer)
+ llvm_report_error("unable to create object writer!");
+
+ // Allow the object writer a chance to perform post-layout binding (for
+ // example, to set the index fields in the symbol data).
+ Writer->ExecutePostLayoutBinding(*this);
+
+ // Evaluate and apply the fixups, generating relocation entries as necessary.
+ //
+ // FIXME: Share layout object.
+ MCAsmLayout Layout(*this);
+ for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) {
+ for (MCSectionData::iterator it2 = it->begin(),
+ ie2 = it->end(); it2 != ie2; ++it2) {
+ MCDataFragment *DF = dyn_cast<MCDataFragment>(it2);
+ if (!DF)
+ continue;
+
+ for (MCDataFragment::fixup_iterator it3 = DF->fixup_begin(),
+ ie3 = DF->fixup_end(); it3 != ie3; ++it3) {
+ MCAsmFixup &Fixup = *it3;
+ // Evaluate the fixup.
+ MCValue Target;
+ uint64_t FixedValue;
+ if (!EvaluateFixup(Layout, Fixup, DF, Target, FixedValue)) {
+ // The fixup was unresolved, we need a relocation. Inform the object
+ // writer of the relocation, and give it an opportunity to adjust the
+ // fixup value if need be.
+ Writer->RecordRelocation(*this, *DF, Fixup, Target, FixedValue);
+ }
+
+ getBackend().ApplyFixup(Fixup, *DF, FixedValue);
+ }
+ }
+ }
+
+ // Write the object file.
+ Writer->WriteObject(*this);
OS.flush();
}
@@ -1354,7 +610,7 @@ bool MCAssembler::LayoutOnce() {
MCSectionData &SD = *it;
// Skip virtual sections.
- if (isVirtualSection(SD.getSection()))
+ if (getBackend().isVirtualSection(SD.getSection()))
continue;
// Align this section if necessary by adding padding bytes to the previous
@@ -1377,7 +633,7 @@ bool MCAssembler::LayoutOnce() {
for (iterator it = begin(), ie = end(); it != ie; ++it) {
MCSectionData &SD = *it;
- if (!isVirtualSection(SD.getSection()))
+ if (!getBackend().isVirtualSection(SD.getSection()))
continue;
// Align this section if necessary by adding padding bytes to the previous
diff --git a/lib/MC/MCCodeEmitter.cpp b/lib/MC/MCCodeEmitter.cpp
index accb06c8af54..d51323785541 100644
--- a/lib/MC/MCCodeEmitter.cpp
+++ b/lib/MC/MCCodeEmitter.cpp
@@ -19,10 +19,10 @@ MCCodeEmitter::~MCCodeEmitter() {
const MCFixupKindInfo &MCCodeEmitter::getFixupKindInfo(MCFixupKind Kind) const {
static const MCFixupKindInfo Builtins[] = {
- { "FK_Data_1", 0, 8 },
- { "FK_Data_2", 0, 16 },
- { "FK_Data_4", 0, 32 },
- { "FK_Data_8", 0, 64 }
+ { "FK_Data_1", 0, 8, 0 },
+ { "FK_Data_2", 0, 16, 0 },
+ { "FK_Data_4", 0, 32, 0 },
+ { "FK_Data_8", 0, 64, 0 }
};
assert(Kind <= 3 && "Unknown fixup kind");
diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp
index 70c89a2333af..37e828252602 100644
--- a/lib/MC/MCContext.cpp
+++ b/lib/MC/MCContext.cpp
@@ -49,17 +49,6 @@ MCSymbol *MCContext::CreateTempSymbol() {
"tmp" + Twine(NextUniqueID++));
}
-
-MCSymbol *MCContext::GetOrCreateTemporarySymbol(StringRef Name) {
- // If there is no name, create a new anonymous symbol.
- // FIXME: Remove this. This form of the method should always take a name.
- if (Name.empty())
- return GetOrCreateTemporarySymbol(Twine(MAI.getPrivateGlobalPrefix()) +
- "tmp" + Twine(NextUniqueID++));
-
- return GetOrCreateSymbol(Name, true);
-}
-
MCSymbol *MCContext::GetOrCreateTemporarySymbol(const Twine &Name) {
SmallString<128> NameSV;
Name.toVector(NameSV);
diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp
index a2ed20bb28ca..275994431ee0 100644
--- a/lib/MC/MCExpr.cpp
+++ b/lib/MC/MCExpr.cpp
@@ -30,7 +30,7 @@ void MCExpr::print(raw_ostream &OS) const {
case MCExpr::SymbolRef: {
const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*this);
const MCSymbol &Sym = SRE.getSymbol();
-
+
// Parenthesize names that start with $ so that they don't look like
// absolute names.
if (Sym.getName()[0] == '$')
@@ -59,14 +59,14 @@ void MCExpr::print(raw_ostream &OS) const {
case MCExpr::Binary: {
const MCBinaryExpr &BE = cast<MCBinaryExpr>(*this);
-
+
// Only print parens around the LHS if it is non-trivial.
if (isa<MCConstantExpr>(BE.getLHS()) || isa<MCSymbolRefExpr>(BE.getLHS())) {
OS << *BE.getLHS();
} else {
OS << '(' << *BE.getLHS() << ')';
}
-
+
switch (BE.getOpcode()) {
default: assert(0 && "Invalid opcode!");
case MCBinaryExpr::Add:
@@ -77,7 +77,7 @@ void MCExpr::print(raw_ostream &OS) const {
return;
}
}
-
+
OS << '+';
break;
case MCBinaryExpr::And: OS << '&'; break;
@@ -98,7 +98,7 @@ void MCExpr::print(raw_ostream &OS) const {
case MCBinaryExpr::Sub: OS << '-'; break;
case MCBinaryExpr::Xor: OS << '^'; break;
}
-
+
// Only print parens around the LHS if it is non-trivial.
if (isa<MCConstantExpr>(BE.getRHS()) || isa<MCSymbolRefExpr>(BE.getRHS())) {
OS << *BE.getRHS();
@@ -193,7 +193,7 @@ void MCTargetExpr::Anchor() {}
bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const {
MCValue Value;
-
+
if (!EvaluateAsRelocatable(Value, Layout) || !Value.isAbsolute())
return false;
@@ -201,16 +201,16 @@ bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const {
return true;
}
-static bool EvaluateSymbolicAdd(const MCValue &LHS, const MCSymbol *RHS_A,
- const MCSymbol *RHS_B, int64_t RHS_Cst,
+static bool EvaluateSymbolicAdd(const MCValue &LHS,const MCSymbolRefExpr *RHS_A,
+ const MCSymbolRefExpr *RHS_B, int64_t RHS_Cst,
MCValue &Res) {
// We can't add or subtract two symbols.
if ((LHS.getSymA() && RHS_A) ||
(LHS.getSymB() && RHS_B))
return false;
- const MCSymbol *A = LHS.getSymA() ? LHS.getSymA() : RHS_A;
- const MCSymbol *B = LHS.getSymB() ? LHS.getSymB() : RHS_B;
+ const MCSymbolRefExpr *A = LHS.getSymA() ? LHS.getSymA() : RHS_A;
+ const MCSymbolRefExpr *B = LHS.getSymB() ? LHS.getSymB() : RHS_B;
if (B) {
// If we have a negated symbol, then we must have also have a non-negated
// symbol in order to encode the expression. We can do this check later to
@@ -228,13 +228,14 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res,
switch (getKind()) {
case Target:
return cast<MCTargetExpr>(this)->EvaluateAsRelocatableImpl(Res, Layout);
-
+
case Constant:
Res = MCValue::get(cast<MCConstantExpr>(this)->getValue());
return true;
case SymbolRef: {
- const MCSymbol &Sym = cast<MCSymbolRefExpr>(this)->getSymbol();
+ const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(this);
+ const MCSymbol &Sym = SRE->getSymbol();
// Evaluate recursively if this is a variable.
if (Sym.isVariable()) {
@@ -245,9 +246,12 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res,
// layout object and the target requests it.
if (Layout && Res.getSymB() &&
Layout->getAssembler().getBackend().hasAbsolutizedSet() &&
- Res.getSymA()->isDefined() && Res.getSymB()->isDefined()) {
- MCSymbolData &A = Layout->getAssembler().getSymbolData(*Res.getSymA());
- MCSymbolData &B = Layout->getAssembler().getSymbolData(*Res.getSymB());
+ Res.getSymA()->getSymbol().isDefined() &&
+ Res.getSymB()->getSymbol().isDefined()) {
+ MCSymbolData &A =
+ Layout->getAssembler().getSymbolData(Res.getSymA()->getSymbol());
+ MCSymbolData &B =
+ Layout->getAssembler().getSymbolData(Res.getSymB()->getSymbol());
Res = MCValue::get(+ A.getFragment()->getAddress() + A.getOffset()
- B.getFragment()->getAddress() - B.getOffset()
+ Res.getConstant());
@@ -256,7 +260,7 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res,
return true;
}
- Res = MCValue::get(&Sym, 0, 0);
+ Res = MCValue::get(SRE, 0, 0);
return true;
}
@@ -277,13 +281,13 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res,
/// -(a - b + const) ==> (b - a - const)
if (Value.getSymA() && !Value.getSymB())
return false;
- Res = MCValue::get(Value.getSymB(), Value.getSymA(),
- -Value.getConstant());
+ Res = MCValue::get(Value.getSymB(), Value.getSymA(),
+ -Value.getConstant());
break;
case MCUnaryExpr::Not:
if (!Value.isAbsolute())
return false;
- Res = MCValue::get(~Value.getConstant());
+ Res = MCValue::get(~Value.getConstant());
break;
case MCUnaryExpr::Plus:
Res = Value;
@@ -296,7 +300,7 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res,
case Binary: {
const MCBinaryExpr *ABE = cast<MCBinaryExpr>(this);
MCValue LHSValue, RHSValue;
-
+
if (!ABE->getLHS()->EvaluateAsRelocatable(LHSValue, Layout) ||
!ABE->getRHS()->EvaluateAsRelocatable(RHSValue, Layout))
return false;
diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp
index 73b1074531d1..9504392bc1bc 100644
--- a/lib/MC/MCMachOStreamer.cpp
+++ b/lib/MC/MCMachOStreamer.cpp
@@ -45,7 +45,6 @@ class MCMachOStreamer : public MCStreamer {
private:
MCAssembler Assembler;
- MCCodeEmitter *Emitter;
MCSectionData *CurSectionData;
private:
@@ -61,7 +60,7 @@ private:
public:
MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB,
raw_ostream &_OS, MCCodeEmitter *_Emitter)
- : MCStreamer(Context), Assembler(Context, TAB, _OS), Emitter(_Emitter),
+ : MCStreamer(Context), Assembler(Context, TAB, *_Emitter, _OS),
CurSectionData(0) {}
~MCMachOStreamer() {}
@@ -370,15 +369,12 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) {
if (Inst.getOperand(i).isExpr())
AddValueSymbols(Inst.getOperand(i).getExpr());
- if (!Emitter)
- llvm_unreachable("no code emitter available!");
-
CurSectionData->setHasInstructions(true);
SmallVector<MCFixup, 4> Fixups;
SmallString<256> Code;
raw_svector_ostream VecOS(Code);
- Emitter->EncodeInstruction(Inst, VecOS, Fixups);
+ Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups);
VecOS.flush();
// Add the fixups and data.
diff --git a/lib/MC/MCObjectWriter.cpp b/lib/MC/MCObjectWriter.cpp
new file mode 100644
index 000000000000..d117e82b8a1f
--- /dev/null
+++ b/lib/MC/MCObjectWriter.cpp
@@ -0,0 +1,15 @@
+//===- lib/MC/MCObjectWriter.cpp - MCObjectWriter implementation ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCObjectWriter.h"
+
+using namespace llvm;
+
+MCObjectWriter::~MCObjectWriter() {
+}
diff --git a/lib/MC/MCValue.cpp b/lib/MC/MCValue.cpp
index 043a49d80c6c..c6ea16ce7b4d 100644
--- a/lib/MC/MCValue.cpp
+++ b/lib/MC/MCValue.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/MC/MCValue.h"
+#include "llvm/MC/MCExpr.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -19,10 +20,12 @@ void MCValue::print(raw_ostream &OS, const MCAsmInfo *MAI) const {
return;
}
- OS << *getSymA();
+ getSymA()->print(OS);
- if (getSymB())
- OS << " - " << *getSymB();
+ if (getSymB()) {
+ OS << " - ";
+ getSymB()->print(OS);
+ }
if (getConstant())
OS << " + " << getConstant();
diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp
new file mode 100644
index 000000000000..4b08c226d144
--- /dev/null
+++ b/lib/MC/MachObjectWriter.cpp
@@ -0,0 +1,1109 @@
+//===- 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 X86::reloc_riprel_4byte_movq_load:
+ 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:
+ case X86::reloc_riprel_4byte_movq_load:
+ return true;
+ }
+}
+
+static bool isFixupKindRIPRel(unsigned Kind) {
+ return Kind == X86::reloc_riprel_4byte ||
+ Kind == X86::reloc_riprel_4byte_movq_load;
+}
+
+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
+ };
+
+ /// X86_64 uses its own relocation types.
+ enum RelocationInfoTypeX86_64 {
+ RIT_X86_64_Unsigned = 0,
+ RIT_X86_64_Signed = 1,
+ RIT_X86_64_Branch = 2,
+ RIT_X86_64_GOTLoad = 3,
+ RIT_X86_64_GOT = 4,
+ RIT_X86_64_Subtractor = 5,
+ RIT_X86_64_Signed1 = 6,
+ RIT_X86_64_Signed2 = 7,
+ RIT_X86_64_Signed4 = 8
+ };
+
+ /// 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_SubsectionsViaSymbols;
+
+ // struct mach_header (28 bytes) or
+ // struct mach_header_64 (32 bytes)
+
+ uint64_t Start = OS.tell();
+ (void) Start;
+
+ Write32(Is64Bit ? Header_Magic64 : Header_Magic32);
+
+ // FIXME: Support cputype.
+ Write32(Is64Bit ? MachO::CPUTypeX86_64 : 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);
+ if (Is64Bit)
+ Write32(0); // reserved
+
+ assert(OS.tell() - Start == Is64Bit ? Header64Size : Header32Size);
+ }
+
+ /// WriteSegmentLoadCommand - Write a segment load command.
+ ///
+ /// \arg NumSections - The number of sections in this segment.
+ /// \arg SectionDataSize - The total size of the sections.
+ void WriteSegmentLoadCommand(unsigned NumSections,
+ uint64_t VMSize,
+ uint64_t SectionDataStartOffset,
+ uint64_t SectionDataSize) {
+ // struct segment_command (56 bytes) or
+ // struct segment_command_64 (72 bytes)
+
+ uint64_t Start = OS.tell();
+ (void) Start;
+
+ unsigned SegmentLoadCommandSize = Is64Bit ? SegmentLoadCommand64Size :
+ SegmentLoadCommand32Size;
+ Write32(Is64Bit ? LCT_Segment64 : LCT_Segment);
+ Write32(SegmentLoadCommandSize +
+ NumSections * (Is64Bit ? Section64Size : Section32Size));
+
+ WriteBytes("", 16);
+ if (Is64Bit) {
+ Write64(0); // vmaddr
+ Write64(VMSize); // vmsize
+ Write64(SectionDataStartOffset); // file offset
+ Write64(SectionDataSize); // file size
+ } else {
+ 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 == SegmentLoadCommandSize);
+ }
+
+ void WriteSection(const MCAssembler &Asm, const MCSectionData &SD,
+ uint64_t FileOffset, uint64_t RelocationsStart,
+ unsigned NumRelocations) {
+ // The offset is unused for virtual sections.
+ if (Asm.getBackend().isVirtualSection(SD.getSection())) {
+ assert(SD.getFileSize() == 0 && "Invalid file size!");
+ FileOffset = 0;
+ }
+
+ // struct section (68 bytes) or
+ // struct section_64 (80 bytes)
+
+ uint64_t Start = OS.tell();
+ (void) Start;
+
+ // FIXME: cast<> support!
+ const MCSectionMachO &Section =
+ static_cast<const MCSectionMachO&>(SD.getSection());
+ WriteBytes(Section.getSectionName(), 16);
+ WriteBytes(Section.getSegmentName(), 16);
+ if (Is64Bit) {
+ Write64(SD.getAddress()); // address
+ Write64(SD.getSize()); // size
+ } else {
+ 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
+ if (Is64Bit)
+ Write32(0); // reserved3
+
+ assert(OS.tell() - Start == Is64Bit ? Section64Size : 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 WriteNlist(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.getAddress();
+ }
+ } 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);
+ if (Is64Bit)
+ Write64(Address);
+ else
+ Write32(Address);
+ }
+
+ void RecordX86_64Relocation(const MCAssembler &Asm,
+ const MCDataFragment &Fragment,
+ const MCAsmFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue) {
+ unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind);
+ unsigned IsRIPRel = isFixupKindRIPRel(Fixup.Kind);
+ unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind);
+
+ // See <reloc.h>.
+ uint32_t Address = Fragment.getOffset() + Fixup.Offset;
+ int64_t Value = 0;
+ unsigned Index = 0;
+ unsigned IsExtern = 0;
+ unsigned Type = 0;
+
+ Value = Target.getConstant();
+
+ if (IsPCRel) {
+ // Compensate for the relocation offset, Darwin x86_64 relocations only
+ // have the addend and appear to have attempted to define it to be the
+ // actual expression addend without the PCrel bias. However, instructions
+ // with data following the relocation are not accomodated for (see comment
+ // below regarding SIGNED{1,2,4}), so it isn't exactly that either.
+ Value += 1 << Log2Size;
+ }
+
+ if (Target.isAbsolute()) { // constant
+ // SymbolNum of 0 indicates the absolute section.
+ Type = RIT_X86_64_Unsigned;
+ Index = 0;
+
+ // FIXME: I believe this is broken, I don't think the linker can
+ // understand it. I think it would require a local relocation, but I'm not
+ // sure if that would work either. The official way to get an absolute
+ // PCrel relocation is to use an absolute symbol (which we don't support
+ // yet).
+ if (IsPCRel) {
+ IsExtern = 1;
+ Type = RIT_X86_64_Branch;
+ }
+ } else if (Target.getSymB()) { // A - B + constant
+ const MCSymbol *A = &Target.getSymA()->getSymbol();
+ MCSymbolData &A_SD = Asm.getSymbolData(*A);
+ const MCSymbolData *A_Base = Asm.getAtom(&A_SD);
+
+ const MCSymbol *B = &Target.getSymB()->getSymbol();
+ MCSymbolData &B_SD = Asm.getSymbolData(*B);
+ const MCSymbolData *B_Base = Asm.getAtom(&B_SD);
+
+ // Neither symbol can be modified.
+ if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None ||
+ Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None)
+ llvm_report_error("unsupported relocation of modified symbol");
+
+ // We don't support PCrel relocations of differences. Darwin 'as' doesn't
+ // implement most of these correctly.
+ if (IsPCRel)
+ llvm_report_error("unsupported pc-relative relocation of difference");
+
+ // We don't currently support any situation where one or both of the
+ // symbols would require a local relocation. This is almost certainly
+ // unused and may not be possible to encode correctly.
+ if (!A_Base || !B_Base)
+ llvm_report_error("unsupported local relocations in difference");
+
+ // Darwin 'as' doesn't emit correct relocations for this (it ends up with
+ // a single SIGNED relocation); reject it for now.
+ if (A_Base == B_Base)
+ llvm_report_error("unsupported relocation with identical base");
+
+ Value += A_SD.getAddress() - A_Base->getAddress();
+ Value -= B_SD.getAddress() - B_Base->getAddress();
+
+ Index = A_Base->getIndex();
+ IsExtern = 1;
+ Type = RIT_X86_64_Unsigned;
+
+ MachRelocationEntry MRE;
+ MRE.Word0 = Address;
+ MRE.Word1 = ((Index << 0) |
+ (IsPCRel << 24) |
+ (Log2Size << 25) |
+ (IsExtern << 27) |
+ (Type << 28));
+ Relocations[Fragment.getParent()].push_back(MRE);
+
+ Index = B_Base->getIndex();
+ IsExtern = 1;
+ Type = RIT_X86_64_Subtractor;
+ } else {
+ const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
+ MCSymbolData &SD = Asm.getSymbolData(*Symbol);
+ const MCSymbolData *Base = Asm.getAtom(&SD);
+
+ // x86_64 almost always uses external relocations, except when there is no
+ // symbol to use as a base address (a local symbol with no preceeding
+ // non-local symbol).
+ if (Base) {
+ Index = Base->getIndex();
+ IsExtern = 1;
+
+ // Add the local offset, if needed.
+ if (Base != &SD)
+ Value += SD.getAddress() - Base->getAddress();
+ } else {
+ // The index is the section ordinal.
+ //
+ // FIXME: O(N)
+ Index = 1;
+ MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end();
+ for (; it != ie; ++it, ++Index)
+ if (&*it == SD.getFragment()->getParent())
+ break;
+ assert(it != ie && "Unable to find section index!");
+ IsExtern = 0;
+ Value += SD.getAddress();
+
+ if (IsPCRel)
+ Value -= Address + (1 << Log2Size);
+ }
+
+ MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind();
+ if (IsPCRel) {
+ if (IsRIPRel) {
+ if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
+ // x86_64 distinguishes movq foo@GOTPCREL so that the linker can
+ // rewrite the movq to an leaq at link time if the symbol ends up in
+ // the same linkage unit.
+ if (unsigned(Fixup.Kind) == X86::reloc_riprel_4byte_movq_load)
+ Type = RIT_X86_64_GOTLoad;
+ else
+ Type = RIT_X86_64_GOT;
+ } else if (Modifier != MCSymbolRefExpr::VK_None)
+ llvm_report_error("unsupported symbol modifier in relocation");
+ else
+ Type = RIT_X86_64_Signed;
+ } else {
+ if (Modifier != MCSymbolRefExpr::VK_None)
+ llvm_report_error("unsupported symbol modifier in branch "
+ "relocation");
+
+ Type = RIT_X86_64_Branch;
+ }
+
+ // The Darwin x86_64 relocation format has a problem where it cannot
+ // encode an address (L<foo> + <constant>) which is outside the atom
+ // containing L<foo>. Generally, this shouldn't occur but it does happen
+ // when we have a RIPrel instruction with data following the relocation
+ // entry (e.g., movb $012, L0(%rip)). Even with the PCrel adjustment
+ // Darwin x86_64 uses, the offset is still negative and the linker has
+ // no way to recognize this.
+ //
+ // To work around this, Darwin uses several special relocation types to
+ // indicate the offsets. However, the specification or implementation of
+ // these seems to also be incomplete; they should adjust the addend as
+ // well based on the actual encoded instruction (the additional bias),
+ // but instead appear to just look at the final offset.
+ if (IsRIPRel) {
+ switch (-(Target.getConstant() + (1 << Log2Size))) {
+ case 1: Type = RIT_X86_64_Signed1; break;
+ case 2: Type = RIT_X86_64_Signed2; break;
+ case 4: Type = RIT_X86_64_Signed4; break;
+ }
+ }
+ } else {
+ if (Modifier == MCSymbolRefExpr::VK_GOT)
+ Type = RIT_X86_64_GOT;
+ else if (Modifier != MCSymbolRefExpr::VK_None)
+ llvm_report_error("unsupported symbol modifier in relocation");
+ else
+ Type = RIT_X86_64_Unsigned;
+ }
+ }
+
+ // x86_64 always writes custom values into the fixups.
+ FixedValue = Value;
+
+ // struct relocation_info (8 bytes)
+ MachRelocationEntry MRE;
+ MRE.Word0 = Address;
+ MRE.Word1 = ((Index << 0) |
+ (IsPCRel << 24) |
+ (Log2Size << 25) |
+ (IsExtern << 27) |
+ (Type << 28));
+ Relocations[Fragment.getParent()].push_back(MRE);
+ }
+
+ void RecordScatteredRelocation(const MCAssembler &Asm,
+ const MCFragment &Fragment,
+ const MCAsmFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue) {
+ 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()->getSymbol();
+ MCSymbolData *A_SD = &Asm.getSymbolData(*A);
+
+ if (!A_SD->getFragment())
+ llvm_report_error("symbol '" + A->getName() +
+ "' can not be undefined in a subtraction expression");
+
+ uint32_t Value = A_SD->getAddress();
+ uint32_t Value2 = 0;
+
+ if (const MCSymbolRefExpr *B = Target.getSymB()) {
+ MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
+
+ if (!B_SD->getFragment())
+ llvm_report_error("symbol '" + B->getSymbol().getName() +
+ "' can not be undefined in a subtraction expression");
+
+ // Select the appropriate difference relocation type.
+ //
+ // Note that there is no longer any semantic difference between these two
+ // relocation types from the linkers point of view, this is done solely
+ // for pedantic compatibility with 'as'.
+ Type = A_SD->isExternal() ? RIT_Difference : RIT_LocalDifference;
+ Value2 = B_SD->getAddress();
+ }
+
+ // Relocations are written out in reverse order, so the PAIR comes first.
+ if (Type == RIT_Difference || Type == RIT_LocalDifference) {
+ MachRelocationEntry MRE;
+ MRE.Word0 = ((0 << 0) |
+ (RIT_Pair << 24) |
+ (Log2Size << 28) |
+ (IsPCRel << 30) |
+ RF_Scattered);
+ MRE.Word1 = Value2;
+ Relocations[Fragment.getParent()].push_back(MRE);
+ }
+
+ MachRelocationEntry MRE;
+ MRE.Word0 = ((Address << 0) |
+ (Type << 24) |
+ (Log2Size << 28) |
+ (IsPCRel << 30) |
+ RF_Scattered);
+ MRE.Word1 = Value;
+ Relocations[Fragment.getParent()].push_back(MRE);
+ }
+
+ void RecordRelocation(const MCAssembler &Asm, const MCDataFragment &Fragment,
+ const MCAsmFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue) {
+ if (Is64Bit) {
+ RecordX86_64Relocation(Asm, Fragment, Fixup, Target, FixedValue);
+ return;
+ }
+
+ unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind);
+ unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind);
+
+ // If this is a difference or a defined symbol plus an offset, then we need
+ // a scattered relocation entry.
+ uint32_t Offset = Target.getConstant();
+ if (IsPCRel)
+ Offset += 1 << Log2Size;
+ if (Target.getSymB() ||
+ (Target.getSymA() && !Target.getSymA()->getSymbol().isUndefined() &&
+ Offset)) {
+ RecordScatteredRelocation(Asm, Fragment, Fixup, Target, FixedValue);
+ return;
+ }
+
+ // See <reloc.h>.
+ uint32_t Address = Fragment.getOffset() + Fixup.Offset;
+ uint32_t Value = 0;
+ unsigned Index = 0;
+ unsigned IsExtern = 0;
+ unsigned Type = 0;
+
+ if (Target.isAbsolute()) { // constant
+ // SymbolNum of 0 indicates the absolute section.
+ //
+ // FIXME: Currently, these are never generated (see code below). I cannot
+ // find a case where they are actually emitted.
+ Type = RIT_Vanilla;
+ Value = 0;
+ } else {
+ const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
+ MCSymbolData *SD = &Asm.getSymbolData(*Symbol);
+
+ if (Symbol->isUndefined()) {
+ IsExtern = 1;
+ Index = SD->getIndex();
+ Value = 0;
+ } else {
+ // The index is the section ordinal.
+ //
+ // FIXME: O(N)
+ Index = 1;
+ MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end();
+ for (; it != ie; ++it, ++Index)
+ if (&*it == SD->getFragment()->getParent())
+ break;
+ assert(it != ie && "Unable to find section index!");
+ Value = SD->getAddress();
+ }
+
+ Type = RIT_Vanilla;
+ }
+
+ // struct relocation_info (8 bytes)
+ MachRelocationEntry MRE;
+ MRE.Word0 = Address;
+ MRE.Word1 = ((Index << 0) |
+ (IsPCRel << 24) |
+ (Log2Size << 25) |
+ (IsExtern << 27) |
+ (Type << 28));
+ Relocations[Fragment.getParent()].push_back(MRE);
+ }
+
+ void BindIndirectSymbols(MCAssembler &Asm) {
+ // This is the point where 'as' creates actual symbols for indirect symbols
+ // (in the following two passes). It would be easier for us to do this
+ // sooner when we see the attribute, but that makes getting the order in the
+ // symbol table much more complicated than it is worth.
+ //
+ // FIXME: Revisit this when the dust settles.
+
+ // Bind non lazy symbol pointers first.
+ for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
+ ie = Asm.indirect_symbol_end(); it != ie; ++it) {
+ // FIXME: cast<> support!
+ const MCSectionMachO &Section =
+ static_cast<const MCSectionMachO&>(it->SectionData->getSection());
+
+ if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS)
+ continue;
+
+ Asm.getOrCreateSymbolData(*it->Symbol);
+ }
+
+ // Then lazy symbol pointers and symbol stubs.
+ for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
+ ie = Asm.indirect_symbol_end(); it != ie; ++it) {
+ // FIXME: cast<> support!
+ const MCSectionMachO &Section =
+ static_cast<const MCSectionMachO&>(it->SectionData->getSection());
+
+ if (Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS &&
+ Section.getType() != MCSectionMachO::S_SYMBOL_STUBS)
+ continue;
+
+ // Set the symbol type to undefined lazy, but only on construction.
+ //
+ // FIXME: Do not hardcode.
+ bool Created;
+ MCSymbolData &Entry = Asm.getOrCreateSymbolData(*it->Symbol, &Created);
+ if (Created)
+ Entry.setFlags(Entry.getFlags() | 0x0001);
+ }
+ }
+
+ /// ComputeSymbolTable - Compute the symbol table data
+ ///
+ /// \param StringTable [out] - The string table data.
+ /// \param StringIndexMap [out] - Map from symbol names to offsets in the
+ /// string table.
+ void ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable,
+ std::vector<MachSymbolData> &LocalSymbolData,
+ std::vector<MachSymbolData> &ExternalSymbolData,
+ std::vector<MachSymbolData> &UndefinedSymbolData) {
+ // Build section lookup table.
+ DenseMap<const MCSection*, uint8_t> SectionIndexMap;
+ unsigned Index = 1;
+ for (MCAssembler::iterator it = Asm.begin(),
+ ie = Asm.end(); it != ie; ++it, ++Index)
+ SectionIndexMap[&it->getSection()] = Index;
+ assert(Index <= 256 && "Too many sections!");
+
+ // Index 0 is always the empty string.
+ StringMap<uint64_t> StringIndexMap;
+ StringTable += '\x00';
+
+ // Build the symbol arrays and the string table, but only for non-local
+ // symbols.
+ //
+ // The particular order that we collect the symbols and create the string
+ // table, then sort the symbols is chosen to match 'as'. Even though it
+ // doesn't matter for correctness, this is important for letting us diff .o
+ // files.
+ for (MCAssembler::symbol_iterator it = Asm.symbol_begin(),
+ ie = Asm.symbol_end(); it != ie; ++it) {
+ const MCSymbol &Symbol = it->getSymbol();
+
+ // Ignore non-linker visible symbols.
+ if (!Asm.isSymbolLinkerVisible(it))
+ continue;
+
+ if (!it->isExternal() && !Symbol.isUndefined())
+ continue;
+
+ uint64_t &Entry = StringIndexMap[Symbol.getName()];
+ if (!Entry) {
+ Entry = StringTable.size();
+ StringTable += Symbol.getName();
+ StringTable += '\x00';
+ }
+
+ MachSymbolData MSD;
+ MSD.SymbolData = it;
+ MSD.StringIndex = Entry;
+
+ if (Symbol.isUndefined()) {
+ MSD.SectionIndex = 0;
+ UndefinedSymbolData.push_back(MSD);
+ } else if (Symbol.isAbsolute()) {
+ MSD.SectionIndex = 0;
+ ExternalSymbolData.push_back(MSD);
+ } else {
+ MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection());
+ assert(MSD.SectionIndex && "Invalid section index!");
+ ExternalSymbolData.push_back(MSD);
+ }
+ }
+
+ // Now add the data for local symbols.
+ for (MCAssembler::symbol_iterator it = Asm.symbol_begin(),
+ ie = Asm.symbol_end(); it != ie; ++it) {
+ const MCSymbol &Symbol = it->getSymbol();
+
+ // Ignore non-linker visible symbols.
+ if (!Asm.isSymbolLinkerVisible(it))
+ continue;
+
+ if (it->isExternal() || Symbol.isUndefined())
+ continue;
+
+ uint64_t &Entry = StringIndexMap[Symbol.getName()];
+ if (!Entry) {
+ Entry = StringTable.size();
+ StringTable += Symbol.getName();
+ StringTable += '\x00';
+ }
+
+ MachSymbolData MSD;
+ MSD.SymbolData = it;
+ MSD.StringIndex = Entry;
+
+ if (Symbol.isAbsolute()) {
+ MSD.SectionIndex = 0;
+ LocalSymbolData.push_back(MSD);
+ } else {
+ MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection());
+ assert(MSD.SectionIndex && "Invalid section index!");
+ LocalSymbolData.push_back(MSD);
+ }
+ }
+
+ // External and undefined symbols are required to be in lexicographic order.
+ std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end());
+ std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end());
+
+ // Set the symbol indices.
+ Index = 0;
+ for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i)
+ LocalSymbolData[i].SymbolData->setIndex(Index++);
+ for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i)
+ ExternalSymbolData[i].SymbolData->setIndex(Index++);
+ for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i)
+ UndefinedSymbolData[i].SymbolData->setIndex(Index++);
+
+ // The string table is padded to a multiple of 4.
+ while (StringTable.size() % 4)
+ StringTable += '\x00';
+ }
+
+ void ExecutePostLayoutBinding(MCAssembler &Asm) {
+ // Create symbol data for any indirect symbols.
+ BindIndirectSymbols(Asm);
+
+ // Compute symbol table information and bind symbol indices.
+ ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData,
+ UndefinedSymbolData);
+ }
+
+ void WriteObject(const MCAssembler &Asm) {
+ unsigned NumSections = Asm.size();
+
+ // The section data starts after the header, the segment load command (and
+ // section headers) and the symbol table.
+ unsigned NumLoadCommands = 1;
+ uint64_t LoadCommandsSize = Is64Bit ?
+ SegmentLoadCommand64Size + NumSections * Section64Size :
+ SegmentLoadCommand32Size + NumSections * Section32Size;
+
+ // Add the symbol table load command sizes, if used.
+ unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() +
+ UndefinedSymbolData.size();
+ if (NumSymbols) {
+ NumLoadCommands += 2;
+ LoadCommandsSize += SymtabLoadCommandSize + DysymtabLoadCommandSize;
+ }
+
+ // Compute the total size of the section data, as well as its file size and
+ // vm size.
+ uint64_t SectionDataStart = (Is64Bit ? Header64Size : Header32Size)
+ + LoadCommandsSize;
+ uint64_t SectionDataSize = 0;
+ uint64_t SectionDataFileSize = 0;
+ uint64_t VMSize = 0;
+ for (MCAssembler::const_iterator it = Asm.begin(),
+ ie = Asm.end(); it != ie; ++it) {
+ const MCSectionData &SD = *it;
+
+ VMSize = std::max(VMSize, SD.getAddress() + SD.getSize());
+
+ if (Asm.getBackend().isVirtualSection(SD.getSection()))
+ continue;
+
+ SectionDataSize = std::max(SectionDataSize,
+ SD.getAddress() + SD.getSize());
+ SectionDataFileSize = std::max(SectionDataFileSize,
+ SD.getAddress() + SD.getFileSize());
+ }
+
+ // The section data is padded to 4 bytes.
+ //
+ // FIXME: Is this machine dependent?
+ unsigned SectionDataPadding = OffsetToAlignment(SectionDataFileSize, 4);
+ SectionDataFileSize += SectionDataPadding;
+
+ // Write the prolog, starting with the header and load command...
+ WriteHeader(NumLoadCommands, LoadCommandsSize,
+ Asm.getSubsectionsViaSymbols());
+ WriteSegmentLoadCommand(NumSections, VMSize,
+ SectionDataStart, SectionDataSize);
+
+ // ... and then the section headers.
+ uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize;
+ for (MCAssembler::const_iterator it = Asm.begin(),
+ ie = Asm.end(); it != ie; ++it) {
+ std::vector<MachRelocationEntry> &Relocs = Relocations[it];
+ unsigned NumRelocs = Relocs.size();
+ uint64_t SectionStart = SectionDataStart + it->getAddress();
+ WriteSection(Asm, *it, SectionStart, RelocTableEnd, NumRelocs);
+ RelocTableEnd += NumRelocs * RelocationInfoSize;
+ }
+
+ // Write the symbol table load command, if used.
+ if (NumSymbols) {
+ unsigned FirstLocalSymbol = 0;
+ unsigned NumLocalSymbols = LocalSymbolData.size();
+ unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols;
+ unsigned NumExternalSymbols = ExternalSymbolData.size();
+ unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols;
+ unsigned NumUndefinedSymbols = UndefinedSymbolData.size();
+ unsigned NumIndirectSymbols = Asm.indirect_symbol_size();
+ unsigned NumSymTabSymbols =
+ NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols;
+ uint64_t IndirectSymbolSize = NumIndirectSymbols * 4;
+ uint64_t IndirectSymbolOffset = 0;
+
+ // If used, the indirect symbols are written after the section data.
+ if (NumIndirectSymbols)
+ IndirectSymbolOffset = RelocTableEnd;
+
+ // The symbol table is written after the indirect symbol data.
+ uint64_t SymbolTableOffset = RelocTableEnd + IndirectSymbolSize;
+
+ // The string table is written after symbol table.
+ uint64_t StringTableOffset =
+ SymbolTableOffset + NumSymTabSymbols * (Is64Bit ? Nlist64Size :
+ Nlist32Size);
+ WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols,
+ StringTableOffset, StringTable.size());
+
+ WriteDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols,
+ FirstExternalSymbol, NumExternalSymbols,
+ FirstUndefinedSymbol, NumUndefinedSymbols,
+ IndirectSymbolOffset, NumIndirectSymbols);
+ }
+
+ // Write the actual section data.
+ for (MCAssembler::const_iterator it = Asm.begin(),
+ ie = Asm.end(); it != ie; ++it)
+ Asm.WriteSectionData(it, Writer);
+
+ // Write the extra padding.
+ WriteZeros(SectionDataPadding);
+
+ // Write the relocation entries.
+ for (MCAssembler::const_iterator it = Asm.begin(),
+ ie = Asm.end(); it != ie; ++it) {
+ // Write the section relocation entries, in reverse order to match 'as'
+ // (approximately, the exact algorithm is more complicated than this).
+ std::vector<MachRelocationEntry> &Relocs = Relocations[it];
+ for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
+ Write32(Relocs[e - i - 1].Word0);
+ Write32(Relocs[e - i - 1].Word1);
+ }
+ }
+
+ // Write the symbol table data, if used.
+ if (NumSymbols) {
+ // Write the indirect symbol entries.
+ for (MCAssembler::const_indirect_symbol_iterator
+ it = Asm.indirect_symbol_begin(),
+ ie = Asm.indirect_symbol_end(); it != ie; ++it) {
+ // Indirect symbols in the non lazy symbol pointer section have some
+ // special handling.
+ const MCSectionMachO &Section =
+ static_cast<const MCSectionMachO&>(it->SectionData->getSection());
+ if (Section.getType() == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) {
+ // If this symbol is defined and internal, mark it as such.
+ if (it->Symbol->isDefined() &&
+ !Asm.getSymbolData(*it->Symbol).isExternal()) {
+ uint32_t Flags = ISF_Local;
+ if (it->Symbol->isAbsolute())
+ Flags |= ISF_Absolute;
+ Write32(Flags);
+ continue;
+ }
+ }
+
+ Write32(Asm.getSymbolData(*it->Symbol).getIndex());
+ }
+
+ // FIXME: Check that offsets match computed ones.
+
+ // Write the symbol table entries.
+ for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i)
+ WriteNlist(LocalSymbolData[i]);
+ for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i)
+ WriteNlist(ExternalSymbolData[i]);
+ for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i)
+ WriteNlist(UndefinedSymbolData[i]);
+
+ // Write the string table.
+ OS << StringTable.str();
+ }
+ }
+};
+
+}
+
+MachObjectWriter::MachObjectWriter(raw_ostream &OS,
+ bool Is64Bit,
+ bool IsLittleEndian)
+ : MCObjectWriter(OS, IsLittleEndian)
+{
+ Impl = new MachObjectWriterImpl(this, Is64Bit);
+}
+
+MachObjectWriter::~MachObjectWriter() {
+ delete (MachObjectWriterImpl*) Impl;
+}
+
+void MachObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) {
+ ((MachObjectWriterImpl*) Impl)->ExecutePostLayoutBinding(Asm);
+}
+
+void MachObjectWriter::RecordRelocation(const MCAssembler &Asm,
+ const MCDataFragment &Fragment,
+ const MCAsmFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue) {
+ ((MachObjectWriterImpl*) Impl)->RecordRelocation(Asm, Fragment, Fixup,
+ Target, FixedValue);
+}
+
+void MachObjectWriter::WriteObject(const MCAssembler &Asm) {
+ ((MachObjectWriterImpl*) Impl)->WriteObject(Asm);
+}
diff --git a/lib/MC/TargetAsmBackend.cpp b/lib/MC/TargetAsmBackend.cpp
index 918d2727daa6..bbfddbe9e71f 100644
--- a/lib/MC/TargetAsmBackend.cpp
+++ b/lib/MC/TargetAsmBackend.cpp
@@ -11,7 +11,10 @@
using namespace llvm;
TargetAsmBackend::TargetAsmBackend(const Target &T)
- : TheTarget(T)
+ : TheTarget(T),
+ HasAbsolutizedSet(false),
+ HasReliableSymbolDifference(false),
+ HasScatteredSymbols(false)
{
}