On Mon, 01 Oct 2012, Matthias Kilian wrote:

> Hi,
> 
> On Mon, Oct 01, 2012 at 04:32:51PM +0200, David Coppa wrote:
> > > >> Loading package integer-gmp ... linking ... ghc: 
> > > >> /usr/local/lib/libgmp.a: unknown symbol `__guard_local'
> [...]
> > > I applied the patches to both amd64 and i386, the two failing ports
> > > hs-vector and hs-type-level built on i386, not on amd64.
> [...]
> > The diff below, replacing SymE_NeedsProto with SymI_NeedsProto,
> > makes things work for me on amd64 (tested with hs-vector and
> > hs-type-level)...
> 
> For me, both versions (using either SymI_NeedsProto or SymE_NeedsProto)
> *appear* to work (on amd64).  I don't understand why the SymE_NeedsProto
> did fail for Nigel on amd64.
> 
> Note: if you don't want to read all the details, just skip forward
> to "What can we do?" ;-)
> 
> Anyway, that's not important, because both "fixes" are wrong, because
> they fix the linker error (unknown symbol `__guard_local') but cause
> random crashes at runtime if there's heavy enough use of libgmp.a (that
> just tries to calculate the 400th fibonacci number):
> 
> $ cd $(make show=WRKBUILD)
> $ echo 'let f = 1 : 1 : zipWith (+) f (tail f) in f !! 400' | 
> ./inplace/bin/ghc-stage2 --interactive
> GHCi, version 7.4.2: http://www.haskell.org/ghc/  :? for help
> Loading package ghc-prim ... linking ... done.
> Loading package integer-gmp ... linking ... done.
> Loading package base ... linking ... done.
> Prelude>
> 284812298108489611757988937681460995615380088782304890986477195645969271404032323901
> Prelude> Leaving GHCi.
> $ echo 'let f = 1 : 1 : zipWith (+) f (tail f) in f !! 400' | 
> ./inplace/bin/ghc-stage2 --interactive
> GHCi, version 7.4.2: http://www.haskell.org/ghc/  :? for help
> Loading package ghc-prim ... linking ... done.
> Loading package integer-gmp ... linking ... done.
> Loading package base ... linking ... done.
> Prelude> Segmentation fault (core dumped)


Hi again,

After three days of puking blood while wandering inside the GHC
build system, I think I've found a possible solution to this messy
problem...

First, the "unknown symbol `__guard_local'" error is an entirely
different beast than the random crashes at runtime with libgmp.a.

Good news is kili's "SymE_NeedsProto" workaround effectively fixes
it.

On the other hand, the root cause of segmentation faults at runtime
is that ghc requires a patched gmp library with customized memory
allocation functions.

Quoting from
http://hackage.haskell.org/trac/ghc/wiki/ReplacingGMPNotes/TheCurrentGMPImplementation:

