Opened 4 years ago

Closed 3 years ago

#8024 closed bug (fixed)

Dynamic linking not working on PowerPC Linux.

Reported by: erikd Owned by:
Priority: normal Milestone:
Component: Compiler Version: 7.7
Keywords: Cc: slyfox@…, ptrommler@…, pho@…
Operating System: Linux Architecture: powerpc
Type of failure: Building GHC failed Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s): D560
Wiki Page:

Description (last modified by erikd)

With dynamic linking enabled, the first binary compiled by the stage1 compiler (dll-split) crashes with an illegal instruction exception.

(gdb) bt
#0  0x0f3f2e24 in cr_str () from /home/erikd/Git/ghc-upstream/rts/dist/build/
#1  0x0f3de490 in stg_catchzh () from /home/erikd/Git/ghc-upstream/rts/dist/build/
#2  0x0f3cc01c in scheduleWaitThread () from /home/erikd/Git/ghc-upstream/rts/dist/build/
#3  0x0f3c63dc in rts_evalLazyIO () from /home/erikd/Git/ghc-upstream/rts/dist/build/
#4  0x0f3c8300 in hs_main () from /home/erikd/Git/ghc-upstream/rts/dist/build/
#5  0x10006ae4 in main ()

Disassmbling the function gives:

Dump of assembler code for function cr_str:
   0x0f3f2dec:  rlwimi  r1,r2,10,0,16
   0x0f3f2df0:  xoris   r2,r27,27237
   0x0f3f2df4:  ori     r20,r27,8293
   0x0f3f2df8:  xoris   r20,r19,25970
   0x0f3f2dfc:  oris    r4,r11,8448
   0x0f3f2e00:  .long 0xfffeae2c
   0x0f3f2e04:  .long 0xfffeae2c
   0x0f3f2e08:  .long 0xfffeae2c
   0x0f3f2e0c:  .long 0xfffeae2c
   0x0f3f2e10:  .long 0xfffeae2c
   0x0f3f2e14:  .long 0xfffeae2c
   0x0f3f2e18:  .long 0xfffeae2c
   0x0f3f2e1c:  .long 0xfffeae2c
   0x0f3f2e20:  .long 0xfffeae2c
=> 0x0f3f2e24:  .long 0xfffeae20
   0x0f3f2e28:  .long 0xfffeae20
   0x0f3f2e2c:  .long 0xfffeae20
   0x0f3f2e30:  .long 0xfffeae20

However function stg_catchzh() in rts/Exception.cmm does not call cr_str().

If I disable dynamic lbraries by adding powerpc-unknow-linux to NoSharedLibsPlatformList in mk/ then the compile builds.

Change History (12)

comment:1 Changed 4 years ago by erikd

Description: modified (diff)
Summary: Illegal instruction in cr_strDynamic linking not working on PowerPC Linux.

comment:2 Changed 4 years ago by erikd

difficulty: Unknown

Mentioned this to Duncan and he suggested this may might be fixed by changing -fpic to -fPIC. Need to research the difference.

Version 0, edited 4 years ago by erikd (next)

comment:3 Changed 4 years ago by slyfox

Cc: slyfox@… added

comment:4 Changed 4 years ago by slyfox

I see odd things happening on sparc and ia64 as well.

On sparc it looks like a wrongly resolved current module (seems to be PIC mis-handling).

comment:5 Changed 4 years ago by erikd

In mk/ tried changing

PIC = pic



ran the whole process from perl boot onwards and that didn't help. This was on ppc64.

Last edited 4 years ago by erikd (previous) (diff)

comment:6 Changed 4 years ago by trommler

Cc: ptrommler@… added

comment:7 Changed 3 years ago by PHO

Cc: pho@… added

comment:8 Changed 3 years ago by slyfox

The bug looks very much like SPARC's bug #8857 where compiler emitted one level more indirection, but assembler didn't generate proper relocations for it:

I wonder if it cures ppc32 for you.

comment:9 Changed 3 years ago by thomie

Status: newinfoneeded

comment:10 Changed 3 years ago by slyfox

Differential Rev(s): D560
Status: infoneededpatch

The problem happened to be in code emitting prologs for basic block entries (also got fixed by

Typically haskell function has single entry point (-fPIC -ddump-asm-native):

; PIC prolog
        bcl     20,31,1f
1:      mflr    %vI_nic
        lwz     %vI_nij, _nii-(1b)(%vI_nic)
        add     %vI_nic, %vI_nic, %vI_nij
; offset to LCTOC from nearest '1:'
.align 2
        .long   .LCTOC1-(1b)+0

But sometimes runtime needs to return back into a middle of haskell function (try/catch primitives?) and prolog gets emitted at each such point using the same LCTOC offset:

; PIC prolog
        bcl     20,31,1f
1:      mflr    %vI_nic ; REF 1
        lwz     %vI_nij, _nii-(1b)(%vI_nic)
        add     %vI_nic, %vI_nic, %vI_nij
; PIC prolog
        bcl     20,31,1f
1:      mflr    %vI_nic ; REF 2
        lwz     %vI_nij, _nii-(1b)(%vI_nic)
        add     %vI_nic, %vI_nic, %vI_nij
; offset to LCTOC from nearest '1:'
.align 2
        .long   .LCTOC1-(1b)+0

Here '_nii' contains offset to nearest '1:' label, not first one (as intended). It leads to miscomputation of LCTOC1 in function entry (around first '1:' which usually manifests in call to random location.

It is fixed by using simpler prolog (similar to what modern gcc emits nowadays):

        bcl     20,31,1f
1:      mflr    %vI_ny4
        addis   %vI_ny4, %vI_ny4, .LCTOC1-(1b)@ha
        addi    %vI_ny4, %vI_ny4, .LCTOC1-(1b)@l
        mr      30, %vI_ny4

And it is safe to duplicate.

comment:11 Changed 3 years ago by Sergei Trofimovich <siarheit@…>

In fa31e8f4a0f853848d96549a429083941877bf8d/ghc:

powerpc: fix and enable shared libraries by default on linux

And fix things all the way down to it. Namely:
    - remove 'r30' from free registers, it's an .LCTOC1 register
      for gcc. generated .plt stubs expect it to be initialised.
    - fix PicBase computation, which originally forgot to use 'tmp'
      reg in 'initializePicBase_ppc.fetchPC'
    - mark 'ForeighTarget's as implicitly using 'PicBase' register
      (see comment for details)
    - add 64-bit MO_Sub and test on alloclimit3/4 regtests
    - fix dynamic label offsets to match with .LCTOC1 offset

Signed-off-by: Sergei Trofimovich <>

Test Plan: validate passes equal amount of vanilla/dyn tests

Reviewers: simonmar, erikd, austin

Reviewed By: erikd, austin

Subscribers: carter, thomie

Differential Revision:

GHC Trac Issues: #8024, #9831

comment:12 Changed 3 years ago by slyfox

Resolution: fixed
Status: patchclosed
Note: See TracTickets for help on using tickets.