Files
clang-p2996/lld/lib/ReaderWriter/MachO/MachOFormat.hpp
Nick Kledzik abb6981f68 Major refactoring: Remove Platform concept. In its place there are
now Reader and Writer subclasses for each file format.  Each Reader and
Writer subclass defines an "options" class which controls how that Reader
or Writer operates.

llvm-svn: 157774
2012-05-31 22:34:00 +00:00

355 lines
8.2 KiB
C++

//===- lib/ReaderWriter/MachO/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/Debug.h"
#include "llvm/Support/Memory.h"
#ifndef LLD_READER_WRITER_MACHO_FORMAT_H_
#define LLD_READER_WRITER_MACHO_FORMAT_H_
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
};
enum {
CPU_TYPE_I386 = 0x00000007,
CPU_TYPE_X86_64 = 0x01000007
};
enum {
CPU_SUBTYPE_X86_ALL = 0x00000003,
CPU_SUBTYPE_X86_64_ALL = 0x00000003
};
enum {
MH_OBJECT = 0x1,
MH_EXECUTE = 0x2,
MH_DYLIB = 0x6,
MH_DYLINKER = 0x7,
MH_BUNDLE = 0x8,
MH_DYLIB_STUB = 0x9,
MH_KEXT_BUNDLE= 0xB
};
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 copyTo(uint8_t* to, bool swap=false) {
::memcpy(to, (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[1];
// 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;
}
};
enum {
LC_LOAD_DYLINKER = 0xe
};
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 {
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);
}
};
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[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,
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 mach_o
} // namespace lld
#endif // LLD_READER_WRITER_MACHO_FORMAT_H_