The RTS wants a fast, thread-local variable called 'gct'. However, it turns out that this is only needed for the parallel garbage collector. This could be done properly using a register variable (as is done on other architectures), but - since the iPhone doesn't use the new multi-core ARM chips yet - it's far safer/easier just to disable the thread-local capability, and avoid the problem by forcing the GC never to run in parallel. main() renamed to Haskell_main() just because it's convenient to be able to write our own start-up routine in C. This is not necessary at all, and it works perfectly fine without this change. --- ghc-6.10.2.orig/rts/sm/GCThread.h 2009-03-31 06:13:16.000000000 +1300 +++ ghc-6.10.2/rts/sm/GCThread.h 2009-06-18 15:54:37.000000000 +1200 @@ -215,6 +215,13 @@ GLOBAL_REG_DECL(gc_thread*, gct, REG_R1) #define DECLARE_GCT /* nothing */ +#elif defined(darwin_HOST_OS) + +/* iPhone: This is not thread-local, but we also change the code elsewhere + * to forbid multi-threaded garbage collection. */ +extern gc_thread* gct; +#define DECLARE_GCT gc_thread* gct; + #elif defined(__GNUC__) extern __thread gc_thread* gct; --- ghc-6.10.2.orig/rts/sm/GC.c 2009-03-31 06:13:16.000000000 +1300 +++ ghc-6.10.2/rts/sm/GC.c 2009-06-18 15:54:37.000000000 +1200 @@ -245,6 +245,7 @@ /* How many threads will be participating in this GC? * We don't try to parallelise minor GC, or mark/compact/sweep GC. */ +#if 0 #if defined(THREADED_RTS) if (n < (4*1024*1024 / BLOCK_SIZE) || oldest_gen->steps[0].mark) { n_gc_threads = 1; @@ -254,6 +255,10 @@ #else n_gc_threads = 1; #endif +#else + n_gc_threads = 1; /* iPhone: We must not allow more than one thread, because + 'gct' is not thread-local. */ +#endif trace(TRACE_gc|DEBUG_gc, "GC (gen %d): %d KB to collect, %ld MB in use, using %d thread(s)", N, n * (BLOCK_SIZE / 1024), mblocks_allocated, n_gc_threads); --- ghc-6.10.2.orig/rts/Main.c 2009-03-31 06:13:15.000000000 +1300 +++ ghc-6.10.2/rts/Main.c 2009-06-18 15:54:37.000000000 +1200 @@ -143,7 +143,7 @@ } shutdownHaskellAndExit(exit_status); } -int main(int argc, char *argv[]) +int Haskell_main(int argc, char *argv[]) { /* We do this dance with argc and argv as otherwise the SEH exception stuff (the BEGIN/END CATCH below) on Windows gets confused */