blob: 2566f7b0088e3740d6514e1370543c9e7b50353f [file] [log] [blame]
//===- Platforms/Darwin/MachOFormat.hpp -----------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains all the structs and constants needed to write a
// mach-o final linked image. The names of the structs and constants
// are the same as in the darwin native header <mach-o/loader.h> so
// they will be familiar to anyone who has used that header.
//
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/raw_ostream.h"
#ifndef LLD_PLATFORM_DARWIN_MACHO_FORMAT_H_
#define LLD_PLATFORM_DARWIN_MACHO_FORMAT_H_
namespace lld {
namespace darwin {
class load_command {
public:
uint32_t cmd;
uint32_t cmdsize;
void write(raw_ostream& out) {
out.write((char*)&cmd, cmdsize);
}
};
enum {
MH_MAGIC = 0xfeedface,
MAGIC_64 = 0xfeedfacf
};
enum {
CPU_TYPE_I386 = 0x00000007,
CPU_TYPE_X86_64 = 0x01000007
};
enum {
CPU_SUBTYPE_X86_ALL = 0x00000003,
CPU_SUBTYPE_X86_64_ALL = 0x00000003
};
enum {
MH_EXECUTE = 0x2,
MH_DYLIB = 0x6,
MH_BUNDLE = 0x8
};
class mach_header {
public:
uint32_t magic;
uint32_t cputype;
uint32_t cpusubtype;
uint32_t filetype;
uint32_t ncmds;
uint32_t sizeofcmds;
uint32_t flags;
uint32_t reserved;
uint64_t size() {
return (magic == 0xfeedfacf) ? 32 : 28;
}
void write(raw_ostream& out) {
out.write((char*)&magic, this->size());
}
void recordLoadCommand(const class load_command* lc) {
++ncmds;
sizeofcmds += lc->cmdsize;
}
};
enum {
SECTION_TYPE = 0x000000FF,
S_REGULAR = 0x00000000,
S_ZEROFILL = 0x00000001,
S_CSTRING_LITERALS = 0x00000002,
S_NON_LAZY_SYMBOL_POINTERS= 0x00000006,
S_LAZY_SYMBOL_POINTERS = 0x00000007,
S_SYMBOL_STUBS = 0x00000008,
S_ATTR_PURE_INSTRUCTIONS = 0x80000000,
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
};
struct section_64 {
char sectname[16];
char segname[16];
uint64_t addr;
uint64_t size;
uint32_t offset;
uint32_t align;
uint32_t reloff;
uint32_t nreloc;
uint32_t flags;
uint32_t reserved1;
uint32_t reserved2;
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 {
public:
char segname[16];
uint64_t vmaddr;
uint64_t vmsize;
uint64_t fileoff;
uint64_t filesize;
uint32_t maxprot;
uint32_t initprot;
uint32_t nsects;
uint32_t flags;
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) {
unsigned size = sizeof(segment_command_64) + sectCount* 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;
}
};
enum {
LC_LOAD_DYLINKER = 0xe
};
class dylinker_command : public load_command {
public:
uint32_t name_offset;
char name[];
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 {
public:
uint32_t n_strx;
uint8_t n_type;
uint8_t n_sect;
uint16_t n_desc;
uint64_t n_value;
void write(raw_ostream& out) {
out.write((char*)&n_strx, 16);
}
};
enum {
LC_SYMTAB = 0x2
};
class symtab_command : public load_command {
public:
uint32_t symoff;
uint32_t nsyms;
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;
}
};
enum {
LC_MAIN = 0x80000028
};
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 */
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;
}
};
enum {
LC_DYLD_INFO_ONLY = 0x80000022
};
struct dyld_info_command : public load_command {
uint32_t rebase_off;
uint32_t rebase_size;
uint32_t bind_off;
uint32_t bind_size;
uint32_t weak_bind_off;
uint32_t weak_bind_size;
uint32_t lazy_bind_off;
uint32_t lazy_bind_size;
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[];
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,
BIND_TYPE_TEXT_PCREL32 = 3
};
enum {
BIND_SPECIAL_DYLIB_SELF = 0,
BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1,
BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2
};
enum {
BIND_SYMBOL_FLAGS_WEAK_IMPORT = 0x1,
BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION = 0x8
};
enum {
BIND_OPCODE_MASK = 0xF0,
BIND_IMMEDIATE_MASK = 0x0F,
BIND_OPCODE_DONE = 0x00,
BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10,
BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20,
BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30,
BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40,
BIND_OPCODE_SET_TYPE_IMM = 0x50,
BIND_OPCODE_SET_ADDEND_SLEB = 0x60,
BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70,
BIND_OPCODE_ADD_ADDR_ULEB = 0x80,
BIND_OPCODE_DO_BIND = 0x90,
BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0,
BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0,
BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0
};
} // namespace darwin
} // namespace lld
#endif // LLD_PLATFORM_DARWIN_MACHO_FORMAT_H_