---8<---

   The most insidious and unique feature of the GHC implementation with
   GMP is memory management. GHC uses the special memory functions in GMP
   ( mp_set_memory_functions( (*alloc)(), (*realloc)(), (*dealloc)() ) to
   let GMP use GHC's own garbage collector. The memory functions are
   implemented in rts/sm/Storage.c as:
          static void* stgAllocForGMP (size_t size_in_bytes);
          static void  stgDeallocForGMP (void *ptr STG_UNUSED,
                                         size_t size STG_UNUSED);
          static void* stgReallocForGMP (void *ptr,
                                         size_t old_size,
                                         size_t new_size);

   These special allocation functions bring most GMP memory usage into the
   GHC heap but do not seem that efficient otherwise. (I could be wrong
   --PDT.) Allocation uses the internal allocate() interface, so no
   garbage collection is performed during a GMP operation. Note that GMP
   operations may use these functions to allocate more memory themselves,
   after being called from Haskell code. The memory allocated is a simple
   array of words (W_), rounded up to a whole number.

---8<---

And indeed:

$ nm 
/usr/ports/pobj/ghc-7.4.2-no_doc/ghc-7.4.2/libraries/integer-gmp/gmp/libgmp.a | 
grep stg
         U stgAllocForGMP
         U stgDeallocForGMP
         U stgReallocForGMP

But since /usr/local/lib/libgmp.a comes from a vanilla gmp-5.0.2,
we're totally belly-up!

As a proof, try this:

$ cd /usr/ports/devel/gmp
$ make clean patch
$ cd /usr/ports/pobj/gmp-5.0.2/gmp-5.0.2/
$ patch -NEp1 -i 
/usr/ports/pobj/ghc-7.4.2-no_doc/ghc-7.4.2/libraries/integer-gmp/gmp/tarball/patch
$ cd -
$ make fake
$ sudo cp /usr/ports/pobj/gmp-5.0.2/fake-amd64/usr/local/lib/libgmp.a 
/usr/local/lib/libgmp.a

and then repeat the fibonacci test:

$ ghci
GHCi, version 7.4.2: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Prelude> let fib n = fibs!!n
Prelude> fib 10000
33644764876431783266621612005107543310302148460680063906564769974680081442166662368155595513633734025582065332680836159373734790483865268263040892463056431887354544369559827491606602099884183933864652731300088830269235673613135117579297437854413752130520504347701602264758318906527890855154366159582987279682987510631200575428783453215515103870818298969791613127856265033195487140214287532698187962046936097879900350962302291026368131493195275630227837628441540360584402572114334961180023091208287046088923962328835461505776583271252546093591128203925285393434620904245248929403901706233888991085841065183173360437470737908552631764325733993712871937587746897479926305837065742830161637408969178426378624212835258112820516370298089332099905707920064367426202389783111470054074998459250360633560933883831923386783056136435351892133279732908133732642652633989763922723407882928177953580570993691049175470808931841056146322338217465637321248226383092103297701648054726243842374862411453093812206564914032751086643394517512161526545361333111314042436854805106765843493523836959653428071768775328348234345557366719731392746273629108210679280784718035329131176778924659089938635459327894523777674406192240337638674004021330343297496902028328145933418826817683893072003634795623117103101291953169794607632737589253530772552375943788434504067715555779056450443016640119462580972216729758615026968443146952034614932291105970676243268515992834709891284706740862008587135016260312071903172086094081298321581077282076353186624611278245537208532365305775956430072517744315051539600905168603220349163222640885248852433158051534849622434848299380905070483482449327453732624567755879089187190803662058009594743150052402532709746995318770724376825907419939632265984147498193609285223945039707165443156421328157688908058783183404917434556270520223564846495196112460268313970975069382648706613264507665074611512677522748621598642530711298441182622661057163515069260029861704945425047491378115154139941550671256271197133252763631939606902895650288268608362241082050562430701794976171121233066073310059947366875
Prelude>
Leaving GHCi.
$

How to properly fix this problem (ports-wise speaking)?

A working solution is to use the gmp library that comes bundled
with GHC.

While doing a build with my diff, for mysterious causes I caught
another error:

---8<---

"inplace/bin/ghc-stage1" -o utils/hsc2hs/dist-install/build/tmp/hsc2hs   -H32m 
-O    -hide-all-packages -i -iutils/hsc2hs/. -iutils/hsc2hs/dist-install/build 
-iutils/hsc2hs/dist-install/build/autogen -Iutils/hsc2hs/dist-install/build 
-Iutils/hsc2hs/dist-install/build/autogen     -optP-include 
-optPutils/hsc2hs/dist-install/build/autogen/cabal_macros.h -package 
base-4.5.1.0 -package containers-0.4.2.1 -package directory-1.1.0.2 -package 
process-1.1.0.1  -XHaskell98 -XCPP -XForeignFunctionInterface  
-no-user-package-conf -rtsopts     -odir utils/hsc2hs/dist-install/build -hidir 
utils/hsc2hs/dist-install/build -stubdir utils/hsc2hs/dist-install/build -hisuf 
hi -osuf  o -hcsuf hc   utils/hsc2hs/dist-install/build/Main.o 
utils/hsc2hs/dist-install/build/HSCParser.o 
utils/hsc2hs/dist-install/build/DirectCodegen.o 
utils/hsc2hs/dist-install/build/CrossCodegen.o 
utils/hsc2hs/dist-install/build/UtilsCodegen.o 
utils/hsc2hs/dist-install/build/Common.o utils/hsc2hs/dist-install/build/C.o 
utils/hsc2hs/dist-install/build/Flags.o 
utils/hsc2hs/dist-install/build/Paths_hsc2hs.o    
/usr/ports/pobj/ghc-7.4.2-no_doc/ghc-7.4.2/rts/dist/build/libHSrts.a(RtsFlags.o):
 In function `copyArg':
RtsFlags.c:(.text+0x2bd): warning: warning: strcpy() is almost always misused, 
please use strlcpy()
/usr/ports/pobj/ghc-7.4.2-no_doc/ghc-7.4.2/rts/dist/build/libHSrts.a(RtsUtils.o):
 In function `showStgWord64':
RtsUtils.c:(.text+0x329): warning: warning: sprintf() is often misused, please 
use snprintf()
/usr/ports/pobj/ghc-7.4.2-no_doc/ghc-7.4.2/rts/dist/build/libHSrts.a(ffi64.o): 
In function `ffi_call':

../src/x86/ffi64.c:486:0:  undefined reference to `ffi_call_unix64'
/usr/ports/pobj/ghc-7.4.2-no_doc/ghc-7.4.2/rts/dist/build/libHSrts.a(ffi64.o): 
In function `ffi_prep_closure_loc':

../src/x86/ffi64.c:512:0:
     undefined reference to `ffi_closure_unix64'

---8<---

So I fixed this too...

Here's the diff, comments are highly appreciated.

Ciao,
David

Index: Makefile
===================================================================
RCS file: /cvs/ports/lang/ghc/Makefile,v
retrieving revision 1.82
diff -u -p -r1.82 Makefile
--- Makefile    5 Oct 2012 19:28:12 -0000       1.82
+++ Makefile    10 Oct 2012 12:11:02 -0000
@@ -11,7 +11,7 @@ COMMENT-doc =         documentation for GHC
 
 DISTNAME =             ghc-${MODGHC_VER}
 PKGNAME-main =         ghc-${MODGHC_VER}
-REVISION-main =                0
+REVISION-main =                1
 PKGNAME-doc =          ghc-doc-${MODGHC_VER}
 CATEGORIES =           lang devel
 HOMEPAGE =             http://www.haskell.org/ghc/
@@ -44,11 +44,11 @@ PKG_ARCH-doc =              *
 BUILD_DEPENDS =                archivers/gtar \
                        textproc/docbook-xsl
 LIB_DEPENDS-doc =
-LIB_DEPENDS-main =     ${LIB_DEPENDS} devel/gmp
+LIB_DEPENDS-main =     ${LIB_DEPENDS}
 RUN_DEPENDS-doc =
 RUN_DEPENDS-main =
 
-WANTLIB-main =         ${WANTLIB} c gmp m ncursesw pthread util
+WANTLIB-main =         ${WANTLIB} c m ncursesw pthread util
 
 WANTLIB-doc =
 
@@ -78,9 +78,7 @@ USE_GMAKE =           Yes
 USE_GROFF =            Yes
 
 CONFIGURE_STYLE =      gnu
-CONFIGURE_ARGS +=      --with-gmp-includes=${LOCALBASE}/include \
-                       --with-gmp-libraries=${LOCALBASE}/lib \
-                       --with-iconv-includes=${LOCALBASE}/include \
+CONFIGURE_ARGS +=      --with-iconv-includes=${LOCALBASE}/include \
                        --with-iconv-libraries=${LOCALBASE}/lib
 CONFIGURE_ENV =                CONF_CC_OPTS_STAGE0="-fno-pie -nopie" \
                        CONF_CC_OPTS_STAGE1="-fno-pie -nopie" \
Index: patches/patch-libffi_ghc_mk
===================================================================
RCS file: patches/patch-libffi_ghc_mk
diff -N patches/patch-libffi_ghc_mk
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-libffi_ghc_mk 10 Oct 2012 12:11:02 -0000
@@ -0,0 +1,15 @@
+$OpenBSD$
+
+Unbreak the build on OpenBSD/amd64: gcc supports @unwind sections
+while GHC's linker does not
+
+--- libffi/ghc.mk.orig Wed Jun  6 19:10:25 2012
++++ libffi/ghc.mk      Wed Oct 10 11:25:30 2012
+@@ -78,6 +78,7 @@ $(libffi_STAMP_CONFIGURE): $(TOUCH_DEP)
+           NM=$(NM) \
+         CFLAGS="$(SRC_CC_OPTS) $(CONF_CC_OPTS_STAGE1) -w" \
+         LDFLAGS="$(SRC_LD_OPTS) $(CONF_GCC_LINKER_OPTS_STAGE1) -w" \
++        libffi_cv_as_x86_64_unwind_section_type=no \
+         "$(SHELL)" configure \
+                 --prefix=$(TOP)/libffi/build/inst \
+                 --enable-static=yes \
Index: patches/patch-libraries_integer-gmp_configure
===================================================================
RCS file: patches/patch-libraries_integer-gmp_configure
diff -N patches/patch-libraries_integer-gmp_configure
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-libraries_integer-gmp_configure       10 Oct 2012 12:11:02 
-0000
@@ -0,0 +1,100 @@
+$OpenBSD$
+
+Coerce GHC to use the bundled gmp library
+
+--- libraries/integer-gmp/configure.orig       Tue Oct  9 22:08:06 2012
++++ libraries/integer-gmp/configure    Tue Oct  9 22:11:52 2012
+@@ -2982,92 +2982,7 @@ fi
+ 
+ 
+ 
+-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __gmpz_fdiv_qr in 
-lgmp" >&5
+-$as_echo_n "checking for __gmpz_fdiv_qr in -lgmp... " >&6; }
+-if test "${ac_cv_lib_gmp___gmpz_fdiv_qr+set}" = set; then :
+-  $as_echo_n "(cached) " >&6
+-else
+-  ac_check_lib_save_LIBS=$LIBS
+-LIBS="-lgmp  $LIBS"
+-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+-/* end confdefs.h.  */
+-
+-/* Override any GCC internal prototype to avoid an error.
+-   Use char because int might match the return type of a GCC
+-   builtin and then its argument prototype would still apply.  */
+-#ifdef __cplusplus
+-extern "C"
+-#endif
+-char __gmpz_fdiv_qr ();
+-int
+-main ()
+-{
+-return __gmpz_fdiv_qr ();
+-  ;
+-  return 0;
+-}
+-_ACEOF
+-if ac_fn_c_try_link "$LINENO"; then :
+-  ac_cv_lib_gmp___gmpz_fdiv_qr=yes
+-else
+-  ac_cv_lib_gmp___gmpz_fdiv_qr=no
+-fi
+-rm -f core conftest.err conftest.$ac_objext \
+-    conftest$ac_exeext conftest.$ac_ext
+-LIBS=$ac_check_lib_save_LIBS
+-fi
+-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: 
$ac_cv_lib_gmp___gmpz_fdiv_qr" >&5
+-$as_echo "$ac_cv_lib_gmp___gmpz_fdiv_qr" >&6; }
+-if test "x$ac_cv_lib_gmp___gmpz_fdiv_qr" = x""yes; then :
+-  HaveLibGmp=YES; GMP_LIBS=gmp
+-else
+-  HaveLibGmp=NO;  GMP_LIBS=
+-fi
+-
+-if test "$HaveLibGmp" = "NO"; then
+-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __gmpz_fdiv_qr in 
-lgmp3" >&5
+-$as_echo_n "checking for __gmpz_fdiv_qr in -lgmp3... " >&6; }
+-if test "${ac_cv_lib_gmp3___gmpz_fdiv_qr+set}" = set; then :
+-  $as_echo_n "(cached) " >&6
+-else
+-  ac_check_lib_save_LIBS=$LIBS
+-LIBS="-lgmp3  $LIBS"
+-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+-/* end confdefs.h.  */
+-
+-/* Override any GCC internal prototype to avoid an error.
+-   Use char because int might match the return type of a GCC
+-   builtin and then its argument prototype would still apply.  */
+-#ifdef __cplusplus
+-extern "C"
+-#endif
+-char __gmpz_fdiv_qr ();
+-int
+-main ()
+-{
+-return __gmpz_fdiv_qr ();
+-  ;
+-  return 0;
+-}
+-_ACEOF
+-if ac_fn_c_try_link "$LINENO"; then :
+-  ac_cv_lib_gmp3___gmpz_fdiv_qr=yes
+-else
+-  ac_cv_lib_gmp3___gmpz_fdiv_qr=no
+-fi
+-rm -f core conftest.err conftest.$ac_objext \
+-    conftest$ac_exeext conftest.$ac_ext
+-LIBS=$ac_check_lib_save_LIBS
+-fi
+-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: 
$ac_cv_lib_gmp3___gmpz_fdiv_qr" >&5
+-$as_echo "$ac_cv_lib_gmp3___gmpz_fdiv_qr" >&6; }
+-if test "x$ac_cv_lib_gmp3___gmpz_fdiv_qr" = x""yes; then :
+-  HaveLibGmp=YES; GMP_LIBS=gmp3
+-else
+-  HaveLibGmp=NO;  GMP_LIBS=
+-fi
+-
+-fi
++HaveLibGmp=NO;  GMP_LIBS=
+ 
+ 
+ case $target_os in
Index: patches/patch-rts_Linker_c
===================================================================
RCS file: patches/patch-rts_Linker_c
diff -N patches/patch-rts_Linker_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-rts_Linker_c  10 Oct 2012 12:11:02 -0000
@@ -0,0 +1,37 @@
+$OpenBSD$
+
+Workaround error: unknown symbol '__guard_local'
+
+--- rts/Linker.c.orig  Tue Oct  9 21:15:55 2012
++++ rts/Linker.c       Tue Oct  9 21:29:11 2012
+@@ -563,6 +563,14 @@ typedef struct _RtsSymbolVal {
+ #define RTS_DARWIN_ONLY_SYMBOLS
+ #endif
+ 
++#if defined(openbsd_HOST_OS)
++#define RTS_OPENBSD_ONLY_SYMBOLS                            \
++     SymE_NeedsProto(__guard_local)                         \
++     SymE_NeedsProto(__stack_smash_handler)
++#else
++#define RTS_OPENBSD_ONLY_SYMBOLS
++#endif
++
+ #ifndef SMP
+ # define MAIN_CAP_SYM SymI_HasProto(MainCapability)
+ #else
+@@ -1084,6 +1092,7 @@ RTS_POSIX_ONLY_SYMBOLS
+ RTS_MINGW_ONLY_SYMBOLS
+ RTS_CYGWIN_ONLY_SYMBOLS
+ RTS_DARWIN_ONLY_SYMBOLS
++RTS_OPENBSD_ONLY_SYMBOLS
+ RTS_LIBGCC_SYMBOLS
+ RTS_LIBFFI_SYMBOLS
+ #undef SymI_NeedsProto
+@@ -1119,6 +1128,7 @@ static RtsSymbolVal rtsSyms[] = {
+       RTS_MINGW_ONLY_SYMBOLS
+       RTS_CYGWIN_ONLY_SYMBOLS
+       RTS_DARWIN_ONLY_SYMBOLS
++      RTS_OPENBSD_ONLY_SYMBOLS
+       RTS_LIBGCC_SYMBOLS
+       RTS_LIBFFI_SYMBOLS
+ #if defined(darwin_HOST_OS) && defined(i386_HOST_ARCH)

Reply via email to