aboutsummaryrefslogtreecommitdiff
path: root/lib/MC/MachObjectWriter.cpp
diff options
context:
space:
mode:
authorBill Wendling <isanbard@gmail.com>2011-06-22 21:07:27 +0000
committerBill Wendling <isanbard@gmail.com>2011-06-22 21:07:27 +0000
commitbbdffa9ab0597b64689c51f2c4a87a781f3bf79d (patch)
tree72a2280a2a5d510d2bd48b430252709f13be90be /lib/MC/MachObjectWriter.cpp
parentdf3ad6697bb849e514c0881ca8700ea36678cbda (diff)
Move class methods out-of-line. This reduces the indentation, and is more in
line with LLVM's general coding style. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@133645 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/MC/MachObjectWriter.cpp')
-rw-r--r--lib/MC/MachObjectWriter.cpp2699
1 files changed, 1410 insertions, 1289 deletions
diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp
index f049b1c6e2..1819c4053b 100644
--- a/lib/MC/MachObjectWriter.cpp
+++ b/lib/MC/MachObjectWriter.cpp
@@ -120,37 +120,8 @@ private:
return SectionAddress.lookup(SD);
}
uint64_t getSymbolAddress(const MCSymbolData* SD,
- const MCAsmLayout &Layout) const {
- const MCSymbol &S = SD->getSymbol();
-
- // If this is a variable, then recursively evaluate now.
- if (S.isVariable()) {
- MCValue Target;
- if (!S.getVariableValue()->EvaluateAsRelocatable(Target, Layout))
- report_fatal_error("unable to evaluate offset for variable '" +
- S.getName() + "'");
-
- // Verify that any used symbols are defined.
- if (Target.getSymA() && Target.getSymA()->getSymbol().isUndefined())
- report_fatal_error("unable to evaluate offset to undefined symbol '" +
- Target.getSymA()->getSymbol().getName() + "'");
- if (Target.getSymB() && Target.getSymB()->getSymbol().isUndefined())
- report_fatal_error("unable to evaluate offset to undefined symbol '" +
- Target.getSymB()->getSymbol().getName() + "'");
-
- uint64_t Address = Target.getConstant();
- if (Target.getSymA())
- Address += getSymbolAddress(&Layout.getAssembler().getSymbolData(
- Target.getSymA()->getSymbol()), Layout);
- if (Target.getSymB())
- Address += getSymbolAddress(&Layout.getAssembler().getSymbolData(
- Target.getSymB()->getSymbol()), Layout);
- return Address;
- }
+ const MCAsmLayout &Layout) const;
- return getSectionAddress(SD->getFragment()->getParent()) +
- Layout.getSymbolOffset(SD);
- }
uint64_t getFragmentAddress(const MCFragment *Fragment,
const MCAsmLayout &Layout) const {
return getSectionAddress(Fragment->getParent()) +
@@ -158,18 +129,7 @@ private:
}
uint64_t getPaddingSize(const MCSectionData *SD,
- const MCAsmLayout &Layout) const {
- uint64_t EndAddr = getSectionAddress(SD) + Layout.getSectionAddressSize(SD);
- unsigned Next = SD->getLayoutOrder() + 1;
- if (Next >= Layout.getSectionOrder().size())
- return 0;
-
- const MCSectionData &NextSD = *Layout.getSectionOrder()[Next];
- if (NextSD.getSection().isVirtualSection())
- return 0;
- return OffsetToAlignment(EndAddr, NextSD.getAlignment());
- }
-
+ const MCAsmLayout &Layout) const;
public:
MachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_ostream &_OS,
bool _IsLittleEndian)
@@ -188,33 +148,7 @@ public:
/// @}
void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize,
- bool SubsectionsViaSymbols) {
- uint32_t Flags = 0;
-
- if (SubsectionsViaSymbols)
- Flags |= macho::HF_SubsectionsViaSymbols;
-
- // struct mach_header (28 bytes) or
- // struct mach_header_64 (32 bytes)
-
- uint64_t Start = OS.tell();
- (void) Start;
-
- Write32(is64Bit() ? macho::HM_Object64 : macho::HM_Object32);
-
- Write32(TargetObjectWriter->getCPUType());
- Write32(TargetObjectWriter->getCPUSubtype());
-
- Write32(macho::HFT_Object);
- Write32(NumLoadCommands);
- Write32(LoadCommandsSize);
- Write32(Flags);
- if (is64Bit())
- Write32(0); // reserved
-
- assert(OS.tell() - Start ==
- (is64Bit() ? macho::Header64Size : macho::Header32Size));
- }
+ bool SubsectionsViaSymbols);
/// WriteSegmentLoadCommand - Write a segment load command.
///
@@ -223,105 +157,15 @@ public:
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() ? macho::SegmentLoadCommand64Size:
- macho::SegmentLoadCommand32Size;
- Write32(is64Bit() ? macho::LCT_Segment64 : macho::LCT_Segment);
- Write32(SegmentLoadCommandSize +
- NumSections * (is64Bit() ? macho::Section64Size :
- macho::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);
- }
+ uint64_t SectionDataSize);
void WriteSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
const MCSectionData &SD, uint64_t FileOffset,
- uint64_t RelocationsStart, unsigned NumRelocations) {
- uint64_t SectionSize = Layout.getSectionAddressSize(&SD);
-
- // The offset is unused for virtual sections.
- if (SD.getSection().isVirtualSection()) {
- assert(Layout.getSectionFileSize(&SD) == 0 && "Invalid file size!");
- FileOffset = 0;
- }
-
- // struct section (68 bytes) or
- // struct section_64 (80 bytes)
-
- uint64_t Start = OS.tell();
- (void) Start;
-
- const MCSectionMachO &Section = cast<MCSectionMachO>(SD.getSection());
- WriteBytes(Section.getSectionName(), 16);
- WriteBytes(Section.getSegmentName(), 16);
- if (is64Bit()) {
- Write64(getSectionAddress(&SD)); // address
- Write64(SectionSize); // size
- } else {
- Write32(getSectionAddress(&SD)); // address
- Write32(SectionSize); // 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(IndirectSymBase.lookup(&SD)); // reserved1
- Write32(Section.getStubSize()); // reserved2
- if (is64Bit())
- Write32(0); // reserved3
-
- assert(OS.tell() - Start == (is64Bit() ? macho::Section64Size :
- macho::Section32Size));
- }
+ uint64_t RelocationsStart, unsigned NumRelocations);
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(macho::LCT_Symtab);
- Write32(macho::SymtabLoadCommandSize);
- Write32(SymbolOffset);
- Write32(NumSymbols);
- Write32(StringTableOffset);
- Write32(StringTableSize);
-
- assert(OS.tell() - Start == macho::SymtabLoadCommandSize);
- }
+ uint32_t StringTableSize);
void WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol,
uint32_t NumLocalSymbols,
@@ -330,100 +174,9 @@ public:
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(macho::LCT_Dysymtab);
- Write32(macho::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 == macho::DysymtabLoadCommandSize);
- }
-
- void WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout) {
- 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 = macho::STT_Undefined;
- else if (Symbol.isAbsolute())
- Type = macho::STT_Absolute;
- else
- Type = macho::STT_Section;
-
- // FIXME: Set STAB bits.
-
- if (Data.isPrivateExtern())
- Type |= macho::STF_PrivateExtern;
-
- // Set external bit.
- if (Data.isExternal() || Symbol.isUndefined())
- Type |= macho::STF_External;
-
- // Compute the symbol address.
- if (Symbol.isDefined()) {
- if (Symbol.isAbsolute()) {
- Address = cast<MCConstantExpr>(Symbol.getVariableValue())->getValue();
- } else {
- Address = getSymbolAddress(&Data, Layout);
- }
- } 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)
- report_fatal_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);
+ uint32_t NumIndirectSymbols);
- // 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 WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout);
// FIXME: We really need to improve the relocation validation. Basically, we
// want to implement a separate computation which evaluates the relocation
@@ -446,650 +199,453 @@ public:
void RecordX86_64Relocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
const MCFragment *Fragment,
const MCFixup &Fixup, MCValue Target,
- uint64_t &FixedValue) {
- unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind());
- unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind());
- unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
-
- // See <reloc.h>.
- uint32_t FixupOffset =
- Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
- uint32_t FixupAddress =
- getFragmentAddress(Fragment, Layout) + Fixup.getOffset();
- 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 accommodated for (see comment
- // below regarding SIGNED{1,2,4}), so it isn't exactly that either.
- Value += 1LL << Log2Size;
- }
-
- if (Target.isAbsolute()) { // constant
- // SymbolNum of 0 indicates the absolute section.
- Type = macho::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 = macho::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)
- report_fatal_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)
- report_fatal_error("unsupported pc-relative relocation of difference");
-
- // The support for the situation where one or both of the symbols would
- // require a local relocation is handled just like if the symbols were
- // external. This is certainly used in the case of debug sections where
- // the section has only temporary symbols and thus the symbols don't have
- // base symbols. This is encoded using the section ordinal and
- // non-extern relocation entries.
-
- // Darwin 'as' doesn't emit correct relocations for this (it ends up with
- // a single SIGNED relocation); reject it for now. Except the case where
- // both symbols don't have a base, equal but both NULL.
- if (A_Base == B_Base && A_Base)
- report_fatal_error("unsupported relocation with identical base");
-
- Value += getSymbolAddress(&A_SD, Layout) -
- (A_Base == NULL ? 0 : getSymbolAddress(A_Base, Layout));
- Value -= getSymbolAddress(&B_SD, Layout) -
- (B_Base == NULL ? 0 : getSymbolAddress(B_Base, Layout));
-
- if (A_Base) {
- Index = A_Base->getIndex();
- IsExtern = 1;
- }
- else {
- Index = A_SD.getFragment()->getParent()->getOrdinal() + 1;
- IsExtern = 0;
- }
- Type = macho::RIT_X86_64_Unsigned;
-
- macho::RelocationEntry MRE;
- MRE.Word0 = FixupOffset;
- MRE.Word1 = ((Index << 0) |
- (IsPCRel << 24) |
- (Log2Size << 25) |
- (IsExtern << 27) |
- (Type << 28));
- Relocations[Fragment->getParent()].push_back(MRE);
-
- if (B_Base) {
- Index = B_Base->getIndex();
- IsExtern = 1;
- }
- else {
- Index = B_SD.getFragment()->getParent()->getOrdinal() + 1;
- IsExtern = 0;
- }
- Type = macho::RIT_X86_64_Subtractor;
- } else {
- const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
- MCSymbolData &SD = Asm.getSymbolData(*Symbol);
- const MCSymbolData *Base = Asm.getAtom(&SD);
-
- // Relocations inside debug sections always use local relocations when
- // possible. This seems to be done because the debugger doesn't fully
- // understand x86_64 relocation entries, and expects to find values that
- // have already been fixed up.
- if (Symbol->isInSection()) {
- const MCSectionMachO &Section = static_cast<const MCSectionMachO&>(
- Fragment->getParent()->getSection());
- if (Section.hasAttribute(MCSectionMachO::S_ATTR_DEBUG))
- Base = 0;
- }
-
- // x86_64 almost always uses external relocations, except when there is no
- // symbol to use as a base address (a local symbol with no preceding
- // non-local symbol).
- if (Base) {
- Index = Base->getIndex();
- IsExtern = 1;
-
- // Add the local offset, if needed.
- if (Base != &SD)
- Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base);
- } else if (Symbol->isInSection() && !Symbol->isVariable()) {
- // The index is the section ordinal (1-based).
- Index = SD.getFragment()->getParent()->getOrdinal() + 1;
- IsExtern = 0;
- Value += getSymbolAddress(&SD, Layout);
-
- if (IsPCRel)
- Value -= FixupAddress + (1 << Log2Size);
- } else if (Symbol->isVariable()) {
- const MCExpr *Value = Symbol->getVariableValue();
- int64_t Res;
- bool isAbs = Value->EvaluateAsAbsolute(Res, Layout, SectionAddress);
- if (isAbs) {
- FixedValue = Res;
- return;
- } else {
- report_fatal_error("unsupported relocation of variable '" +
- Symbol->getName() + "'");
- }
- } else {
- report_fatal_error("unsupported relocation of undefined symbol '" +
- Symbol->getName() + "'");
- }
-
- 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.getKind()) == X86::reloc_riprel_4byte_movq_load)
- Type = macho::RIT_X86_64_GOTLoad;
- else
- Type = macho::RIT_X86_64_GOT;
- } else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
- Type = macho::RIT_X86_64_TLV;
- } else if (Modifier != MCSymbolRefExpr::VK_None) {
- report_fatal_error("unsupported symbol modifier in relocation");
- } else {
- Type = macho::RIT_X86_64_Signed;
-
- // 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.
- switch (-(Target.getConstant() + (1LL << Log2Size))) {
- case 1: Type = macho::RIT_X86_64_Signed1; break;
- case 2: Type = macho::RIT_X86_64_Signed2; break;
- case 4: Type = macho::RIT_X86_64_Signed4; break;
- }
- }
- } else {
- if (Modifier != MCSymbolRefExpr::VK_None)
- report_fatal_error("unsupported symbol modifier in branch "
- "relocation");
-
- Type = macho::RIT_X86_64_Branch;
- }
- } else {
- if (Modifier == MCSymbolRefExpr::VK_GOT) {
- Type = macho::RIT_X86_64_GOT;
- } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) {
- // GOTPCREL is allowed as a modifier on non-PCrel instructions, in
- // which case all we do is set the PCrel bit in the relocation entry;
- // this is used with exception handling, for example. The source is
- // required to include any necessary offset directly.
- Type = macho::RIT_X86_64_GOT;
- IsPCRel = 1;
- } else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
- report_fatal_error("TLVP symbol modifier should have been rip-rel");
- } else if (Modifier != MCSymbolRefExpr::VK_None)
- report_fatal_error("unsupported symbol modifier in relocation");
- else
- Type = macho::RIT_X86_64_Unsigned;
- }
- }
-
- // x86_64 always writes custom values into the fixups.
- FixedValue = Value;
-
- // struct relocation_info (8 bytes)
- macho::RelocationEntry MRE;
- MRE.Word0 = FixupOffset;
- MRE.Word1 = ((Index << 0) |
- (IsPCRel << 24) |
- (Log2Size << 25) |
- (IsExtern << 27) |
- (Type << 28));
- Relocations[Fragment->getParent()].push_back(MRE);
- }
+ uint64_t &FixedValue);
void RecordScatteredRelocation(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
const MCFixup &Fixup, MCValue Target,
unsigned Log2Size,
- uint64_t &FixedValue) {
- uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
- unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind());
- unsigned Type = macho::RIT_Vanilla;
-
- // See <reloc.h>.
- const MCSymbol *A = &Target.getSymA()->getSymbol();
- MCSymbolData *A_SD = &Asm.getSymbolData(*A);
-
- if (!A_SD->getFragment())
- report_fatal_error("symbol '" + A->getName() +
- "' can not be undefined in a subtraction expression");
-
- uint32_t Value = getSymbolAddress(A_SD, Layout);
- uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent());
- FixedValue += SecAddr;
- uint32_t Value2 = 0;
-
- if (const MCSymbolRefExpr *B = Target.getSymB()) {
- MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
-
- if (!B_SD->getFragment())
- report_fatal_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() ? (unsigned)macho::RIT_Difference :
- (unsigned)macho::RIT_Generic_LocalDifference;
- Value2 = getSymbolAddress(B_SD, Layout);
- FixedValue -= getSectionAddress(B_SD->getFragment()->getParent());
- }
-
- // Relocations are written out in reverse order, so the PAIR comes first.
- if (Type == macho::RIT_Difference ||
- Type == macho::RIT_Generic_LocalDifference) {
- macho::RelocationEntry MRE;
- MRE.Word0 = ((0 << 0) |
- (macho::RIT_Pair << 24) |
- (Log2Size << 28) |
- (IsPCRel << 30) |
- macho::RF_Scattered);
- MRE.Word1 = Value2;
- Relocations[Fragment->getParent()].push_back(MRE);
- }
-
- macho::RelocationEntry MRE;
- MRE.Word0 = ((FixupOffset << 0) |
- (Type << 24) |
- (Log2Size << 28) |
- (IsPCRel << 30) |
- macho::RF_Scattered);
- MRE.Word1 = Value;
- Relocations[Fragment->getParent()].push_back(MRE);
- }
+ uint64_t &FixedValue);
void RecordARMScatteredRelocation(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
const MCFixup &Fixup, MCValue Target,
unsigned Log2Size,
- uint64_t &FixedValue) {
- uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
- unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind());
- unsigned Type = macho::RIT_Vanilla;
+ uint64_t &FixedValue);
- // See <reloc.h>.
- const MCSymbol *A = &Target.getSymA()->getSymbol();
- MCSymbolData *A_SD = &Asm.getSymbolData(*A);
+ void RecordARMMovwMovtRelocation(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFragment *Fragment,
+ const MCFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue);
- if (!A_SD->getFragment())
- report_fatal_error("symbol '" + A->getName() +
- "' can not be undefined in a subtraction expression");
+ void RecordTLVPRelocation(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFragment *Fragment,
+ const MCFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue);
- uint32_t Value = getSymbolAddress(A_SD, Layout);
- uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent());
- FixedValue += SecAddr;
- uint32_t Value2 = 0;
+ static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
+ unsigned &Log2Size);
- if (const MCSymbolRefExpr *B = Target.getSymB()) {
- MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
+ void RecordARMRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFragment *Fragment, const MCFixup &Fixup,
+ MCValue Target, uint64_t &FixedValue);
- if (!B_SD->getFragment())
- report_fatal_error("symbol '" + B->getSymbol().getName() +
- "' can not be undefined in a subtraction expression");
+ void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFragment *Fragment, const MCFixup &Fixup,
+ MCValue Target, uint64_t &FixedValue);
- // Select the appropriate difference relocation type.
- Type = macho::RIT_Difference;
- Value2 = getSymbolAddress(B_SD, Layout);
- FixedValue -= getSectionAddress(B_SD->getFragment()->getParent());
- }
+ void BindIndirectSymbols(MCAssembler &Asm);
- // Relocations are written out in reverse order, so the PAIR comes first.
- if (Type == macho::RIT_Difference ||
- Type == macho::RIT_Generic_LocalDifference) {
- macho::RelocationEntry MRE;
- MRE.Word0 = ((0 << 0) |
- (macho::RIT_Pair << 24) |
- (Log2Size << 28) |
- (IsPCRel << 30) |
- macho::RF_Scattered);
- MRE.Word1 = Value2;
- Relocations[Fragment->getParent()].push_back(MRE);
- }
+ /// 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);
- macho::RelocationEntry MRE;
- MRE.Word0 = ((FixupOffset << 0) |
- (Type << 24) |
- (Log2Size << 28) |
- (IsPCRel << 30) |
- macho::RF_Scattered);
- MRE.Word1 = Value;
- Relocations[Fragment->getParent()].push_back(MRE);
- }
+ void computeSectionAddresses(const MCAssembler &Asm,
+ const MCAsmLayout &Layout);
- void RecordARMMovwMovtRelocation(const MCAssembler &Asm,
- const MCAsmLayout &Layout,
- const MCFragment *Fragment,
- const MCFixup &Fixup, MCValue Target,
- uint64_t &FixedValue) {
- uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
- unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind());
- unsigned Type = macho::RIT_ARM_Half;
+ void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout);
- // See <reloc.h>.
- const MCSymbol *A = &Target.getSymA()->getSymbol();
- MCSymbolData *A_SD = &Asm.getSymbolData(*A);
+ virtual bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
+ const MCSymbolData &DataA,
+ const MCFragment &FB,
+ bool InSet,
+ bool IsPCRel) const;
- if (!A_SD->getFragment())
- report_fatal_error("symbol '" + A->getName() +
- "' can not be undefined in a subtraction expression");
+ void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout);
+};
- uint32_t Value = getSymbolAddress(A_SD, Layout);
- uint32_t Value2 = 0;
- uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent());
- FixedValue += SecAddr;
+} // end anonymous namespace
- if (const MCSymbolRefExpr *B = Target.getSymB()) {
- MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
+uint64_t MachObjectWriter::getSymbolAddress(const MCSymbolData* SD,
+ const MCAsmLayout &Layout) const {
+ const MCSymbol &S = SD->getSymbol();
- if (!B_SD->getFragment())
- report_fatal_error("symbol '" + B->getSymbol().getName() +
- "' can not be undefined in a subtraction expression");
+ // If this is a variable, then recursively evaluate now.
+ if (S.isVariable()) {
+ MCValue Target;
+ if (!S.getVariableValue()->EvaluateAsRelocatable(Target, Layout))
+ report_fatal_error("unable to evaluate offset for variable '" +
+ S.getName() + "'");
- // Select the appropriate difference relocation type.
- Type = macho::RIT_ARM_HalfDifference;
- Value2 = getSymbolAddress(B_SD, Layout);
- FixedValue -= getSectionAddress(B_SD->getFragment()->getParent());
- }
+ // Verify that any used symbols are defined.
+ if (Target.getSymA() && Target.getSymA()->getSymbol().isUndefined())
+ report_fatal_error("unable to evaluate offset to undefined symbol '" +
+ Target.getSymA()->getSymbol().getName() + "'");
+ if (Target.getSymB() && Target.getSymB()->getSymbol().isUndefined())
+ report_fatal_error("unable to evaluate offset to undefined symbol '" +
+ Target.getSymB()->getSymbol().getName() + "'");
- // Relocations are written out in reverse order, so the PAIR comes first.
- // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
- //
- // For these two r_type relocations they always have a pair following them
- // and the r_length bits are used differently. The encoding of the
- // r_length is as follows:
- // low bit of r_length:
- // 0 - :lower16: for movw instructions
- // 1 - :upper16: for movt instructions
- // high bit of r_length:
- // 0 - arm instructions
- // 1 - thumb instructions
- // the other half of the relocated expression is in the following pair
- // relocation entry in the the low 16 bits of r_address field.
- unsigned ThumbBit = 0;
- unsigned MovtBit = 0;
- switch ((unsigned)Fixup.getKind()) {
- default: break;
- case ARM::fixup_arm_movt_hi16:
- case ARM::fixup_arm_movt_hi16_pcrel:
- MovtBit = 1;
- break;
- case ARM::fixup_t2_movt_hi16:
- case ARM::fixup_t2_movt_hi16_pcrel:
- MovtBit = 1;
- // Fallthrough
- case ARM::fixup_t2_movw_lo16:
- case ARM::fixup_t2_movw_lo16_pcrel:
- ThumbBit = 1;
- break;
- }
+ uint64_t Address = Target.getConstant();
+ if (Target.getSymA())
+ Address += getSymbolAddress(&Layout.getAssembler().getSymbolData(
+ Target.getSymA()->getSymbol()), Layout);
+ if (Target.getSymB())
+ Address += getSymbolAddress(&Layout.getAssembler().getSymbolData(
+ Target.getSymB()->getSymbol()), Layout);
+ return Address;
+ }
+ return getSectionAddress(SD->getFragment()->getParent()) +
+ Layout.getSymbolOffset(SD);
+}
- if (Type == macho::RIT_ARM_HalfDifference) {
- uint32_t OtherHalf = MovtBit
- ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
+uint64_t MachObjectWriter::getPaddingSize(const MCSectionData *SD,
+ const MCAsmLayout &Layout) const {
+ uint64_t EndAddr = getSectionAddress(SD) + Layout.getSectionAddressSize(SD);
+ unsigned Next = SD->getLayoutOrder() + 1;
+ if (Next >= Layout.getSectionOrder().size())
+ return 0;
+
+ const MCSectionData &NextSD = *Layout.getSectionOrder()[Next];
+ if (NextSD.getSection().isVirtualSection())
+ return 0;
+ return OffsetToAlignment(EndAddr, NextSD.getAlignment());
+}
- macho::RelocationEntry MRE;
- MRE.Word0 = ((OtherHalf << 0) |
- (macho::RIT_Pair << 24) |
- (MovtBit << 28) |
- (ThumbBit << 29) |
- (IsPCRel << 30) |
- macho::RF_Scattered);
- MRE.Word1 = Value2;
- Relocations[Fragment->getParent()].push_back(MRE);
- }
+void MachObjectWriter::WriteHeader(unsigned NumLoadCommands,
+ unsigned LoadCommandsSize,
+ bool SubsectionsViaSymbols) {
+ uint32_t Flags = 0;
- macho::RelocationEntry MRE;
- MRE.Word0 = ((FixupOffset << 0) |
- (Type << 24) |
- (MovtBit << 28) |
- (ThumbBit << 29) |
- (IsPCRel << 30) |
- macho::RF_Scattered);
- MRE.Word1 = Value;
- Relocations[Fragment->getParent()].push_back(MRE);
+ if (SubsectionsViaSymbols)
+ Flags |= macho::HF_SubsectionsViaSymbols;
+
+ // struct mach_header (28 bytes) or
+ // struct mach_header_64 (32 bytes)
+
+ uint64_t Start = OS.tell();
+ (void) Start;
+
+ Write32(is64Bit() ? macho::HM_Object64 : macho::HM_Object32);
+
+ Write32(TargetObjectWriter->getCPUType());
+ Write32(TargetObjectWriter->getCPUSubtype());
+
+ Write32(macho::HFT_Object);
+ Write32(NumLoadCommands);
+ Write32(LoadCommandsSize);
+ Write32(Flags);
+ if (is64Bit())
+ Write32(0); // reserved
+
+ assert(OS.tell() - Start ==
+ (is64Bit() ? macho::Header64Size : macho::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 MachObjectWriter::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() ? macho::SegmentLoadCommand64Size:
+ macho::SegmentLoadCommand32Size;
+ Write32(is64Bit() ? macho::LCT_Segment64 : macho::LCT_Segment);