Merge the macho32 and macho64 (outmac32/64) backends

Merge the two Mach-O backends for cleanliness and maintainability.
This should also make the recent fixes to MachO-64 available in
MachO-32.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2016-02-12 03:04:41 -08:00
parent d7043da281
commit c635497870
7 changed files with 350 additions and 1636 deletions

View File

@ -84,8 +84,7 @@ NASM = nasm.$(O) nasmlib.$(O) ver.$(O) \
output/outelf.$(O) output/outelf32.$(O) output/outelf64.$(O) \
output/outelfx32.$(O) \
output/outobj.$(O) output/outas86.$(O) output/outrdf2.$(O) \
output/outdbg.$(O) output/outieee.$(O) output/outmac32.$(O) \
output/outmac64.$(O) \
output/outdbg.$(O) output/outieee.$(O) output/outmac.$(O) \
md5c.$(O) output/codeview.$(O) \
preproc.$(O) quote.$(O) pptok.$(O) \
macros.$(O) listing.$(O) eval.$(O) exprlib.$(O) stdscan.$(O) \
@ -404,12 +403,9 @@ output/outieee.$(O): output/outieee.c compiler.h config.h directiv.h \
output/outlib.$(O): output/outlib.c compiler.h config.h directiv.h insnsi.h \
nasm.h nasmlib.h opflags.h output/outlib.h pptok.h preproc.h regs.h \
tables.h
output/outmac32.$(O): output/outmac32.c compiler.h config.h directiv.h \
eval.h insnsi.h nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h \
pptok.h preproc.h raa.h regs.h saa.h tables.h
output/outmac64.$(O): output/outmac64.c compiler.h config.h directiv.h \
insnsi.h nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h \
pptok.h preproc.h raa.h regs.h saa.h tables.h
output/outmac.$(O): output/outmac.c compiler.h config.h directiv.h insnsi.h \
nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h pptok.h \
preproc.h raa.h regs.h saa.h tables.h
output/outobj.$(O): output/outobj.c compiler.h config.h directiv.h eval.h \
insnsi.h nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h \
pptok.h preproc.h regs.h stdscan.h tables.h

View File

@ -55,8 +55,7 @@ NASM = nasm.$(O) nasmlib.$(O) ver.$(O) \
output/outelf.$(O) output/outelf32.$(O) output/outelf64.$(O) \
output/outelfx32.$(O) \
output/outobj.$(O) output/outas86.$(O) output/outrdf2.$(O) \
output/outdbg.$(O) output/outieee.$(O) output/outmac32.$(O) \
output/outmac64.$(O) \
output/outdbg.$(O) output/outieee.$(O) output/outmac.$(O) \
md5c.$(O) output/codeview.$(O) \
preproc.$(O) quote.$(O) pptok.$(O) \
macros.$(O) listing.$(O) eval.$(O) exprlib.$(O) stdscan.$(O) \
@ -320,12 +319,9 @@ output/outieee.$(O): output/outieee.c compiler.h directiv.h insnsi.h nasm.h \
regs.h tables.h
output/outlib.$(O): output/outlib.c compiler.h directiv.h insnsi.h nasm.h \
nasmlib.h opflags.h output/outlib.h pptok.h preproc.h regs.h tables.h
output/outmac32.$(O): output/outmac32.c compiler.h directiv.h eval.h \
insnsi.h nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h \
pptok.h preproc.h raa.h regs.h saa.h tables.h
output/outmac64.$(O): output/outmac64.c compiler.h directiv.h insnsi.h \
nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h pptok.h \
preproc.h raa.h regs.h saa.h tables.h
output/outmac.$(O): output/outmac.c compiler.h directiv.h insnsi.h nasm.h \
nasmlib.h opflags.h output/outform.h output/outlib.h pptok.h preproc.h \
raa.h regs.h saa.h tables.h
output/outobj.$(O): output/outobj.c compiler.h directiv.h eval.h insnsi.h \
nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h pptok.h \
preproc.h regs.h stdscan.h tables.h

View File

@ -42,8 +42,7 @@ NASM = nasm.o nasmlib.o ver.o \
outelf.o outelf32.o outelf64.o \
outelfx32.o \
outobj.o outas86.o outrdf2.o \
outdbg.o outieee.o outmac32.o \
outmac64.o \
outdbg.o outieee.o outmac.o \
md5c.o codeview.o \
preproc.o quote.o pptok.o \
macros.o listing.o eval.o exprlib.o stdscan.o \
@ -224,12 +223,8 @@ outieee.o: outieee.c compiler.h config.h directiv.h insnsi.h nasm.h \
nasmlib.h opflags.h outform.h outlib.h pptok.h preproc.h regs.h tables.h
outlib.o: outlib.c compiler.h config.h directiv.h insnsi.h nasm.h nasmlib.h \
opflags.h outlib.h pptok.h preproc.h regs.h tables.h
outmac32.o: outmac32.c compiler.h config.h directiv.h eval.h insnsi.h nasm.h \
nasmlib.h opflags.h outform.h outlib.h pptok.h preproc.h raa.h regs.h saa.h \
tables.h
outmac64.o: outmac64.c compiler.h config.h directiv.h insnsi.h nasm.h \
nasmlib.h opflags.h outform.h outlib.h pptok.h preproc.h raa.h regs.h saa.h \
tables.h
outmac.o: outmac.c compiler.h config.h directiv.h insnsi.h nasm.h nasmlib.h \
opflags.h outform.h outlib.h pptok.h preproc.h raa.h regs.h saa.h tables.h
outobj.o: outobj.c compiler.h config.h directiv.h eval.h insnsi.h nasm.h \
nasmlib.h opflags.h outform.h outlib.h pptok.h preproc.h regs.h stdscan.h \
tables.h

