[llvm-commits] [lld] r158133 - in /lld/trunk/lib/ReaderWriter/MachO: MachOFormat.hpp WriterMachO.cpp
Nick Kledzik
kledzik at apple.com
Wed Jun 6 18:45:39 PDT 2012
Author: kledzik
Date: Wed Jun 6 20:45:39 2012
New Revision: 158133
URL: http://llvm.org/viewvc/llvm-project?rev=158133&view=rev
Log:
abstract load commands to that WriterMachO can write 64-bit and 32-bit mach-o files
Modified:
lld/trunk/lib/ReaderWriter/MachO/MachOFormat.hpp
lld/trunk/lib/ReaderWriter/MachO/WriterMachO.cpp
Modified: lld/trunk/lib/ReaderWriter/MachO/MachOFormat.hpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOFormat.hpp?rev=158133&r1=158132&r2=158133&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOFormat.hpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOFormat.hpp Wed Jun 6 20:45:39 2012
@@ -24,29 +24,23 @@
namespace lld {
namespace mach_o {
-class load_command {
-public:
- uint32_t cmd;
- uint32_t cmdsize;
-
- void copyTo(uint8_t* to, bool swap=false) {
- ::memcpy(to, (uint8_t*)&cmd, cmdsize);
- }
-};
enum {
- MH_MAGIC = 0xfeedface,
- MAGIC_64 = 0xfeedfacf
+ MH_MAGIC = 0xfeedface,
+ MH_MAGIC_64 = 0xfeedfacf
};
enum {
+ CPU_TYPE_ARM = 0x0000000C,
CPU_TYPE_I386 = 0x00000007,
CPU_TYPE_X86_64 = 0x01000007
};
enum {
- CPU_SUBTYPE_X86_ALL = 0x00000003,
- CPU_SUBTYPE_X86_64_ALL = 0x00000003
+ CPU_SUBTYPE_X86_ALL = 0x00000003,
+ CPU_SUBTYPE_X86_64_ALL = 0x00000003,
+ CPU_SUBTYPE_ARM_V6 = 0x00000006,
+ CPU_SUBTYPE_ARM_V7 = 0x00000009
};
enum {
@@ -60,6 +54,10 @@
};
+//
+// Every mach-o file starts with this header. The header size is
+// 28 bytes for 32-bit architecures and 32-bytes for 64-bit architectures.
+//
class mach_header {
public:
uint32_t magic;
@@ -75,19 +73,91 @@
return (magic == 0xfeedfacf) ? 32 : 28;
}
- void copyTo(uint8_t* to, bool swap=false) {
+ void copyTo(uint8_t *to, bool swap=false) {
::memcpy(to, (char*)&magic, this->size());
}
- void recordLoadCommand(const class load_command* lc) {
- ++ncmds;
- sizeofcmds += lc->cmdsize;
+ void recordLoadCommand(const class load_command *lc);
+};
+
+
+//
+// Every mach-o file has a list of load commands after the mach_header.
+// Each load command starts with a type and length, so you can iterate
+// through the load commands even if you don't understand the content
+// of a particular type.
+//
+// The model for handling endianness and 32 vs 64 bitness is that the in-memory
+// object is always 64-bit and the native endianess. The endianess swapping
+// and pointer sizing is done when writing (copyTo method) or when reading
+// (constructor that takes a buffer).
+//
+// The load_command subclasses are designed so to mirror the traditional "C"
+// structs, so you can get and set the same field names (e.g. seg->vmaddr = 0).
+//
+class load_command {
+public:
+ const uint32_t cmd; // type of load command
+ const uint32_t cmdsize; // length of load command including this header
+
+ load_command(uint32_t cmdNumber, uint32_t sz, bool is64, bool align=false)
+ : cmd(cmdNumber), cmdsize(pointerAlign(sz, is64, align)) {
}
-
+
+ virtual ~load_command() {
+ }
+
+ virtual void copyTo(uint8_t *to, bool swap=false) = 0;
+private:
+ // Load commands must be pointer-size aligned. Most load commands are
+ // a fixed size, so there is a runtime assert to check those. For variable
+ // length load commands, setting the align option to true will add padding
+ // at the end of the load command to round up its size for proper alignment.
+ uint32_t pointerAlign(uint32_t size, bool is64, bool align) {
+ if ( align ) {
+ if ( is64 )
+ return (size + 7) & (-8);
+ else
+ return (size + 3) & (-4);
+ }
+ else {
+ if ( is64 )
+ assert((size % 8) == 0);
+ else
+ assert((size % 4) == 0);
+ return size;
+ }
+ }
+
+};
+
+void mach_header::recordLoadCommand(const load_command *lc) {
+ ++ncmds;
+ sizeofcmds += lc->cmdsize;
+}
+
+// Supported load command types
+enum {
+ LC_SEGMENT = 0x00000001,
+ LC_SYMTAB = 0x00000002,
+ LC_LOAD_DYLIB = 0x0000000C,
+ LC_LOAD_DYLINKER = 0x0000000E,
+ LC_SEGMENT_64 = 0x00000019,
+ LC_MAIN = 0x80000028,
+ LC_DYLD_INFO_ONLY = 0x80000022
+};
+// Memory protection bit used in segment_command.initprot
+enum {
+ VM_PROT_NONE = 0x0,
+ VM_PROT_READ = 0x1,
+ VM_PROT_WRITE = 0x2,
+ VM_PROT_EXECUTE = 0x4,
};
+// Bits for the section.flags field
enum {
+ // Section "type" is the low byte
SECTION_TYPE = 0x000000FF,
S_REGULAR = 0x00000000,
S_ZEROFILL = 0x00000001,
@@ -96,10 +166,28 @@
S_LAZY_SYMBOL_POINTERS = 0x00000007,
S_SYMBOL_STUBS = 0x00000008,
+ // Other bits in section.flags
S_ATTR_PURE_INSTRUCTIONS = 0x80000000,
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
};
+
+// section record for 32-bit architectures
+struct section {
+ char sectname[16];
+ char segname[16];
+ uint32_t addr;
+ uint32_t size;
+ uint32_t offset;
+ uint32_t align;
+ uint32_t reloff;
+ uint32_t nreloc;
+ uint32_t flags;
+ uint32_t reserved1;
+ uint32_t reserved2;
+};
+
+// section record for 64-bit architectures
struct section_64 {
char sectname[16];
char segname[16];
@@ -115,20 +203,13 @@
uint32_t reserved3;
};
-enum {
- LC_SEGMENT_64 = 0x19
-};
-
-enum {
- VM_PROT_NONE = 0x0,
- VM_PROT_READ = 0x1,
- VM_PROT_WRITE = 0x2,
- VM_PROT_EXECUTE = 0x4,
-};
-
-
-class segment_command_64 : public load_command {
+//
+// A segment load command has a fixed set of fields followed by an 'nsect'
+// array of section records. The in-memory object uses a pointer to
+// a dynamically allocated array of sections.
+//
+class segment_command : public load_command {
public:
char segname[16];
uint64_t vmaddr;
@@ -139,81 +220,111 @@
uint32_t initprot;
uint32_t nsects;
uint32_t flags;
- section_64 sections[1];
+ section_64 *sections;
+
+ segment_command(unsigned sectCount, bool is64)
+ : load_command((is64 ? LC_SEGMENT_64 : LC_SEGMENT),
+ (is64 ? (72 + sectCount*80) : (56 + sectCount*68)),
+ is64),
+ vmaddr(0), vmsize(0), fileoff(0), filesize(0),
+ maxprot(0), initprot(0), nsects(sectCount), flags(0) {
+ sections = new section_64[sectCount];
+ this->nsects = sectCount;
+ }
- // The segment_command_64 load commands has a nsect trailing
- // section_64 records appended to the end.
- static segment_command_64* make(unsigned sectCount) {
- // Compute size in portable way. Can't use offsetof() in non-POD class.
- // Can't use zero size sections[] array above.
- // So, since sizeof() already includes one section_64, subtract it off.
- unsigned size = sizeof(segment_command_64)
- + ((int)sectCount -1) * sizeof(section_64);
- segment_command_64* result = reinterpret_cast<segment_command_64*>
- (::calloc(1, size));
- result->cmd = LC_SEGMENT_64;
- result->cmdsize = size;
- result->nsects = sectCount;
- return result;
+ ~segment_command() {
+ delete sections;
}
+ void copyTo(uint8_t *to, bool swap) {
+ if ( swap ) {
+ assert(0 && "non-native endianness not supported yet");
+ }
+ else {
+ if( is64() ) {
+ // in-memory matches on-disk, so copy segment fields followed by sections
+ ::memcpy(to, (uint8_t*)&cmd, 72);
+ if ( nsects != 0 )
+ ::memcpy(&to[72], sections, sizeof(section_64)*nsects);
+ }
+ else {
+ // on-disk is 32-bit struct, so copy each field
+ ::memcpy(to, (uint8_t*)&cmd, 24);
+ copy32(to, 24, vmaddr);
+ copy32(to, 28, vmsize);
+ copy32(to, 32, fileoff);
+ copy32(to, 36, filesize);
+ copy32(to, 40, maxprot);
+ copy32(to, 44, initprot);
+ copy32(to, 48, nsects);
+ copy32(to, 52, flags);
+ for(uint32_t i=0; i < nsects; ++i) {
+ unsigned off = 56+i*68;
+ ::memcpy(&to[off], sections[i].sectname, 32);
+ copy32(to, off+32, sections[i].addr);
+ copy32(to, off+36, sections[i].size);
+ copy32(to, off+40, sections[i].offset);
+ copy32(to, off+44, sections[i].align);
+ copy32(to, off+48, sections[i].reloff);
+ copy32(to, off+52, sections[i].nreloc);
+ copy32(to, off+56, sections[i].flags);
+ copy32(to, off+60, sections[i].reserved1);
+ copy32(to, off+64, sections[i].reserved2);
+ }
+ }
+ }
+ }
+
+private:
+ void copy32(uint8_t *to, unsigned offset, uint64_t value) {
+ uint32_t value32 = value; // FIXME: range check
+ ::memcpy(&to[offset], &value32, sizeof(uint32_t));
+ }
+
+ bool is64() {
+ return (cmd == LC_SEGMENT_64);
+ }
};
-enum {
- LC_LOAD_DYLINKER = 0xe
-};
-
+//
+// The dylinker_command contains the path to the dynamic loader to use
+// with the program (e.g. "/usr/lib/dyld"). So, it is variable length.
+// But load commands must be pointer size aligned.
+//
+//
class dylinker_command : public load_command {
public:
uint32_t name_offset;
- char name[1];
-
- static dylinker_command* make(const char* path) {
- unsigned size = (sizeof(dylinker_command) + strlen(path) + 7) & (-8);
- dylinker_command* result = reinterpret_cast<dylinker_command*>
- (::calloc(1, size));
- result->cmd = LC_LOAD_DYLINKER;
- result->cmdsize = size;
- result->name_offset = 12;
- strcpy(result->name, path);
- return result;
- }
-};
-
-
-
-
-
-
-enum {
- N_UNDF = 0x00,
- N_EXT = 0x01,
- N_PEXT = 0x10,
- N_SECT = 0x0e
-};
-
-class nlist_64 {
+private:
+ StringRef _name;
public:
- uint32_t n_strx;
- uint8_t n_type;
- uint8_t n_sect;
- uint16_t n_desc;
- uint64_t n_value;
-
- void copyTo(uint8_t* to, bool swap=false) {
- ::memcpy(to, (uint8_t*)&n_strx, 16);
+ dylinker_command(StringRef path, bool is64)
+ : load_command(LC_LOAD_DYLINKER,12 + path.size(), is64, true),
+ name_offset(12), _name(path) {
}
+ virtual void copyTo(uint8_t *to, bool swap=false) {
+ if ( swap ) {
+ assert(0 && "non-native endianness not supported yet");
+ }
+ else {
+ // in-memory matches on-disk, so copy first fields followed by path
+ ::memcpy(to, (uint8_t*)&cmd, 12);
+ ::memcpy(&to[12], _name.data(), _name.size());
+ ::bzero(&to[12+_name.size()], cmdsize-(12+_name.size()));
+ }
+ }
};
-enum {
- LC_SYMTAB = 0x2
-};
+//
+// The symtab_command just holds the offset to the array of nlist structs
+// and the offsets to the string pool for all symbol names.
+//
class symtab_command : public load_command {
public:
uint32_t symoff;
@@ -221,40 +332,89 @@
uint32_t stroff;
uint32_t strsize;
- static symtab_command* make() {
- unsigned size = sizeof(symtab_command);
- symtab_command* result = reinterpret_cast<symtab_command*>
- (::calloc(1, size));
- result->cmd = LC_SYMTAB;
- result->cmdsize = size;
- return result;
+ symtab_command(bool is64)
+ : load_command(LC_SYMTAB, 24, is64),
+ symoff(0), nsyms(0), stroff(0), strsize(0) {
+ }
+
+ virtual void copyTo(uint8_t *to, bool swap=false) {
+ if ( swap ) {
+ assert(0 && "non-native endianness not supported yet");
+ }
+ else {
+ // in-memory matches on-disk, so copy fields
+ ::memcpy(to, (uint8_t*)&cmd, 24);
+ }
}
+
};
-enum {
- LC_MAIN = 0x80000028
-};
-
+//
+// The entry_point_command load command holds the offset to the function
+// _main in a dynamic executable.
+//
class entry_point_command : public load_command {
public:
- uint64_t entryoff; /* file (__TEXT) offset of main() */
- uint64_t stacksize;/* if not zero, initial stack size */
+ uint64_t entryoff;
+ uint64_t stacksize;
- static entry_point_command* make() {
- unsigned size = sizeof(entry_point_command);
- entry_point_command* result = reinterpret_cast<entry_point_command*>
- (::calloc(1, size));
- result->cmd = LC_MAIN;
- result->cmdsize = size;
- return result;
+ entry_point_command(bool is64)
+ : load_command(LC_MAIN, 24, is64), entryoff(0), stacksize(0) {
+ }
+
+ virtual void copyTo(uint8_t *to, bool swap=false) {
+ if ( swap ) {
+ assert(0 && "non-native endianness not supported yet");
+ }
+ else {
+ // in-memory matches on-disk, so copy fields
+ ::memcpy(to, (uint8_t*)&cmd, 24);
+ }
}
};
-enum {
- LC_DYLD_INFO_ONLY = 0x80000022
+
+
+//
+// The dylib_command load command holds the name/path of a dynamic shared
+// library which this mach-o image depends on.
+//
+struct dylib_command : public load_command {
+ uint32_t name_offset;
+ uint32_t timestamp;
+ uint32_t current_version;
+ uint32_t compatibility_version;
+private:
+ StringRef _loadPath;
+public:
+
+ dylib_command(StringRef path, bool is64)
+ : load_command(LC_LOAD_DYLIB, 24 + path.size(), is64, true),
+ name_offset(24), timestamp(0),
+ current_version(0x10000), compatibility_version(0x10000),
+ _loadPath(path) {
+ }
+
+ virtual void copyTo(uint8_t *to, bool swap=false) {
+ if ( swap ) {
+ assert(0 && "non-native endianness not supported yet");
+ }
+ else {
+ // in-memory matches on-disk, so copy first fields followed by path
+ ::memcpy(to, (uint8_t*)&cmd, 24);
+ ::memcpy(&to[24], _loadPath.data(), _loadPath.size());
+ ::bzero(&to[12+_loadPath.size()], cmdsize-(12+_loadPath.size()));
+ }
+ }
+
};
+
+//
+// The dyld_info_command load command holds the offsets to various tables
+// of information needed by dyld to prepare the image for execution.
+//
struct dyld_info_command : public load_command {
uint32_t rebase_off;
uint32_t rebase_size;
@@ -267,46 +427,25 @@
uint32_t export_off;
uint32_t export_size;
- static dyld_info_command* make() {
- unsigned size = sizeof(dyld_info_command);
- dyld_info_command* result = reinterpret_cast<dyld_info_command*>
- (::calloc(1, size));
- result->cmd = LC_DYLD_INFO_ONLY;
- result->cmdsize = size;
- return result;
- }
-};
-
-
-enum {
- LC_LOAD_DYLIB = 0xC
-};
-
-
-struct dylib_command : public load_command {
- uint32_t name_offset;
- uint32_t timestamp;
- uint32_t current_version;
- uint32_t compatibility_version;
- char name[1];
+ dyld_info_command(bool is64)
+ : load_command(LC_DYLD_INFO_ONLY, 48, is64),
+ rebase_off(0), rebase_size(0),
+ bind_off(0), bind_size(0), weak_bind_off(0), weak_bind_size(0),
+ lazy_bind_off(0), lazy_bind_size(0), export_off(0), export_size(0) {
+ }
- static dylib_command* make(const char* path) {
- unsigned size = (sizeof(dylib_command) + strlen(path) + 7) & (-8);
- dylib_command* result = reinterpret_cast<dylib_command*>
- (::calloc(1, size));
- result->cmd = LC_LOAD_DYLIB;
- result->cmdsize = size;
- result->name_offset = 24;
- result->name_offset = 24;
- result->timestamp = 0;
- result->current_version = 0x10000;
- result->compatibility_version = 0x10000;
- strcpy(result->name, path);
- return result;
+ virtual void copyTo(uint8_t *to, bool swap=false) {
+ if ( swap ) {
+ assert(0 && "non-native endianness not supported yet");
+ }
+ else {
+ // in-memory matches on-disk, so copy fields
+ ::memcpy(to, (uint8_t*)&cmd, 48);
+ }
}
-
};
+
enum {
BIND_TYPE_POINTER = 1,
BIND_TYPE_TEXT_ABSOLUTE32 = 2,
@@ -345,6 +484,48 @@
+enum {
+ N_UNDF = 0x00,
+ N_EXT = 0x01,
+ N_PEXT = 0x10,
+ N_SECT = 0x0e
+};
+
+class nlist {
+public:
+ uint32_t n_strx;
+ uint8_t n_type;
+ uint8_t n_sect;
+ uint16_t n_desc;
+ uint64_t n_value;
+
+ static unsigned size(bool is64) {
+ return (is64 ? 16 : 12);
+ }
+
+ void copyTo(uint8_t *to, bool is64, bool swap=false) {
+ if ( swap ) {
+ assert(0 && "non-native endianness not supported yet");
+ }
+ else {
+ if ( is64 ) {
+ // in-memory matches on-disk, so just copy whole struct
+ ::memcpy(to, (uint8_t*)&n_strx, 16);
+ }
+ else {
+ // on-disk uses 32-bit n_value, so special case n_value
+ ::memcpy(to, (uint8_t*)&n_strx, 8);
+ uint32_t value32 = n_value; // FIXME: range check
+ ::memcpy(&to[8], &value32, sizeof(uint32_t));
+ }
+ }
+ }
+};
+
+
+
+
+
} // namespace mach_o
} // namespace lld
Modified: lld/trunk/lib/ReaderWriter/MachO/WriterMachO.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/WriterMachO.cpp?rev=158133&r1=158132&r2=158133&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/WriterMachO.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/WriterMachO.cpp Wed Jun 6 20:45:39 2012
@@ -73,6 +73,7 @@
//
class Chunk {
public:
+ virtual ~Chunk() { }
virtual StringRef segmentName() const = 0;
virtual bool occupiesNoDiskSpace();
virtual void write(uint8_t *fileBuffer) = 0;
@@ -158,8 +159,9 @@
uint64_t loadCommandsSize();
private:
- uint32_t filetype(WriterOptionsMachO::OutputKind kind);
-
+ uint32_t filetype(WriterOptionsMachO::OutputKind kind);
+ uint32_t magic(uint32_t cpuType);
+
mach_header _mh;
};
@@ -187,20 +189,21 @@
void addLoadCommand(load_command* lc);
void setMachOSection(SectionChunk *chunk,
- segment_command_64 *seg, uint32_t index);
+ segment_command *seg, uint32_t index);
uint32_t permissionsFromSections(
const SmallVector<SectionChunk*,16> &);
+ bool use64BitMachO() const;
struct ChunkSegInfo {
- SectionChunk* chunk;
- segment_command_64* segment;
- section_64* section;
+ SectionChunk *chunk;
+ segment_command *segment;
+ section_64 *section;
};
MachHeaderChunk &_mh;
const WriterOptionsMachO &_options;
class MachOWriter &_writer;
- segment_command_64 *_linkEditSegment;
+ segment_command *_linkEditSegment;
symtab_command *_symbolTableLoadCommand;
entry_point_command *_entryPointLoadCommand;
dyld_info_command *_dyldInfoLoadCommand;
@@ -297,7 +300,7 @@
//
class SymbolTableChunk : public LinkEditChunk {
public:
- SymbolTableChunk(class SymbolStringsChunk&);
+ SymbolTableChunk(class SymbolStringsChunk&, MachOWriter&);
virtual void write(uint8_t *fileBuffer);
virtual void computeSize(const lld::File &file,
const std::vector<SectionChunk*>&);
@@ -307,10 +310,11 @@
private:
uint8_t nType(const DefinedAtom*);
- SymbolStringsChunk &_stringsChunk;
- std::vector<nlist_64> _globalDefinedsymbols;
- std::vector<nlist_64> _localDefinedsymbols;
- std::vector<nlist_64> _undefinedsymbols;
+ MachOWriter &_writer;
+ SymbolStringsChunk &_stringsChunk;
+ std::vector<nlist> _globalDefinedsymbols;
+ std::vector<nlist> _localDefinedsymbols;
+ std::vector<nlist> _undefinedsymbols;
};
@@ -350,7 +354,8 @@
uint64_t *segStartAddr, uint64_t *segEndAddr);
const std::vector<Chunk*> chunks() { return _chunks; }
-
+ bool use64BitMachO() const;
+
private:
friend class LoadCommandsChunk;
friend class LazyBindingInfoChunk;
@@ -612,7 +617,7 @@
MachHeaderChunk::MachHeaderChunk(const WriterOptionsMachO &options,
const File &file) {
// Set up mach_header based on options
- _mh.magic = MAGIC_64;
+ _mh.magic = this->magic(options.cpuType());
_mh.cputype = options.cpuType();
_mh.cpusubtype = options.cpuSubtype();
_mh.filetype = this->filetype(options.outputKind());
@@ -645,6 +650,18 @@
return _mh.sizeofcmds;
}
+uint32_t MachHeaderChunk::magic(uint32_t cpuType) {
+ switch ( cpuType ) {
+ case CPU_TYPE_ARM:
+ case CPU_TYPE_I386:
+ return MH_MAGIC;
+ case CPU_TYPE_X86_64:
+ return MH_MAGIC_64;
+ }
+ assert(0 && "file cpu type not supported");
+ return 0;
+}
+
uint32_t MachHeaderChunk::filetype(WriterOptionsMachO::OutputKind kind) {
switch ( kind ) {
case WriterOptionsMachO::outputDynamicExecutable:
@@ -692,7 +709,7 @@
}
void LoadCommandsChunk::setMachOSection(SectionChunk *chunk,
- segment_command_64 *seg, uint32_t index) {
+ segment_command *seg, uint32_t index) {
for (ChunkSegInfo &entry : _sectionInfo) {
if ( entry.chunk == chunk ) {
entry.section = &(seg->sections[index]);
@@ -713,10 +730,12 @@
}
void LoadCommandsChunk::computeSize(const lld::File &file) {
+ const bool is64 = _writer.use64BitMachO();
// Main executables have a __PAGEZERO segment.
uint64_t pageZeroSize = _options.pageZeroSize();
if ( pageZeroSize != 0 ) {
- segment_command_64* pzSegCmd = segment_command_64::make(0);
+ assert(is64 || (pageZeroSize < 0xFFFFFFFF));
+ segment_command* pzSegCmd = new segment_command(0, is64);
strcpy(pzSegCmd->segname, "__PAGEZERO");
pzSegCmd->vmaddr = 0;
pzSegCmd->vmsize = pageZeroSize;
@@ -735,7 +754,7 @@
StringRef entryName = entry.chunk->segmentName();
if ( !lastSegName.equals(entryName) ) {
// Start of new segment, so create load command for all previous sections.
- segment_command_64* segCmd = segment_command_64::make(sections.size());
+ segment_command* segCmd = new segment_command(sections.size(), is64);
strncpy(segCmd->segname, lastSegName.data(), 16);
segCmd->initprot = this->permissionsFromSections(sections);
segCmd->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
@@ -752,7 +771,7 @@
sections.push_back(entry.chunk);
}
// Add last segment load command.
- segment_command_64* segCmd = segment_command_64::make(sections.size());
+ segment_command* segCmd = new segment_command(sections.size(), is64);
strncpy(segCmd->segname, lastSegName.data(), 16);
segCmd->initprot = this->permissionsFromSections(sections);;
segCmd->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
@@ -764,14 +783,14 @@
}
// Add LINKEDIT segment load command
- _linkEditSegment = segment_command_64::make(0);
+ _linkEditSegment = new segment_command(0, is64);
strcpy(_linkEditSegment->segname, "__LINKEDIT");
_linkEditSegment->initprot = VM_PROT_READ;
_linkEditSegment->maxprot = VM_PROT_READ;
this->addLoadCommand(_linkEditSegment);
// Add dyld load command.
- this->addLoadCommand(dylinker_command::make("/usr/lib/dyld"));
+ this->addLoadCommand(new dylinker_command("/usr/lib/dyld", is64));
// Add dylib load commands.
llvm::StringMap<uint32_t> dylibNamesToOrdinal;
@@ -784,20 +803,20 @@
}
for (llvm::StringMap<uint32_t>::iterator it=dylibNamesToOrdinal.begin(),
end=dylibNamesToOrdinal.end(); it != end; ++it) {
- this->addLoadCommand(dylib_command::make(it->first().data()));
+ this->addLoadCommand(new dylib_command(it->first(), is64));
}
// Add symbol table load command
- _symbolTableLoadCommand = symtab_command::make();
+ _symbolTableLoadCommand = new symtab_command(is64);
this->addLoadCommand(_symbolTableLoadCommand);
// Add dyld info load command
- _dyldInfoLoadCommand = dyld_info_command::make();
+ _dyldInfoLoadCommand = new dyld_info_command(is64);
this->addLoadCommand(_dyldInfoLoadCommand);
// Add entry point load command to main executables
if (_options.outputKind() == WriterOptionsMachO::outputDynamicExecutable) {
- _entryPointLoadCommand = entry_point_command::make();
+ _entryPointLoadCommand = new entry_point_command(is64);
this->addLoadCommand(_entryPointLoadCommand);
}
@@ -808,7 +827,7 @@
void LoadCommandsChunk::updateLoadCommandContent(const lld::File &file) {
// Update segment/section information in segment load commands
- segment_command_64 *lastSegment = nullptr;
+ segment_command *lastSegment = nullptr;
for (ChunkSegInfo &entry : _sectionInfo) {
// Set section info.
::strncpy(entry.section->sectname, entry.chunk->sectionName().data(), 16);
@@ -1158,23 +1177,25 @@
// SymbolTableChunk
//===----------------------------------------------------------------------===//
-SymbolTableChunk::SymbolTableChunk(SymbolStringsChunk& str)
- : _stringsChunk(str) {
+SymbolTableChunk::SymbolTableChunk(SymbolStringsChunk &str, MachOWriter &wrtr)
+ : _writer(wrtr), _stringsChunk(str) {
}
void SymbolTableChunk::write(uint8_t *chunkBuffer) {
+ const bool is64 = _writer.use64BitMachO();
+ const unsigned nlistSize = nlist::size(is64);
uint8_t *p = chunkBuffer;
- for ( nlist_64 &sym : _globalDefinedsymbols ) {
- sym.copyTo(p);
- p += sizeof(nlist_64);
- }
- for ( nlist_64 &sym : _localDefinedsymbols ) {
- sym.copyTo(p);
- p += sizeof(nlist_64);
- }
- for ( nlist_64 &sym : _undefinedsymbols ) {
- sym.copyTo(p);
- p += sizeof(nlist_64);
+ for ( nlist &sym : _globalDefinedsymbols ) {
+ sym.copyTo(p, is64);
+ p += nlistSize;
+ }
+ for ( nlist &sym : _localDefinedsymbols ) {
+ sym.copyTo(p, is64);
+ p += nlistSize;
+ }
+ for ( nlist &sym : _undefinedsymbols ) {
+ sym.copyTo(p, is64);
+ p += nlistSize;
}
}
@@ -1212,7 +1233,7 @@
if ( info.atom->name().empty() )
continue;
uint64_t atomAddress = chunk->address() + info.offsetInSection;
- nlist_64 sym;
+ nlist sym;
sym.n_strx = _stringsChunk.stringIndex(info.atom->name());
sym.n_type = this->nType(info.atom);
sym.n_sect = sectionIndex;
@@ -1227,7 +1248,7 @@
// Add symbols for undefined/sharedLibrary symbols
for (const SharedLibraryAtom* atom : file.sharedLibrary() ) {
- nlist_64 sym;
+ nlist sym;
sym.n_strx = _stringsChunk.stringIndex(atom->name());
sym.n_type = N_UNDF;
sym.n_sect = 0;
@@ -1235,7 +1256,7 @@
_undefinedsymbols.push_back(sym);
}
- _size = sizeof(nlist_64) * this->count();
+ _size = nlist::size(_writer.use64BitMachO()) * this->count();
}
@@ -1350,7 +1371,7 @@
_bindingInfo = new BindingInfoChunk(*this);
_lazyBindingInfo = new LazyBindingInfoChunk(*this);
_stringsChunk = new SymbolStringsChunk();
- _symbolTableChunk = new SymbolTableChunk(*_stringsChunk);
+ _symbolTableChunk = new SymbolTableChunk(*_stringsChunk, *this);
this->addLinkEditChunk(_bindingInfo);
this->addLinkEditChunk(_lazyBindingInfo);
this->addLinkEditChunk(_symbolTableChunk);
@@ -1459,6 +1480,18 @@
}
}
+bool MachOWriter::use64BitMachO() const {
+ switch ( _options.cpuType() ) {
+ case CPU_TYPE_ARM:
+ case CPU_TYPE_I386:
+ return false;
+ case CPU_TYPE_X86_64:
+ return true;
+ }
+ assert(0 && "unknown cpu type");
+ return false;
+}
+
//
// Creates a mach-o final linked image from the given atom graph and writes
@@ -1519,7 +1552,7 @@
: _outputkind(outputDynamicExecutable),
_archName("x86_64"),
_architecture(arch_x86_64),
- _pageZeroSize(0x10000000),
+ _pageZeroSize(0x100000000),
_cpuType(mach_o::CPU_TYPE_X86_64),
_cpuSubtype(mach_o::CPU_SUBTYPE_X86_64_ALL),
_noTextRelocations(true) {
More information about the llvm-commits
mailing list