ExecutableFileMachO.cpp [plain text]
namespace ExecutableFileMachO {
class Writer : public ExecutableFile::Writer
{
public:
Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
virtual ~Writer();
virtual const char* getPath();
virtual std::vector<class ObjectFile::Atom*>& getAtoms();
virtual std::vector<class ObjectFile::Atom*>* getJustInTimeAtomsFor(const char* name);
virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo();
virtual class ObjectFile::Atom* getUndefinedProxyAtom(const char* name);
virtual void write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom);
private:
void assignFileOffsets();
void partitionIntoSections();
void adjustLoadCommandsAndPadding();
void createDynamicLinkerCommand();
void createDylibCommands();
void buildLinkEdit();
void writeAtoms();
void collectExportedAndImportedAndLocalAtoms();
void setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
void buildSymbolTable();
void setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
void setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
void setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
uint64_t getAtomLoadAddress(const ObjectFile::Atom* atom);
uint8_t ordinalForLibrary(ObjectFile::Reader* file);
bool shouldExport(ObjectFile::Atom& atom);
void buildFixups();
void adjustLinkEditSections();
void buildObjectFileFixups();
void buildExecutableFixups();
uint32_t symbolIndex(ObjectFile::Atom& atom);
uint32_t addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
unsigned int collectStabs();
macho_uintptr_t valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom);
void addStabs(uint32_t startIndex, uint32_t count);
class SectionInfo : public ObjectFile::Section {
public:
SectionInfo();
void setIndex(unsigned int index) { fIndex=index; }
std::vector<ObjectFile::Atom*> fAtoms;
char fSegmentName[20];
char fSectionName[20];
uint64_t fFileOffset;
uint64_t fSize;
uint32_t fRelocCount;
uint32_t fRelocOffset;
uint32_t fIndirectSymbolOffset;
uint8_t fAlignment;
bool fAllLazyPointers;
bool fAllNonLazyPointers;
bool fAllZeroFill;
bool fVirtualSection;
};
class SegmentInfo
{
public:
SegmentInfo();
std::vector<class SectionInfo*> fSections;
char fName[20];
uint32_t fInitProtection;
uint32_t fMaxProtection;
uint64_t fFileOffset;
uint64_t fFileSize;
uint64_t fBaseAddress;
uint64_t fSize;
};
struct DirectLibrary {
class ObjectFile::Reader* fLibrary;
bool fWeak;
bool fReExport;
};
struct IndirectEntry {
uint32_t indirectIndex;
uint32_t symbolIndex;
};
struct StabChunks {
ObjectFile::Atom* fAtom;
ObjectFile::Reader* fReader;
unsigned int fOrderInReader;
std::vector<ObjectFile::StabsInfo>* fStabs;
};
static bool stabChunkCompare(const StabChunks& lhs, const StabChunks& rhs);
friend class WriterAtom;
friend class PageZeroAtom;
friend class CustomStackAtom;
friend class MachHeaderAtom;
friend class SegmentLoadCommandsAtom;
friend class SymbolTableLoadCommandsAtom;
friend class ThreadsLoadCommandsAtom;
friend class DylibIDLoadCommandsAtom;
friend class RoutinesLoadCommandsAtom;
friend class DyldLoadCommandsAtom;
friend class LinkEditAtom;
friend class LocalRelocationsLinkEditAtom;
friend class ExternalRelocationsLinkEditAtom;
friend class SymbolTableLinkEditAtom;
friend class IndirectTableLinkEditAtom;
friend class StringsLinkEditAtom;
const char* fFilePath;
Options& fOptions;
int fFileDescriptor;
std::vector<class ObjectFile::Atom*>* fAllAtoms;
class SectionInfo* fLoadCommandsSection;
class SegmentInfo* fLoadCommandsSegment;
class SegmentLoadCommandsAtom* fSegmentCommands;
class SymbolTableLoadCommandsAtom* fSymbolTableCommands;
class LoadCommandsPaddingAtom* fHeaderPadding;
std::vector<class ObjectFile::Atom*> fWriterSynthesizedAtoms;
std::vector<SegmentInfo*> fSegmentInfos;
class ObjectFile::Atom* fEntryPoint;
std::vector<DirectLibrary> fDirectLibraries;
std::map<class ObjectFile::Reader*, uint32_t> fLibraryToOrdinal;
std::vector<StabChunks> fStabChunks;
std::vector<class ObjectFile::Atom*> fExportedAtoms;
std::vector<class ObjectFile::Atom*> fImportedAtoms;
std::vector<class ObjectFile::Atom*> fLocalSymbolAtoms;
LocalRelocationsLinkEditAtom* fLocalRelocationsAtom;
ExternalRelocationsLinkEditAtom* fExternalRelocationsAtom;
SymbolTableLinkEditAtom* fSymbolTableAtom;
IndirectTableLinkEditAtom* fIndirectTableAtom;
StringsLinkEditAtom* fStringsAtom;
macho_nlist* fSymbolTable;
std::vector<macho_relocation_info> fInternalRelocs;
std::vector<macho_relocation_info> fExternalRelocs;
std::vector<IndirectEntry> fIndirectSymbolTable;
uint32_t fSymbolTableCount;
uint32_t fSymbolTableStabsCount;
uint32_t fSymbolTableStabsStartIndex;
uint32_t fSymbolTableLocalCount;
uint32_t fSymbolTableLocalStartIndex;
uint32_t fSymbolTableExportCount;
uint32_t fSymbolTableExportStartIndex;
uint32_t fSymbolTableImportCount;
uint32_t fSymbolTableImportStartIndex;
bool fEmitVirtualSections;
bool fHasWeakExports;
bool fReferencesWeakImports;
};
class WriterAtom : public ObjectFile::Atom
{
protected:
class Segment;
public:
enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
WriterAtom(Writer& writer, class WriterAtom::Segment& segment) : fWriter(writer), fSegment(segment) {}
virtual ObjectFile::Reader* getFile() const { return &fWriter; }
virtual const char* getName() const { return NULL; }
virtual const char* getDisplayName() const { return this->getName(); }
virtual Scope getScope() const { return ObjectFile::Atom::scopeTranslationUnit; }
virtual bool isTentativeDefinition() const { return false; }
virtual bool isWeakDefinition() const { return false; }
virtual bool isCoalesableByName() const { return false; }
virtual bool isCoalesableByValue() const { return false; }
virtual bool isZeroFill() const { return false; }
virtual bool dontDeadStrip() const { return true; }
virtual bool dontStripName() const { return false; }
virtual bool isImportProxy() const { return false; }
virtual std::vector<ObjectFile::Reference*>& getReferences() const { return fgEmptyReferenceList; }
virtual bool mustRemainInSection() const { return true; }
virtual ObjectFile::Segment& getSegment() const { return fSegment; }
virtual bool requiresFollowOnAtom() const { return false; }
virtual ObjectFile::Atom& getFollowOnAtom() const { return *((ObjectFile::Atom*)NULL); }
virtual std::vector<ObjectFile::StabsInfo>* getStabsDebugInfo() const { return NULL; }
virtual uint8_t getAlignment() const { return 2; }
virtual WeakImportSetting getImportWeakness() const { return Atom::kWeakUnset; }
virtual void copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
virtual void setScope(Scope) { }
virtual void setImportWeakness(bool weakImport) { }
protected:
virtual ~WriterAtom() {}
class Segment : public ObjectFile::Segment
{
public:
Segment(const char* name, bool readable, bool writable, bool executable)
: fName(name), fReadable(readable), fWritable(writable), fExecutable(executable) {}
virtual const char* getName() const { return fName; }
virtual bool isContentReadable() const { return fReadable; }
virtual bool isContentWritable() const { return fWritable; }
virtual bool isContentExecutable() const { return fExecutable; }
private:
const char* fName;
const bool fReadable;
const bool fWritable;
const bool fExecutable;
};
static std::vector<ObjectFile::Reference*> fgEmptyReferenceList;
static Segment fgTextSegment;
static Segment fgPageZeroSegment;
static Segment fgLinkEditSegment;
static Segment fgStackSegment;
Writer& fWriter;
Segment& fSegment;
};
WriterAtom::Segment WriterAtom::fgPageZeroSegment("__PAGEZERO", false, false, false);
WriterAtom::Segment WriterAtom::fgTextSegment("__TEXT", true, false, true);
WriterAtom::Segment WriterAtom::fgLinkEditSegment("__LINKEDIT", true, false, false);
WriterAtom::Segment WriterAtom::fgStackSegment("__UNIXSTACK", true, true, false);
std::vector<ObjectFile::Reference*> WriterAtom::fgEmptyReferenceList;
class PageZeroAtom : public WriterAtom
{
public:
PageZeroAtom(Writer& writer) : WriterAtom(writer, fgPageZeroSegment) {}
virtual const char* getDisplayName() const { return "page zero content"; }
virtual bool isZeroFill() const { return true; }
virtual uint64_t getSize() const { return fWriter.fOptions.zeroPageSize(); }
virtual const char* getSectionName() const { return "._zeropage"; }
virtual uint8_t getAlignment() const { return 12; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
};
class MachHeaderAtom : public WriterAtom
{
public:
MachHeaderAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
virtual const char* getName() const;
virtual const char* getDisplayName() const;
virtual Scope getScope() const;
virtual bool dontStripName() const;
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 12; }
virtual const char* getSectionName() const { return "._mach_header"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
};
class CustomStackAtom : public WriterAtom
{
public:
CustomStackAtom(Writer& writer);
virtual const char* getDisplayName() const { return "custom stack content"; }
virtual bool isZeroFill() const { return true; }
virtual uint64_t getSize() const { return fWriter.fOptions.customStackSize(); }
virtual const char* getSectionName() const { return "._stack"; }
virtual uint8_t getAlignment() const { return 12; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
};
class SegmentLoadCommandsAtom : public WriterAtom
{
public:
SegmentLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment), fCommandCount(0), fSize(0) { writer.fSegmentCommands = this; }
virtual const char* getDisplayName() const { return "segment load commands"; }
virtual uint64_t getSize() const { return fSize; }
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_commands"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
void computeSize();
void setup();
unsigned int commandCount() { return fCommandCount; }
void assignFileOffsets();
private:
unsigned int fCommandCount;
uint32_t fSize;
};
class SymbolTableLoadCommandsAtom : public WriterAtom
{
public:
SymbolTableLoadCommandsAtom(Writer&);
virtual const char* getDisplayName() const { return "symbol table load commands"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_commands"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
private:
macho_symtab_command fSymbolTable;
macho_dysymtab_command fDynamicSymbolTable;
};
class ThreadsLoadCommandsAtom : public WriterAtom
{
public:
ThreadsLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
virtual const char* getDisplayName() const { return "thread load commands"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_commands"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
private:
uint8_t* fBuffer;
uint32_t fBufferSize;
};
class DyldLoadCommandsAtom : public WriterAtom
{
public:
DyldLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
virtual const char* getDisplayName() const { return "dyld load command"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_commands"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
};
class DylibLoadCommandsAtom : public WriterAtom
{
public:
DylibLoadCommandsAtom(Writer& writer, ExecutableFile::DyLibUsed& info) : WriterAtom(writer, fgTextSegment), fInfo(info) {}
virtual const char* getDisplayName() const { return "dylib load command"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_commands"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
private:
ExecutableFile::DyLibUsed& fInfo;
};
class DylibIDLoadCommandsAtom : public WriterAtom
{
public:
DylibIDLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
virtual const char* getDisplayName() const { return "dylib ID load command"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_commands"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
};
class RoutinesLoadCommandsAtom : public WriterAtom
{
public:
RoutinesLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
virtual const char* getDisplayName() const { return "routines load command"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_commands"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
};
class SubUmbrellaLoadCommandsAtom : public WriterAtom
{
public:
SubUmbrellaLoadCommandsAtom(Writer& writer, const char* name) : WriterAtom(writer, fgTextSegment), fName(name) {}
virtual const char* getDisplayName() const { return "sub-umbrella load command"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_commands"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
private:
const char* fName;
};
class SubLibraryLoadCommandsAtom : public WriterAtom
{
public:
SubLibraryLoadCommandsAtom(Writer& writer, const char* nameStart, int nameLen)
: WriterAtom(writer, fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
virtual const char* getDisplayName() const { return "sub-library load command"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_commands"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
private:
const char* fNameStart;
int fNameLength;
};
class UmbrellaLoadCommandsAtom : public WriterAtom
{
public:
UmbrellaLoadCommandsAtom(Writer& writer, const char* name)
: WriterAtom(writer, fgTextSegment), fName(name) {}
virtual const char* getDisplayName() const { return "umbrella load command"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_commands"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
private:
const char* fName;
};
class LoadCommandsPaddingAtom : public WriterAtom
{
public:
LoadCommandsPaddingAtom(Writer& writer)
: WriterAtom(writer, fgTextSegment), fSize(0) {}
virtual const char* getDisplayName() const { return "header padding"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._load_cmds_pad"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
void setSize(uint64_t newSize) { fSize = newSize; }
private:
uint64_t fSize;
};
class LinkEditAtom : public WriterAtom
{
public:
LinkEditAtom(Writer& writer) : WriterAtom(writer, fgLinkEditSegment) {}
uint64_t getFileOffset() const;
};
class LocalRelocationsLinkEditAtom : public LinkEditAtom
{
public:
LocalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
virtual const char* getDisplayName() const { return "local relocations"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 3; }
virtual const char* getSectionName() const { return "._local_relocs"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
};
class SymbolTableLinkEditAtom : public LinkEditAtom
{
public:
SymbolTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
virtual const char* getDisplayName() const { return "symbol table"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._symbol_table"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
};
class ExternalRelocationsLinkEditAtom : public LinkEditAtom
{
public:
ExternalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
virtual const char* getDisplayName() const { return "external relocations"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 3; }
virtual const char* getSectionName() const { return "._extern_relocs"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
};
class IndirectTableLinkEditAtom : public LinkEditAtom
{
public:
IndirectTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
virtual const char* getDisplayName() const { return "indirect symbol table"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._indirect_syms"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
};
class StringsLinkEditAtom : public LinkEditAtom
{
public:
StringsLinkEditAtom(Writer& writer);
virtual const char* getDisplayName() const { return "string pool"; }
virtual uint64_t getSize() const;
virtual uint8_t getAlignment() const { return 2; }
virtual const char* getSectionName() const { return "._string_pool"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
int32_t add(const char* name);
int32_t emptyString();
private:
enum { kBufferSize = 0x01000000 };
std::vector<char*> fFullBuffers;
char* fCurrentBuffer;
uint32_t fCurrentBufferUsed;
};
class UndefinedSymbolProxyAtom : public WriterAtom
{
public:
UndefinedSymbolProxyAtom(Writer& writer, const char* name) : WriterAtom(writer, fgLinkEditSegment), fName(name), fWeakImportSetting(Atom::kWeakUnset) {}
virtual const char* getName() const { return fName; }
virtual Scope getScope() const { return ObjectFile::Atom::scopeGlobal; }
virtual uint64_t getSize() const { return 0; }
virtual bool isWeakDefinition() const { return true; }
virtual bool isImportProxy() const { return true; }
virtual const char* getSectionName() const { return "._imports"; }
virtual void writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
virtual WeakImportSetting getImportWeakness() const { return fWeakImportSetting; }
virtual void setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; }
private:
const char* fName;
WeakImportSetting fWeakImportSetting;
};
struct ExportSorter
{
bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
{
return (strcmp(left->getName(), right->getName()) < 0);
}
};
ExecutableFile::Writer* MakeWriter(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
{
return new Writer(path, options, dynamicLibraries);
}
Writer::SectionInfo::SectionInfo()
: fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0), fAlignment(0),
fAllLazyPointers(false), fAllNonLazyPointers(false), fAllZeroFill(false), fVirtualSection(false)
{
fSegmentName[0] = '\0';
fSectionName[0] = '\0';
}
Writer::SegmentInfo::SegmentInfo()
: fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), fBaseAddress(0), fSize(0)
{
fName[0] = '\0';
}
Writer::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
: ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL),
fLoadCommandsSegment(NULL),
fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false)
{
int permissions = 0777;
if ( fOptions.outputKind() == Options::kObjectFile )
permissions = 0666;
(void)unlink(fFilePath);
fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
if ( fFileDescriptor == -1 ) {
throw "can't open file for writing";
}
switch ( fOptions.outputKind() ) {
case Options::kDynamicExecutable:
case Options::kStaticExecutable:
fWriterSynthesizedAtoms.push_back(new PageZeroAtom(*this));
fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
if ( fOptions.outputKind() == Options::kDynamicExecutable )
fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this));
fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this));
if ( fOptions.hasCustomStack() )
fWriterSynthesizedAtoms.push_back(new CustomStackAtom(*this));
fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
break;
case Options::kDynamicLibrary:
case Options::kDynamicBundle:
case Options::kObjectFile:
fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom(*this));
if ( fOptions.initFunctionName() != NULL )
fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom(*this));
}
fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
break;
case Options::kDyld:
fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this));
fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this));
fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
break;
}
uint8_t ordinal = 1;
switch ( fOptions.outputKind() ) {
case Options::kDynamicExecutable:
case Options::kDynamicLibrary:
case Options::kDynamicBundle:
{
const unsigned int libCount = dynamicLibraries.size();
for (unsigned int i=0; i < libCount; ++i) {
ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
if ( dylibInfo.indirect ) {
if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
bool found = false;
for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
if ( it->first == dylibInfo.directReader ) {
fLibraryToOrdinal[dylibInfo.reader] = it->second;
found = true;
break;
}
}
if ( ! found )
fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL);
}
}
else {
bool newDylib = true;
const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
if ( dylibInfo.options.fInstallPathOverride != NULL )
dylibInstallPath = dylibInfo.options.fInstallPathOverride;
for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
if ( !seenDylibInfo.indirect ) {
const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
if ( seenDylibInfo.options.fInstallPathOverride != NULL )
seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
newDylib = false;
break;
}
}
}
if ( newDylib ) {
fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom(*this, dylibInfo));
if ( dylibInfo.options.fReExport ) {
bool isFrameworkReExport = false;
const char* lastSlash = strrchr(dylibInstallPath, '/');
if ( lastSlash != NULL ) {
char frameworkName[strlen(lastSlash)+20];
sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
}
if ( isFrameworkReExport ) {
fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom(*this, &lastSlash[1]));
}
else {
const char* nameStart = &lastSlash[1];
if ( lastSlash == NULL )
nameStart = dylibInstallPath;
int len = strlen(nameStart);
const char* dot = strchr(nameStart, '.');
if ( dot != NULL )
len = dot - nameStart;
fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom(*this, nameStart, len));
}
}
}
}
}
if ( fOptions.umbrellaName() != NULL ) {
fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom(*this, fOptions.umbrellaName()));
}
}
break;
case Options::kStaticExecutable:
case Options::kObjectFile:
case Options::kDyld:
break;
}
}
Writer::~Writer()
{
if ( fFilePath != NULL )
free((void*)fFilePath);
if ( fSymbolTable != NULL )
delete [] fSymbolTable;
}
const char* Writer::getPath()
{
return fFilePath;
}
std::vector<class ObjectFile::Atom*>& Writer::getAtoms()
{
return fWriterSynthesizedAtoms;
}
std::vector<class ObjectFile::Atom*>* Writer::getJustInTimeAtomsFor(const char* name)
{
return NULL;
}
std::vector<ObjectFile::StabsInfo>* Writer::getStabsDebugInfo()
{
return NULL;
}
ObjectFile::Atom* Writer::getUndefinedProxyAtom(const char* name)
{
if ( (fOptions.outputKind() == Options::kObjectFile)
|| (fOptions.undefinedTreatment() != Options::kUndefinedError) )
return new UndefinedSymbolProxyAtom(*this, name);
else
return NULL;
}
uint8_t Writer::ordinalForLibrary(ObjectFile::Reader* lib)
{
if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
return 0;
if ( lib == this )
if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
return DYNAMIC_LOOKUP_ORDINAL;
std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
if ( pos != fLibraryToOrdinal.end() )
return pos->second;
throw "can't find ordinal for imported symbol";
}
void Writer::write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom)
{
fAllAtoms = &atoms;
fEntryPoint = entryPointAtom;
partitionIntoSections();
adjustLoadCommandsAndPadding();
assignFileOffsets();
buildLinkEdit();
writeAtoms();
}
void Writer::buildLinkEdit()
{
this->collectExportedAndImportedAndLocalAtoms();
this->buildSymbolTable();
this->buildFixups();
this->adjustLinkEditSections();
}
uint64_t Writer::getAtomLoadAddress(const ObjectFile::Atom* atom)
{
return atom->getAddress();
}
void Writer::setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
{
entry->set_n_type(N_EXT | N_SECT);
if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) )
entry->set_n_type(N_EXT | N_SECT | N_PEXT);
uint8_t sectionIndex = atom->getSection()->getIndex();
entry->set_n_sect(sectionIndex);
if ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0) && atom->dontStripName())
entry->set_n_type(N_EXT | N_ABS);
uint16_t desc = 0;
if ( atom->dontStripName() )
desc |= REFERENCED_DYNAMICALLY;
if ( atom->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) {
desc |= N_WEAK_DEF;
fHasWeakExports = true;
}
entry->set_n_desc(desc);
entry->set_n_value(this->getAtomLoadAddress(atom));
}
void Writer::setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
{
entry->set_n_type(N_UNDF | N_EXT);
entry->set_n_sect(0);
uint16_t desc = 0;
if ( fOptions.outputKind() != Options::kObjectFile ) {
desc = REFERENCE_FLAG_UNDEFINED_LAZY; try {
uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
SET_LIBRARY_ORDINAL(desc, ordinal);
}
catch (const char* msg) {
throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
}
}
if ( atom->dontStripName() )
desc |= REFERENCED_DYNAMICALLY;
if ( ( fOptions.outputKind() != Options::kObjectFile) && atom->getFile()->isDefinitionWeak(*atom) ) {
desc |= N_REF_TO_WEAK;
fReferencesWeakImports = true;
}
if ( atom->getImportWeakness() == ObjectFile::Atom::kWeakImport )
desc |= N_WEAK_REF;
entry->set_n_desc(desc);
entry->set_n_value(atom->getSize());
}
void Writer::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
{
uint8_t type = N_SECT;
if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
type |= N_PEXT;
entry->set_n_type(type);
uint8_t sectIndex = atom->getSection()->getIndex();
if ( sectIndex == 0 ) {
if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
sectIndex = 1;
}
entry->set_n_sect(sectIndex);
uint16_t desc = 0;
if ( atom->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) desc |= N_WEAK_DEF;
entry->set_n_desc(desc);
entry->set_n_value(this->getAtomLoadAddress(atom));
}
void Writer::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
{
macho_nlist* entry = &fSymbolTable[startIndex];
for (uint32_t i=0; i < count; ++i, ++entry) {
ObjectFile::Atom* atom = atoms[i];
entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
if ( &atoms == &fExportedAtoms ) {
this->setExportNlist(atom, entry);
}
else if ( &atoms == &fImportedAtoms ) {
this->setImportNlist(atom, entry);
}
else {
this->setLocalNlist(atom, entry);
}
}
}
void Writer::buildSymbolTable()
{
fSymbolTableStabsStartIndex = 0;
fSymbolTableStabsCount = this->collectStabs();
fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
fSymbolTableLocalCount = fLocalSymbolAtoms.size();
fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
fSymbolTableExportCount = fExportedAtoms.size();
fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
fSymbolTableImportCount = fImportedAtoms.size();
fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
fSymbolTable = new macho_nlist[fSymbolTableCount];
setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex, fSymbolTableLocalCount);
setNlistRange(fExportedAtoms, fSymbolTableExportStartIndex, fSymbolTableExportCount);
setNlistRange(fImportedAtoms, fSymbolTableImportStartIndex, fSymbolTableImportCount);
addStabs(fSymbolTableStabsStartIndex, fSymbolTableStabsCount);
}
bool Writer::shouldExport(ObjectFile::Atom& atom)
{
switch ( atom.getScope() ) {
case ObjectFile::Atom::scopeGlobal:
return true;
case ObjectFile::Atom::scopeLinkageUnit:
return ( fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) );
default:
return false;
}
}
void Writer::collectExportedAndImportedAndLocalAtoms()
{
const int atomCount = fAllAtoms->size();
for (int i=0; i < atomCount; ++i) {
ObjectFile::Atom* atom = (*fAllAtoms)[i];
if ( atom->getName() != NULL ) {
if ( atom->isImportProxy() || ((fOptions.outputKind() == Options::kObjectFile) && (strcmp(atom->getSectionName(), "__common") == 0)) )
fImportedAtoms.push_back(atom);
else if ( this->shouldExport(*atom) )
fExportedAtoms.push_back(atom);
else if ( !fOptions.stripLocalSymbols() )
fLocalSymbolAtoms.push_back(atom);
}
}
std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter());
}
bool Writer::stabChunkCompare(const struct StabChunks& lhs, const struct StabChunks& rhs)
{
if ( lhs.fReader != rhs.fReader ) {
return lhs.fReader < rhs.fReader;
}
return lhs.fOrderInReader < rhs.fOrderInReader;
}
unsigned int Writer::collectStabs()
{
unsigned int count = 0;
std::set<ObjectFile::Reader*> seenReaders;
const int atomCount = fAllAtoms->size();
for (int i=0; i < atomCount; ++i) {
ObjectFile::Atom* atom = (*fAllAtoms)[i];
ObjectFile::Reader* atomsReader = atom->getFile();
if ( (atomsReader != NULL) && (seenReaders.count(atomsReader) == 0) ) {
seenReaders.insert(atomsReader);
std::vector<ObjectFile::StabsInfo>* readerStabs = atomsReader->getStabsDebugInfo();
if ( readerStabs != NULL ) {
StabChunks chunk;
chunk.fAtom = NULL;
chunk.fReader = atomsReader;
chunk.fOrderInReader = 0;
chunk.fStabs = readerStabs;
fStabChunks.push_back(chunk);
count += readerStabs->size() + 1; }
}
std::vector<ObjectFile::StabsInfo>* atomStabs = atom->getStabsDebugInfo();
if ( atomStabs != NULL ) {
StabChunks chunk;
chunk.fAtom = atom;
chunk.fReader = atomsReader;
chunk.fOrderInReader = atom->getSortOrder();
chunk.fStabs = atomStabs;
fStabChunks.push_back(chunk);
count += atomStabs->size();
}
}
std::sort(fStabChunks.begin(), fStabChunks.end(), stabChunkCompare);
return count;
}
macho_uintptr_t Writer::valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom)
{
switch ( stab.type ) {
case N_FUN:
if ( stab.other == 0 )
break;
case N_BNSYM:
case N_ENSYM:
case N_LBRAC:
case N_RBRAC:
case N_SLINE:
case N_STSYM:
case N_LCSYM:
if ( atom != NULL )
return getAtomLoadAddress(atom) + stab.atomOffset;
}
return stab.atomOffset;
}
void Writer::addStabs(uint32_t startIndex, uint32_t count)
{
macho_nlist* entry = &fSymbolTable[startIndex];
const int chunkCount = fStabChunks.size();
for (int i=0; i < chunkCount; ++i ) {
const StabChunks& chunk = fStabChunks[i];
const int stabCount = chunk.fStabs->size();
for (int j=0; j < stabCount; ++j ) {
const ObjectFile::StabsInfo& stab = (*chunk.fStabs)[j];
entry->set_n_type(stab.type);
entry->set_n_sect(stab.other);
entry->set_n_desc(stab.desc);
entry->set_n_value(valueForStab(stab, chunk.fAtom));
entry->set_n_strx(this->fStringsAtom->add(stab.string));
++entry;
}
if ( (i == chunkCount-1) || (fStabChunks[i+1].fReader != chunk.fReader) ) {
entry->set_n_type(N_SO);
entry->set_n_sect(1);
entry->set_n_desc(0);
entry->set_n_value(0);
entry->set_n_strx(this->fStringsAtom->emptyString());
++entry;
}
}
}
uint32_t Writer::symbolIndex(ObjectFile::Atom& atom)
{
const int importCount = fImportedAtoms.size();
for (int i=0; i < importCount; ++i) {
if ( &atom == fImportedAtoms[i] )
return i + fSymbolTableImportStartIndex;
}
const int localCount = fLocalSymbolAtoms.size();
for (int i=0; i < localCount; ++i) {
if ( &atom == fLocalSymbolAtoms[i] )
return i + fSymbolTableLocalStartIndex;
}
const int exportCount = fExportedAtoms.size();
for (int i=0; i < exportCount; ++i) {
if ( &atom == fExportedAtoms[i] )
return i + fSymbolTableExportStartIndex;
}
fprintf(stderr, "symbolIndex(%s)\n", atom.getDisplayName());
fprintf(stderr, "from %s\n", atom.getFile()->getPath());
throw "atom not found";
}
void Writer::buildFixups()
{
if ( fOptions.outputKind() == Options::kObjectFile )
this->buildObjectFileFixups();
else
this->buildExecutableFixups();
}
uint32_t Writer::addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
{
ObjectFile::Atom& target = ref->getTarget();
bool isExtern = target.isImportProxy() || ( strcmp(target.getSectionName(), "__common") == 0 );
uint32_t symbolIndex = 0;
if ( isExtern )
symbolIndex = this->symbolIndex(target);
uint32_t sectionNum = target.getSection()->getIndex();
uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
macho_relocation_info reloc1;
macho_relocation_info reloc2;
macho_scattered_relocation_info* sreloc1 = (macho_scattered_relocation_info*)&reloc1;
macho_scattered_relocation_info* sreloc2 = (macho_scattered_relocation_info*)&reloc2;
switch ( ref->getKind() ) {
case ObjectFile::Reference::noFixUp:
return 0;
case ObjectFile::Reference::pointer:
reloc1.set_r_address(address);
if ( isExtern )
reloc1.set_r_symbolnum(symbolIndex);
else
reloc1.set_r_symbolnum(sectionNum);
reloc1.set_r_pcrel(false);
reloc1.set_r_length(macho_relocation_info::pointer_length);
reloc1.set_r_extern(isExtern);
reloc1.set_r_type(GENERIC_RELOC_VANILLA);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
return 1;
case ObjectFile::Reference::ppcFixupBranch24:
if ( (ref->getTargetOffset() == 0) || isExtern ) {
reloc1.set_r_address(address);
if ( isExtern )
reloc1.set_r_symbolnum(symbolIndex);
else
reloc1.set_r_symbolnum(sectionNum);
reloc1.set_r_pcrel(true);
reloc1.set_r_length(2);
reloc1.set_r_type(PPC_RELOC_BR24);
reloc1.set_r_extern(isExtern);
}
else {
sreloc1->set_r_scattered(true);
sreloc1->set_r_pcrel(true);
sreloc1->set_r_length(2);
sreloc1->set_r_type(PPC_RELOC_BR24);
sreloc1->set_r_address(address);
sreloc1->set_r_value(target.getAddress());
}
fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
return 1;
case ObjectFile::Reference::ppcFixupBranch14:
reloc1.set_r_address(address);
reloc1.set_r_symbolnum(sectionNum);
reloc1.set_r_pcrel(true);
reloc1.set_r_length(2);
reloc1.set_r_extern(false);
reloc1.set_r_type(PPC_RELOC_BR14);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
return 1;
case ObjectFile::Reference::ppcFixupPicBaseLow14:
case ObjectFile::Reference::ppcFixupPicBaseLow16:
{
macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
uint32_t overflow = 0;
if ( ((toAddr-fromAddr) & 0x00008000) != 0 )
overflow = 1;
sreloc1->set_r_scattered(true);
sreloc1->set_r_pcrel(false);
sreloc1->set_r_length(2);
if ( ref->getKind() == ObjectFile::Reference::ppcFixupPicBaseLow16 )
sreloc1->set_r_type(PPC_RELOC_LO16_SECTDIFF);
else
sreloc1->set_r_type(PPC_RELOC_LO14_SECTDIFF);
sreloc1->set_r_address(address);
sreloc1->set_r_value(target.getAddress());
sreloc2->set_r_scattered(true);
sreloc2->set_r_pcrel(false);
sreloc2->set_r_length(2);
sreloc2->set_r_type(PPC_RELOC_PAIR);
sreloc2->set_r_address(((toAddr-fromAddr) >> 16));
sreloc2->set_r_value(fromAddr);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
return 2;
}
case ObjectFile::Reference::ppcFixupPicBaseHigh16:
{
macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
sreloc1->set_r_scattered(true);
sreloc1->set_r_pcrel(false);
sreloc1->set_r_length(2);
sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
sreloc1->set_r_address(address);
sreloc1->set_r_value(target.getAddress());
sreloc2->set_r_scattered(true);
sreloc2->set_r_pcrel(false);
sreloc2->set_r_length(2);
sreloc2->set_r_type(PPC_RELOC_PAIR);
sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
sreloc2->set_r_value(fromAddr);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
return 2;
}
case ObjectFile::Reference::ppcFixupAbsLow14:
case ObjectFile::Reference::ppcFixupAbsLow16:
{
macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
if ( (ref->getTargetOffset() == 0) || isExtern ) {
reloc1.set_r_address(address);
if ( isExtern )
reloc1.set_r_symbolnum(symbolIndex);
else
reloc1.set_r_symbolnum(sectionNum);
reloc1.set_r_pcrel(false);
reloc1.set_r_length(2);
reloc1.set_r_extern(isExtern);
if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 )
reloc1.set_r_type(PPC_RELOC_LO16);
else
reloc1.set_r_type(PPC_RELOC_LO14);
}
else {
sreloc1->set_r_scattered(true);
sreloc1->set_r_pcrel(false);
sreloc1->set_r_length(2);
if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 )
sreloc1->set_r_type(PPC_RELOC_LO16);
else
sreloc1->set_r_type(PPC_RELOC_LO14);
sreloc1->set_r_address(address);
sreloc1->set_r_value(target.getAddress());
}
if ( isExtern )
reloc2.set_r_address(ref->getTargetOffset() >> 16);
else
reloc2.set_r_address(toAddr >> 16);
reloc2.set_r_symbolnum(0);
reloc2.set_r_pcrel(false);
reloc2.set_r_length(2);
reloc2.set_r_extern(false);
reloc2.set_r_type(PPC_RELOC_PAIR);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
return 2;
}
case ObjectFile::Reference::ppcFixupAbsHigh16:
{
macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
if ( (ref->getTargetOffset() == 0) || isExtern ) {
reloc1.set_r_address(address);
if ( isExtern )
reloc1.set_r_symbolnum(symbolIndex);
else
reloc1.set_r_symbolnum(sectionNum);
reloc1.set_r_pcrel(false);
reloc1.set_r_length(2);
reloc1.set_r_extern(isExtern);
reloc1.set_r_type(PPC_RELOC_HI16);
}
else {
sreloc1->set_r_scattered(true);
sreloc1->set_r_pcrel(false);
sreloc1->set_r_length(2);
sreloc1->set_r_type(PPC_RELOC_HI16);
sreloc1->set_r_address(address);
sreloc1->set_r_value(target.getAddress());
}
if ( isExtern )
reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
else
reloc2.set_r_address(toAddr & 0xFFFF);
reloc2.set_r_symbolnum(0);
reloc2.set_r_pcrel(false);
reloc2.set_r_length(2);
reloc2.set_r_extern(false);
reloc2.set_r_type(PPC_RELOC_PAIR);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
return 2;
}
case ObjectFile::Reference::ppcFixupAbsHigh16AddLow:
{
macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
uint32_t overflow = 0;
if ( (toAddr & 0x00008000) != 0 )
overflow = 0x10000;
if ( (ref->getTargetOffset() == 0) || isExtern ) {
reloc1.set_r_address(address);
if ( isExtern )
reloc1.set_r_symbolnum(symbolIndex);
else
reloc1.set_r_symbolnum(sectionNum);
reloc1.set_r_pcrel(false);
reloc1.set_r_length(2);
reloc1.set_r_extern(isExtern);
reloc1.set_r_type(PPC_RELOC_HA16);
}
else {
sreloc1->set_r_scattered(true);
sreloc1->set_r_pcrel(false);
sreloc1->set_r_length(2);
sreloc1->set_r_type(PPC_RELOC_HA16);
sreloc1->set_r_address(address);
sreloc1->set_r_value(target.getAddress());
}
if ( isExtern )
reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
else
reloc2.set_r_address(toAddr & 0xFFFF);
reloc2.set_r_symbolnum(0);
reloc2.set_r_pcrel(false);
reloc2.set_r_length(2);
reloc2.set_r_extern(false);
reloc2.set_r_type(PPC_RELOC_PAIR);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
return 2;
}
case ObjectFile::Reference::pointer32Difference:
case ObjectFile::Reference::pointer64Difference:
{
macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
macho_uintptr_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
sreloc1->set_r_scattered(true);
sreloc1->set_r_pcrel(false);
if ( ref->getKind() == ObjectFile::Reference::pointer64Difference )
sreloc1->set_r_length(3);
else
sreloc1->set_r_length(2);
if ( ref->getTargetOffset() != 0 )
sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
else
sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
sreloc1->set_r_address(address);
sreloc1->set_r_value(toAddr);
sreloc2->set_r_scattered(true);
sreloc2->set_r_pcrel(false);
sreloc2->set_r_length(macho_relocation_info::pointer_length);
sreloc2->set_r_type(PPC_RELOC_PAIR);
sreloc2->set_r_address(0);
sreloc2->set_r_value(fromAddr);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
return 2;
}
case ObjectFile::Reference::x86FixupBranch32:
reloc1.set_r_address(address);
reloc1.set_r_symbolnum(sectionNum);
reloc1.set_r_pcrel(true);
reloc1.set_r_length(2);
reloc1.set_r_extern(false);
reloc1.set_r_type(GENERIC_RELOC_VANILLA);
fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
return 1;
}
return 0;
}
void Writer::buildObjectFileFixups()
{
uint32_t relocIndex = 0;
std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
const int segCount = segmentInfos.size();
for(int i=0; i < segCount; ++i) {
SegmentInfo* curSegment = segmentInfos[i];
std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
const int sectionCount = sectionInfos.size();
for(int j=0; j < sectionCount; ++j) {
SectionInfo* curSection = sectionInfos[j];
std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
if ( ! curSection->fAllZeroFill ) {
if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers )
curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size();
curSection->fRelocOffset = relocIndex;
const int atomCount = sectionAtoms.size();
for (int k=0; k < atomCount; ++k) {
ObjectFile::Atom* atom = sectionAtoms[k];
std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
const int refCount = refs.size();
for (int l=0; l < refCount; ++l) {
ObjectFile::Reference* ref = refs[l];
relocIndex += this->addRelocs(atom, ref);
if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
uint32_t offsetInSection = atom->getSectionOffset();
uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);
uint32_t undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
fIndirectSymbolTable.push_back(entry);
}
}
}
curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
}
}
}
for(int i=0; i < segCount; ++i) {
SegmentInfo* curSegment = segmentInfos[i];
std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
const int sectionCount = sectionInfos.size();
for(int j=0; j < sectionCount; ++j) {
SectionInfo* curSection = sectionInfos[j];
curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
}
}
}
void Writer::buildExecutableFixups()
{
const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
const int segCount = segmentInfos.size();
for(int i=0; i < segCount; ++i) {
SegmentInfo* curSegment = segmentInfos[i];
std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
const int sectionCount = sectionInfos.size();
for(int j=0; j < sectionCount; ++j) {
SectionInfo* curSection = sectionInfos[j];
std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
if ( ! curSection->fAllZeroFill ) {
if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers )
curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size();
const int atomCount = sectionAtoms.size();
for (int k=0; k < atomCount; ++k) {
ObjectFile::Atom* atom = sectionAtoms[k];
std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
const int refCount = refs.size();
for (int l=0; l < refCount; ++l) {
ObjectFile::Reference* ref = refs[l];
if ( ref->requiresRuntimeFixUp() ) {
if ( ! atom->getSegment().isContentWritable() )
throwf("relocations in read-only segments not supported. %s in %s reference to %s", atom->getDisplayName(), atom->getFile()->getPath(), ref->getTarget().getDisplayName());
if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
if ( atom->getSize() != sizeof(macho_uintptr_t) ) {
printf("oversize pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
}
uint32_t offsetInSection = atom->getSectionOffset();
uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);
uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
if ( ref->getTarget().isImportProxy()
|| ref->getTarget().isWeakDefinition()
|| (fOptions.interposable() && fOptions.shouldExport(ref->getTarget().getName()))
|| (fOptions.nameSpace() == Options::kFlatNameSpace)
|| (fOptions.nameSpace() == Options::kForceFlatNameSpace) ) {
undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
}
uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
fIndirectSymbolTable.push_back(entry);
if ( slideable && curSection->fAllLazyPointers ) {
macho_relocation_info pblaReloc;
macho_scattered_relocation_info* pblaSReloc = (macho_scattered_relocation_info*)&pblaReloc;
pblaSReloc->set_r_scattered(true);
pblaSReloc->set_r_pcrel(false);
pblaSReloc->set_r_length(macho_relocation_info::pointer_length);
pblaSReloc->set_r_type(PPC_RELOC_PB_LA_PTR);
pblaSReloc->set_r_address(atom->getAddress()-fOptions.baseAddress());
pblaSReloc->set_r_value(ref->getFromTarget().getAddress()); fInternalRelocs.push_back(pblaReloc);
}
}
else if ( ref->getTarget().isImportProxy() ) {
macho_relocation_info externalReloc;
externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
externalReloc.set_r_pcrel(false);
externalReloc.set_r_length(macho_relocation_info::pointer_length);
externalReloc.set_r_extern(true);
externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
fExternalRelocs.push_back(externalReloc);
}
else if ( slideable ) {
macho_relocation_info internalReloc;
SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
uint32_t sectionNum = sectInfo->getIndex();
if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
sectionNum = 1;
internalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
internalReloc.set_r_symbolnum(sectionNum);
internalReloc.set_r_pcrel(false);
internalReloc.set_r_length(macho_relocation_info::pointer_length);
internalReloc.set_r_extern(false);
internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
fInternalRelocs.push_back(internalReloc);
}
}
}
}
}
}
}
}
class ContentWriter : public ObjectFile::ContentWriter
{
public:
ContentWriter(int fd, uint64_t fileOffset) : fFileDescriptor(fd), fFileOffset(fileOffset) {}
virtual void write(uint64_t atomOffset, const void* buffer, uint64_t size) {
::pwrite(fFileDescriptor, buffer, size, fFileOffset+atomOffset);
}
private:
int fFileDescriptor;
uint64_t fFileOffset;
};
void Writer::writeAtoms()
{
const bool requireAllFixUps = (fOptions.outputKind() != Options::kObjectFile);
std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
const int segCount = segmentInfos.size();
for(int i=0; i < segCount; ++i) {
SegmentInfo* curSegment = segmentInfos[i];
bool isText = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
const int sectionCount = sectionInfos.size();
for(int j=0; j < sectionCount; ++j) {
SectionInfo* curSection = sectionInfos[j];
std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
if ( ! curSection->fAllZeroFill ) {
const int atomCount = sectionAtoms.size();
uint32_t end = curSection->fFileOffset;
for (int k=0; k < atomCount; ++k) {
ObjectFile::Atom* atom = sectionAtoms[k];
if ( !atom->isImportProxy() ) {
uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
if ( isText && (offset != end) ) {
#if defined(ARCH_PPC) || defined(ARCH_PPC64)
uint32_t ppcNop;
OSWriteBigInt32(&ppcNop, 0, 0x60000000);
for (uint32_t p=end; p < offset; p += 4)
::pwrite(fFileDescriptor, &ppcNop, 4, p);
#else defined(ARCH_I386)
uint8_t x86Nop = 0x90;
for (uint32_t p=end; p < offset; ++p)
::pwrite(fFileDescriptor, &x86Nop, 1, p);
#endif
}
ContentWriter writer(fFileDescriptor, offset);
atom->writeContent(requireAllFixUps, writer);
end = offset+atom->getSize();
}
}
}
}
}
}
void Writer::partitionIntoSections()
{
const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
ObjectFile::Section* curSection = NULL;
SectionInfo* currentSectionInfo = NULL;
SegmentInfo* currentSegmentInfo = NULL;
unsigned int sectionIndex = 1;
for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
ObjectFile::Atom* atom = (*fAllAtoms)[i];
if ( atom->getSection() != curSection ) {
if ( oneSegmentCommand ) {
if ( currentSegmentInfo == NULL ) {
currentSegmentInfo = new SegmentInfo();
currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
this->fSegmentInfos.push_back(currentSegmentInfo);
}
currentSectionInfo = new SectionInfo();
strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
currentSectionInfo->fAlignment = atom->getAlignment();
currentSectionInfo->fAllZeroFill = atom->isZeroFill();
currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
currentSectionInfo->setIndex(sectionIndex++);
currentSegmentInfo->fSections.push_back(currentSectionInfo);
}
else {
if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
currentSegmentInfo = new SegmentInfo();
strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
uint32_t initprot = 0;
if ( atom->getSegment().isContentReadable() )
initprot |= VM_PROT_READ;
if ( atom->getSegment().isContentWritable() )
initprot |= VM_PROT_WRITE;
if ( atom->getSegment().isContentExecutable() )
initprot |= VM_PROT_EXECUTE;
currentSegmentInfo->fInitProtection = initprot;
if ( initprot == 0 )
currentSegmentInfo->fMaxProtection = 0; else
currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
this->fSegmentInfos.push_back(currentSegmentInfo);
}
currentSectionInfo = new SectionInfo();
strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
currentSectionInfo->fAlignment = atom->getAlignment();
std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
currentSectionInfo->fAlignment = it->alignment;
}
currentSectionInfo->fAllZeroFill = atom->isZeroFill();
currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
currentSectionInfo->setIndex(sectionIndex++);
currentSegmentInfo->fSections.push_back(currentSectionInfo);
}
if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
fLoadCommandsSection = currentSectionInfo;
fLoadCommandsSegment = currentSegmentInfo;
}
if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
currentSectionInfo->fAllLazyPointers = true;
if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
currentSectionInfo->fAllNonLazyPointers = true;
curSection = atom->getSection();
}
if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
currentSectionInfo->fAllZeroFill = false;
atom->setSection(currentSectionInfo);
uint8_t atomAlign = atom->getAlignment();
if ( currentSectionInfo->fAlignment < atomAlign )
currentSectionInfo->fAlignment = atomAlign;
uint64_t offset = currentSectionInfo->fSize;
uint64_t alignment = 1 << atomAlign;
offset = ( (offset+alignment-1) & (-alignment) );
atom->setSectionOffset(offset);
currentSectionInfo->fSize = offset + atom->getSize();
currentSectionInfo->fAtoms.push_back(atom);
}
}
void Writer::adjustLoadCommandsAndPadding()
{
fSegmentCommands->computeSize();
uint64_t offset = 0;
std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
const unsigned int atomCount = loadCommandAtoms.size();
for (unsigned int i=0; i < atomCount; ++i) {
ObjectFile::Atom* atom = loadCommandAtoms[i];
uint64_t alignment = 1 << atom->getAlignment();
offset = ( (offset+alignment-1) & (-alignment) );
atom->setSectionOffset(offset);
offset += atom->getSize();
fLoadCommandsSection->fSize = offset;
}
std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
const int sectionCount = sectionInfos.size();
uint64_t paddingSize = 0;
if ( fOptions.outputKind() == Options::kDyld ) {
uint32_t totalSizeOfHeaderAndLoadCommands = 0;
for(int j=0; j < sectionCount; ++j) {
SectionInfo* curSection = sectionInfos[j];
totalSizeOfHeaderAndLoadCommands += curSection->fSize;
if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
break;
}
paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
}
else {
uint64_t totalSize = 0;
uint64_t worstCaseAlignmentPadding = 0;
for(int j=0; j < sectionCount; ++j) {
SectionInfo* curSection = sectionInfos[j];
totalSize += curSection->fSize;
if ( j != 0 ) worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
}
uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
paddingSize = segmentSize - totalSize;
if ( paddingSize < fOptions.minimumHeaderPad() ) {
int extraPages = (fOptions.minimumHeaderPad() - paddingSize + 4095)/4096;
paddingSize += extraPages * 4096;
}
}
fHeaderPadding->setSize(paddingSize);
for(int j=0; j < sectionCount; ++j) {
SectionInfo* curSection = sectionInfos[j];
if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
curSection->fSize = paddingSize;
}
}
void Writer::assignFileOffsets()
{
bool haveFixedSegments = false;
uint64_t fileOffset = 0;
uint64_t nextContiguousAddress = fOptions.baseAddress();
std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
const int segCount = segmentInfos.size();
for(int i=0; i < segCount; ++i) {
SegmentInfo* curSegment = segmentInfos[i];
fileOffset = (fileOffset+4095) & (-4096);
curSegment->fFileOffset = fileOffset;
if ( curSegment->fBaseAddress == 0 ) {
curSegment->fBaseAddress = nextContiguousAddress;
}
else {
haveFixedSegments = true;
}
uint64_t address = curSegment->fBaseAddress;
std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
const int sectionCount = sectionInfos.size();
for(int j=0; j < sectionCount; ++j) {
SectionInfo* curSection = sectionInfos[j];
uint64_t alignment = 1 << curSection->fAlignment;
fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
address = ( (address+alignment-1) & (-alignment) );
curSection->fFileOffset = fileOffset;
curSection->setBaseAddress(address);
curSegment->fSize = curSection->getBaseAddress() + curSection->fSize - curSegment->fBaseAddress;
if ( (fOptions.outputKind() != Options::kObjectFile) || ! curSection->fVirtualSection )
address += curSection->fSize;
if ( !curSection->fAllZeroFill ) {
curSegment->fFileSize = curSegment->fSize;
fileOffset += curSection->fSize;
}
}
if ( curSegment->fBaseAddress == nextContiguousAddress )
nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
}
if ( haveFixedSegments ) {
for(int i=0; i < segCount; ++i) {
SegmentInfo* segment1 = segmentInfos[i];
for(int j=0; j < segCount; ++j) {
if ( i != j ) {
SegmentInfo* segment2 = segmentInfos[j];
if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
}
else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
}
else {
throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
}
}
}
}
}
}
void Writer::adjustLinkEditSections()
{
SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
unsigned int firstLinkEditSectionIndex = 0;
while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
++firstLinkEditSectionIndex;
const unsigned int sectionCount = lastSeg->fSections.size();
uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
const unsigned int atomCount = atoms.size();
uint64_t sectionOffset = 0;
lastSeg->fSections[i]->fFileOffset = fileOffset;
lastSeg->fSections[i]->setBaseAddress(address);
for (unsigned int j=0; j < atomCount; ++j) {
ObjectFile::Atom* atom = atoms[j];
uint64_t alignment = 1 << atom->getAlignment();
sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
atom->setSectionOffset(sectionOffset);
sectionOffset += atom->getSize();
}
lastSeg->fSections[i]->fSize = sectionOffset;
fileOffset += sectionOffset;
address += sectionOffset;
}
if ( fOptions.outputKind() == Options::kObjectFile ) {
}
else {
lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
lastSeg->fSize = address - lastSeg->fBaseAddress;
}
}
ObjectFile::Atom::Scope MachHeaderAtom::getScope() const
{
switch ( fWriter.fOptions.outputKind() ) {
case Options::kDynamicExecutable:
case Options::kStaticExecutable:
return ObjectFile::Atom::scopeGlobal;
case Options::kDynamicLibrary:
case Options::kDynamicBundle:
case Options::kDyld:
case Options::kObjectFile:
return ObjectFile::Atom::scopeLinkageUnit;
}
throw "unknown header type";
}
bool MachHeaderAtom::dontStripName() const
{
switch ( fWriter.fOptions.outputKind() ) {
case Options::kDynamicExecutable:
case Options::kStaticExecutable:
return true;
case Options::kDynamicLibrary:
case Options::kDynamicBundle:
case Options::kDyld:
case Options::kObjectFile:
return false;
}
throw "unknown header type";
}
const char* MachHeaderAtom::getName() const
{
switch ( fWriter.fOptions.outputKind() ) {
case Options::kDynamicExecutable:
case Options::kStaticExecutable:
return "__mh_execute_header";
case Options::kDynamicLibrary:
return "__mh_dylib_header";
case Options::kDynamicBundle:
return "__mh_bundle_header";
case Options::kObjectFile:
return NULL;
case Options::kDyld:
return "__mh_dylinker_header";
}
throw "unknown header type";
}
const char* MachHeaderAtom::getDisplayName() const
{
switch ( fWriter.fOptions.outputKind() ) {
case Options::kDynamicExecutable:
case Options::kStaticExecutable:
case Options::kDynamicLibrary:
case Options::kDynamicBundle:
case Options::kDyld:
return this->getName();
case Options::kObjectFile:
return "mach header";
}
throw "unknown header type";
}
uint64_t MachHeaderAtom::getSize() const
{
return macho_header::size;
}
void MachHeaderAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
macho_header mh;
uint32_t fileType = 0;
switch ( fWriter.fOptions.outputKind() ) {
case Options::kDynamicExecutable:
case Options::kStaticExecutable:
fileType = MH_EXECUTE;
break;
case Options::kDynamicLibrary:
fileType = MH_DYLIB;
break;
case Options::kDynamicBundle:
fileType = MH_BUNDLE;
break;
case Options::kObjectFile:
fileType = MH_OBJECT;
break;
case Options::kDyld:
fileType = MH_DYLINKER;
break;
}
uint32_t flags = 0;
if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
flags = MH_SUBSECTIONS_VIA_SYMBOLS;
}
else {
flags = MH_DYLDLINK;
if ( fWriter.fOptions.bindAtLoad() )
flags |= MH_BINDATLOAD;
switch ( fWriter.fOptions.nameSpace() ) {
case Options::kTwoLevelNameSpace:
flags |= MH_TWOLEVEL | MH_NOUNDEFS;
break;
case Options::kFlatNameSpace:
break;
case Options::kForceFlatNameSpace:
flags |= MH_FORCE_FLAT;
break;
}
if ( fWriter.fHasWeakExports )
flags |= MH_WEAK_DEFINES;
if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
flags |= MH_BINDS_TO_WEAK;
}
uint32_t commandsSize = 0;
uint32_t commandsCount = 0;
std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
const unsigned int atomCount = loadCommandAtoms.size();
for (unsigned int i=0; i < atomCount; ++i) {
ObjectFile::Atom* atom = loadCommandAtoms[i];
commandsSize += atom->getSize();
if ( atom == fWriter.fSegmentCommands )
commandsCount += fWriter.fSegmentCommands->commandCount();
else if ( atom == fWriter.fSymbolTableCommands )
commandsCount += 2;
else
++commandsCount;
}
mh.set_magic(macho_header::magic_value);
mh.set_cputype(fWriter.fOptions.architecture());
mh.set_cpusubtype(0);
mh.set_filetype(fileType);
mh.set_ncmds(commandsCount);
mh.set_sizeofcmds(commandsSize);
mh.set_flags(flags);
mh.set_reserved();
writer.write(0, &mh, macho_header::size);
}
CustomStackAtom::CustomStackAtom(Writer& writer)
: WriterAtom(writer, fgStackSegment)
{
#if defined(ARCH_PPC) || defined(ARCH_PPC64) || defined(ARCH_I386)
fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
#else
#error unknown architecture
#endif
}
void SegmentLoadCommandsAtom::computeSize()
{
uint64_t size = 0;
std::vector<Writer::SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
const int segCount = segmentInfos.size();
for(int i=0; i < segCount; ++i) {
size += macho_segment_command::size;
std::vector<Writer::SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
const int sectionCount = sectionInfos.size();
for(int j=0; j < sectionCount; ++j) {
if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
size += macho_section::content_size;
}
}
fSize = size;
fCommandCount = segCount;
}
void SegmentLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint64_t size = this->getSize();
uint8_t buffer[size];
const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
bzero(buffer, fSize);
uint8_t* p = buffer;
std::vector<Writer::SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
const int segCount = segmentInfos.size();
for(int i=0; i < segCount; ++i) {
Writer::SegmentInfo* segInfo = segmentInfos[i];
const int sectionCount = segInfo->fSections.size();
macho_segment_command* cmd = (macho_segment_command*)p;
cmd->set_cmd(macho_segment_command::command);
cmd->set_segname(segInfo->fName);
cmd->set_vmaddr(segInfo->fBaseAddress);
cmd->set_vmsize(segInfo->fSize);
cmd->set_fileoff(segInfo->fFileOffset);
cmd->set_filesize(segInfo->fFileSize);
cmd->set_maxprot(segInfo->fMaxProtection);
cmd->set_initprot(segInfo->fInitProtection);
macho_section* const sections = (macho_section*)&p[macho_segment_command::size];
unsigned int sectionsEmitted = 0;
for (int j=0; j < sectionCount; ++j) {
Writer::SectionInfo* sectInfo = segInfo->fSections[j];
if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
macho_section* sect = §ions[sectionsEmitted++];
if ( oneSegment ) {
if ( sectionsEmitted == 1 ) {
cmd->set_vmaddr(sectInfo->getBaseAddress());
cmd->set_fileoff(sectInfo->fFileOffset);
cmd->set_filesize(segInfo->fFileSize-sectInfo->fFileOffset);
}
cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
}
sect->set_sectname(sectInfo->fSectionName);
sect->set_segname(sectInfo->fSegmentName);
sect->set_addr(sectInfo->getBaseAddress());
sect->set_size(sectInfo->fSize);
sect->set_offset(sectInfo->fFileOffset);
sect->set_align(sectInfo->fAlignment);
if ( sectInfo->fRelocCount != 0 ) {
sect->set_reloff(sectInfo->fRelocOffset * macho_relocation_info::size + fWriter.fLocalRelocationsAtom->getFileOffset());
sect->set_nreloc(sectInfo->fRelocCount);
}
if ( sectInfo->fAllZeroFill ) {
sect->set_flags(S_ZEROFILL);
}
else if ( sectInfo->fAllLazyPointers ) {
sect->set_flags(S_LAZY_SYMBOL_POINTERS);
sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
}
else if ( sectInfo->fAllNonLazyPointers ) {
sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
}
else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
}
else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
}
}
}
p = &p[macho_segment_command::size + sectionsEmitted*macho_section::content_size];
cmd->set_cmdsize(macho_segment_command::size + sectionsEmitted*macho_section::content_size);
cmd->set_nsects(sectionsEmitted);
}
writer.write(0, buffer, size);
}
SymbolTableLoadCommandsAtom::SymbolTableLoadCommandsAtom(Writer& writer)
: WriterAtom(writer, fgTextSegment)
{
bzero(&fSymbolTable, macho_symtab_command::size);
bzero(&fDynamicSymbolTable, macho_dysymtab_command::size);
writer.fSymbolTableCommands = this;
}
uint64_t SymbolTableLoadCommandsAtom::getSize() const
{
return macho_symtab_command::size + macho_dysymtab_command::size;
}
void SymbolTableLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
macho_symtab_command symbolTableCmd;
bzero(&symbolTableCmd, macho_symtab_command::size);
symbolTableCmd.set_cmd(LC_SYMTAB);
symbolTableCmd.set_cmdsize(macho_symtab_command::size);
symbolTableCmd.set_nsyms(fWriter.fSymbolTableCount);
symbolTableCmd.set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
symbolTableCmd.set_stroff(fWriter.fStringsAtom->getFileOffset());
symbolTableCmd.set_strsize(fWriter.fStringsAtom->getSize());
writer.write(0, &symbolTableCmd, macho_symtab_command::size);
macho_dysymtab_command dynamicSymbolTableCmd;
bzero(&dynamicSymbolTableCmd, macho_dysymtab_command::size);
dynamicSymbolTableCmd.set_cmd(LC_DYSYMTAB);
dynamicSymbolTableCmd.set_cmdsize(macho_dysymtab_command::size);
dynamicSymbolTableCmd.set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
dynamicSymbolTableCmd.set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
dynamicSymbolTableCmd.set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
dynamicSymbolTableCmd.set_nextdefsym(fWriter.fSymbolTableExportCount);
dynamicSymbolTableCmd.set_iundefsym(fWriter.fSymbolTableImportStartIndex);
dynamicSymbolTableCmd.set_nundefsym(fWriter.fSymbolTableImportCount);
dynamicSymbolTableCmd.set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
dynamicSymbolTableCmd.set_nindirectsyms(fWriter.fIndirectSymbolTable.size());
if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
dynamicSymbolTableCmd.set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
dynamicSymbolTableCmd.set_nextrel(fWriter.fExternalRelocs.size());
dynamicSymbolTableCmd.set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
dynamicSymbolTableCmd.set_nlocrel(fWriter.fInternalRelocs.size());
}
writer.write(macho_symtab_command::size, &dynamicSymbolTableCmd, macho_dysymtab_command::size);
}
uint64_t DyldLoadCommandsAtom::getSize() const
{
uint32_t len = macho_dylinker_command::name_offset + strlen("/usr/lib/dyld");
len = (len+7) & (-8); return len;
}
void DyldLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint64_t size = this->getSize();
uint8_t buffer[size];
macho_dylinker_command* cmd = (macho_dylinker_command*)buffer;
if ( fWriter.fOptions.outputKind() == Options::kDyld )
cmd->set_cmd(LC_ID_DYLINKER);
else
cmd->set_cmd(LC_LOAD_DYLINKER);
cmd->set_cmdsize(this->getSize());
cmd->set_name_offset();
strcpy((char*)&buffer[macho_dylinker_command::name_offset], "/usr/lib/dyld");
writer.write(0, buffer, size);
}
uint64_t DylibLoadCommandsAtom::getSize() const
{
const char* path = fInfo.reader->getInstallPath();
if ( fInfo.options.fInstallPathOverride != NULL )
path = fInfo.options.fInstallPathOverride;
uint32_t len = macho_dylib_command::name_offset + strlen(path);
len = (len+7) & (-8); return len;
}
void DylibLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint64_t size = this->getSize();
uint8_t buffer[size];
bzero(buffer, size);
const char* path = fInfo.reader->getInstallPath();
if ( fInfo.options.fInstallPathOverride != NULL )
path = fInfo.options.fInstallPathOverride;
macho_dylib_command* cmd = (macho_dylib_command*)buffer;
if ( fInfo.options.fWeakImport )
cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
else
cmd->set_cmd(LC_LOAD_DYLIB);
cmd->set_cmdsize(this->getSize());
cmd->set_timestamp(fInfo.reader->getTimestamp());
cmd->set_current_version(fInfo.reader->getCurrentVersion());
cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
cmd->set_name_offset();
strcpy((char*)&buffer[macho_dylib_command::name_offset], path);
writer.write(0, buffer, size);
}
uint64_t DylibIDLoadCommandsAtom::getSize() const
{
uint32_t len = macho_dylib_command::name_offset + strlen(fWriter.fOptions.installPath());
len = (len+7) & (-8); return len;
}
void DylibIDLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
struct timeval currentTime = { 0 , 0 };
gettimeofday(¤tTime, NULL);
time_t timestamp = currentTime.tv_sec;
uint64_t size = this->getSize();
uint8_t buffer[size];
bzero(buffer, size);
macho_dylib_command* cmd = (macho_dylib_command*)buffer;
cmd->set_cmd(LC_ID_DYLIB);
cmd->set_cmdsize(this->getSize());
cmd->set_name_offset();
cmd->set_timestamp(timestamp);
cmd->set_current_version(fWriter.fOptions.currentVersion());
cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
strcpy((char*)&buffer[macho_dylib_command::name_offset], fWriter.fOptions.installPath());
writer.write(0, buffer, size);
}
uint64_t RoutinesLoadCommandsAtom::getSize() const
{
return macho_routines_command::size;
}
void RoutinesLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
uint8_t buffer[macho_routines_command::size];
bzero(buffer, macho_routines_command::size);
macho_routines_command* cmd = (macho_routines_command*)buffer;
cmd->set_cmd(macho_routines_command::command);
cmd->set_cmdsize(this->getSize());
cmd->set_init_address(initAddr);
writer.write(0, buffer, macho_routines_command::size);
}
uint64_t SubUmbrellaLoadCommandsAtom::getSize() const
{
uint32_t len = macho_sub_umbrella_command::name_offset + strlen(fName);
len = (len+7) & (-8); return len;
}
void SubUmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint64_t size = this->getSize();
uint8_t buffer[size];
bzero(buffer, size);
macho_sub_umbrella_command* cmd = (macho_sub_umbrella_command*)buffer;
cmd->set_cmd(LC_SUB_UMBRELLA);
cmd->set_cmdsize(this->getSize());
cmd->set_name_offset();
strcpy((char*)&buffer[macho_sub_umbrella_command::name_offset], fName);
writer.write(0, buffer, size);
}
uint64_t SubLibraryLoadCommandsAtom::getSize() const
{
uint32_t len = macho_sub_library_command::name_offset + fNameLength + 1;
len = (len+7) & (-8); return len;
}
void SubLibraryLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint64_t size = this->getSize();
uint8_t buffer[size];
bzero(buffer, size);
macho_sub_library_command* cmd = (macho_sub_library_command*)buffer;
cmd->set_cmd(LC_SUB_LIBRARY);
cmd->set_cmdsize(this->getSize());
cmd->set_name_offset();
strncpy((char*)&buffer[macho_sub_library_command::name_offset], fNameStart, fNameLength);
buffer[macho_sub_library_command::name_offset+fNameLength] = '\0';
writer.write(0, buffer, size);
}
uint64_t UmbrellaLoadCommandsAtom::getSize() const
{
uint32_t len = macho_sub_framework_command::name_offset + strlen(fName);
len = (len+7) & (-8); return len;
}
void UmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint64_t size = this->getSize();
uint8_t buffer[size];
bzero(buffer, size);
macho_sub_framework_command* cmd = (macho_sub_framework_command*)buffer;
cmd->set_cmd(LC_SUB_FRAMEWORK);
cmd->set_cmdsize(this->getSize());
cmd->set_name_offset();
strcpy((char*)&buffer[macho_sub_framework_command::name_offset], fName);
writer.write(0, buffer, size);
}
uint64_t ThreadsLoadCommandsAtom::getSize() const
{
#if defined(ARCH_PPC)
uint32_t stateSize = 40; #elif defined(ARCH_PPC64)
uint32_t stateSize = 76; #elif defined(ARCH_I386)
uint32_t stateSize = 16; #else
#error unknown architecture
#endif
return macho_thread_command::size + stateSize*4;
}
void ThreadsLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint64_t size = this->getSize();
uint8_t buffer[size];
uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
bzero(buffer, size);
macho_thread_command* cmd = (macho_thread_command*)buffer;
cmd->set_cmd(LC_UNIXTHREAD);
cmd->set_cmdsize(size);
#if defined(ARCH_PPC)
cmd->set_flavor(1); cmd->set_count(40); cmd->set_threadState32(0, start);
if ( fWriter.fOptions.hasCustomStack() )
cmd->set_threadState32(3, fWriter.fOptions.customStackAddr()); #elif defined(ARCH_PPC64)
cmd->set_flavor(5); cmd->set_count(76); cmd->set_threadState64(0, start);
if ( fWriter.fOptions.hasCustomStack() )
cmd->set_threadState64(6, fWriter.fOptions.customStackAddr()); #elif defined(ARCH_I386)
cmd->set_flavor(0xFFFFFFFF); cmd->set_count(16); cmd->set_threadState32(0, start);
if ( fWriter.fOptions.hasCustomStack() )
cmd->set_threadState32(15, fWriter.fOptions.customStackAddr()); #else
#error unknown architecture
#endif
writer.write(0, buffer, size);
}
uint64_t LoadCommandsPaddingAtom::getSize() const
{
return fSize;
}
void LoadCommandsPaddingAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint8_t buffer[fSize];
bzero(buffer, fSize);
writer.write(0, buffer, fSize);
}
uint64_t LinkEditAtom::getFileOffset() const
{
return ((Writer::SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
}
uint64_t LocalRelocationsLinkEditAtom::getSize() const
{
return fWriter.fInternalRelocs.size() * macho_relocation_info::size;
}
void LocalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
writer.write(0, &fWriter.fInternalRelocs[0], this->getSize());
}
uint64_t SymbolTableLinkEditAtom::getSize() const
{
return fWriter.fSymbolTableCount * macho_nlist::size;
}
void SymbolTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
writer.write(0, fWriter.fSymbolTable, this->getSize());
}
uint64_t ExternalRelocationsLinkEditAtom::getSize() const
{
return fWriter.fExternalRelocs.size() * macho_relocation_info::size;
}
void ExternalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
writer.write(0, &fWriter.fExternalRelocs[0], this->getSize());
}
uint64_t IndirectTableLinkEditAtom::getSize() const
{
return fWriter.fIndirectSymbolTable.size() * sizeof(uint32_t);
}
void IndirectTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint64_t size = this->getSize();
uint8_t buffer[size];
bzero(buffer, size);
const uint32_t indirectTableSize = fWriter.fIndirectSymbolTable.size();
uint32_t* indirectTable = (uint32_t*)buffer;
for (uint32_t i=0; i < indirectTableSize; ++i) {
Writer::IndirectEntry& entry = fWriter.fIndirectSymbolTable[i];
if ( entry.indirectIndex < indirectTableSize ) {
ENDIAN_WRITE32(indirectTable[entry.indirectIndex], entry.symbolIndex);
}
else {
throw "malformed indirect table";
}
}
writer.write(0, buffer, size);
}
StringsLinkEditAtom::StringsLinkEditAtom(Writer& writer)
: LinkEditAtom(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
{
fCurrentBuffer = new char[kBufferSize];
fCurrentBuffer[fCurrentBufferUsed++] = ' ';
fCurrentBuffer[fCurrentBufferUsed++] = '\0';
}
uint64_t StringsLinkEditAtom::getSize() const
{
return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
}
void StringsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
{
uint64_t offset = 0;
for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
writer.write(offset, fFullBuffers[i], kBufferSize);
offset += kBufferSize;
}
writer.write(offset, fCurrentBuffer, fCurrentBufferUsed);
}
int32_t StringsLinkEditAtom::add(const char* name)
{
int lenNeeded = strlen(name)+1;
while ( lenNeeded + fCurrentBufferUsed >= kBufferSize ) {
int firstLen = kBufferSize - fCurrentBufferUsed;
memcpy(&fCurrentBuffer[fCurrentBufferUsed], name, firstLen);
fFullBuffers.push_back(fCurrentBuffer);
fCurrentBuffer = new char[kBufferSize];
fCurrentBufferUsed = 0;
name += firstLen;
lenNeeded -= firstLen;
}
strcpy(&fCurrentBuffer[fCurrentBufferUsed], name);
int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
fCurrentBufferUsed += lenNeeded;
return offset;
}
int32_t StringsLinkEditAtom::emptyString()
{
return 1;
}
};