View File

@ -58,8 +58,7 @@ NASM = nasm.$(O) nasmlib.$(O) ver.$(O) &
output/outelf.$(O) output/outelf32.$(O) output/outelf64.$(O) &
output/outelfx32.$(O) &
output/outobj.$(O) output/outas86.$(O) output/outrdf2.$(O) &
output/outdbg.$(O) output/outieee.$(O) output/outmac32.$(O) &
output/outmac64.$(O) &
output/outdbg.$(O) output/outieee.$(O) output/outmac.$(O) &
md5c.$(O) output/codeview.$(O) &
preproc.$(O) quote.$(O) pptok.$(O) &
macros.$(O) listing.$(O) eval.$(O) exprlib.$(O) stdscan.$(O) &
@ -371,12 +370,9 @@ output/outieee.$(O): output/outieee.c compiler.h config.h directiv.h &
output/outlib.$(O): output/outlib.c compiler.h config.h directiv.h insnsi.h &
nasm.h nasmlib.h opflags.h output/outlib.h pptok.h preproc.h regs.h &
tables.h
output/outmac32.$(O): output/outmac32.c compiler.h config.h directiv.h &
eval.h insnsi.h nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h &
pptok.h preproc.h raa.h regs.h saa.h tables.h
output/outmac64.$(O): output/outmac64.c compiler.h config.h directiv.h &
insnsi.h nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h &
pptok.h preproc.h raa.h regs.h saa.h tables.h
output/outmac.$(O): output/outmac.c compiler.h config.h directiv.h insnsi.h &
nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h pptok.h &
preproc.h raa.h regs.h saa.h tables.h
output/outobj.$(O): output/outobj.c compiler.h config.h directiv.h eval.h &
insnsi.h nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h &
pptok.h preproc.h regs.h stdscan.h tables.h

View File

@ -69,8 +69,7 @@ NASM = nasm.$(O) nasmlib.$(O) ver.$(O) \
output/outelf.$(O) output/outelf32.$(O) output/outelf64.$(O) \
output/outelfx32.$(O) \
output/outobj.$(O) output/outas86.$(O) output/outrdf2.$(O) \
output/outdbg.$(O) output/outieee.$(O) output/outmac32.$(O) \
output/outmac64.$(O) \
output/outdbg.$(O) output/outieee.$(O) output/outmac.$(O) \
md5c.$(O) output/codeview.$(O) \
preproc.$(O) quote.$(O) pptok.$(O) \
macros.$(O) listing.$(O) eval.$(O) exprlib.$(O) stdscan.$(O) \
@ -334,12 +333,9 @@ output/outieee.$(O): output/outieee.c compiler.h directiv.h insnsi.h nasm.h \
regs.h tables.h
output/outlib.$(O): output/outlib.c compiler.h directiv.h insnsi.h nasm.h \
nasmlib.h opflags.h output/outlib.h pptok.h preproc.h regs.h tables.h
output/outmac32.$(O): output/outmac32.c compiler.h directiv.h eval.h \
insnsi.h nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h \
pptok.h preproc.h raa.h regs.h saa.h tables.h
output/outmac64.$(O): output/outmac64.c compiler.h directiv.h insnsi.h \
nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h pptok.h \
preproc.h raa.h regs.h saa.h tables.h
output/outmac.$(O): output/outmac.c compiler.h directiv.h insnsi.h nasm.h \
nasmlib.h opflags.h output/outform.h output/outlib.h pptok.h preproc.h \
raa.h regs.h saa.h tables.h
output/outobj.$(O): output/outobj.c compiler.h directiv.h eval.h insnsi.h \
nasm.h nasmlib.h opflags.h output/outform.h output/outlib.h pptok.h \
preproc.h regs.h stdscan.h tables.h

