diff --git a/Makefile b/Makefile
index 981fec0d8c52026d82e73e0e9a79cbcd4927f3bd..192a0d5cc11429c524be6fd44f393ae5d76e1103 100644
--- a/Makefile
+++ b/Makefile
@@ -199,6 +199,11 @@ install ::
 endif
 endif
 
+# Install gcc-extra-opts
+install ::
+	@$(INSTALL_DIR) $(libdir)
+	$(INSTALL_DATA) $(INSTALL_OPTS) extra-gcc-opts $(libdir)
+
 install-docs ::
 	@case '${MFLAGS}' in *-[ik]*) x_on_err=0;; *-r*[ik]*) x_on_err=0;; *) x_on_err=1;; esac; \
 	for i in $(SUBDIRS); do \
@@ -262,6 +267,7 @@ BIN_DIST_TOP= distrib/Makefile \
               ANNOUNCE \
               LICENSE \
               install-sh \
+	      extra-gcc-opts.in \
               config.guess \
               config.sub   \
               aclocal.m4
diff --git a/aclocal.m4 b/aclocal.m4
index e5aed8acb6961ae5dd843e31b865a9be93b37ff2..12db959bb1dae0fcbea0239c25a965a700803b0a 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -936,45 +936,47 @@ AC_SUBST([GhcHasReadline], [`echo $fp_cv_ghc_has_readline | sed 'y/yesno/YESNO/'
 ])# FP_GHC_HAS_READLINE
 
 
-# FP_GCC_NEEDS_NO_OMIT_LFPTR
-# --------------------------
+# FP_GCC_EXTRA_FLAGS
+# ------------------
+# Determine which extra flags we need to pass gcc when we invoke it
+# to compile .hc code.
+#
 # Some OSs (Mandrake Linux, in particular) configure GCC with
-# -momit-leaf-frame-pointer on by default. If this is the case, we need to turn
-# it off for mangling to work. The test is currently a bit crude, using only the
-# version number of gcc. Defines HAVE_GCC_MNO_OMIT_LFPTR.
-AC_DEFUN([FP_GCC_NEEDS_NO_OMIT_LFPTR],
-[AC_REQUIRE([FP_HAVE_GCC])
-AC_CACHE_CHECK([whether gcc needs -mno-omit-leaf-frame-pointer], [fp_cv_gcc_needs_no_omit_lfptr],
-[FP_COMPARE_VERSIONS([$fp_gcc_version], [-ge], [3.2],
-  [fp_cv_gcc_needs_no_omit_lfptr=yes],
-  [fp_cv_gcc_needs_no_omit_lfptr=no])])
-if test "$fp_cv_gcc_needs_no_omit_lfptr" = "yes"; then
-   AC_DEFINE([HAVE_GCC_MNO_OMIT_LFPTR], [1], [Define to 1 if gcc supports -mno-omit-leaf-frame-pointer.])
-fi])# FP_GCC_NEEDS_NO_OMIT_LFPTR
-
-# FP_GCC_HAS_NO_UNIT_AT_A_TIME
-# --------------------------
-AC_DEFUN([FP_GCC_HAS_NO_UNIT_AT_A_TIME],
+# -momit-leaf-frame-pointer on by default. If this is the case, we
+# need to turn it off for mangling to work. The test is currently a
+# bit crude, using only the version number of gcc.
+# 
+# -fwrapv is needed for gcc to emit well-behaved code in the presence of
+# integer wrap around. (Trac #952)
+#
+# -fno-unit-at-a-time or -fno-toplevel-reoder is necessary to avoid gcc
+# reordering things in the module and confusing the manger and/or splitter.
+# (eg. Trac #1427)
+#
+AC_DEFUN([FP_GCC_EXTRA_FLAGS],
 [AC_REQUIRE([FP_HAVE_GCC])
-AC_CACHE_CHECK([whether gcc has -fno-unit-at-a-time], [fp_cv_gcc_has_no_unit_at_a_time],
-[FP_COMPARE_VERSIONS([$fp_gcc_version], [-ge], [3.4],
-  [fp_cv_gcc_has_no_unit_at_a_time=yes],
-  [fp_cv_gcc_has_no_unit_at_a_time=no])])
-if test "$fp_cv_gcc_has_no_unit_at_a_time" = "yes"; then
-   AC_DEFINE([HAVE_GCC_HAS_NO_UNIT_AT_A_TIME], [1], [Define to 1 if gcc supports -fno-unit-at-a-time.])
-fi])
+AC_CACHE_CHECK([for extra options to pass gcc when compiling via C], [fp_cv_gcc_extra_opts],
+[fp_cv_gcc_extra_opts=
+ FP_COMPARE_VERSIONS([$fp_gcc_version], [-ge], [3.4],
+  [fp_cv_gcc_extra_opts="$fp_cv_gcc_extra_opts -fwrapv"],
+  [])
+ case $TargetPlatform in
+  i386-*|x86_64-*) 
+     FP_COMPARE_VERSIONS([$fp_gcc_version], [-ge], [3.2],
+      [fp_cv_gcc_extra_opts="$fp_cv_gcc_extra_opts -mno-omit-leaf-frame-pointer"],
+      [])
+    FP_COMPARE_VERSIONS([$fp_gcc_version], [-ge], [3.4],
+     [FP_COMPARE_VERSIONS([$fp_gcc_version], [-ge], [4.2],
+       [fp_cv_gcc_extra_opts="$fp_cv_gcc_extra_opts -fno-toplevel-reorder"],
+       [fp_cv_gcc_extra_opts="$fp_cv_gcc_extra_opts -fno-unit-at-a-time"]
+     )],
+     [])
+  ;;
+ esac
+])
+AC_SUBST([GccExtraViaCOpts],$fp_cv_gcc_extra_opts)
+])
 
-# FP_GCC_HAS_WRAPV
-# --------------------------
-AC_DEFUN([FP_GCC_HAS_WRAPV],
-[AC_REQUIRE([FP_HAVE_GCC])
-AC_CACHE_CHECK([whether gcc has -fwrapv], [fp_cv_gcc_has_wrapv],
-[FP_COMPARE_VERSIONS([$fp_gcc_version], [-ge], [3.4],
-  [fp_cv_gcc_has_wrapv=yes],
-  [fp_cv_gcc_has_wrapv=no])])
-if test "$fp_cv_gcc_has_wrapv" = "yes"; then
-   AC_DEFINE([HAVE_GCC_HAS_WRAPV], [1], [Define to 1 if gcc supports -fwrapv.])
-fi])
 
 # FP_SETUP_PROJECT_VERSION
 # ---------------------
diff --git a/compiler/main/DriverPipeline.hs b/compiler/main/DriverPipeline.hs
index e414f4cb3d61e40652207882c98dd60de27fe0f8..cf6bff18eef2321a61a693a8ff6bf19fdca2dc68 100644
--- a/compiler/main/DriverPipeline.hs
+++ b/compiler/main/DriverPipeline.hs
@@ -811,6 +811,7 @@ runPhase cc_phase stop dflags basename suff input_fn get_output_fn maybe_loc
 			      (cmdline_include_paths ++ pkg_include_dirs)
 
 	let (md_c_flags, md_regd_c_flags) = machdepCCOpts dflags
+        gcc_extra_viac_flags <- getExtraViaCOpts dflags
         let pic_c_flags = picCCOpts dflags
 
         let verb = getVerbFlag dflags
@@ -877,6 +878,13 @@ runPhase cc_phase stop dflags basename suff input_fn get_output_fn maybe_loc
 		       ++ (if hcc && mangle
 		  	     then md_regd_c_flags
 		  	     else [])
+		       ++ (if hcc
+		  	     then if mangle 
+                                     then gcc_extra_viac_flags
+                                     else filter (=="-fwrapv")
+                                                gcc_extra_viac_flags
+                                -- still want -fwrapv even for unreg'd
+		  	     else [])
 		       ++ (if hcc 
 			     then more_hcc_opts
 			     else [])
@@ -886,10 +894,6 @@ runPhase cc_phase stop dflags basename suff input_fn get_output_fn maybe_loc
 		       ++ split_opt
 		       ++ include_paths
 		       ++ pkg_extra_cc_opts
-#ifdef HAVE_GCC_HAS_WRAPV
-                  -- We need consistent integer overflow (trac #952)
-               ++ ["-fwrapv"]
-#endif
 		       ))
 
 	return (next_phase, dflags, maybe_loc, output_fn)
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 8880550fa34b5a70e3fe25f1a0ac58676581ce81..1721b4c0b36a8198f8fe5d4eb4d59f991c1db48b 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -1515,6 +1515,18 @@ setOptHpcDir arg  = upd $ \ d -> d{hpcDir = arg}
 -----------------------------------------------------------------------------
 -- Via-C compilation stuff
 
+-- There are some options that we need to pass to gcc when compiling
+-- Haskell code via C, but are only supported by recent versions of
+-- gcc.  The configure script decides which of these options we need,
+-- and puts them in the file "extra-gcc-opts" in $topdir, which is
+-- read before each via-C compilation.  The advantage of having these
+-- in a separate file is that the file can be created at install-time
+-- depending on the available gcc version, and even re-generated  later
+-- if gcc is upgraded.
+--
+-- The options below are not dependent on the version of gcc, only the
+-- platform.
+
 machdepCCOpts :: DynFlags -> ([String], -- flags for all C compilations
 			      [String]) -- for registerised HC compilations
 machdepCCOpts dflags
@@ -1557,20 +1569,6 @@ machdepCCOpts dflags
 --                    , if "mingw32" `isSuffixOf` cTARGETPLATFORM then "-mno-cygwin" else "" 
 		      ],
 		      [ "-fno-defer-pop",
-#ifdef HAVE_GCC_MNO_OMIT_LFPTR
-			-- Some gccs are configured with
-			-- -momit-leaf-frame-pointer on by default, and it
-			-- apparently takes precedence over 
-			-- -fomit-frame-pointer, so we disable it first here.
-			"-mno-omit-leaf-frame-pointer",
-#endif
-#ifdef HAVE_GCC_HAS_NO_UNIT_AT_A_TIME
-		 	"-fno-unit-at-a-time",
-			-- unit-at-a-time doesn't do us any good, and screws
-			-- up -split-objs by moving the split markers around.
-			-- It's only turned on with -O2, but put it here just
-			-- in case someone uses -optc-O2.
-#endif
 			"-fomit-frame-pointer",
 			-- we want -fno-builtin, because when gcc inlines
 			-- built-in functions like memcpy() it tends to
@@ -1589,13 +1587,6 @@ machdepCCOpts dflags
 			-- and get in the way of -split-objs.  Another option
 			-- would be to throw them away in the mangler, but this
 			-- is easier.
-#ifdef HAVE_GCC_HAS_NO_UNIT_AT_A_TIME
-		 "-fno-unit-at-a-time",
-			-- unit-at-a-time doesn't do us any good, and screws
-			-- up -split-objs by moving the split markers around.
-			-- It's only turned on with -O2, but put it here just
-			-- in case someone uses -optc-O2.
-#endif
 		 "-fno-builtin"
 			-- calling builtins like strlen() using the FFI can
 			-- cause gcc to run out of regs, so use the external
diff --git a/compiler/main/SysTools.lhs b/compiler/main/SysTools.lhs
index 64e7b7803f1ecef11553a6cdebb3ee1fc414339b..e098dd9eabce8cf301e895694ebe4014d38f95b5 100644
--- a/compiler/main/SysTools.lhs
+++ b/compiler/main/SysTools.lhs
@@ -22,6 +22,7 @@ module SysTools (
 	copy,
         copyWithHeader,
 	normalisePath,          -- FilePath -> FilePath
+        getExtraViaCOpts,
 	
 	-- Temporary-file management
 	setTmpDir,
@@ -536,6 +537,10 @@ copyWithHeader dflags purpose maybe_header from to = do
   hPutStr h ls
   hClose h
 
+getExtraViaCOpts :: DynFlags -> IO [String]
+getExtraViaCOpts dflags = do
+  f <- readFile (topDir dflags `joinFileName` "extra-gcc-opts")
+  return (words f)
 \end{code}
 
 %************************************************************************
diff --git a/configure.ac b/configure.ac
index b35c7e7d39c1790d159f941303eb3b72164f7d44..8dec5693929c4effceba4dca74558d53e3b795b6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -876,9 +876,7 @@ dnl     If gcc, make sure it's at least 2.1
 dnl
 FP_HAVE_GCC
 FP_MINGW_GCC
-FP_GCC_NEEDS_NO_OMIT_LFPTR
-FP_GCC_HAS_NO_UNIT_AT_A_TIME
-FP_GCC_HAS_WRAPV
+FP_GCC_EXTRA_FLAGS
 
 dnl ** figure out how to invoke cpp directly (gcc -E is no good)
 AC_PROG_CPP
@@ -1230,6 +1228,6 @@ else
 fi
 AC_SUBST(HavePapi)
 
-AC_CONFIG_FILES([mk/config.mk ghc.spec docs/users_guide/ug-book.xml])
+AC_CONFIG_FILES([mk/config.mk ghc.spec extra-gcc-opts docs/users_guide/ug-book.xml])
 AC_CONFIG_COMMANDS([mk/stamp-h],[echo timestamp > mk/stamp-h])
 AC_OUTPUT
diff --git a/distrib/configure-bin.ac b/distrib/configure-bin.ac
index 0d01388e8086797d653e89dae73dd7d5776e38b4..8d9ea90d27beedd38e95a6e0f0ef47ceef7d06f0 100644
--- a/distrib/configure-bin.ac
+++ b/distrib/configure-bin.ac
@@ -148,7 +148,13 @@ FP_HAVE_GCC
 AC_PROG_CPP
 
 #
-AC_OUTPUT(Makefile-vars)
+dnl ** Check gcc version and flags we need to pass it **
+#
+FP_GCC_EXTRA_FLAGS
+
+#
+AC_CONFIG_FILES(Makefile-vars extra-gcc-opts)
+AC_OUTPUT
 
 echo "****************************************************"
 echo "Configuration done, ready to either 'make install'"
diff --git a/extra-gcc-opts.in b/extra-gcc-opts.in
new file mode 100644
index 0000000000000000000000000000000000000000..8c9832c835feb54efa708ace3f4e45e74362cf4b
--- /dev/null
+++ b/extra-gcc-opts.in
@@ -0,0 +1 @@
+@GccExtraViaCOpts@