[project @ 2005-01-14 22:12:54 by wolfgang]
authorwolfgang <unknown>
Fri, 14 Jan 2005 22:12:55 +0000 (22:12 +0000)
committerwolfgang <unknown>
Fri, 14 Jan 2005 22:12:55 +0000 (22:12 +0000)
When -dynamic is specified but -fPIC is not, generate code that works around
the ELF dynamic linker's misguided attempts to keep the main program unaware
of dynamic linking.

This involves generating indirect references and computed jumps for position
dependent code, too, and making all constant data sections writable in order
to persuade ld to not use "COPY" relocations.

Tested on powerpc-linux; in theory, it also applies to i386-linux, but other
parts of the PIC story are missing there.

Note that the writable-const-data hack could be improved a bit by
distinguishing between "really" constant data and "relocatable" constant data,
which would be a nice thing to do anyway.

ghc/compiler/nativeGen/PositionIndependentCode.hs
ghc/compiler/nativeGen/PprMach.hs

index a6a7b27..5b6dda8 100644 (file)
@@ -63,7 +63,7 @@ import MachRegs
 import MachInstrs
 import NCGMonad         ( NatM, getNewRegNat, getNewLabelNat )
 
-import CmdLineOpts      ( opt_PIC )
+import CmdLineOpts      ( opt_PIC, opt_Static )
 
 import Pretty
 import qualified Outputable
@@ -195,46 +195,30 @@ howToAccessLabel False lbl
     | opt_PIC && externallyVisibleCLabel lbl = AccessViaSymbolPtr
 howToAccessLabel _ _ = AccessDirectly
 
-#elif linux_TARGET_OS && powerpc_TARGET_ARCH
--- PowerPC Linux
---
--- PowerPC Linux is just plain broken.
--- While it's theoretically possible to use GOT offsets larger
--- than 16 bit, the standard crt*.o files don't, which leads to
--- linker errors as soon as the GOT size exceeds 16 bit.
--- Also, the assembler doesn't support @gotoff labels.
--- In order to be able to use a larger GOT, we circumvent the
--- entire GOT mechanism and do it ourselves (this is what GCC does).
-
--- In this scheme, we need to do _all data references_ (even refs
--- to static data) via a SymbolPtr when we are generating PIC.
--- Luckily, the PLT works as expected, so we can simply access
--- dynamically linked code via the PLT.
+#elif linux_TARGET_OS && powerpc64_TARGET_ARCH
+-- ELF PPC64 (powerpc64-linux), AIX, MacOS 9, BeOS/PPC
 
-howToAccessLabel _ _ | not opt_PIC = AccessDirectly
-howToAccessLabel True lbl
-    = if labelDynamic lbl then AccessViaStub
-                          else AccessDirectly
-howToAccessLabel False lbl
-    = AccessViaSymbolPtr
+howToAccessLabel True lbl = AccessDirectly -- actually, .label instead of label
+howToAccessLabel _ lbl = AccessViaSymbolPtr
 
 #elif linux_TARGET_OS
 -- ELF (Linux)
 --
+-- ELF tries to pretend to the main application code that dynamic linking does 
+-- not exist. While this may sound convenient, it tends to mess things up in
+-- very bad ways, so we have to be careful when we generate code for the main
+-- program (-dynamic but no -fPIC).
+--
 -- Indirect access is required for references to imported symbols
--- from position independent code.
--- It is always possible to access something indirectly,
--- even when it's not necessary.
-
--- For code, we can use a relative jump to a piece of
--- stub code instead (this allows lazy binding of imported symbols).
+-- from position independent code. It is also required from the main program
+-- when dynamic libraries containing Haskell code are used.
 
 howToAccessLabel isJump lbl
-        -- no PIC -> the dynamic linker does everything for us
-   | not opt_PIC = AccessDirectly
-        -- if it's not imported, we need no indirection
-        -- ("foo" will end up being accessed as "foo@GOTOFF")
-   | not (labelDynamic lbl) = AccessDirectly
+       -- no PIC -> the dynamic linker does everything for us;
+       --           if we don't dynamically link to Haskell code,
+       --           it actually manages to do so without messing thins up.
+    | not opt_PIC && opt_Static = AccessDirectly
+   
 #if !i386_TARGET_ARCH
 -- for Intel, we temporarily disable the use of the
 -- Procedure Linkage Table, because PLTs on intel require the
