abstract load commands to that WriterMachO can write 64-bit and 32-bit mach-o files

llvm-svn: 158133
This commit is contained in:
Nick Kledzik 2012-06-07 01:45:39 +00:00
parent aefcedae65
commit 40b8655082
2 changed files with 401 additions and 187 deletions

View File

@ -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 @@ enum {
};
//
// 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 @@ public:
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 @@ enum {
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 @@ struct section_64 {
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 @@ public:
uint32_t initprot;
uint32_t nsects;
uint32_t flags;
section_64 sections[1];
section_64 *sections;
// 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(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;
}
~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 @@ public:
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 @@ struct dyld_info_command : public load_command {
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;
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) {
}
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 {
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];
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;
}
};
enum {
BIND_TYPE_POINTER = 1,
BIND_TYPE_TEXT_ABSOLUTE32 = 2,
@ -345,6 +484,48 @@ enum {
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

View File

@ -73,6 +73,7 @@ namespace mach_o {
//
class Chunk {
public:
virtual ~Chunk() { }
virtual StringRef segmentName() const = 0;
virtual bool occupiesNoDiskSpace();
virtual void write(uint8_t *fileBuffer) = 0;
@ -158,8 +159,9 @@ public:
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 @@ private:
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 @@ private:
//
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 @@ public:
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 @@ public:
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 @@ void SectionChunk::applyFixup(Reference::Kind kind, uint64_t addend,
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 @@ uint64_t MachHeaderChunk::loadCommandsSize() {
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 @@ const char* LoadCommandsChunk::info() {
}
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 @@ uint32_t LoadCommandsChunk::permissionsFromSections(
}
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 @@ void LoadCommandsChunk::computeSize(const lld::File &file) {
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 @@ void LoadCommandsChunk::computeSize(const lld::File &file) {
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 @@ void LoadCommandsChunk::computeSize(const lld::File &file) {
}
// 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 @@ void LoadCommandsChunk::computeSize(const lld::File &file) {
}
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::computeSize(const lld::File &file) {
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 @@ void LazyBindingInfoChunk::computeSize(const lld::File &file,
// 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 &sym : _globalDefinedsymbols ) {
sym.copyTo(p, is64);
p += nlistSize;
}
for ( nlist_64 &sym : _localDefinedsymbols ) {
sym.copyTo(p);
p += sizeof(nlist_64);
for ( nlist &sym : _localDefinedsymbols ) {
sym.copyTo(p, is64);
p += nlistSize;
}
for ( nlist_64 &sym : _undefinedsymbols ) {
sym.copyTo(p);
p += sizeof(nlist_64);
for ( nlist &sym : _undefinedsymbols ) {
sym.copyTo(p, is64);
p += nlistSize;
}
}
@ -1212,7 +1233,7 @@ void SymbolTableChunk::computeSize(const lld::File &file,
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 @@ void SymbolTableChunk::computeSize(const lld::File &file,
// 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 @@ void SymbolTableChunk::computeSize(const lld::File &file,
_undefinedsymbols.push_back(sym);
}
_size = sizeof(nlist_64) * this->count();
_size = nlist::size(_writer.use64BitMachO()) * this->count();
}
@ -1350,7 +1371,7 @@ void MachOWriter::createChunks(const lld::File &file) {
_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 @@ void MachOWriter::findSegment(StringRef segmentName, uint32_t *segIndex,
}
}
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 @@ WriterOptionsMachO::WriterOptionsMachO()
: _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) {