[project @ 2001-02-14 10:33:05 by simonmar]
authorsimonmar <unknown>
Wed, 14 Feb 2001 10:33:05 +0000 (10:33 +0000)
committersimonmar <unknown>
Wed, 14 Feb 2001 10:33:05 +0000 (10:33 +0000)
Fix for tail-calling on HP-UX, and a lengthy explanation, thanks to
Andy Bennet <andy_bennet@hp.com>.

ghc/includes/TailCalls.h

index fd0152e..8002451 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: TailCalls.h,v 1.6 2000/11/07 10:42:56 simonmar Exp $
+ * $Id: TailCalls.h,v 1.7 2001/02/14 10:33:05 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -98,13 +98,55 @@ register void *_procedure __asm__("$27");
 
 /* -----------------------------------------------------------------------------
    Tail calling on HP
+
+Description of HP's weird procedure linkage, many thanks to Andy Bennet
+<andy_bennett@hp.com>:
+
+I've been digging a little further into the problem of how HP-UX does
+dynamic procedure calls. My solution in the last e-mail inserting an extra
+'if' statement into the JMP_ I think is probably the best general solution I
+can come up with. There are still a few problems with it however: It wont
+work, if JMP_ ever has to call anything in a shared library, if this is
+likely to be required it'll need something more elaborate. It also wont work
+with PA-RISC 2.0 wide mode (64-bit) which uses a different format PLT.
+
+I had some feedback from someone in HP's compiler lab and the problem
+relates to the linker on HP-UX, not gcc as I first suspected. The reason the
+'hsc' executable works is most likely due to a change in 'ld's behaviour for
+performance reasons between your revision and mine.
+
+The major issue relating to this is shared libraries and how they are
+implented under HP-UX. The whole point of the Procedure Label Table (PLT) is
+to allow a function pointer to hold the address of the function and a
+pointer to the library's global data lookup table (DLT) used by position
+independent code (PIC). This makes the PLT absolutely essential for shared
+library calls. HP has two linker introduced assembly functions for dealing
+with dynamic calls, $$dyncall and $$dyncall_external. The former does a
+check to see if the address is a PLT pointer and dereferences if necessary
+or just calls the address otherwise; the latter skips the check and just
+does the indirect jump no matter what.
+
+Since $$dyncall_external runs faster due to its not having the test, the
+linker nowadays prefers to generate calls to that, rather than $$dyncall. It
+makes this decision based on the presence of any shared library. If it even
+smells an sl's existence at link time, it rigs the runtime system to
+generate PLT references for everything on the assumption that the result
+will be slightly more efficient. This is what is crashing GHC since the
+calls it is generating have no understanding of the procedure label proper.
+The only way to get real addresses is to link everything archive, including
+system libraries, at which point it assumes you probably are going to be
+using calls similar to GHC's (its rigged for HP's +ESfic compiler option)
+but uses $$dyncall if necessary to cope, just in case you aren't.
+
    -------------------------------------------------------------------------- */
 
 #ifdef hppa1_1_hp_hpux_TARGET
 
-#define JMP_(cont)                             \
-    do { void *_procedure = (void *)(cont);    \
-         goto *_procedure;                     \
+#define JMP_(cont)                              \
+    do { void *_procedure = (void *)(cont);     \
+         if (((int) _procedure) & 2)            \
+            _procedure = (void *)(*((int *) (_procedure - 2))); \
+         goto *_procedure;                      \
        } while(0)
 
 #endif /* hppa1_1_hp_hpux_TARGET */