/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
*
- * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
OutputFile::OutputFile(const Options& opts)
:
hasWeakExternalSymbols(false), usesWeakExternalSymbols(false), overridesWeakExternalSymbols(false),
- _noReExportedDylibs(false), hasThreadLocalVariableDefinitions(false), pieDisabled(false),
+ _noReExportedDylibs(false), hasThreadLocalVariableDefinitions(false), pieDisabled(false), hasDataInCode(false),
headerAndLoadCommandsSection(NULL),
rebaseSection(NULL), bindingSection(NULL), weakBindingSection(NULL),
lazyBindingSection(NULL), exportSection(NULL),
splitSegInfoSection(NULL), functionStartsSection(NULL),
+ dataInCodeSection(NULL), dependentDRsSection(NULL),
symbolTableSection(NULL), stringPoolSection(NULL),
localRelocationsSection(NULL), externalRelocationsSection(NULL),
sectionRelocationsSection(NULL),
_hasSectionRelocations(opts.outputKind() == Options::kObjectFile),
_hasSplitSegInfo(opts.sharedRegionEligible()),
_hasFunctionStartsInfo(opts.addFunctionStarts()),
+ _hasDataInCodeInfo(opts.addDataInCodeInfo()),
+ _hasDependentDRInfo(opts.needsDependentDRInfo()),
_hasDynamicSymbolTable(true),
_hasLocalRelocations(!opts.makeCompressedDyldInfo()),
_hasExternalRelocations(!opts.makeCompressedDyldInfo()),
_weakBindingInfoAtom(NULL),
_exportInfoAtom(NULL),
_splitSegInfoAtom(NULL),
- _functionStartsAtom(NULL)
+ _functionStartsAtom(NULL),
+ _dataInCodeAtom(NULL),
+ _dependentDRInfoAtom(NULL)
{
}
void OutputFile::assignAtomAddresses(ld::Internal& state)
{
+ const bool log = false;
+ if ( log ) fprintf(stderr, "assignAtomAddresses()\n");
for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
ld::Internal::FinalSection* sect = *sit;
+ if ( log ) fprintf(stderr, " section=%s/%s\n", sect->segmentName(), sect->sectionName());
for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
const ld::Atom* atom = *ait;
+ if ( log ) fprintf(stderr, " atom=%p, name=%s\n", atom, atom->name());
switch ( sect-> type() ) {
case ld::Section::typeImportProxies:
// want finalAddress() of all proxy atoms to be zero
_functionStartsAtom->encode();
}
+ if ( _options.addDataInCodeInfo() ) {
+ // build data-in-code info
+ assert(_dataInCodeAtom != NULL);
+ _dataInCodeAtom->encode();
+ }
+
+ if ( _options.needsDependentDRInfo() ) {
+ // build dependent dylib DR info
+ assert(_dependentDRInfoAtom != NULL);
+ _dependentDRInfoAtom->encode();
+ }
+
// build classic symbol table
assert(_symbolTableAtom != NULL);
_symbolTableAtom->encode();
uint64_t offset = 0;
for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
const ld::Atom* atom = *ait;
- if ( atom->alignment().powerOf2 > maxAlignment )
- maxAlignment = atom->alignment().powerOf2;
+ bool pagePerAtom = false;
+ uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
+ if ( _options.pageAlignDataAtoms() && ( strcmp(atom->section().segmentName(), "__DATA") == 0) ) {
+ switch ( atom->section().type() ) {
+ case ld::Section::typeUnclassified:
+ case ld::Section::typeTentativeDefs:
+ case ld::Section::typeZeroFill:
+ pagePerAtom = true;
+ if ( atomAlignmentPowerOf2 < 12 )
+ atomAlignmentPowerOf2 = 12;
+ break;
+ default:
+ break;
+ }
+ }
+ if ( atomAlignmentPowerOf2 > maxAlignment )
+ maxAlignment = atomAlignmentPowerOf2;
// calculate section offset for this atom
- uint64_t alignment = 1 << atom->alignment().powerOf2;
+ uint64_t alignment = 1 << atomAlignmentPowerOf2;
uint64_t currentModulus = (offset % alignment);
uint64_t requiredModulus = atom->alignment().modulus;
if ( currentModulus != requiredModulus ) {
if ( sect->type() != ld::Section::typeLinkEdit ) {
(const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
offset += atom->size();
+ if ( pagePerAtom ) {
+ offset = (offset + 4095) & (-4096); // round up to end of page
+ }
}
if ( (atom->scope() == ld::Atom::scopeGlobal)
&& (atom->definition() == ld::Atom::definitionRegular)
// second pass, assign section address to sections in segments that are contiguous with previous segment
address = floatingAddressStart;
lastSegName = "";
+ ld::Internal::FinalSection* overlappingFixedSection = NULL;
+ ld::Internal::FinalSection* overlappingFlowSection = NULL;
if ( log ) fprintf(stderr, "Regular layout segments:\n");
for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
ld::Internal::FinalSection* sect = *it;
&& (_options.outputKind() != Options::kStaticExecutable) )
throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range",
sect->sectionName(), address, sect->size);
+
+ // sanity check it does not overlap a fixed address segment
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* otherSect = *sit;
+ if ( ! _options.hasCustomSegmentAddress(otherSect->segmentName()) )
+ continue;
+ if ( sect->address > otherSect->address ) {
+ if ( (otherSect->address+otherSect->size) > sect->address ) {
+ overlappingFixedSection = otherSect;
+ overlappingFlowSection = sect;
+ }
+ }
+ else {
+ if ( (sect->address+sect->size) > otherSect->address ) {
+ overlappingFixedSection = otherSect;
+ overlappingFlowSection = sect;
+ }
+ }
+ }
- if ( log ) fprintf(stderr, " address=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
- sect->address, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes,
+ if ( log ) fprintf(stderr, " address=0x%08llX, size=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
+ sect->address, sect->size, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes,
sect->segmentName(), sect->sectionName());
// update running totals
if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
address += sect->size;
}
+ if ( overlappingFixedSection != NULL ) {
+ fprintf(stderr, "Section layout:\n");
+ for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+ ld::Internal::FinalSection* sect = *it;
+ if ( sect->isSectionHidden() )
+ continue;
+ fprintf(stderr, " address:0x%08llX, alignment:2^%d, size:0x%08llX, padBytes:%d, section:%s/%s\n",
+ sect->address, sect->alignment, sect->size, sect->alignmentPaddingBytes,
+ sect->segmentName(), sect->sectionName());
+
+ }
+ throwf("Section (%s/%s) overlaps fixed address section (%s/%s)",
+ overlappingFlowSection->segmentName(), overlappingFlowSection->sectionName(),
+ overlappingFixedSection->segmentName(), overlappingFixedSection->sectionName());
+ }
// third pass, assign section file offsets
if ( hasZeroForFileOffset(sect) ) {
// fileoff of zerofill sections is moot, but historically it is set to zero
sect->fileOffset = 0;
+
+ // <rdar://problem/10445047> align file offset with address layout
+ fileOffset += sect->alignmentPaddingBytes;
}
else {
// page align file offset at start of each segment
for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
ld::Internal::FinalSection* sect = *it;
if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
- _encryptedTEXTendOffset = pageAlign(sect->fileOffset);
+ _encryptedTEXTendOffset = pageAlign(sect->fileOffset + sect->size);
}
}
}
return (*target)->finalAddress();
case ld::Fixup::bindingsIndirectlyBound:
*target = state.indirectBindingTable[fixup->u.bindingIndex];
+ #ifndef NDEBUG
+ if ( ! (*target)->finalAddressMode() ) {
+ throwf("reference to symbol (which has not been assigned an address) %s", (*target)->name());
+ }
+ #endif
return (*target)->finalAddress();
}
throw "unexpected binding";
printSectionLayout(state);
const ld::Atom* target;
- throwf("32-bit branch out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)",
+ throwf("32-bit branch out of range (%lld max is +/-2GB): from %s (0x%08llX) to %s (0x%08llX)",
displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
addressOf(state, fixup, &target));
}
}
+
+void OutputFile::rangeCheckAbsolute32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+ const int64_t fourGigLimit = 0xFFFFFFFF;
+ if ( displacement > fourGigLimit ) {
+ // <rdar://problem/9610466> cannot enforce 32-bit range checks on 32-bit archs because assembler loses sign information
+ // .long _foo - 0xC0000000
+ // is encoded in mach-o the same as:
+ // .long _foo + 0x40000000
+ // so if _foo lays out to 0xC0000100, the first is ok, but the second is not.
+ if ( (_options.architecture() == CPU_TYPE_ARM) || (_options.architecture() == CPU_TYPE_I386) ) {
+ // Unlikely userland code does funky stuff like this, so warn for them, but not warn for -preload
+ if ( _options.outputKind() != Options::kPreload ) {
+ warning("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX",
+ displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), displacement);
+ }
+ return;
+ }
+ // show layout of final image
+ printSectionLayout(state);
+
+ const ld::Atom* target;
+ if ( fixup->binding == ld::Fixup::bindingNone )
+ throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX",
+ displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), displacement);
+ else
+ throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to %s (0x%08llX)",
+ displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), referenceTargetAtomName(state, fixup),
+ addressOf(state, fixup, &target));
+ }
+}
+
+
void OutputFile::rangeCheckRIP32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
{
const int64_t twoGigLimit = 0x7FFFFFFF;
- if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
+ if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
// show layout of final image
printSectionLayout(state);
void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
{
- // armv7 supports a larger displacement
- if ( _options.preferSubArchitecture() && (_options.subArchitecture() == CPU_SUBTYPE_ARM_V7) ) {
+ // thumb2 supports a larger displacement
+ if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
if ( (displacement > 16777214LL) || (displacement < (-16777216LL)) ) {
// show layout of final image
printSectionLayout(state);
}
}
-void OutputFile::rangeCheckPPCBranch24(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
-{
- const int64_t bl_eightMegLimit = 0x00FFFFFF;
- if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
- // show layout of final image
- printSectionLayout(state);
-
- const ld::Atom* target;
- throwf("bl PPC branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)",
- displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
- addressOf(state, fixup, &target));
- }
-}
-
-void OutputFile::rangeCheckPPCBranch14(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
-{
- const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
- if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
- // show layout of final image
- printSectionLayout(state);
-
- const ld::Atom* target;
- throwf("bcc PPC branch out of range (%lld max is +/-64KB): from %s (0x%08llX) to %s (0x%08llX)",
- displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),
- addressOf(state, fixup, &target));
- }
-}
int64_t delta;
uint32_t instruction;
uint32_t newInstruction;
- uint16_t instructionLowHalf;
bool is_bl;
bool is_blx;
bool is_b;
set32LE(fixUpLocation, (get32LE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
break;
case ld::Fixup::kindStoreLittleEndian32:
+ rangeCheckAbsolute32(accumulator, state, atom, fit);
set32LE(fixUpLocation, accumulator);
break;
case ld::Fixup::kindStoreLittleEndian64:
set32BE(fixUpLocation, (get32BE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
break;
case ld::Fixup::kindStoreBigEndian32:
+ rangeCheckAbsolute32(accumulator, state, atom, fit);
set32BE(fixUpLocation, accumulator);
break;
case ld::Fixup::kindStoreBigEndian64:
}
set32LE(fixUpLocation, newInstruction);
break;
- case ld::Fixup::kindStorePPCBranch14:
- delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
- rangeCheckPPCBranch14(delta, state, atom, fit);
- instruction = get32BE(fixUpLocation);
- newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)delta & 0x0000FFFC);
- set32BE(fixUpLocation, newInstruction);
- break;
- case ld::Fixup::kindStorePPCPicLow14:
- case ld::Fixup::kindStorePPCAbsLow14:
- instruction = get32BE(fixUpLocation);
- if ( (accumulator & 0x3) != 0 )
- throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)accumulator);
- newInstruction = (instruction & 0xFFFF0003) | (accumulator & 0xFFFC);
- set32BE(fixUpLocation, newInstruction);
- break;
- case ld::Fixup::kindStorePPCAbsLow16:
- case ld::Fixup::kindStorePPCPicLow16:
- instruction = get32BE(fixUpLocation);
- newInstruction = (instruction & 0xFFFF0000) | (accumulator & 0xFFFF);
- set32BE(fixUpLocation, newInstruction);
- break;
- case ld::Fixup::kindStorePPCAbsHigh16AddLow:
- case ld::Fixup::kindStorePPCPicHigh16AddLow:
- instructionLowHalf = (accumulator >> 16) & 0xFFFF;
- if ( accumulator & 0x00008000 )
- ++instructionLowHalf;
- instruction = get32BE(fixUpLocation);
- newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
- set32BE(fixUpLocation, newInstruction);
- break;
- case ld::Fixup::kindStorePPCAbsHigh16:
- instruction = get32BE(fixUpLocation);
- newInstruction = (instruction & 0xFFFF0000) | ((accumulator >> 16) & 0xFFFF);
- set32BE(fixUpLocation, newInstruction);
- break;
case ld::Fixup::kindDtraceExtra:
break;
case ld::Fixup::kindStoreX86DtraceCallSiteNop:
fixUpLocation[3] = 0x90; // 1-byte nop
}
break;
- case ld::Fixup::kindStorePPCDtraceCallSiteNop:
- if ( _options.outputKind() != Options::kObjectFile ) {
- // change call site to a NOP
- set32BE(fixUpLocation, 0x60000000);
- }
- break;
- case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
- if ( _options.outputKind() != Options::kObjectFile ) {
- // change call site to a li r3,0
- set32BE(fixUpLocation, 0x38600000);
- }
- break;
case ld::Fixup::kindStoreARMDtraceCallSiteNop:
if ( _options.outputKind() != Options::kObjectFile ) {
// change call site to a NOP
assert(fit->binding == ld::Fixup::bindingDirectlyBound);
accumulator = this->lazyBindingInfoOffsetForLazyPointerAddress(fit->u.target->finalAddress());
break;
+ case ld::Fixup::kindDataInCodeStartData:
+ case ld::Fixup::kindDataInCodeStartJT8:
+ case ld::Fixup::kindDataInCodeStartJT16:
+ case ld::Fixup::kindDataInCodeStartJT32:
+ case ld::Fixup::kindDataInCodeStartJTA32:
+ case ld::Fixup::kindDataInCodeEnd:
+ break;
case ld::Fixup::kindStoreTargetAddressLittleEndian32:
accumulator = addressOf(state, fit, &toTarget);
thumbTarget = targetIsThumb(state, fit);
accumulator |= 1;
if ( fit->contentAddendOnly )
accumulator = 0;
+ rangeCheckAbsolute32(accumulator, state, atom, fit);
set32LE(fixUpLocation, accumulator);
break;
case ld::Fixup::kindStoreTargetAddressLittleEndian64:
// Make sure we are calling arm with bl, thumb with blx
is_bl = ((instruction & 0xFF000000) == 0xEB000000);
is_blx = ((instruction & 0xFE000000) == 0xFA000000);
+ is_b = !is_blx && ((instruction & 0x0F000000) == 0x0A000000);
if ( is_bl && thumbTarget ) {
uint32_t opcode = 0xFA000000;
uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
newInstruction = opcode | disp;
}
+ else if ( is_b && thumbTarget ) {
+ if ( fit->contentDetlaToAddendOnly )
+ newInstruction = (instruction & 0xFF000000) | ((uint32_t)(delta >> 2) & 0x00FFFFFF);
+ else
+ throwf("no pc-rel bx arm instruction. Can't fix up branch to %s in %s",
+ referenceTargetAtomName(state, fit), atom->name());
+ }
else if ( !is_bl && !is_blx && thumbTarget ) {
throwf("don't know how to convert instruction %x referencing %s to thumb",
instruction, referenceTargetAtomName(state, fit));
// Since blx cannot have the low bit set, set bit[1] of the target to
// bit[1] of the base address, so that the difference is a multiple of
// 4 bytes.
- if ( !thumbTarget ) {
+ if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
accumulator &= -3ULL;
accumulator |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
}
// The pc added will be +4 from the pc
delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
rangeCheckThumbBranch22(delta, state, atom, fit);
- if ( _options.preferSubArchitecture() && _options.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
+ if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
// The instruction is really two instructions:
// The lower 16 bits are the first instruction, which contains the high
// 11 bits of the displacement.
instruction = 0xC000F000; // keep blx
}
else if ( is_b ) {
- if ( !thumbTarget )
- throwf("don't know how to convert instruction %x referencing %s to arm",
- instruction, referenceTargetAtomName(state, fit));
instruction = 0x9000F000; // keep b
+ if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
+ throwf("armv7 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s",
+ referenceTargetAtomName(state, fit), atom->name());
+ }
}
- else if ( is_b ) {
+ else {
if ( !thumbTarget )
throwf("don't know how to convert branch instruction %x referencing %s to bx",
instruction, referenceTargetAtomName(state, fit));
else if ( is_blx && thumbTarget ) {
instruction = 0xF800F000;
}
- else if ( !is_bl && !is_blx && !thumbTarget ) {
- throwf("don't know how to convert instruction %x referencing %s to arm",
- instruction, referenceTargetAtomName(state, fit));
- }
+ else if ( is_b ) {
+ instruction = 0x9000F000; // keep b
+ if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
+ throwf("armv6 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s",
+ referenceTargetAtomName(state, fit), atom->name());
+ }
+ }
else {
instruction = instruction & 0xF800F800;
}
set32LE(fixUpLocation, newInstruction);
}
break;
- case ld::Fixup::kindStoreTargetAddressPPCBranch24:
- accumulator = addressOf(state, fit, &toTarget);
- if ( fit->contentDetlaToAddendOnly )
- accumulator = 0;
- // fall into kindStorePPCBranch24 case
- case ld::Fixup::kindStorePPCBranch24:
- delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
- rangeCheckPPCBranch24(delta, state, atom, fit);
- instruction = get32BE(fixUpLocation);
- newInstruction = (instruction & 0xFC000003) | ((uint32_t)delta & 0x03FFFFFC);
- set32BE(fixUpLocation, newInstruction);
- break;
}
}
}
-void OutputFile::copyNoOps(uint8_t* from, uint8_t* to)
+void OutputFile::copyNoOps(uint8_t* from, uint8_t* to, bool thumb)
{
switch ( _options.architecture() ) {
- case CPU_TYPE_POWERPC:
- for (uint8_t* p=from; p < to; p += 4)
- OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
- break;
case CPU_TYPE_I386:
case CPU_TYPE_X86_64:
for (uint8_t* p=from; p < to; ++p)
*p = 0x90;
break;
case CPU_TYPE_ARM:
- // fixme: need thumb nop?
- for (uint8_t* p=from; p < to; p += 4)
- OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
+ if ( thumb ) {
+ for (uint8_t* p=from; p < to; p += 2)
+ OSWriteLittleInt16((uint16_t*)p, 0, 0x46c0);
+ }
+ else {
+ for (uint8_t* p=from; p < to; p += 4)
+ OSWriteLittleInt32((uint32_t*)p, 0, 0xe1a00000);
+ }
break;
default:
for (uint8_t* p=from; p < to; ++p)
return false;
}
-
-void OutputFile::writeOutputFile(ld::Internal& state)
+void OutputFile::writeAtoms(ld::Internal& state, uint8_t* wholeBuffer)
{
- // for UNIX conformance, error if file exists and is not writable
- if ( (access(_options.outputFilePath(), F_OK) == 0) && (access(_options.outputFilePath(), W_OK) == -1) )
- throwf("can't write output file: %s", _options.outputFilePath());
-
- int permissions = 0777;
- if ( _options.outputKind() == Options::kObjectFile )
- permissions = 0666;
- // Calling unlink first assures the file is gone so that open creates it with correct permissions
- // It also handles the case where __options.outputFilePath() file is not writable but its directory is
- // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
- // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
- struct stat stat_buf;
- if ( (stat(_options.outputFilePath(), &stat_buf) != -1) && (stat_buf.st_mode & S_IFREG) )
- (void)unlink(_options.outputFilePath());
-
- // try to allocate buffer for entire output file content
- uint8_t* wholeBuffer = (uint8_t*)calloc(_fileSize, 1);
- if ( wholeBuffer == NULL )
- throwf("can't create buffer of %llu bytes for output", _fileSize);
-
- if ( _options.UUIDMode() == Options::kUUIDRandom ) {
- uint8_t bits[16];
- ::uuid_generate_random(bits);
- _headersAndLoadCommandAtom->setUUID(bits);
- }
-
// have each atom write itself
uint64_t fileOffsetOfEndOfLastAtom = 0;
uint64_t mhAddress = 0;
const bool sectionUsesNops = (sect->type() == ld::Section::typeCode);
//fprintf(stderr, "file offset=0x%08llX, section %s\n", sect->fileOffset, sect->sectionName());
std::vector<const ld::Atom*>& atoms = sect->atoms;
+ bool lastAtomWasThumb = false;
for (std::vector<const ld::Atom*>::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) {
const ld::Atom* atom = *ait;
if ( atom->definition() == ld::Atom::definitionProxy )
uint64_t fileOffset = atom->finalAddress() - sect->address + sect->fileOffset;
// check for alignment padding between atoms
if ( (fileOffset != fileOffsetOfEndOfLastAtom) && lastAtomUsesNoOps ) {
- this->copyNoOps(&wholeBuffer[fileOffsetOfEndOfLastAtom], &wholeBuffer[fileOffset]);
+ this->copyNoOps(&wholeBuffer[fileOffsetOfEndOfLastAtom], &wholeBuffer[fileOffset], lastAtomWasThumb);
}
// copy atom content
atom->copyRawContent(&wholeBuffer[fileOffset]);
this->applyFixUps(state, mhAddress, atom, &wholeBuffer[fileOffset]);
fileOffsetOfEndOfLastAtom = fileOffset+atom->size();
lastAtomUsesNoOps = sectionUsesNops;
+ lastAtomWasThumb = atom->isThumb();
}
catch (const char* msg) {
if ( atom->file() != NULL )
}
}
}
-
- // compute UUID
- if ( _options.UUIDMode() == Options::kUUIDContent ) {
- const bool log = false;
- if ( (_options.outputKind() != Options::kObjectFile) || state.someObjectFileHasDwarf ) {
- uint8_t digest[CC_MD5_DIGEST_LENGTH];
- uint32_t stabsStringsOffsetStart;
- uint32_t tabsStringsOffsetEnd;
- uint32_t stabsOffsetStart;
- uint32_t stabsOffsetEnd;
- if ( _symbolTableAtom->hasStabs(stabsStringsOffsetStart, tabsStringsOffsetEnd, stabsOffsetStart, stabsOffsetEnd) ) {
- // find two areas of file that are stabs info and should not contribute to checksum
- uint64_t stringPoolFileOffset = 0;
- uint64_t symbolTableFileOffset = 0;
- for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
- ld::Internal::FinalSection* sect = *sit;
- if ( sect->type() == ld::Section::typeLinkEdit ) {
- if ( strcmp(sect->sectionName(), "__string_pool") == 0 )
- stringPoolFileOffset = sect->fileOffset;
- else if ( strcmp(sect->sectionName(), "__symbol_table") == 0 )
- symbolTableFileOffset = sect->fileOffset;
- }
+}
+
+
+void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
+{
+ const bool log = false;
+ if ( (_options.outputKind() != Options::kObjectFile) || state.someObjectFileHasDwarf ) {
+ uint8_t digest[CC_MD5_DIGEST_LENGTH];
+ uint32_t stabsStringsOffsetStart;
+ uint32_t tabsStringsOffsetEnd;
+ uint32_t stabsOffsetStart;
+ uint32_t stabsOffsetEnd;
+ if ( _symbolTableAtom->hasStabs(stabsStringsOffsetStart, tabsStringsOffsetEnd, stabsOffsetStart, stabsOffsetEnd) ) {
+ // find two areas of file that are stabs info and should not contribute to checksum
+ uint64_t stringPoolFileOffset = 0;
+ uint64_t symbolTableFileOffset = 0;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() == ld::Section::typeLinkEdit ) {
+ if ( strcmp(sect->sectionName(), "__string_pool") == 0 )
+ stringPoolFileOffset = sect->fileOffset;
+ else if ( strcmp(sect->sectionName(), "__symbol_table") == 0 )
+ symbolTableFileOffset = sect->fileOffset;
}
- uint64_t firstStabNlistFileOffset = symbolTableFileOffset + stabsOffsetStart;
- uint64_t lastStabNlistFileOffset = symbolTableFileOffset + stabsOffsetEnd;
- uint64_t firstStabStringFileOffset = stringPoolFileOffset + stabsStringsOffsetStart;
- uint64_t lastStabStringFileOffset = stringPoolFileOffset + tabsStringsOffsetEnd;
- if ( log ) fprintf(stderr, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset);
- if ( log ) fprintf(stderr, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset);
- if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
- if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
- assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
-
- CC_MD5_CTX md5state;
- CC_MD5_Init(&md5state);
- // checksum everything up to first stabs nlist
- if ( log ) fprintf(stderr, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset);
- CC_MD5_Update(&md5state, &wholeBuffer[0], firstStabNlistFileOffset);
- // checkusm everything after last stabs nlist and up to first stabs string
- if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset, firstStabStringFileOffset);
- CC_MD5_Update(&md5state, &wholeBuffer[lastStabNlistFileOffset], firstStabStringFileOffset-lastStabNlistFileOffset);
- // checksum everything after last stabs string to end of file
- if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset, _fileSize);
- CC_MD5_Update(&md5state, &wholeBuffer[lastStabStringFileOffset], _fileSize-lastStabStringFileOffset);
- CC_MD5_Final(digest, &md5state);
- if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2],
- digest[3], digest[4], digest[5], digest[6], digest[7]);
}
- else {
- CC_MD5(wholeBuffer, _fileSize, digest);
- }
- // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
- digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
- digest[8] = ( digest[8] & 0x3F ) | 0x80;
- // update buffer with new UUID
- _headersAndLoadCommandAtom->setUUID(digest);
- _headersAndLoadCommandAtom->recopyUUIDCommand();
+ uint64_t firstStabNlistFileOffset = symbolTableFileOffset + stabsOffsetStart;
+ uint64_t lastStabNlistFileOffset = symbolTableFileOffset + stabsOffsetEnd;
+ uint64_t firstStabStringFileOffset = stringPoolFileOffset + stabsStringsOffsetStart;
+ uint64_t lastStabStringFileOffset = stringPoolFileOffset + tabsStringsOffsetEnd;
+ if ( log ) fprintf(stderr, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset);
+ if ( log ) fprintf(stderr, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset);
+ if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
+ if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
+ assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
+
+ CC_MD5_CTX md5state;
+ CC_MD5_Init(&md5state);
+ // checksum everything up to first stabs nlist
+ if ( log ) fprintf(stderr, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset);
+ CC_MD5_Update(&md5state, &wholeBuffer[0], firstStabNlistFileOffset);
+ // checkusm everything after last stabs nlist and up to first stabs string
+ if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset, firstStabStringFileOffset);
+ CC_MD5_Update(&md5state, &wholeBuffer[lastStabNlistFileOffset], firstStabStringFileOffset-lastStabNlistFileOffset);
+ // checksum everything after last stabs string to end of file
+ if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset, _fileSize);
+ CC_MD5_Update(&md5state, &wholeBuffer[lastStabStringFileOffset], _fileSize-lastStabStringFileOffset);
+ CC_MD5_Final(digest, &md5state);
+ if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2],
+ digest[3], digest[4], digest[5], digest[6], digest[7]);
+ }
+ else {
+ CC_MD5(wholeBuffer, _fileSize, digest);
+ }
+ // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
+ digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
+ digest[8] = ( digest[8] & 0x3F ) | 0x80;
+ // update buffer with new UUID
+ _headersAndLoadCommandAtom->setUUID(digest);
+ _headersAndLoadCommandAtom->recopyUUIDCommand();
+ }
+}
+
+
+void OutputFile::writeOutputFile(ld::Internal& state)
+{
+ // for UNIX conformance, error if file exists and is not writable
+ if ( (access(_options.outputFilePath(), F_OK) == 0) && (access(_options.outputFilePath(), W_OK) == -1) )
+ throwf("can't write output file: %s", _options.outputFilePath());
+
+ mode_t permissions = 0777;
+ if ( _options.outputKind() == Options::kObjectFile )
+ permissions = 0666;
+ mode_t umask = ::umask(0);
+ ::umask(umask); // put back the original umask
+ permissions &= ~umask;
+ // Calling unlink first assures the file is gone so that open creates it with correct permissions
+ // It also handles the case where __options.outputFilePath() file is not writable but its directory is
+ // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
+ // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
+ struct stat stat_buf;
+ bool outputIsRegularFile = true;
+ if ( stat(_options.outputFilePath(), &stat_buf) != -1 ) {
+ if (stat_buf.st_mode & S_IFREG) {
+ (void)unlink(_options.outputFilePath());
+ } else {
+ outputIsRegularFile = false;
+ }
+ }
+
+ int fd;
+ // Construct a temporary path of the form {outputFilePath}.ld_XXXXXX
+ const char filenameTemplate[] = ".ld_XXXXXX";
+ char tmpOutput[PATH_MAX];
+ uint8_t *wholeBuffer;
+ if (outputIsRegularFile) {
+ strcpy(tmpOutput, _options.outputFilePath());
+ // If the path is too long to add a suffix for a temporary name then
+ // just fall back to using the output path.
+ if (strlen(tmpOutput)+strlen(filenameTemplate) < PATH_MAX) {
+ strcat(tmpOutput, filenameTemplate);
+ fd = mkstemp(tmpOutput);
+ } else {
+ fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);
}
+ if ( fd == -1 )
+ throwf("can't open output file for writing: %s, errno=%d", tmpOutput, errno);
+ ftruncate(fd, _fileSize);
+
+ wholeBuffer = (uint8_t *)mmap(NULL, _fileSize, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
+ if ( wholeBuffer == MAP_FAILED )
+ throwf("can't create buffer of %llu bytes for output", _fileSize);
+ } else {
+ fd = open(_options.outputFilePath(), O_WRONLY);
+ if ( fd == -1 )
+ throwf("can't open output file for writing: %s, errno=%d", _options.outputFilePath(), errno);
+ // try to allocate buffer for entire output file content
+ wholeBuffer = (uint8_t*)calloc(_fileSize, 1);
+ if ( wholeBuffer == NULL )
+ throwf("can't create buffer of %llu bytes for output", _fileSize);
+ }
+
+ if ( _options.UUIDMode() == Options::kUUIDRandom ) {
+ uint8_t bits[16];
+ ::uuid_generate_random(bits);
+ _headersAndLoadCommandAtom->setUUID(bits);
}
- // write whole output file in one chunk
- int fd = open(_options.outputFilePath(), O_CREAT | O_WRONLY | O_TRUNC, permissions);
- if ( fd == -1 )
- throwf("can't open output file for writing: %s, errno=%d", _options.outputFilePath(), errno);
- if ( ::pwrite(fd, wholeBuffer, _fileSize, 0) == -1 )
- throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
- close(fd);
- free(wholeBuffer);
+ writeAtoms(state, wholeBuffer);
+
+ // compute UUID
+ if ( _options.UUIDMode() == Options::kUUIDContent )
+ computeContentUUID(state, wholeBuffer);
+
+ if (outputIsRegularFile) {
+ if ( ::chmod(tmpOutput, permissions) == -1 ) {
+ unlink(tmpOutput);
+ throwf("can't set permissions on output file: %s, errno=%d", tmpOutput, errno);
+ }
+ if ( ::rename(tmpOutput, _options.outputFilePath()) == -1 && strcmp(tmpOutput, _options.outputFilePath()) != 0) {
+ unlink(tmpOutput);
+ throwf("can't move output file in place, errno=%d", errno);
+ }
+ } else {
+ if ( ::write(fd, wholeBuffer, _fileSize) == -1 ) {
+ throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
+ }
+ }
}
struct AtomByNameSorter
}
};
+class NotInSet
+{
+public:
+ NotInSet(const std::set<const ld::Atom*>& theSet) : _set(theSet) {}
+
+ bool operator()(const ld::Atom* atom) const {
+ return ( _set.count(atom) == 0 );
+ }
+private:
+ const std::set<const ld::Atom*>& _set;
+};
+
+
void OutputFile::buildSymbolTable(ld::Internal& state)
{
unsigned int machoSectionIndex = 0;
continue;
}
- // <rdar://problem/7977374> Add command line options to control symbol weak-def bit on exported symbols
- if ( _options.hasWeakBitTweaks() && (atom->definition() == ld::Atom::definitionRegular) ) {
- const char* name = atom->name();
- if ( atom->scope() == ld::Atom::scopeGlobal ) {
- if ( atom->combine() == ld::Atom::combineNever ) {
- if ( _options.forceWeak(name) )
- (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineByName);
- }
- else if ( atom->combine() == ld::Atom::combineByName ) {
- if ( _options.forceNotWeak(name) )
- (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineNever);
- }
- }
- else {
- if ( _options.forceWeakNonWildCard(name) )
- warning("cannot force to be weak, non-external symbol %s", name);
- else if ( _options.forceNotWeakNonWildcard(name) )
- warning("cannot force to be not-weak, non-external symbol %s", name);
- }
- }
-
switch ( atom->scope() ) {
case ld::Atom::scopeTranslationUnit:
if ( _options.keepLocalSymbol(atom->name()) ) {
}
}
else {
- if ( _options.keepLocalSymbol(atom->name()) )
+ if ( _options.keepLocalSymbol(atom->name()) )
+ _localAtoms.push_back(atom);
+ // <rdar://problem/5804214> ld should never have a symbol in the non-lazy indirect symbol table with index 0
+ // this works by making __mh_execute_header be a local symbol which takes symbol index 0
+ else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip) && !_options.makeCompressedDyldInfo() )
_localAtoms.push_back(atom);
else
(const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn);
}
}
+ // <rdar://problem/6978069> ld adds undefined symbol from .exp file to binary
+ if ( (_options.outputKind() == Options::kKextBundle) && _options.hasExportRestrictList() ) {
+ // search for referenced undefines
+ std::set<const ld::Atom*> referencedProxyAtoms;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingsIndirectlyBound:
+ referencedProxyAtoms.insert(state.indirectBindingTable[fit->u.bindingIndex]);
+ break;
+ case ld::Fixup::bindingDirectlyBound:
+ referencedProxyAtoms.insert(fit->u.target);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ // remove any unreferenced _importedAtoms
+ _importedAtoms.erase(std::remove_if(_importedAtoms.begin(), _importedAtoms.end(), NotInSet(referencedProxyAtoms)), _importedAtoms.end());
+ }
+
// sort by name
std::sort(_exportedAtoms.begin(), _exportedAtoms.end(), AtomByNameSorter());
std::sort(_importedAtoms.begin(), _importedAtoms.end(), AtomByNameSorter());
-
}
void OutputFile::addPreloadLinkEdit(ld::Internal& state)
{
switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_i386
case CPU_TYPE_I386:
if ( _hasLocalRelocations ) {
_localRelocsAtom = new LocalRelocationsAtom<x86>(_options, state, *this);
stringPoolSection = state.addAtom(*_stringPoolAtom);
}
break;
+#endif
+#if SUPPORT_ARCH_x86_64
case CPU_TYPE_X86_64:
if ( _hasLocalRelocations ) {
_localRelocsAtom = new LocalRelocationsAtom<x86_64>(_options, state, *this);
stringPoolSection = state.addAtom(*_stringPoolAtom);
}
break;
+#endif
+#if SUPPORT_ARCH_arm_any
case CPU_TYPE_ARM:
if ( _hasLocalRelocations ) {
_localRelocsAtom = new LocalRelocationsAtom<arm>(_options, state, *this);
stringPoolSection = state.addAtom(*_stringPoolAtom);
}
break;
+#endif
default:
throw "architecture not supported for -preload";
}
return addPreloadLinkEdit(state);
switch ( _options.architecture() ) {
- case CPU_TYPE_POWERPC:
- if ( _hasSectionRelocations ) {
- _sectionsRelocationsAtom = new SectionRelocationsAtom<ppc>(_options, state, *this);
- sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
- }
- if ( _hasDyldInfo ) {
- _rebasingInfoAtom = new RebaseInfoAtom<ppc>(_options, state, *this);
- rebaseSection = state.addAtom(*_rebasingInfoAtom);
-
- _bindingInfoAtom = new BindingInfoAtom<ppc>(_options, state, *this);
- bindingSection = state.addAtom(*_bindingInfoAtom);
-
- _weakBindingInfoAtom = new WeakBindingInfoAtom<ppc>(_options, state, *this);
- weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
-
- _lazyBindingInfoAtom = new LazyBindingInfoAtom<ppc>(_options, state, *this);
- lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
-
- _exportInfoAtom = new ExportInfoAtom<ppc>(_options, state, *this);
- exportSection = state.addAtom(*_exportInfoAtom);
- }
- if ( _hasLocalRelocations ) {
- _localRelocsAtom = new LocalRelocationsAtom<ppc>(_options, state, *this);
- localRelocationsSection = state.addAtom(*_localRelocsAtom);
- }
- if ( _hasSplitSegInfo ) {
- _splitSegInfoAtom = new SplitSegInfoAtom<ppc>(_options, state, *this);
- splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
- }
- if ( _hasFunctionStartsInfo ) {
- _functionStartsAtom = new FunctionStartsAtom<ppc>(_options, state, *this);
- functionStartsSection = state.addAtom(*_functionStartsAtom);
- }
- if ( _hasSymbolTable ) {
- _symbolTableAtom = new SymbolTableAtom<ppc>(_options, state, *this);
- symbolTableSection = state.addAtom(*_symbolTableAtom);
- }
- if ( _hasExternalRelocations ) {
- _externalRelocsAtom = new ExternalRelocationsAtom<ppc>(_options, state, *this);
- externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
- }
- if ( _hasSymbolTable ) {
- _indirectSymbolTableAtom = new IndirectSymbolTableAtom<ppc>(_options, state, *this);
- indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
- _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
- stringPoolSection = state.addAtom(*_stringPoolAtom);
- }
- break;
+#if SUPPORT_ARCH_i386
case CPU_TYPE_I386:
if ( _hasSectionRelocations ) {
_sectionsRelocationsAtom = new SectionRelocationsAtom<x86>(_options, state, *this);
_functionStartsAtom = new FunctionStartsAtom<x86>(_options, state, *this);
functionStartsSection = state.addAtom(*_functionStartsAtom);
}
+ if ( _hasDataInCodeInfo ) {
+ _dataInCodeAtom = new DataInCodeAtom<x86>(_options, state, *this);
+ dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+ }
+ if ( _hasDependentDRInfo ) {
+ _dependentDRInfoAtom = new DependentDRAtom<x86>(_options, state, *this);
+ dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+ }
if ( _hasSymbolTable ) {
_symbolTableAtom = new SymbolTableAtom<x86>(_options, state, *this);
symbolTableSection = state.addAtom(*_symbolTableAtom);
stringPoolSection = state.addAtom(*_stringPoolAtom);
}
break;
+#endif
+#if SUPPORT_ARCH_x86_64
case CPU_TYPE_X86_64:
if ( _hasSectionRelocations ) {
_sectionsRelocationsAtom = new SectionRelocationsAtom<x86_64>(_options, state, *this);
_functionStartsAtom = new FunctionStartsAtom<x86_64>(_options, state, *this);
functionStartsSection = state.addAtom(*_functionStartsAtom);
}
+ if ( _hasDataInCodeInfo ) {
+ _dataInCodeAtom = new DataInCodeAtom<x86_64>(_options, state, *this);
+ dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+ }
+ if ( _hasDependentDRInfo ) {
+ _dependentDRInfoAtom = new DependentDRAtom<x86_64>(_options, state, *this);
+ dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+ }
if ( _hasSymbolTable ) {
_symbolTableAtom = new SymbolTableAtom<x86_64>(_options, state, *this);
symbolTableSection = state.addAtom(*_symbolTableAtom);
stringPoolSection = state.addAtom(*_stringPoolAtom);
}
break;
+#endif
+#if SUPPORT_ARCH_arm_any
case CPU_TYPE_ARM:
if ( _hasSectionRelocations ) {
_sectionsRelocationsAtom = new SectionRelocationsAtom<arm>(_options, state, *this);
_functionStartsAtom = new FunctionStartsAtom<arm>(_options, state, *this);
functionStartsSection = state.addAtom(*_functionStartsAtom);
}
+ if ( _hasDataInCodeInfo ) {
+ _dataInCodeAtom = new DataInCodeAtom<arm>(_options, state, *this);
+ dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+ }
+ if ( _hasDependentDRInfo ) {
+ _dependentDRInfoAtom = new DependentDRAtom<arm>(_options, state, *this);
+ dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+ }
if ( _hasSymbolTable ) {
_symbolTableAtom = new SymbolTableAtom<arm>(_options, state, *this);
symbolTableSection = state.addAtom(*_symbolTableAtom);
stringPoolSection = state.addAtom(*_stringPoolAtom);
}
break;
- case CPU_TYPE_POWERPC64:
- if ( _hasSectionRelocations ) {
- _sectionsRelocationsAtom = new SectionRelocationsAtom<ppc64>(_options, state, *this);
- sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
- }
- if ( _hasDyldInfo ) {
- _rebasingInfoAtom = new RebaseInfoAtom<ppc64>(_options, state, *this);
- rebaseSection = state.addAtom(*_rebasingInfoAtom);
-
- _bindingInfoAtom = new BindingInfoAtom<ppc64>(_options, state, *this);
- bindingSection = state.addAtom(*_bindingInfoAtom);
-
- _weakBindingInfoAtom = new WeakBindingInfoAtom<ppc64>(_options, state, *this);
- weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
-
- _lazyBindingInfoAtom = new LazyBindingInfoAtom<ppc64>(_options, state, *this);
- lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
-
- _exportInfoAtom = new ExportInfoAtom<ppc64>(_options, state, *this);
- exportSection = state.addAtom(*_exportInfoAtom);
- }
- if ( _hasLocalRelocations ) {
- _localRelocsAtom = new LocalRelocationsAtom<ppc64>(_options, state, *this);
- localRelocationsSection = state.addAtom(*_localRelocsAtom);
- }
- if ( _hasSplitSegInfo ) {
- _splitSegInfoAtom = new SplitSegInfoAtom<ppc64>(_options, state, *this);
- splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
- }
- if ( _hasFunctionStartsInfo ) {
- _functionStartsAtom = new FunctionStartsAtom<ppc64>(_options, state, *this);
- functionStartsSection = state.addAtom(*_functionStartsAtom);
- }
- if ( _hasSymbolTable ) {
- _symbolTableAtom = new SymbolTableAtom<ppc64>(_options, state, *this);
- symbolTableSection = state.addAtom(*_symbolTableAtom);
- }
- if ( _hasExternalRelocations ) {
- _externalRelocsAtom = new ExternalRelocationsAtom<ppc64>(_options, state, *this);
- externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
- }
- if ( _hasSymbolTable ) {
- _indirectSymbolTableAtom = new IndirectSymbolTableAtom<ppc64>(_options, state, *this);
- indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
- _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
- stringPoolSection = state.addAtom(*_stringPoolAtom);
- }
- break;
+#endif
default:
throw "unknown architecture";
}
void OutputFile::addLoadCommands(ld::Internal& state)
{
switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_x86_64
case CPU_TYPE_X86_64:
_headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86_64>(_options, state, *this);
headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
break;
+#endif
+#if SUPPORT_ARCH_arm_any
case CPU_TYPE_ARM:
_headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<arm>(_options, state, *this);
headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
break;
+#endif
+#if SUPPORT_ARCH_i386
case CPU_TYPE_I386:
_headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
break;
- case CPU_TYPE_POWERPC:
- _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<ppc>(_options, state, *this);
- headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
- break;
- case CPU_TYPE_POWERPC64:
- _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<ppc64>(_options, state, *this);
- headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
- break;
+#endif
default:
throw "unknown architecture";
}
case ld::Fixup::kindStoreARMBranch24:
case ld::Fixup::kindStoreThumbBranch22:
case ld::Fixup::kindStoreARMLoad12:
- case ld::Fixup::kindStorePPCBranch24:
- case ld::Fixup::kindStorePPCBranch14:
- case ld::Fixup::kindStorePPCPicLow14:
- case ld::Fixup::kindStorePPCPicLow16:
- case ld::Fixup::kindStorePPCPicHigh16AddLow:
case ld::Fixup::kindStoreTargetAddressX86PCRel32:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
case ld::Fixup::kindStoreTargetAddressARMBranch24:
case ld::Fixup::kindStoreTargetAddressThumbBranch22:
case ld::Fixup::kindStoreTargetAddressARMLoad12:
- case ld::Fixup::kindStoreTargetAddressPPCBranch24:
return true;
case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
return (_options.outputKind() != Options::kKextBundle);
case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+ case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
case ld::Fixup::kindStoreTargetAddressARMBranch24:
case ld::Fixup::kindStoreTargetAddressThumbBranch22:
case ld::Fixup::kindStoreTargetAddressARMLoad12:
- case ld::Fixup::kindStoreTargetAddressPPCBranch24:
return true;
case ld::Fixup::kindStoreX86DtraceCallSiteNop:
case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
- case ld::Fixup::kindStorePPCDtraceCallSiteNop:
- case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
return (_options.outputKind() == Options::kObjectFile);
default:
break;
}
assert(minusTarget != NULL);
break;
- default:
+ case ld::Fixup::kindDataInCodeStartData:
+ case ld::Fixup::kindDataInCodeStartJT8:
+ case ld::Fixup::kindDataInCodeStartJT16:
+ case ld::Fixup::kindDataInCodeStartJT32:
+ case ld::Fixup::kindDataInCodeStartJTA32:
+ case ld::Fixup::kindDataInCodeEnd:
+ hasDataInCode = true;
+ break;
+ default:
break;
}
if ( this->isStore(fit->kind) ) {
if ( _options.warnAboutTextRelocs() )
warning("text reloc in %s to %s", atom->name(), target->name());
}
- else if ( _options.positionIndependentExecutable() && ((_options.iphoneOSVersionMin() >= ld::iPhone4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
+ else if ( _options.positionIndependentExecutable() && (_options.outputKind() == Options::kDynamicExecutable)
+ && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
if ( ! this->pieDisabled ) {
warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
"but used in %s from %s. "
}
this->pieDisabled = true;
}
+ else if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) ) {
+ throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+ }
else {
- throwf("illegal text reloc to %s from %s in %s", target->name(), target->file()->path(), atom->name());
+ throwf("illegal text-relocation to %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
}
}
// no need to rebase or bind PCRel stores
if ( this->isPcRelStore(fixupWithStore->kind) ) {
// as long as target is in same linkage unit
- if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) )
+ if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) ) {
+ // make sure target is not global and weak
+ if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular)) {
+ if ( (atom->section().type() == ld::Section::typeCFI)
+ || (atom->section().type() == ld::Section::typeDtraceDOF)
+ || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+ // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+ return;
+ }
+ // Have direct reference to weak-global. This should be an indrect reference
+ const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+ warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
+ "This was likely caused by different translation units being compiled with different visibility settings.",
+ demangledName, _options.demangleSymbol(target->name()));
+ }
return;
+ }
}
// no need to rebase or bind PIC internal pointer diff
return;
}
- // make sure target is not global and weak
- if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName)
- && (atom->section().type() != ld::Section::typeCFI)
- && (atom->section().type() != ld::Section::typeDtraceDOF)
- && (atom->section().type() != ld::Section::typeUnwindInfo) ) {
- // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
- throwf("bad codegen, pointer diff in %s to global weak symbol %s", atom->name(), target->name());
+ // check if target of pointer-diff is global and weak
+ if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) ) {
+ if ( (atom->section().type() == ld::Section::typeCFI)
+ || (atom->section().type() == ld::Section::typeDtraceDOF)
+ || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+ // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+ return;
+ }
+ // Have direct reference to weak-global. This should be an indrect reference
+ const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+ warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
+ "This was likely caused by different translation units being compiled with different visibility settings.",
+ demangledName, _options.demangleSymbol(target->name()));
}
return;
}
uint8_t rebaseType = REBASE_TYPE_POINTER;
uint8_t type = BIND_TYPE_POINTER;
const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
- bool weak_import = ((dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()));
+ bool weak_import = (fixupWithTarget->weakImport || ((dylib != NULL) && dylib->forcedWeakLinked()));
uint64_t address = atom->finalAddress() + fixupWithTarget->offsetInAtom;
uint64_t addend = targetAddend - minusTargetAddend;
sect->hasLocalRelocs = true; // so dyld knows to change permissions on __TEXT segment
rebaseType = REBASE_TYPE_TEXT_ABSOLUTE32;
}
+ if ( (addend != 0) && _options.sharedRegionEligible() ) {
+ // make sure the addend does not cause the pointer to point outside the target's segment
+ // if it does, update_dyld_shared_cache will not be able to put this dylib into the shared cache
+ uint64_t targetAddress = target->finalAddress();
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sct = *sit;
+ uint64_t sctEnd = (sct->address+sct->size);
+ if ( (sct->address <= targetAddress) && (targetAddress < sctEnd) ) {
+ if ( (targetAddress+addend) > sctEnd ) {
+ warning("data symbol %s from %s has pointer to %s + 0x%08llX. "
+ "That large of an addend may disable %s from being put in the dyld shared cache.",
+ atom->name(), atom->file()->path(), target->name(), addend, _options.installPath() );
+ }
+ }
+ }
+ }
_rebaseInfo.push_back(RebaseInfo(rebaseType, address));
}
if ( needsBinding ) {
}
if ( needsWeakBinding )
_weakBindingInfo.push_back(BindingInfo(type, 0, target->name(), false, address, addend));
-
- // record if weak imported
- if ( weak_import && (target->definition() == ld::Atom::definitionProxy) )
- (const_cast<ld::Atom*>(target))->setWeakImported();
}
return;
// non-lazy-pointer section is encoded in indirect symbol table - not using relocations
- if ( (sect->type() == ld::Section::typeNonLazyPointer) && (_options.outputKind() != Options::kKextBundle) ) {
- assert(target != NULL);
- assert(fixupWithTarget != NULL);
- // record if weak imported
- const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
- if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
- (const_cast<ld::Atom*>(target))->setWeakImported();
- return;
+ if ( sect->type() == ld::Section::typeNonLazyPointer ) {
+ // except kexts and static pie which *do* use relocations
+ switch (_options.outputKind()) {
+ case Options::kKextBundle:
+ break;
+ case Options::kStaticExecutable:
+ if ( _options.positionIndependentExecutable() )
+ break;
+ // else fall into default case
+ default:
+ assert(target != NULL);
+ assert(fixupWithTarget != NULL);
+ return;
+ }
}
// no need to rebase or bind PCRel stores
switch ( fixupWithStore->kind ) {
case ld::Fixup::kindLazyTarget:
- {
- // lazy pointers don't need relocs, but might need weak_import bit set
- const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
- if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
- (const_cast<ld::Atom*>(target))->setWeakImported();
- }
+ // lazy pointers don't need relocs
break;
case ld::Fixup::kindStoreLittleEndian32:
case ld::Fixup::kindStoreLittleEndian64:
_externalRelocsAtom->addExternalPointerReloc(relocAddress, target);
sect->hasExternalRelocs = true;
fixupWithTarget->contentAddendOnly = true;
- // record if weak imported
- if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
- (const_cast<ld::Atom*>(target))->setWeakImported();
}
else if ( needsLocalReloc ) {
assert(target != NULL);
sect->hasLocalRelocs = true;
}
break;
- case ld::Fixup::kindStorePPCAbsLow14:
- case ld::Fixup::kindStorePPCAbsLow16:
- case ld::Fixup::kindStorePPCAbsHigh16AddLow:
- case ld::Fixup::kindStorePPCAbsHigh16:
- {
- assert(target != NULL);
- if ( target->definition() == ld::Atom::definitionProxy )
- throwf("half word text relocs not supported in %s", atom->name());
- if ( _options.outputSlidable() ) {
- if ( inReadOnlySeg )
- noteTextReloc(atom, target);
- uint32_t machoSectionIndex = (target->definition() == ld::Atom::definitionAbsolute)
- ? R_ABS : target->machoSection();
- _localRelocsAtom->addTextReloc(relocAddress, fixupWithTarget->kind,
- target->finalAddress(), machoSectionIndex);
- sect->hasLocalRelocs = true;
- }
- }
- break;
case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
if ( _options.outputKind() == Options::kKextBundle ) {
assert(target != NULL);
}
}
break;
+
+ case ld::Fixup::kindStoreARMLow16:
+ case ld::Fixup::kindStoreThumbLow16:
+ // no way to encode rebasing of binding for these instructions
+ if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) )
+ throwf("no supported runtime lo16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name());
+ break;
+
+ case ld::Fixup::kindStoreARMHigh16:
+ case ld::Fixup::kindStoreThumbHigh16:
+ // no way to encode rebasing of binding for these instructions
+ if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) )
+ throwf("no supported runtime hi16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name());
+ break;
+
default:
break;
}
// x86_64 uses external relocations for everthing that has a symbol
return ( target->symbolTableInclusion() != ld::Atom::symbolTableNotIn );
}
+
+ // <rdar://problem/9513487> support arm branch interworking in -r mode
+ if ( (_options.architecture() == CPU_TYPE_ARM) && (_options.outputKind() == Options::kObjectFile) ) {
+ if ( atom->isThumb() != target->isThumb() ) {
+ switch ( fixupWithTarget->kind ) {
+ // have branch that switches mode, then might be 'b' not 'bl'
+ // Force external relocation, since no way to do local reloc for 'b'
+ case ld::Fixup::kindStoreTargetAddressThumbBranch22 :
+ case ld::Fixup::kindStoreTargetAddressARMBranch24:
+ return true;
+ default:
+ break;
+ }
+ }
+ }
+
+ if ( (_options.architecture() == CPU_TYPE_I386) && (_options.outputKind() == Options::kObjectFile) ) {
+ if ( target->contentType() == ld::Atom::typeTLV )
+ return true;
+ }
+
// most architectures use external relocations only for references
// to a symbol in another translation unit or for references to "weak symbols" or tentative definitions
assert(target != NULL);
// pc-rel instructions are funny. If the target is _foo+8 and _foo is
// external, then the pc-rel instruction *evalutates* to the address 8.
if ( targetUsesExternalReloc ) {
- if ( isPcRelStore(fixupWithStore->kind) ) {
+ // TLV support for i386 acts like RIP relative addressing
+ // The addend is the offset from the PICBase to the end of the instruction
+ if ( (_options.architecture() == CPU_TYPE_I386)
+ && (_options.outputKind() == Options::kObjectFile)
+ && (fixupWithStore->kind == ld::Fixup::kindStoreX86PCRel32TLVLoad) ) {
+ fixupWithTarget->contentAddendOnly = true;
+ fixupWithStore->contentAddendOnly = true;
+ }
+ else if ( isPcRelStore(fixupWithStore->kind) ) {
fixupWithTarget->contentDetlaToAddendOnly = true;
fixupWithStore->contentDetlaToAddendOnly = true;
}
for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
const ld::Atom* atom = *ait;
const ld::Atom* target = NULL;
+ const ld::Atom* fromTarget = NULL;
+ uint64_t accumulator = 0;
+ bool thumbTarget;
bool hadSubtract = false;
for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
if ( fit->firstInCluster() )
target = NULL;
- if ( fit->kind == ld::Fixup::kindSubtractTargetAddress ) {
- hadSubtract = true;
- continue;
+ if ( this->setsTarget(fit->kind) ) {
+ accumulator = addressOf(state, fit, &target);
+ thumbTarget = targetIsThumb(state, fit);
+ if ( thumbTarget )
+ accumulator |= 1;
}
- switch ( fit->binding ) {
- case ld::Fixup::bindingNone:
- case ld::Fixup::bindingByNameUnbound:
+ switch ( fit->kind ) {
+ case ld::Fixup::kindSubtractTargetAddress:
+ accumulator -= addressOf(state, fit, &fromTarget);
+ hadSubtract = true;
break;
- case ld::Fixup::bindingByContentBound:
- case ld::Fixup::bindingDirectlyBound:
- target = fit->u.target;
+ case ld::Fixup::kindAddAddend:
+ accumulator += fit->u.addend;
break;
- case ld::Fixup::bindingsIndirectlyBound:
- target = state.indirectBindingTable[fit->u.bindingIndex];
+ case ld::Fixup::kindSubtractAddend:
+ accumulator -= fit->u.addend;
break;
- }
- switch ( fit->kind ) {
case ld::Fixup::kindStoreBigEndian32:
case ld::Fixup::kindStoreLittleEndian32:
case ld::Fixup::kindStoreLittleEndian64:
// there is also a text reloc which update_dyld_shared_cache will use.
if ( ! hadSubtract )
break;
+ // fall through
case ld::Fixup::kindStoreX86PCRel32:
case ld::Fixup::kindStoreX86PCRel32_1:
case ld::Fixup::kindStoreX86PCRel32_2:
case ld::Fixup::kindStoreX86PCRel32GOTLoad:
case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
case ld::Fixup::kindStoreX86PCRel32GOT:
- case ld::Fixup::kindStorePPCPicHigh16AddLow:
case ld::Fixup::kindStoreTargetAddressX86PCRel32:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+ case ld::Fixup::kindStoreARMLow16:
+ case ld::Fixup::kindStoreThumbLow16:
assert(target != NULL);
if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {
_splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind));
}
break;
+ case ld::Fixup::kindStoreARMHigh16:
+ case ld::Fixup::kindStoreThumbHigh16:
+ assert(target != NULL);
+ if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {
+ // hi16 needs to know upper 4-bits of low16 to compute carry
+ uint32_t extra = (accumulator >> 12) & 0xF;
+ _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind, extra));
+ }
+ break;
+ case ld::Fixup::kindSetTargetImageOffset:
+ accumulator = addressOf(state, fit, &target);
+ assert(target != NULL);
+ hadSubtract = true;
+ break;
default:
break;
}
// uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
//}
// write table of object files
- std::map<const ld::File*, uint32_t> readerToOrdinal;
- std::map<uint32_t, const ld::File*> ordinalToReader;
+ std::map<const ld::File*, ld::File::Ordinal> readerToOrdinal;
+ std::map<ld::File::Ordinal, const ld::File*> ordinalToReader;
std::map<const ld::File*, uint32_t> readerToFileOrdinal;
for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
ld::Internal::FinalSection* sect = *sit;
const ld::File* reader = atom->file();
if ( reader == NULL )
continue;
- uint32_t readerOrdinal = reader->ordinal();
- std::map<const ld::File*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
+ ld::File::Ordinal readerOrdinal = reader->ordinal();
+ std::map<const ld::File*, ld::File::Ordinal>::iterator pos = readerToOrdinal.find(reader);
if ( pos == readerToOrdinal.end() ) {
readerToOrdinal[reader] = readerOrdinal;
ordinalToReader[readerOrdinal] = reader;
}
fprintf(mapFile, "# Object files:\n");
fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
- uint32_t fileIndex = 0;
- readerToFileOrdinal[NULL] = fileIndex++;
- for(std::map<uint32_t, const ld::File*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
- if ( it->first != 0 ) {
- fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->path());
- readerToFileOrdinal[it->second] = fileIndex++;
- }
+ uint32_t fileIndex = 1;
+ for(std::map<ld::File::Ordinal, const ld::File*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
+ fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->path());
+ readerToFileOrdinal[it->second] = fileIndex++;
}
// write table of sections
fprintf(mapFile, "# Sections:\n");
bool operator()(const ld::Atom* left, const ld::Atom* right) const
{
// first sort by reader
- uint32_t leftFileOrdinal = left->file()->ordinal();
- uint32_t rightFileOrdinal = right->file()->ordinal();
+ ld::File::Ordinal leftFileOrdinal = left->file()->ordinal();
+ ld::File::Ordinal rightFileOrdinal = right->file()->ordinal();
if ( leftFileOrdinal!= rightFileOrdinal)
return (leftFileOrdinal < rightFileOrdinal);
// then sort by atom objectAddress
- uint64_t leftAddr = left->objectAddress();
- uint64_t rightAddr = right->objectAddress();
+ uint64_t leftAddr = left->finalAddress();
+ uint64_t rightAddr = right->finalAddress();
return leftAddr < rightAddr;
}
};
const ld::Atom* atom = *it;
const ld::File* atomFile = atom->file();
const ld::relocatable::File* atomObjFile = dynamic_cast<const ld::relocatable::File*>(atomFile);
- const char* newDirPath;
- const char* newFilename;
- //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
- if ( atom->translationUnitSource(&newDirPath, &newFilename) ) {
+ //fprintf(stderr, "debug note for %s\n", atom->name());
+ const char* newPath = atom->translationUnitSource();
+ if ( newPath != NULL ) {
+ const char* newDirPath;
+ const char* newFilename;
+ const char* lastSlash = strrchr(newPath, '/');
+ if ( lastSlash == NULL )
+ continue;
+ newFilename = lastSlash+1;
+ char* temp = strdup(newPath);
+ newDirPath = temp;
+ // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
+ temp[lastSlash-newPath+1] = '\0';
// need SO's whenever the translation unit source file changes
- if ( newFilename != filename ) {
- // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
- if ( (newDirPath != NULL) && (strlen(newDirPath) > 1 ) && (newDirPath[strlen(newDirPath)-1] != '/') )
- asprintf((char**)&newDirPath, "%s/", newDirPath);
+ if ( (filename == NULL) || (strcmp(newFilename,filename) != 0) ) {
if ( filename != NULL ) {
// translation unit change, emit ending SO
ld::relocatable::File::Stab endFileStab;
// add the source file path to seenFiles so it does not show up in SOLs
seenFiles.insert(newFilename);
char* fullFilePath;
- asprintf(&fullFilePath, "%s/%s", newDirPath, newFilename);
+ asprintf(&fullFilePath, "%s%s", newDirPath, newFilename);
// add both leaf path and full path
seenFiles.insert(fullFilePath);
}