#include "PosixSource.h"
#endif
-/* Linux needs _GNU_SOURCE to get RTLD_DEFAULT from <dlfcn.h> and
+/* Linux needs _GNU_SOURCE to get RTLD_DEFAULT from <dlfcn.h> and
MREMAP_MAYMOVE from <sys/mman.h>.
*/
#ifdef __linux__
#include "LinkerInternals.h"
#include "RtsUtils.h"
#include "Schedule.h"
-#include "Storage.h"
#include "Sparks.h"
+#include "RtsTypeable.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#if defined(powerpc_HOST_ARCH)
# include <mach-o/ppc/reloc.h>
#endif
+#if defined(x86_64_HOST_ARCH)
+# include <mach-o/x86_64/reloc.h>
+#endif
#endif
/* Hash table mapping symbol names to Symbol */
static /*Str*/HashTable *symhash;
-typedef struct {
- void *addr;
-} rootEntry;
-
/* Hash table mapping symbol names to StgStablePtr */
static /*Str*/HashTable *stablehash;
-rootEntry *root_ptr_table = NULL;
-static rootEntry *root_ptr_free = NULL;
-
-static unsigned int RPT_size = 0;
/* List of currently loaded objects */
ObjectCode *objects = NULL; /* initially empty */
static int ocGetNames_ELF ( ObjectCode* oc );
static int ocResolve_ELF ( ObjectCode* oc );
#if defined(powerpc_HOST_ARCH)
-static int ocAllocateJumpIslands_ELF ( ObjectCode* oc );
+static int ocAllocateSymbolExtras_ELF ( ObjectCode* oc );
#endif
#elif defined(OBJFORMAT_PEi386)
static int ocVerifyImage_PEi386 ( ObjectCode* oc );
static int ocResolve_MachO ( ObjectCode* oc );
static int machoGetMisalignment( FILE * );
+#if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
+static int ocAllocateSymbolExtras_MachO ( ObjectCode* oc );
+#endif
#ifdef powerpc_HOST_ARCH
-static int ocAllocateJumpIslands_MachO ( ObjectCode* oc );
static void machoInitSymbolsWithoutUnderscore( void );
#endif
#endif
-#if defined(x86_64_HOST_ARCH)
+#if defined(x86_64_HOST_ARCH) && defined(OBJFORMAT_ELF)
static void*x86_64_high_symbol( char *lbl, void *addr );
#endif
#define RTS_MINGW_EXTRA_SYMS
#endif
+#if HAVE_GETTIMEOFDAY
+#define RTS_MINGW_GETTIMEOFDAY_SYM Sym(gettimeofday)
+#else
+#define RTS_MINGW_GETTIMEOFDAY_SYM /**/
+#endif
+
/* These are statically linked from the mingw libraries into the ghc
executable, so we have to employ this hack. */
#define RTS_MINGW_ONLY_SYMBOLS \
Sym(mktime) \
Sym(_imp___timezone) \
Sym(_imp___tzname) \
+ Sym(_imp__tzname) \
Sym(_imp___iob) \
Sym(_imp___osver) \
Sym(localtime) \
Sym(readdir) \
Sym(rewinddir) \
RTS_MINGW_EXTRA_SYMS \
+ RTS_MINGW_GETTIMEOFDAY_SYM \
Sym(closedir)
#endif
#define RTS_USER_SIGNALS_SYMBOLS \
SymX(setIOManagerPipe)
#else
-#define RTS_USER_SIGNALS_SYMBOLS /* nothing */
+#define RTS_USER_SIGNALS_SYMBOLS \
+ SymX(sendIOManagerEvent) \
+ SymX(readIOManagerEvent) \
+ SymX(getIOManagerEvent) \
+ SymX(console_handler)
#endif
#ifdef TABLES_NEXT_TO_CODE
SymX(stg_block_1) \
SymX(stg_block_takemvar) \
SymX(stg_block_putmvar) \
- SymX(stg_seq_frame_info) \
MAIN_CAP_SYM \
SymX(MallocFailHook) \
SymX(OnExitHook) \
SymX(__encodeDouble) \
SymX(__encodeFloat) \
SymX(addDLL) \
- SymX(__gmpn_gcd_1) \
- SymX(__gmpz_cmp) \
- SymX(__gmpz_cmp_si) \
- SymX(__gmpz_cmp_ui) \
- SymX(__gmpz_get_si) \
- SymX(__gmpz_get_ui) \
+ SymExtern(__gmpn_gcd_1) \
+ SymExtern(__gmpz_cmp) \
+ SymExtern(__gmpz_cmp_si) \
+ SymExtern(__gmpz_cmp_ui) \
+ SymExtern(__gmpz_get_si) \
+ SymExtern(__gmpz_get_ui) \
SymX(__int_encodeDouble) \
SymX(__int_encodeFloat) \
SymX(andIntegerzh_fast) \
SymX(catchzh_fast) \
SymX(catchRetryzh_fast) \
SymX(catchSTMzh_fast) \
+ SymX(checkzh_fast) \
SymX(closure_flags) \
SymX(cmp_thread) \
SymX(cmpIntegerzh_fast) \
SymX(forkOS_createThread) \
SymX(freeHaskellFunctionPtr) \
SymX(freeStablePtr) \
+ SymX(getOrSetTypeableStore) \
SymX(gcdIntegerzh_fast) \
SymX(gcdIntegerIntzh_fast) \
SymX(gcdIntzh_fast) \
SymX(genSymZh) \
SymX(genericRaise) \
SymX(getProgArgv) \
+ SymX(getFullProgArgv) \
SymX(getStablePtr) \
SymX(hs_init) \
SymX(hs_exit) \
SymX(hs_free_stable_ptr) \
SymX(hs_free_fun_ptr) \
SymX(initLinker) \
+ SymX(unpackClosurezh_fast) \
+ SymX(getApStackValzh_fast) \
SymX(int2Integerzh_fast) \
SymX(integer2Intzh_fast) \
SymX(integer2Wordzh_fast) \
SymX(newMVarzh_fast) \
SymX(newMutVarzh_fast) \
SymX(newTVarzh_fast) \
+ SymX(noDuplicatezh_fast) \
SymX(atomicModifyMutVarzh_fast) \
SymX(newPinnedByteArrayzh_fast) \
SymX(newSpark) \
SymX(xorIntegerzh_fast) \
SymX(yieldzh_fast) \
SymX(stg_interp_constr_entry) \
- SymX(stg_interp_constr1_entry) \
- SymX(stg_interp_constr2_entry) \
- SymX(stg_interp_constr3_entry) \
- SymX(stg_interp_constr4_entry) \
- SymX(stg_interp_constr5_entry) \
- SymX(stg_interp_constr6_entry) \
- SymX(stg_interp_constr7_entry) \
- SymX(stg_interp_constr8_entry) \
- SymX(stgMallocBytesRWX) \
+ SymX(allocateExec) \
+ SymX(freeExec) \
SymX(getAllocations) \
SymX(revertCAFs) \
SymX(RtsFlags) \
+ SymX(rts_breakpoint_io_action) \
+ SymX(rts_stop_next_breakpoint) \
+ SymX(rts_stop_on_exception) \
RTS_USER_SIGNALS_SYMBOLS
#ifdef SUPPORT_LONG_LONGS
/* entirely bogus claims about types of these symbols */
#define Sym(vvv) extern void vvv(void);
+#if defined(__PIC__) && defined(mingw32_TARGET_OS)
+#define SymExtern(vvv) extern void _imp__ ## vvv (void);
+#else
+#define SymExtern(vvv) SymX(vvv)
+#endif
#define SymX(vvv) /**/
#define SymX_redirect(vvv,xxx) /**/
RTS_SYMBOLS
#undef Sym
#undef SymX
#undef SymX_redirect
+#undef SymExtern
#ifdef LEADING_UNDERSCORE
#define MAYBE_LEADING_UNDERSCORE_STR(s) ("_" s)
#define Sym(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
(void*)(&(vvv)) },
#define SymX(vvv) Sym(vvv)
+#define SymExtern(vvv) { MAYBE_LEADING_UNDERSCORE_STR(#vvv), \
+ (void*)DLL_IMPORT_DATA_REF(vvv) },
// SymX_redirect allows us to redirect references to one symbol to
// another symbol. See newCAF/newDynCAF for an example.
RTS_POSIX_ONLY_SYMBOLS
RTS_MINGW_ONLY_SYMBOLS
RTS_CYGWIN_ONLY_SYMBOLS
+ RTS_DARWIN_ONLY_SYMBOLS
RTS_LIBGCC_SYMBOLS
#if defined(darwin_HOST_OS) && defined(i386_HOST_ARCH)
// dyld stub code contains references to this,
};
-/* -----------------------------------------------------------------------------
- * Utilities for handling root pointers.
- * -------------------------------------------------------------------------- */
-
-
-#define INIT_RPT_SIZE 64
-
-STATIC_INLINE void
-initFreeList(rootEntry *table, nat n, rootEntry *free)
-{
- rootEntry *p;
-
- for (p = table + n - 1; p >= table; p--) {
- p->addr = (P_)free;
- free = p;
- }
- root_ptr_free = table;
-}
-
-void
-initRootPtrTable(void)
-{
- if (RPT_size > 0)
- return;
-
- RPT_size = INIT_RPT_SIZE;
- root_ptr_table = stgMallocBytes(RPT_size * sizeof(rootEntry),
- "initRootPtrTable");
-
- initFreeList(root_ptr_table,INIT_RPT_SIZE,NULL);
-}
-
-
-void
-enlargeRootPtrTable(void)
-{
- nat old_RPT_size = RPT_size;
-
- // 2nd and subsequent times
- RPT_size *= 2;
- root_ptr_table =
- stgReallocBytes(root_ptr_table,
- RPT_size * sizeof(rootEntry),
- "enlargeRootPtrTable");
-
- initFreeList(root_ptr_table + old_RPT_size, old_RPT_size, NULL);
-}
-
-static void
-addRootObject(void *addr)
-{
- StgWord rt;
- initRootPtrTable();
- if (root_ptr_free == NULL) {
- enlargeRootPtrTable();
- }
-
- rt = root_ptr_free - root_ptr_table;
- root_ptr_free = (rootEntry*)(root_ptr_free->addr);
- root_ptr_table[rt].addr = addr;
-}
-
-/* -----------------------------------------------------------------------------
- * Treat root pointers as roots for the garbage collector.
- * -------------------------------------------------------------------------- */
-
-void
-markRootPtrTable(evac_fn evac)
-{
- rootEntry *p, *end_root_ptr_table;
- StgPtr q;
-
- end_root_ptr_table = &root_ptr_table[RPT_size];
-
- for (p = root_ptr_table; p < end_root_ptr_table; p++) {
- q = p->addr;
-
- if (q && (q < (P_)root_ptr_table || q >= (P_)end_root_ptr_table)) {
- evac((StgClosure **)p->addr);
- }
- }
-}
-
-/* -----------------------------------------------------------------------------
- * End of utilities for handling root pointers.
- * -------------------------------------------------------------------------- */
-
/* -----------------------------------------------------------------------------
* Insert symbols into hash tables, checking for duplicates.
*/
+
static void ghciInsertStrHashTable ( char* obj_name,
HashTable *table,
char* key,
);
exit(1);
}
-
-
/* -----------------------------------------------------------------------------
* initialize the object linker
*/
static void *dl_prog_handle;
#endif
-/* dlopen(NULL,..) doesn't work so we grab libc explicitly */
-#if defined(openbsd_HOST_OS)
-static void *dl_libc_handle;
-#endif
-
void
initLinker( void )
{
dl_prog_handle = RTLD_DEFAULT;
# else
dl_prog_handle = dlopen(NULL, RTLD_LAZY);
-# if defined(openbsd_HOST_OS)
- dl_libc_handle = dlopen("libc.so", RTLD_LAZY);
-# endif
# endif /* RTLD_DEFAULT */
# endif
}
if (val == NULL) {
# if defined(OBJFORMAT_ELF)
-# if defined(openbsd_HOST_OS)
- val = dlsym(dl_prog_handle, lbl);
- return (val != NULL) ? val : dlsym(dl_libc_handle,lbl);
-# elif defined(x86_64_HOST_ARCH)
+# if defined(x86_64_HOST_ARCH)
val = dlsym(dl_prog_handle, lbl);
if (val >= (void *)0x80000000) {
void *new_val;
} else {
return val;
}
-# else /* not openbsd */
+# else
return dlsym(dl_prog_handle, lbl);
# endif
# elif defined(OBJFORMAT_MACHO)
void *map_addr = NULL;
#else
FILE *f;
- int misalignment;
#endif
initLinker();
/* debugBelch("loadObj %s\n", path ); */
- /* Check that we haven't already loaded this object.
+ /* Check that we haven't already loaded this object.
Ignore requests to load multiple times */
{
ObjectCode *o;
#define EXTRA_MAP_FLAGS 0
#endif
- oc->image = mmap(map_addr, n, PROT_EXEC|PROT_READ|PROT_WRITE,
+ oc->image = mmap(map_addr, n, PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_PRIVATE|EXTRA_MAP_FLAGS, fd, 0);
if (oc->image == MAP_FAILED)
barf("loadObj: can't map `%s'", path);
if (!f)
barf("loadObj: can't read `%s'", path);
-#ifdef darwin_HOST_OS
+# if defined(mingw32_HOST_OS)
+ // TODO: We would like to use allocateExec here, but allocateExec
+ // cannot currently allocate blocks large enough.
+ oc->image = VirtualAlloc(NULL, oc->fileSize, MEM_RESERVE | MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE);
+# elif defined(darwin_HOST_OS)
// In a Mach-O .o file, all sections can and will be misaligned
// if the total size of the headers is not a multiple of the
// desired alignment. This is fine for .o files that only serve
// We calculate the correct alignment from the header before
// reading the file, and then we misalign oc->image on purpose so
// that the actual sections end up aligned again.
- misalignment = machoGetMisalignment(f);
- oc->misalignment = misalignment;
-#else
- misalignment = 0;
-#endif
+ oc->misalignment = machoGetMisalignment(f);
+ oc->image = stgMallocBytes(oc->fileSize + oc->misalignment, "loadObj(image)");
+ oc->image += oc->misalignment;
+# else
+ oc->image = stgMallocBytes(oc->fileSize, "loadObj(image)");
+# endif
- oc->image = stgMallocBytes(oc->fileSize + misalignment, "loadObj(image)");
- oc->image += misalignment;
-
n = fread ( oc->image, 1, oc->fileSize, f );
if (n != oc->fileSize)
barf("loadObj: error whilst reading `%s'", path);
fclose(f);
-
#endif /* USE_MMAP */
-# if defined(OBJFORMAT_MACHO) && defined(powerpc_HOST_ARCH)
- r = ocAllocateJumpIslands_MachO ( oc );
+# if defined(OBJFORMAT_MACHO) && (defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH))
+ r = ocAllocateSymbolExtras_MachO ( oc );
if (!r) { return r; }
# elif defined(OBJFORMAT_ELF) && defined(powerpc_HOST_ARCH)
- r = ocAllocateJumpIslands_ELF ( oc );
+ r = ocAllocateSymbolExtras_ELF ( oc );
if (!r) { return r; }
#endif
prev->next = oc->next;
}
- /* We're going to leave this in place, in case there are
- any pointers from the heap into it: */
- /* stgFree(oc->image); */
+ // We're going to leave this in place, in case there are
+ // any pointers from the heap into it:
+ // #ifdef mingw32_HOST_OS
+ // VirtualFree(oc->image);
+ // #else
+ // stgFree(oc->image);
+ // #endif
stgFree(oc->fileName);
stgFree(oc->symbols);
stgFree(oc->sections);
/* --------------------------------------------------------------------------
- * PowerPC specifics (jump islands)
- * ------------------------------------------------------------------------*/
+ * Symbol Extras.
+ * This is about allocating a small chunk of memory for every symbol in the
+ * object file. We make sure that the SymboLExtras are always "in range" of
+ * limited-range PC-relative instructions on various platforms by allocating
+ * them right next to the object code itself.
+ */
-#if defined(powerpc_HOST_ARCH)
+#if defined(powerpc_HOST_ARCH) || (defined(x86_64_HOST_ARCH) \
+ && defined(darwin_TARGET_OS))
/*
- ocAllocateJumpIslands
-
+ ocAllocateSymbolExtras
+
Allocate additional space at the end of the object file image to make room
- for jump islands.
+ for jump islands (powerpc, x86_64) and GOT entries (x86_64).
PowerPC relative branch instructions have a 24 bit displacement field.
As PPC code is always 4-byte-aligned, this yields a +-32MB range.
If a particular imported symbol is outside this range, we have to redirect
the jump to a short piece of new code that just loads the 32bit absolute
address and jumps there.
- This function just allocates space for one 16 byte ppcJumpIsland for every
- undefined symbol in the object file. The code for the islands is filled in by
- makeJumpIsland below.
+ On x86_64, PC-relative jumps and PC-relative accesses to the GOT are limited
+ to 32 bits (+-2GB).
+
+ This function just allocates space for one SymbolExtra for every
+ undefined symbol in the object file. The code for the jump islands is
+ filled in by makeSymbolExtra below.
*/
-static int ocAllocateJumpIslands( ObjectCode* oc, int count, int first )
+static int ocAllocateSymbolExtras( ObjectCode* oc, int count, int first )
{
#ifdef USE_MMAP
int pagesize, n, m;
#ifdef USE_MMAP
#ifndef linux_HOST_OS /* mremap is a linux extension */
- #error ocAllocateJumpIslands doesnt want USE_MMAP to be defined
+ #error ocAllocateSymbolExtras doesnt want USE_MMAP to be defined
#endif
pagesize = getpagesize();
n = ROUND_UP( oc->fileSize, pagesize );
- m = ROUND_UP( aligned + sizeof (ppcJumpIsland) * count, pagesize );
+ m = ROUND_UP( aligned + sizeof (SymbolExtra) * count, pagesize );
/* If we have a half-page-size file and map one page of it then
* the part of the page after the size of the file remains accessible.
oc->image -= misalignment;
oc->image = stgReallocBytes( oc->image,
misalignment +
- aligned + sizeof (ppcJumpIsland) * count,
- "ocAllocateJumpIslands" );
+ aligned + sizeof (SymbolExtra) * count,
+ "ocAllocateSymbolExtras" );
oc->image += misalignment;
#endif /* USE_MMAP */
- oc->jump_islands = (ppcJumpIsland *) (oc->image + aligned);
- memset( oc->jump_islands, 0, sizeof (ppcJumpIsland) * count );
+ oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
+ memset( oc->symbol_extras, 0, sizeof (SymbolExtra) * count );
}
else
- oc->jump_islands = NULL;
+ oc->symbol_extras = NULL;
- oc->island_start_symbol = first;
- oc->n_islands = count;
+ oc->first_symbol_extra = first;
+ oc->n_symbol_extras = count;
return 1;
}
-static unsigned long makeJumpIsland( ObjectCode* oc,
+static SymbolExtra* makeSymbolExtra( ObjectCode* oc,
unsigned long symbolNumber,
unsigned long target )
{
- ppcJumpIsland *island;
+ SymbolExtra *extra;
- if( symbolNumber < oc->island_start_symbol ||
- symbolNumber - oc->island_start_symbol > oc->n_islands)
- return 0;
+ ASSERT( symbolNumber >= oc->first_symbol_extra
+ && symbolNumber - oc->first_symbol_extra < oc->n_symbol_extras);
- island = &oc->jump_islands[symbolNumber - oc->island_start_symbol];
+ extra = &oc->symbol_extras[symbolNumber - oc->first_symbol_extra];
+#ifdef powerpc_HOST_ARCH
// lis r12, hi16(target)
- island->lis_r12 = 0x3d80;
- island->hi_addr = target >> 16;
+ extra->jumpIsland.lis_r12 = 0x3d80;
+ extra->jumpIsland.hi_addr = target >> 16;
// ori r12, r12, lo16(target)
- island->ori_r12_r12 = 0x618c;
- island->lo_addr = target & 0xffff;
+ extra->jumpIsland.ori_r12_r12 = 0x618c;
+ extra->jumpIsland.lo_addr = target & 0xffff;
// mtctr r12
- island->mtctr_r12 = 0x7d8903a6;
+ extra->jumpIsland.mtctr_r12 = 0x7d8903a6;
// bctr
- island->bctr = 0x4e800420;
+ extra->jumpIsland.bctr = 0x4e800420;
+#endif
+#ifdef x86_64_HOST_ARCH
+ // jmp *-14(%rip)
+ static uint8_t jmp[] = { 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF };
+ extra->addr = target;
+ memcpy(extra->jumpIsland, jmp, 6);
+#endif
- return (unsigned long) island;
+ return extra;
}
+#endif
+
+/* --------------------------------------------------------------------------
+ * PowerPC specifics (instruction cache flushing)
+ * ------------------------------------------------------------------------*/
+
+#ifdef powerpc_TARGET_ARCH
/*
ocFlushInstructionCache
static void ocFlushInstructionCache( ObjectCode *oc )
{
- int n = (oc->fileSize + sizeof( ppcJumpIsland ) * oc->n_islands + 3) / 4;
+ int n = (oc->fileSize + sizeof( SymbolExtra ) * oc->n_symbol_extras + 3) / 4;
unsigned long *p = (unsigned long *) oc->image;
while( n-- )
&& 0 != strcmp(".stabstr", sectab_i->Name)
/* ignore constructor section for now */
&& 0 != strcmp(".ctors", sectab_i->Name)
+ /* ignore section generated from .ident */
+ && 0!= strcmp("/4", sectab_i->Name)
) {
errorBelch("Unknown PEi386 section name `%s' (while processing: %s)", sectab_i->Name, oc->fileName);
return 0;
+ sym->Value);
} else {
copyName ( sym->Name, strtab, symbol, 1000-1 );
- (void*)S = lookupLocalSymbol( oc, symbol );
+ S = (UInt32) lookupLocalSymbol( oc, symbol );
if ((void*)S != NULL) goto foundit;
- (void*)S = lookupSymbol( symbol );
+ S = (UInt32) lookupSymbol( symbol );
if ((void*)S != NULL) goto foundit;
zapTrailingAtSign ( symbol );
- (void*)S = lookupLocalSymbol( oc, symbol );
+ S = (UInt32) lookupLocalSymbol( oc, symbol );
if ((void*)S != NULL) goto foundit;
- (void*)S = lookupSymbol( symbol );
+ S = (UInt32) lookupSymbol( symbol );
if ((void*)S != NULL) goto foundit;
/* Newline first because the interactive linker has printed "linking..." */
errorBelch("\n%s: unknown symbol `%s'", oc->fileName, symbol);
IF_DEBUG(linker,debugBelch( "Architecture is " ));
switch (ehdr->e_machine) {
case EM_386: IF_DEBUG(linker,debugBelch( "x86" )); break;
+#ifdef EM_SPARC32PLUS
+ case EM_SPARC32PLUS:
+#endif
case EM_SPARC: IF_DEBUG(linker,debugBelch( "sparc" )); break;
#ifdef EM_IA_64
case EM_IA_64: IF_DEBUG(linker,debugBelch( "ia64" )); break;
S = (Elf_Addr)S_tmp;
} else {
stableVal = deRefStablePtr( stablePtr );
- addRootObject((void*)P);
S_tmp = stableVal;
S = (Elf_Addr)S_tmp;
}
if( delta << 6 >> 6 != delta )
{
- value = makeJumpIsland( oc, ELF_R_SYM(info), value );
+ value = (Elf_Addr) (&makeSymbolExtra( oc, ELF_R_SYM(info), value )
+ ->jumpIsland);
delta = value - P;
if( value == 0 || delta << 6 >> 6 != delta )
{
- barf( "Unable to make ppcJumpIsland for #%d",
+ barf( "Unable to make SymbolExtra for #%d",
ELF_R_SYM(info) );
return 0;
}
#ifdef powerpc_HOST_ARCH
-static int ocAllocateJumpIslands_ELF( ObjectCode *oc )
+static int ocAllocateSymbolExtras_ELF( ObjectCode *oc )
{
Elf_Ehdr *ehdr;
Elf_Shdr* shdr;
return 0;
}
- return ocAllocateJumpIslands( oc, shdr[i].sh_size / sizeof( Elf_Sym ), 0 );
+ return ocAllocateSymbolExtras( oc, shdr[i].sh_size / sizeof( Elf_Sym ), 0 );
}
#endif /* powerpc */
*) add still more sanity checks.
*/
+#if x86_64_HOST_ARCH || powerpc64_HOST_ARCH
+#define mach_header mach_header_64
+#define segment_command segment_command_64
+#define section section_64
+#define nlist nlist_64
+#endif
+
#ifdef powerpc_HOST_ARCH
-static int ocAllocateJumpIslands_MachO(ObjectCode* oc)
+static int ocAllocateSymbolExtras_MachO(ObjectCode* oc)
{
struct mach_header *header = (struct mach_header *) oc->image;
struct load_command *lc = (struct load_command *) (header + 1);
}
}
if(max >= min)
- return ocAllocateJumpIslands(oc, max - min + 1, min);
+ return ocAllocateSymbolExtras(oc, max - min + 1, min);
break;
}
lc = (struct load_command *) ( ((char *)lc) + lc->cmdsize );
}
- return ocAllocateJumpIslands(oc,0,0);
+ return ocAllocateSymbolExtras(oc,0,0);
+}
+#endif
+#ifdef x86_64_HOST_ARCH
+static int ocAllocateSymbolExtras_MachO(ObjectCode* oc)
+{
+ struct mach_header *header = (struct mach_header *) oc->image;
+ struct load_command *lc = (struct load_command *) (header + 1);
+ unsigned i;
+
+ for( i = 0; i < header->ncmds; i++ )
+ {
+ if( lc->cmd == LC_SYMTAB )
+ {
+ // Just allocate one entry for every symbol
+ struct symtab_command *symLC = (struct symtab_command *) lc;
+
+ return ocAllocateSymbolExtras(oc, symLC->nsyms, 0);
+ }
+
+ lc = (struct load_command *) ( ((char *)lc) + lc->cmdsize );
+ }
+ return ocAllocateSymbolExtras(oc,0,0);
}
#endif
-static int ocVerifyImage_MachO(ObjectCode* oc STG_UNUSED)
+static int ocVerifyImage_MachO(ObjectCode* oc)
{
- // FIXME: do some verifying here
+ char *image = (char*) oc->image;
+ struct mach_header *header = (struct mach_header*) image;
+
+#if x86_64_TARGET_ARCH || powerpc64_TARGET_ARCH
+ if(header->magic != MH_MAGIC_64)
+ return 0;
+#else
+ if(header->magic != MH_MAGIC)
+ return 0;
+#endif
+ // FIXME: do some more verifying here
return 1;
}
for(i=0;i<n;i++)
{
+#ifdef x86_64_HOST_ARCH
+ struct relocation_info *reloc = &relocs[i];
+
+ char *thingPtr = image + sect->offset + reloc->r_address;
+ uint64_t thing;
+ uint64_t value;
+ uint64_t baseValue;
+ int type = reloc->r_type;
+
+ checkProddableBlock(oc,thingPtr);
+ switch(reloc->r_length)
+ {
+ case 0:
+ thing = *(uint8_t*)thingPtr;
+ baseValue = (uint64_t)thingPtr + 1;
+ break;
+ case 1:
+ thing = *(uint16_t*)thingPtr;
+ baseValue = (uint64_t)thingPtr + 2;
+ break;
+ case 2:
+ thing = *(uint32_t*)thingPtr;
+ baseValue = (uint64_t)thingPtr + 4;
+ break;
+ case 3:
+ thing = *(uint64_t*)thingPtr;
+ baseValue = (uint64_t)thingPtr + 8;
+ break;
+ default:
+ barf("Unknown size.");
+ }
+
+ if(type == X86_64_RELOC_GOT
+ || type == X86_64_RELOC_GOT_LOAD)
+ {
+ ASSERT(reloc->r_extern);
+ value = (uint64_t) &makeSymbolExtra(oc, reloc->r_symbolnum, value)->addr;
+
+ type = X86_64_RELOC_SIGNED;
+ }
+ else if(reloc->r_extern)
+ {
+ struct nlist *symbol = &nlist[reloc->r_symbolnum];
+ char *nm = image + symLC->stroff + symbol->n_un.n_strx;
+ if(symbol->n_value == 0)
+ value = (uint64_t) lookupSymbol(nm);
+ else
+ value = relocateAddress(oc, nSections, sections,
+ symbol->n_value);
+ }
+ else
+ {
+ value = sections[reloc->r_symbolnum-1].offset
+ - sections[reloc->r_symbolnum-1].addr
+ + (uint64_t) image;
+ }
+
+ if(type == X86_64_RELOC_BRANCH)
+ {
+ if((int32_t)(value - baseValue) != (int64_t)(value - baseValue))
+ {
+ ASSERT(reloc->r_extern);
+ value = (uint64_t) &makeSymbolExtra(oc, reloc->r_symbolnum, value)
+ -> jumpIsland;
+ }
+ ASSERT((int32_t)(value - baseValue) == (int64_t)(value - baseValue));
+ type = X86_64_RELOC_SIGNED;
+ }
+
+ switch(type)
+ {
+ case X86_64_RELOC_UNSIGNED:
+ ASSERT(!reloc->r_pcrel);
+ thing += value;
+ break;
+ case X86_64_RELOC_SIGNED:
+ ASSERT(reloc->r_pcrel);
+ thing += value - baseValue;
+ break;
+ case X86_64_RELOC_SUBTRACTOR:
+ ASSERT(!reloc->r_pcrel);
+ thing -= value;
+ break;
+ default:
+ barf("unkown relocation");
+ }
+
+ switch(reloc->r_length)
+ {
+ case 0:
+ *(uint8_t*)thingPtr = thing;
+ break;
+ case 1:
+ *(uint16_t*)thingPtr = thing;
+ break;
+ case 2:
+ *(uint32_t*)thingPtr = thing;
+ break;
+ case 3:
+ *(uint64_t*)thingPtr = thing;
+ break;
+ }
+#else
if(relocs[i].r_address & R_SCATTERED)
{
struct scattered_relocation_info *scat =
// In the .o file, this should be a relative jump to NULL
// and we'll change it to a relative jump to the symbol
ASSERT(-word == reloc->r_address);
- jumpIsland = makeJumpIsland(oc,reloc->r_symbolnum,(unsigned long) symbolAddress);
+ jumpIsland = (unsigned long)
+ &makeSymbolExtra(oc,
+ reloc->r_symbolnum,
+ (unsigned long) symbolAddress)
+ -> jumpIsland;
if(jumpIsland != 0)
{
offsetToJumpIsland = word + jumpIsland
barf("\nunknown relocation %d",reloc->r_type);
return 0;
}
+#endif
}
return 1;
}
for(i=0;i<header->ncmds;i++)
{
- if(lc->cmd == LC_SEGMENT)
+ if(lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64)
segLC = (struct segment_command*) lc;
else if(lc->cmd == LC_SYMTAB)
symLC = (struct symtab_command*) lc;
sections = (struct section*) (segLC+1);
nlist = symLC ? (struct nlist*) (image + symLC->symoff)
: NULL;
+
+ if(!segLC)
+ barf("ocGetNames_MachO: no segment load command");
for(i=0;i<segLC->nsects;i++)
{
if(nlist[i].n_type & N_EXT)
{
char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
- ghciInsertStrHashTable(oc->fileName, symhash, nm,
- image
- + sections[nlist[i].n_sect-1].offset
- - sections[nlist[i].n_sect-1].addr
- + nlist[i].n_value);
- oc->symbols[curSymbol++] = nm;
- }
- else
- {
- char *nm = image + symLC->stroff + nlist[i].n_un.n_strx;
- ghciInsertStrHashTable(oc->fileName, oc->lochash, nm,
- image
- + sections[nlist[i].n_sect-1].offset
- - sections[nlist[i].n_sect-1].addr
- + nlist[i].n_value);
+ if((nlist[i].n_desc & N_WEAK_DEF) && lookupSymbol(nm))
+ ; // weak definition, and we already have a definition
+ else
+ {
+ ghciInsertStrHashTable(oc->fileName, symhash, nm,
+ image
+ + sections[nlist[i].n_sect-1].offset
+ - sections[nlist[i].n_sect-1].addr
+ + nlist[i].n_value);
+ oc->symbols[curSymbol++] = nm;
+ }
}
}
}
for(i=0;i<header->ncmds;i++)
{
- if(lc->cmd == LC_SEGMENT)
+ if(lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64)
segLC = (struct segment_command*) lc;
else if(lc->cmd == LC_SYMTAB)
symLC = (struct symtab_command*) lc;
fread(&header, sizeof(header), 1, f);
rewind(f);
+#if x86_64_TARGET_ARCH || powerpc64_TARGET_ARCH
+ if(header.magic != MH_MAGIC_64)
+ return 0;
+#else
if(header.magic != MH_MAGIC)
return 0;
-
+#endif
+
misalignment = (header.sizeofcmds + sizeof(header))
& 0xF;
}
#endif
+