View File

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------- *
*
*
* Copyright 1996-2016 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
@ -14,7 +14,7 @@
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
@ -54,26 +54,32 @@
#include "output/outform.h"
#include "output/outlib.h"
#if defined(OF_MACHO64)
#if defined(OF_MACHO) || defined(OF_MACHO64)
/* Mach-O in-file header structure sizes */
#define MACHO_HEADER64_SIZE (32)
#define MACHO_SEGCMD64_SIZE (72)
#define MACHO_SECTCMD64_SIZE (80)
#define MACHO_SYMCMD_SIZE (24)
#define MACHO_NLIST64_SIZE (16)
#define MACHO_RELINFO64_SIZE (8)
#define MACHO_DATA_IN_CODE_CMD_SIZE (16)
#define MACHO_HEADER_SIZE 28
#define MACHO_SEGCMD_SIZE 56
#define MACHO_SECTCMD_SIZE 68
#define MACHO_SYMCMD_SIZE 24
#define MACHO_NLIST_SIZE 12
#define MACHO_RELINFO_SIZE 8
#define MACHO_HEADER64_SIZE 32
#define MACHO_SEGCMD64_SIZE 72
#define MACHO_SECTCMD64_SIZE 80
#define MACHO_NLIST64_SIZE 16
/* Mach-O file header values */
#define MH_MAGIC_64 (0xfeedfacf)
#define CPU_TYPE_X86_64 (0x01000007) /* x86-64 platform */
#define CPU_SUBTYPE_I386_ALL (3) /* all-x86 compatible */
#define MH_OBJECT (0x1) /* object file */
#define MH_MAGIC 0xfeedface
#define MH_MAGIC_64 0xfeedfacf
#define CPU_TYPE_I386 7 /* x86 platform */
#define CPU_TYPE_X86_64 0x01000007 /* x86-64 platform */
#define CPU_SUBTYPE_I386_ALL 3 /* all-x86 compatible */
#define MH_OBJECT 0x1 /* object file */
#define LC_SEGMENT_64 (0x19) /* segment load command */
#define LC_SYMTAB (0x2) /* symbol table load command */
#define LC_DATA_IN_CODE (0x29) /* data in code command */
#define LC_SEGMENT 0x1 /* 32-bit segment load cmd */
#define LC_SEGMENT_64 0x19 /* 64-bit segment load cmd */
#define LC_SYMTAB 0x2 /* symbol table load command */
#define VM_PROT_NONE (0x00)
#define VM_PROT_READ (0x01)
@ -83,6 +89,46 @@
#define VM_PROT_DEFAULT (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
#define VM_PROT_ALL (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
struct macho_fmt {
uint32_t ptrsize; /* Pointer size in bytes */
uint32_t mh_magic; /* Which magic number to use */
uint32_t cpu_type; /* Which CPU type */
uint32_t lc_segment; /* Which segment load command */
uint32_t header_size; /* Header size */
uint32_t segcmd_size; /* Segment command size */
uint32_t sectcmd_size; /* Section command size */
uint32_t nlist_size; /* Nlist (symbol) size */
};
static const struct macho_fmt macho32_fmt = {
4,
MH_MAGIC,
CPU_TYPE_I386,
LC_SEGMENT,
MACHO_HEADER_SIZE,
MACHO_SEGCMD_SIZE,
MACHO_SECTCMD_SIZE,
MACHO_NLIST_SIZE
};
static const struct macho_fmt macho64_fmt = {
8,
MH_MAGIC_64,
CPU_TYPE_X86_64,
LC_SEGMENT_64,
MACHO_HEADER64_SIZE,
MACHO_SEGCMD64_SIZE,
MACHO_SECTCMD64_SIZE,
MACHO_NLIST64_SIZE
};
static const struct macho_fmt *fmt;
static void fwriteptr(uint64_t data, FILE * fp)
{
fwriteaddr(data, fmt->ptrsize, fp);
}
struct section {
/* nasm internal data */
struct section *next;
@ -231,10 +277,13 @@ static uint64_t rel_padcnt = 0;
xdst[sizeof(xdst) - 1] = '\0'; /* proper null-termination */
#define alignint32_t(x) \
ALIGN(x, sizeof(int32_t)) /* align x to int32_t boundary */
ALIGN(x, sizeof(int32_t)) /* align x to int32_t boundary */
#define alignint64_t(x) \
ALIGN(x, sizeof(int64_t)) /* align x to int64_t boundary */
ALIGN(x, sizeof(int64_t)) /* align x to int64_t boundary */
#define alignptr(x) \
ALIGN(x, fmt->ptrsize) /* align x to output format width */
static void debug_reloc (struct reloc *);
static void debug_section_relocs (struct section *) _unused;
@ -330,8 +379,6 @@ static int32_t macho_gotpcrel_sect;
static void macho_init(void)
{
char zero = 0;
sects = NULL;
sectstail = &sects;
@ -345,14 +392,9 @@ static void macho_init(void)
extsyms = raa_init();
strs = saa_init(1L);
/* string table starts with a zero byte - don't ask why */
saa_wbytes(strs, &zero, sizeof(char));
/* string table starts with a zero byte so index 0 is an empty string */
saa_wbytes(strs, zero_buffer, 1);
strslen = 1;
/* add special symbol for ..gotpcrel */
macho_gotpcrel_sect = seg_alloc();
macho_gotpcrel_sect++;
define_label("..gotpcrel", macho_gotpcrel_sect, 0L, NULL, false, false);
}
static void sect_write(struct section *sect,
@ -362,14 +404,25 @@ static void sect_write(struct section *sect,
sect->size += len;
}
enum reltype {
RL_ABS, /* Absolute relocation */
RL_REL, /* Relative relocation */
RL_SUB, /* X86_64_RELOC_SUBTRACT */
RL_GOT, /* X86_64_RELOC_GOT */
RL_GOTLOAD, /* X86_64_RELOC_GOT_LOAD */
};
static int32_t add_reloc(struct section *sect, int32_t section,
int pcrel, int bytes, int64_t reloff)
enum reltype reltype, int bytes, int64_t reloff)
{
struct reloc *r;
struct symbol *sym;
int32_t fi;
int32_t adjustment = 0;
if (section == NO_SEG)
return 0;
/* NeXT as puts relocs in reversed order (address-wise) into the
** files, so we do the same, doesn't seem to make much of a
** difference either way */
@ -383,97 +436,81 @@ static int32_t add_reloc(struct section *sect, int32_t section,
** bit by accident */
r->addr = sect->size & ~R_SCATTERED;
r->ext = 1;
r->pcrel = (pcrel ? 1 : 0);
/* match byte count 1, 2, 4, 8 to length codes 0, 1, 2, 3 respectively */
switch(bytes){
case 1:
r->length = 0;
break;
case 2:
r->length = 1;
break;
case 4:
r->length = 2;
break;
case 8:
r->length = 3;
break;
default:
break;
}
r->length = ilog2_32(bytes);
/* set default relocation values */
r->type = 0; // X86_64_RELOC_UNSIGNED
r->snum = R_ABS; // Absolute Symbol (indicates no relocation)
r->type = 0;
r->pcrel = 0;
r->snum = R_ABS;
/* absolute relocation */
if (pcrel == 0) {
/* intra-section */
if (section == NO_SEG) {
// r->snum = R_ABS; // Set above
/* inter-section */
} else {
fi = get_section_fileindex_by_index(section);
/* external */
if (fi == NO_SECT) {
r->snum = raa_read(extsyms, section);
/* local */
} else {
sym = get_closest_section_symbol_by_offset(fi, reloff);
r->snum = sym->initial_snum;
adjustment = sym->value;
}
}
/* absolute relocation */
switch (reltype) {
case RL_ABS:
if (section == NO_SEG) {
/* intra-section */
r->snum = R_ABS;
} else {
/* inter-section */
fi = get_section_fileindex_by_index(section);
/* relative relocation */
} else if (pcrel == 1) {
/* intra-section */
if (section == NO_SEG) {
r->type = 1; // X86_64_RELOC_SIGNED
/* inter-section */
} else {
r->type = 1; // X86_64_RELOC_SIGNED
fi = get_section_fileindex_by_index(section);
/* external */
if (fi == NO_SECT) {
sect->extreloc = 1;
r->snum = raa_read(extsyms, section);
/* local */
} else {
sym = get_closest_section_symbol_by_offset(fi, reloff);
r->snum = sym->initial_snum;
adjustment = sym->value;
}
}
/* subtractor */
} else if (pcrel == 2) {
r->pcrel = 0;
r->type = 5; // X86_64_RELOC_SUBTRACTOR
/* gotpcrel */
} else if (pcrel == 3) {
r->type = 4; // X86_64_RELOC_GOT
r->snum = macho_gotpcrel_sect;
/* gotpcrel MOVQ load */
} else if (pcrel == 4) {
r->type = 3; // X86_64_RELOC_GOT_LOAD
r->snum = macho_gotpcrel_sect;
if (fi == NO_SECT) {
/* external */
r->snum = raa_read(extsyms, section);
} else {
/* local */
sym = get_closest_section_symbol_by_offset(fi, reloff);
r->snum = sym->initial_snum;
adjustment = sym->value;
}
}
break;
++sect->nreloc;
case RL_REL:
r->pcrel = 1;
if (section == NO_SEG) {
/* intra-section */
r->type = 1; // X86_64_RELOC_SIGNED
} else {
/* inter-section */
r->type = 1; // X86_64_RELOC_SIGNED
fi = get_section_fileindex_by_index(section);
return adjustment;
if (fi == NO_SECT) {
/* external */
sect->extreloc = 1;
r->snum = raa_read(extsyms, section);
} else {
/* local */
sym = get_closest_section_symbol_by_offset(fi, reloff);
r->snum = sym->initial_snum;
adjustment = sym->value;
}
}
break;
case RL_SUB:
r->pcrel = 0;
r->type = 5; // X86_64_RELOC_SUBTRACTOR
break;
case RL_GOT:
r->pcrel = 1;
r->type = 4; // X86_64_RELOC_GOT
r->snum = macho_gotpcrel_sect;
break;
case RL_GOTLOAD:
r->pcrel = 1;
r->type = 3; // X86_64_RELOC_GOT_LOAD
r->snum = macho_gotpcrel_sect;
break;
}
++sect->nreloc;
return adjustment;
}
static void macho_output(int32_t secto, const void *data,
@ -544,25 +581,18 @@ static void macho_output(int32_t secto, const void *data,
if (section % 2) {
nasm_error(ERR_NONFATAL, "Mach-O format does not support"
" section base references");
} else {
if (wrt == NO_SEG) {
if (asize < 8) {
nasm_error(ERR_NONFATAL, "Mach-O 64-bit format does not support"
" 32-bit absolute addresses");
/*
Seemingly, Mach-O's X86_64_RELOC_SUBTRACTOR would require
pre-determined knowledge of where the image base would be,
making it impractical for use in intermediate object files
*/
} else {
addr -= add_reloc(s, section, 0, asize, addr); // X86_64_RELOC_UNSIGNED
}
} else {
nasm_error(ERR_NONFATAL, "Mach-O format does not support"
" this use of WRT");
}
}
} else if (wrt == NO_SEG) {
if (fmt->ptrsize == 8 && asize != 8) {
nasm_error(ERR_NONFATAL, "Mach-O 64-bit format does not support"
" 32-bit absolute addresses");
} else {
addr -= add_reloc(s, section, RL_ABS, asize, addr);
}
} else {
nasm_error(ERR_NONFATAL, "Mach-O format does not support"
" this use of WRT");
}
}
p = mydata;
WRITEADDR(p, addr, asize);
@ -571,62 +601,67 @@ static void macho_output(int32_t secto, const void *data,
}
case OUT_REL2ADR:
nasm_assert(section != secto);
p = mydata;
WRITESHORT(p, *(int64_t *)data);
if (section == secto)
nasm_error(ERR_PANIC, "intra-section OUT_REL2ADR");
if (section == NO_SEG) {
/* Do nothing */
} else if (section % 2) {
nasm_error(ERR_NONFATAL, "Mach-O format does not support"
" section base references");
} else {
nasm_error(ERR_NONFATAL, "Unsupported non-32-bit"
" Macho-O relocation [2]");
}
sect_write(s, mydata, 2L);
break;
case OUT_REL4ADR:
p = mydata;
addr = *(int64_t *)data + 4 - size;
if (section == secto)
nasm_error(ERR_PANIC, "intra-section OUT_REL4ADR");
addr = *(int64_t *)data + 2 - size;
if (section != NO_SEG && section % 2) {
nasm_error(ERR_NONFATAL, "Mach-O format does not support"
" section base references");
} else {
if (wrt == NO_SEG) {
addr -= add_reloc(s, section, 1, 4, addr); // X86_64_RELOC_SIGNED/BRANCH
} else if (wrt == macho_gotpcrel_sect) {
if (s->data->datalen > 1) {
saa_fread(s->data, s->data->datalen-2, &gotload, 1); // Retrieve Instruction Opcode
} else {
gotload = 0;
}
if (gotload == 0x8B) { // Check for MOVQ Opcode
addr -= add_reloc(s, section, 4, 4, addr); // X86_64_GOT_LOAD (MOVQ load)
} else {
addr -= add_reloc(s, section, 3, 4, addr); // X86_64_GOT
}
} else {
nasm_error(ERR_NONFATAL, "Mach-O format does not support"
" this use of WRT");
wrt = NO_SEG; /* we can at least _try_ to continue */
}
}
" section base references");
} else if (fmt->ptrsize == 8) {
nasm_error(ERR_NONFATAL, "Unsupported non-32-bit"
" Macho-O relocation [2]");
} else if (wrt != NO_SEG) {
nasm_error(ERR_NONFATAL, "Mach-O format does not support"
" this use of WRT");
wrt = NO_SEG; /* we can at least _try_ to continue */
} else {
addr -= add_reloc(s, section, RL_REL, 2, addr);
}
WRITESHORT(p, addr);
sect_write(s, mydata, 2);
break;
case OUT_REL4ADR:
nasm_assert(section != secto);
p = mydata;
addr = *(int64_t *)data + 4 - size;
if (section != NO_SEG && section % 2) {
nasm_error(ERR_NONFATAL, "Mach-O format does not support"
" section base references");
} else if (wrt == NO_SEG) {
/* Plain relative relocation */
addr -= add_reloc(s, section, RL_REL, 4, addr);
} else if (wrt == macho_gotpcrel_sect) {
if (s->data->datalen > 1) {
/* Retrieve instruction opcode */
saa_fread(s->data, s->data->datalen-2, &gotload, 1);
} else {
gotload = 0;
}
if (gotload == 0x8B) {
/* Check for MOVQ Opcode -> X86_64_RELOC_GOT_LOAD */
addr -= add_reloc(s, section, RL_GOTLOAD, 4, addr);
} else {
/* X86_64_RELOC_GOT */
addr -= add_reloc(s, section, RL_GOT, 4, addr);
}
} else {
nasm_error(ERR_NONFATAL, "Mach-O format does not support"
" this use of WRT");
wrt = NO_SEG; /* we can at least _try_ to continue */
}
WRITELONG(p, addr);
sect_write(s, mydata, 4L);
sect_write(s, mydata, 4);
break;
default:
nasm_error(ERR_PANIC, "unknown output type?");
nasm_error(ERR_NONFATAL, "Unrepresentable relocation in Mach-O");
break;
}
}
@ -796,7 +831,7 @@ static void macho_symdef(char *name, int32_t section, int64_t offset,
/* get the in-file index of the section the symbol was defined in */
sym->sect = get_section_fileindex_by_index(section);
/* track the initially allocated symbol number for use in future fix-ups */
sym->initial_snum = nsyms;
@ -1004,8 +1039,7 @@ static void macho_calculate_sizes (void)
** get a pointer to the start of all the raw data */
if (seg_nsects > 0) {
++head_ncmds;
head_sizeofcmds +=
MACHO_SEGCMD64_SIZE + seg_nsects * MACHO_SECTCMD64_SIZE;
head_sizeofcmds += fmt->segcmd_size + seg_nsects * fmt->sectcmd_size;
}
if (nsyms > 0) {
@ -1024,49 +1058,48 @@ static void macho_calculate_sizes (void)
static void macho_write_header (void)
{
fwriteint32_t(MH_MAGIC_64, ofile); /* magic */
fwriteint32_t(CPU_TYPE_X86_64, ofile); /* CPU type */
fwriteint32_t(fmt->mh_magic, ofile); /* magic */
fwriteint32_t(fmt->cpu_type, ofile); /* CPU type */
fwriteint32_t(CPU_SUBTYPE_I386_ALL, ofile); /* CPU subtype */
fwriteint32_t(MH_OBJECT, ofile); /* Mach-O file type */
fwriteint32_t(head_ncmds, ofile); /* number of load commands */
fwriteint32_t(head_sizeofcmds, ofile); /* size of load commands */
fwriteint32_t(0, ofile); /* no flags */
fwriteint32_t(0, ofile); /* reserved for future use */
fwriteint32_t(0, ofile); /* no flags */
fwritezero(fmt->header_size - 7*4, ofile); /* reserved fields */
}
/* Write out the segment load command at offset. */
static uint32_t macho_write_segment (uint64_t offset)
{
uint64_t rel_base = alignint64_t (offset + seg_filesize);
uint64_t rel_base = alignptr(offset + seg_filesize);
uint32_t s_reloff = 0;
struct section *s;
fwriteint32_t(LC_SEGMENT_64, ofile); /* cmd == LC_SEGMENT_64 */
fwriteint32_t(fmt->lc_segment, ofile); /* cmd == LC_SEGMENT_64 */
/* size of load command including section load commands */
fwriteint32_t(MACHO_SEGCMD64_SIZE +
seg_nsects * MACHO_SECTCMD64_SIZE,
fwriteint32_t(fmt->segcmd_size + seg_nsects * fmt->sectcmd_size,
ofile);
/* in an MH_OBJECT file all sections are in one unnamed (name
** all zeros) segment */
fwritezero(16, ofile);
fwriteint64_t(0, ofile); /* in-memory offset */
fwriteint64_t(seg_vmsize, ofile); /* in-memory size */
fwriteint64_t(offset, ofile); /* in-file offset to data */
fwriteint64_t(seg_filesize, ofile); /* in-file size */
fwriteptr(0, ofile); /* in-memory offset */
fwriteptr(seg_vmsize, ofile); /* in-memory size */
fwriteptr(offset, ofile); /* in-file offset to data */
fwriteptr(seg_filesize, ofile); /* in-file size */
fwriteint32_t(VM_PROT_DEFAULT, ofile); /* maximum vm protection */
fwriteint32_t(VM_PROT_DEFAULT, ofile); /* initial vm protection */
fwriteint32_t(seg_nsects, ofile); /* number of sections */
fwriteint32_t(0, ofile); /* no flags */
fwriteint32_t(0, ofile); /* no flags */
/* emit section headers */
for (s = sects; s != NULL; s = s->next) {
nasm_write(s->sectname, sizeof(s->sectname), ofile);
nasm_write(s->segname, sizeof(s->segname), ofile);
fwriteint64_t(s->addr, ofile);
fwriteint64_t(s->size, ofile);
fwriteptr(s->addr, ofile);
fwriteptr(s->size, ofile);
/* dummy data for zerofill sections or proper values */
if ((s->flags & SECTION_TYPE) != S_ZEROFILL) {
@ -1076,33 +1109,29 @@ static uint32_t macho_write_segment (uint64_t offset)
offset += s->size;
/* Write out section alignment, as a power of two.
e.g. 32-bit word alignment would be 2 (2^2 = 4). */
if (s->align == -1)
s->align = DEFAULT_SECTION_ALIGNMENT;
fwriteint32_t(s->align, ofile);
/* To be compatible with cctools as we emit
a zero reloff if we have no relocations. */
fwriteint32_t(s->nreloc ? rel_base + s_reloff : 0, ofile);
fwriteint32_t(s->nreloc, ofile);
s_reloff += s->nreloc * MACHO_RELINFO64_SIZE;
s_reloff += s->nreloc * MACHO_RELINFO_SIZE;
} else {
fwriteint32_t(0, ofile);
fwriteint32_t(0, ofile); /* No alignment?! */
fwriteint32_t(s->align, ofile);
fwriteint32_t(0, ofile);
fwriteint32_t(0, ofile);
}
if (s->nreloc) {
s->flags |= S_ATTR_LOC_RELOC;
if (s->extreloc)
s->flags |= S_ATTR_EXT_RELOC;
}
if (s->nreloc) {
s->flags |= S_ATTR_LOC_RELOC;
if (s->extreloc)
s->flags |= S_ATTR_EXT_RELOC;
}
fwriteint32_t(s->flags, ofile); /* flags */
fwriteint32_t(0, ofile); /* reserved */
fwriteint32_t(0, ofile); /* reserved */
fwriteint32_t(0, ofile); /* align */
fwriteptr(0, ofile); /* reserved */
}
rel_padcnt = rel_base - offset;
@ -1136,9 +1165,13 @@ static void macho_write_section (void)
{
struct section *s, *s2;
struct reloc *r;
uint8_t fi, *p, *q, blk[8];
int32_t len;
uint8_t fi, *p;
int32_t len;
int64_t l;
union offset {
uint64_t val;
uint8_t buf[8];
} blk;
for (s = sects; s != NULL; s = s->next) {
if ((s->flags & SECTION_TYPE) == S_ZEROFILL)
@ -1150,31 +1183,26 @@ static void macho_write_section (void)
* for more information. */
saa_rewind(s->data);
for (r = s->relocs; r != NULL; r = r->next) {
len = (int32_t)r->length << 1;
if(len > 4) len = 8;
saa_fread(s->data, r->addr, blk, len);
p = q = blk;
l = *p++;
len = (uint32_t)1 << r->length;
if (len > 4) /* Can this ever be an issue?! */
len = 8;
blk.val = 0;
saa_fread(s->data, r->addr, blk.buf, len);
/* get offset based on relocation type */
if (r->length > 0) {
l += ((int64_t)*p++) << 8;
#ifdef WORDS_LITTLEENDIAN
l = blk.val;
#else
l = blk.buf[0];
l += ((int64_t)blk.buf[1]) << 8;
l += ((int64_t)blk.buf[2]) << 16;
l += ((int64_t)blk.buf[3]) << 24;
l += ((int64_t)blk.buf[4]) << 32;
l += ((int64_t)blk.buf[5]) << 40;
l += ((int64_t)blk.buf[6]) << 48;
l += ((int64_t)blk.buf[7]) << 56;
#endif
if (r->length > 1) {
l += ((int64_t)*p++) << 16;
l += ((int64_t)*p++) << 24;
}
if (r->length > 2) {
l += ((int64_t)*p++) << 32;
l += ((int64_t)*p++) << 40;
l += ((int64_t)*p++) << 48;
l += ((int64_t)*p++) << 56;
}
}
/* If the relocation is internal add to the current section
offset. Otherwise the only value we need is the symbol
offset which we already have. The linker takes care
@ -1191,16 +1219,9 @@ static void macho_write_section (void)
}
/* write new offset back */
if (r->length == 3)
WRITEDLONG(q, l);
else if (r->length == 2)
WRITELONG(q, l);
else if (r->length == 1)
WRITESHORT(q, l);
else
*q++ = l & 0xFF;
saa_fwrite(s->data, r->addr, blk, len);
p = blk.buf;
WRITEDLONG(p, l);
saa_fwrite(s->data, r->addr, blk.buf, len);
}
/* dump the section data to file */
@ -1208,7 +1229,7 @@ static void macho_write_section (void)
saa_fpwrite(s->data, ofile);
}
/* pad last section up to reloc entries on int64_t boundary */
/* pad last section up to reloc entries on pointer boundary */
fwritezero(rel_padcnt, ofile);
/* emit relocation entries */
@ -1239,7 +1260,7 @@ static void macho_write_symtab (void)
sym->value += sectstab[sym->sect]->addr;
}
fwriteint64_t(sym->value, ofile); /* value (i.e. offset) */
fwriteptr(sym->value, ofile); /* value (i.e. offset) */
}
}
@ -1257,7 +1278,7 @@ static void macho_write_symtab (void)
sym->value += sectstab[sym->sect]->addr;
}
fwriteint64_t(sym->value, ofile); /* value (i.e. offset) */
fwriteptr(sym->value, ofile); /* value (i.e. offset) */
}
for (i = 0; i < nundefsym; i++) {
@ -1267,13 +1288,14 @@ static void macho_write_symtab (void)
nasm_write(&sym->sect, 1, ofile); /* section */
fwriteint16_t(sym->desc, ofile); /* description */
// Fix up the symbol value now that we know the final section sizes.
/* Fix up the symbol value now that we know the final section
sizes. */
if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) {
nasm_assert(sym->sect <= seg_nsects);
sym->value += sectstab[sym->sect]->addr;
}
fwriteint64_t(sym->value, ofile); // value (i.e. offset)
fwriteptr(sym->value, ofile); /* value (i.e. offset) */
}
}
@ -1286,12 +1308,12 @@ static void macho_fixup_relocs (struct reloc *r)
while (r != NULL) {
if (r->ext) {
for (sym = syms; sym != NULL; sym = sym->next) {
for (sym = syms; sym != NULL; sym = sym->next) {
if (sym->initial_snum == r->snum) {
r->snum = sym->snum;
break;
r->snum = sym->snum;
break;
}
}
}
}
r = r->next;
}
@ -1316,14 +1338,14 @@ static void macho_write (void)
** uint32_t flags
**
** segment command
** uint32_t command type == LC_SEGMENT_64
** uint32_t command type == LC_SEGMENT[_64]
** uint32_t size of load command
** (including section load commands)
** char[16] segment name
** uint64_t in-memory offset
** uint64_t in-memory size
** uint64_t in-file offset to data area
** uint64_t in-file size
** pointer in-memory offset
** pointer in-memory size
** pointer in-file offset to data area
** pointer in-file size
** (in-memory size excluding zerofill sections)
** int maximum vm protection
** int initial vm protection
@ -1333,8 +1355,8 @@ static void macho_write (void)
** section commands
** char[16] section name
** char[16] segment name
** uint64_t in-memory offset
** uint64_t in-memory size
** pointer in-memory offset
** pointer in-memory size
** uint32_t in-file offset
** uint32_t alignment
** (irrelevant in MH_OBJECT)
@ -1354,7 +1376,7 @@ static void macho_write (void)
**
** raw section data
**
** padding to int64_t boundary
** padding to pointer boundary
**
** relocation data (struct reloc)
** int32_t offset
@ -1370,7 +1392,7 @@ static void macho_write (void)
** [type == extern])
** int16_t description
** (for stab debugging format)
** uint64_t value (i.e. file offset) of symbol or stab offset
** pointer value (i.e. file offset) of symbol or stab offset
**
** string table data
** list of null-terminated strings
@ -1379,7 +1401,7 @@ static void macho_write (void)
/* Emit the Mach-O header. */
macho_write_header();
offset = MACHO_HEADER64_SIZE + head_sizeofcmds;
offset = fmt->header_size + head_sizeofcmds;
/* emit the segment load command */
if (seg_nsects > 0)
@ -1394,7 +1416,7 @@ static void macho_write (void)
fwriteint32_t(offset, ofile); /* symbol table offset */
fwriteint32_t(nsyms, ofile); /* number of symbol
** table entries */
offset += nsyms * MACHO_NLIST64_SIZE;
offset += nsyms * fmt->nlist_size;
fwriteint32_t(offset, ofile); /* string table offset */
fwriteint32_t(strslen, ofile); /* string table size */
}
@ -1407,7 +1429,7 @@ static void macho_write (void)
if (nsyms > 0)
macho_write_symtab ();
/* we don't need to pad here since MACHO_NLIST64_SIZE == 16 */
/* we don't need to pad here, we are already aligned */
/* emit string table */
saa_fpwrite(strs, ofile);
@ -1489,15 +1511,24 @@ static void debug_section_relocs (struct section *s)
}
}
struct ofmt of_macho64 = {
"NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (x86_64) object files",
#ifdef OF_MACHO32
static void macho32_init(void)
{
fmt = &macho32_fmt;
macho_init();
macho_gotpcrel_sect = NO_SEG;
}
struct ofmt of_macho32 = {
"NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (i386) object files",
"macho64",
0,
64,
32,
null_debug_arr,
&null_debug_form,
macho_stdmac,
macho_init,
macho32_init,
null_setinfo,
macho_output,
macho_symdef,
@ -1508,6 +1539,40 @@ struct ofmt of_macho64 = {
macho_filename,
macho_cleanup
};
#endif
#ifdef OF_MACHO64
static void macho64_init(void)
{
fmt = &macho64_fmt;
macho_init();
/* add special symbol for ..gotpcrel */
macho_gotpcrel_sect = seg_alloc();
macho_gotpcrel_sect++;
define_label("..gotpcrel", macho_gotpcrel_sect, 0L, NULL, false, false);
}
struct ofmt of_macho64 = {
"NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (x86_64) object files",
"macho64",
0,
64,
null_debug_arr,
&null_debug_form,
macho_stdmac,
macho64_init,
null_setinfo,
macho_output,
macho_symdef,
macho_section,
macho_sectalign,
macho_segbase,
null_directive,
macho_filename,
macho_cleanup
};
#endif
#endif

File diff suppressed because it is too large Load Diff