summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwolfgang <unknown>2005-06-13 02:44:22 +0000
committerwolfgang <unknown>2005-06-13 02:44:22 +0000
commitc26a153cb20aa69dce35cf0317205336f4e5f0bb (patch)
treeb17dabbfe451c723ccce41b0f8ed5b8fb5cdec18
parent4302b12e6fd876a190ce6091e6ce14dbeb15bc00 (diff)
downloadhaskell-c26a153cb20aa69dce35cf0317205336f4e5f0bb.tar.gz
[project @ 2005-06-13 02:44:22 by wolfgang]
Darwin: Deal with the fact that the code and data in a .o file might not be 16-byte aligned even if it contains instructions that require 16-byte alignment. This fixes floating point related crashes on Darwin/x86; there might also have been problems on Darwin/ppc if people load .o files with AltiVec code into GHCi.
-rw-r--r--ghc/rts/Linker.c46
1 files changed, 43 insertions, 3 deletions
diff --git a/ghc/rts/Linker.c b/ghc/rts/Linker.c
index 9cee55a11b..52412dcb35 100644
--- a/ghc/rts/Linker.c
+++ b/ghc/rts/Linker.c
@@ -110,6 +110,7 @@ static int ocVerifyImage_MachO ( ObjectCode* oc );
static int ocGetNames_MachO ( ObjectCode* oc );
static int ocResolve_MachO ( ObjectCode* oc );
+static int machoGetMisalignment( FILE * );
#ifdef powerpc_HOST_ARCH
static int ocAllocateJumpIslands_MachO ( ObjectCode* oc );
static void machoInitSymbolsWithoutUnderscore( void );
@@ -690,7 +691,7 @@ static RtsSymbolVal rtsSyms[] = {
// dyld stub code contains references to this,
// but it should never be called because we treat
// lazy pointers as nonlazy.
- { "dyld_stub_binding_helper", 0xDEADBEEF },
+ { "dyld_stub_binding_helper", (void*)0xDEADBEEF },
#endif
{ 0, 0 } /* sentinel */
};
@@ -1029,6 +1030,7 @@ loadObj( char *path )
void *map_addr = NULL;
#else
FILE *f;
+ int misalignment;
#endif
initLinker();
@@ -1133,13 +1135,29 @@ loadObj( char *path )
#else /* !USE_MMAP */
- oc->image = stgMallocBytes(oc->fileSize, "loadObj(image)");
-
/* load the image into memory */
f = fopen(path, "rb");
if (!f)
barf("loadObj: can't read `%s'", path);
+#ifdef 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
+ // as input for the static linker, but it's not fine for us,
+ // as SSE (used by gcc for floating point) and Altivec require
+ // 16-byte alignment.
+ // 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);
+#else
+ misalignment = 0;
+#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);
@@ -4021,4 +4039,26 @@ static void machoInitSymbolsWithoutUnderscore()
#undef Sym
}
#endif
+
+/*
+ * Figure out by how much to shift the entire Mach-O file in memory
+ * when loading so that its single segment ends up 16-byte-aligned
+ */
+static int machoGetMisalignment( FILE * f )
+{
+ struct mach_header header;
+ int misalignment;
+
+ fread(&header, sizeof(header), 1, f);
+ rewind(f);
+
+ if(header.magic != MH_MAGIC)
+ return 0;
+
+ misalignment = (header.sizeofcmds + sizeof(header))
+ & 0xF;
+
+ return misalignment ? (16 - misalignment) : 0;
+}
+
#endif