@@ -242,9 +226,35 @@ howToAccessLabel isJump lbl
 -- a jump through the PLT is made.
 -- TODO: make the i386 NCG ensure this before jumping to a
 --       CodeStub label, so we can remove this special case.
-   | isJump = AccessViaStub
+
+       -- As long as we're in a shared library ourselves,
+       -- we can use the plt.
+       -- NOTE: We might want to disable this, because this
+       --       prevents -fPIC code from being linked statically.
+    | isJump && labelDynamic lbl && opt_PIC = AccessViaStub
+
+       -- TODO: it would be OK to access non-Haskell code via a stub
+--  | isJump && labelDynamic lbl && not isHaskellCode lbl = AccessViaStub
+
+       -- Using code stubs for jumps from the main program to an entry
+       -- label in a dynamic library is deadly; this will cause the dynamic
+       -- linker to replace all references (even data references) to that
+       -- label by references to the stub, so we won't find our info tables
+       -- any more.
+#endif
+
+       -- A dynamic label needs to be accessed via a symbol pointer.
+       -- NOTE: It would be OK to jump to foreign code via a PLT stub.
+    | labelDynamic lbl = AccessViaSymbolPtr
+    
+#if powerpc_ARGET_ARCH
+       -- For PowerPC32 -fPIC, we have to access even static data
+       -- via a symbol pointer (see below for an explanation why
+       -- PowerPC32 Linux is especially broken).
+    | opt_PIC && not isJump = AccessViaSymbolPtr
 #endif
-   | otherwise = AccessViaSymbolPtr
+
+    | otherwise = AccessDirectly
 
 #else
 --
@@ -375,8 +385,22 @@ pprImportedSymbol importedLbl
 
 #elif powerpc_TARGET_ARCH && linux_TARGET_OS
 
--- For PowerPC linux, we don't do anything unless we're generating PIC.
-needImportedSymbols = opt_PIC
+-- PowerPC Linux
+--
+-- PowerPC Linux is just plain broken.
+-- While it's theoretically possible to use GOT offsets larger
+-- than 16 bit, the standard crt*.o files don't, which leads to
+-- linker errors as soon as the GOT size exceeds 16 bit.
+-- Also, the assembler doesn't support @gotoff labels.
+-- In order to be able to use a larger GOT, we circumvent the
+-- entire GOT mechanism and do it ourselves (this is what GCC does).
+
+-- In this scheme, we need to do _all data references_ (even refs
+-- to static data) via a SymbolPtr when we are generating PIC.
+
+-- We need to do this whenever we explicitly access something via
+-- a symbol pointer.
+needImportedSymbols = opt_PIC || not opt_Static
 
 -- If we're generating PIC, we need to create our own "fake GOT".
 
index 846a855..a807cc2 100644 (file)
@@ -34,7 +34,7 @@ import Pretty
 import FastString
 import qualified Outputable
 
-import CmdLineOpts      ( opt_PIC )
+import CmdLineOpts      ( opt_PIC, opt_Static )
 
 #if __GLASGOW_HASKELL__ >= 504
 import Data.Array.ST
@@ -512,6 +512,15 @@ pprAddr (AddrRegImm r1 imm) = hcat [ pprImm imm, char '(', pprReg r1, char ')' ]
 -- -----------------------------------------------------------------------------
 -- pprData: print a 'CmmStatic'
 
+#if defined(linux_TARGET_OS)
+#if defined(powerpc_TARGET_ARCH) || defined(i386_TARGET_ARCH)
+    -- Hack to make dynamic linking work
+pprSectionHeader ReadOnlyData
+    | not opt_PIC && not opt_Static
+    = pprSectionHeader Data
+#endif
+#endif
+
 pprSectionHeader Text
     = ptext
        IF_ARCH_alpha(SLIT("\t.text\n\t.align 3") {-word boundary-}