浏览代码

Fix shared library loading and unloading for Linux platforms. Shared library initialization and finalization are now called correctly at program startup for compile-time linked dynamic libraries on powerpc-/powerpc64-/arm-/i386- and x86_64-linux.

Every startup code must now provide an additional entry point called "_dynamic_start" that is set as new the entry point if the program links to a Pascal shared library. Its purpose is to set up an exit hook usually passed via a register, which should be called during program finalization if non-nil.

We use this additional entry point because this register only has meaningful content when there are any compile-time linked shared libraries, otherwise it often contains random garbage. The difference between the _dynamic_start and the original code is minimal; actually in all implementations the _dynamic_start code passes on control to the old startup code, so we use an additional entry point instead of an additional startup file.

Detailed changes and fixes list:
compiler:
  always link to the dynamic loader (ld.so) when compiling shared libraries. Fixes crashes in the loader during shared library finalization on some Linuxes
  remove additional ENTRY() section in arm linker script
  select either _dynamic_start or _start as entry point depending on whether this is a static or dynamic executable
powerpc*:
  do not set System.isLibrary in startup code, it will be set during library initialization anyway
  trap in case of reaching code locations that should not be reached instead of looping (possibly endlessly)
powerpc:
  register atexit() function pointer if supplied to the executable and call it during shutdown
  correctly set argc/argv/envp in shared library code and return correctly to the caller after initialization
  pass on exitcode in shared library haltproc
  use the more recent exit_group system call if available for shutdown
powerpc64
  fix .ptrgl stub, do not set the environment register to the value of the GOT entry in the function descriptor
arm
  do not set System.isLibrary in startup code, it will be set during library initialization anyway
  reload exitcode to pass to shutdown
mips,mipsel,sparc
  added stubs to allow correct linking

git-svn-id: trunk@19036 -
tom_at_work 14 年之前
父节点
当前提交
9ce34c63c9

+ 15 - 3
compiler/systems/t_linux.pas

@@ -330,6 +330,7 @@ Var
   s,s1,s2      : TCmdStr;
   s,s1,s2      : TCmdStr;
   found1,
   found1,
   found2       : boolean;
   found2       : boolean;
+  linksToSharedLibFiles : boolean;
 begin
 begin
   result:=False;
   result:=False;
 { set special options for some targets }
 { set special options for some targets }
@@ -432,6 +433,13 @@ begin
 
 
       { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
       { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
         here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
         here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
+      if (isdll) then
+       begin
+         Add('INPUT(');
+         Add(info.DynamicLinker);
+         Add(')');
+       end;
+      linksToSharedLibFiles := not SharedLibFiles.Empty;
 
 
       if not SharedLibFiles.Empty then
       if not SharedLibFiles.Empty then
        begin
        begin
@@ -497,8 +505,13 @@ begin
           end;
           end;
        end;
        end;
 
 
-      {Entry point.}
-      add('ENTRY(_start)');
+      {Entry point. Only needed for executables, set on the linker command line for
+       shared libraries. }
+      if (not isdll) then
+       if (linksToSharedLibFiles and not linklibc) then
+        add('ENTRY(_dynamic_start)')
+       else
+        add('ENTRY(_start)');
 
 
 {$ifdef x86_64}
 {$ifdef x86_64}
 {$define LINKERSCRIPT_INCLUDED}
 {$define LINKERSCRIPT_INCLUDED}
@@ -641,7 +654,6 @@ begin
           add('OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",');
           add('OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",');
           add('	      "elf32-littlearm")');
           add('	      "elf32-littlearm")');
           add('OUTPUT_ARCH(arm)');
           add('OUTPUT_ARCH(arm)');
-          add('ENTRY(_start)');
           add('SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");');
           add('SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");');
           add('SECTIONS');
           add('SECTIONS');
           add('{');
           add('{');

+ 21 - 6
rtl/linux/arm/dllprt0.as

@@ -1,3 +1,18 @@
+/*
+ * This file is part of the Free Pascal run time library.
+ * Copyright (c) 2011 by Thomas Schatzl,
+ * member of the Free Pascal development team.
+ *
+ * Startup code for shared libraries, ARM version.
+ *
+ * See the file COPYING.FPC, included in this distribution,
+ * for details about the copyright.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
 .file   "dllprt0.as"
 .file   "dllprt0.as"
 .text
 .text
         .globl  _startlib
         .globl  _startlib
@@ -24,10 +39,6 @@ FPC_SHARED_LIB_START:
         ldr ip, =__stklen
         ldr ip, =__stklen
         str sp, [ip]
         str sp, [ip]
 
 
-        ldr ip, =TC_SYSTEM_ISLIBRARY
-        mov a1, #1
-        str a1, [ip]
-
         /* call main and exit normally */
         /* call main and exit normally */
         bl PASCALMAIN
         bl PASCALMAIN
         ldmdb fp, {fp, sp, pc}
         ldmdb fp, {fp, sp, pc}
@@ -35,14 +46,18 @@ FPC_SHARED_LIB_START:
         .globl  _haltproc
         .globl  _haltproc
         .type   _haltproc,#function
         .type   _haltproc,#function
 _haltproc:
 _haltproc:
-        /* r0 contains exitcode */
+        /* reload exitcode */
+        ldr r0,=operatingsystem_result
+        ldr r0,[r0]
         swi 0x900001
         swi 0x900001
         b _haltproc
         b _haltproc
 
 
         .globl  _haltproc_eabi
         .globl  _haltproc_eabi
         .type   _haltproc_eabi,#function
         .type   _haltproc_eabi,#function
 _haltproc_eabi:
 _haltproc_eabi:
-        /* r0 contains exitcode */
+        /* reload exitcode */
+        ldr r0,=operatingsystem_result
+        ldr r0,[r0]
         mov r7,#248
         mov r7,#248
         swi 0x0
         swi 0x0
         b _haltproc_eabi
         b _haltproc_eabi

+ 21 - 3
rtl/linux/arm/prt0.as

@@ -41,6 +41,14 @@
 					NULL
 					NULL
 */
 */
 
 
+	.text
+	.globl _dynamic_start
+	.type _dynamic_start,#function
+_dynamic_start:
+         ldr ip,=__dl_fini
+         str a1,[ip]
+         b _start
+
 	.text
 	.text
 	.globl _start
 	.globl _start
 	.type _start,#function
 	.type _start,#function
@@ -81,11 +89,20 @@ _haltproc:
 	.globl  _haltproc_eabi
 	.globl  _haltproc_eabi
         .type   _haltproc_eabi,#function
         .type   _haltproc_eabi,#function
 _haltproc_eabi:
 _haltproc_eabi:
+        ldr r0,=__dl_fini
+        ldr r0,[r0]
+        cmp r0,#0
+
+        /* only branch if not equal zero */
+        movne lr,pc
+        bxne  r0     /* we require armv5 anyway, so use bx here */
+
+.Lloop:
         ldr r0,=operatingsystem_result
         ldr r0,=operatingsystem_result
-        ldrb r0,[r0]
-        mov r7,#248
+        ldr r0,[r0]
+        mov r7,#248  /* exit group call */
 	swi 0x0
 	swi 0x0
-	b _haltproc_eabi
+	b .Lloop
 
 
 	/* Define a symbol for the first piece of initialized data.  */
 	/* Define a symbol for the first piece of initialized data.  */
 	.data
 	.data
@@ -96,6 +113,7 @@ __data_start:
 	data_start = __data_start
 	data_start = __data_start
 
 
 .bss
 .bss
+        .comm __dl_fini,4
         .comm __stkptr,4
         .comm __stkptr,4
 
 
         .comm operatingsystem_parameter_envp,4
         .comm operatingsystem_parameter_envp,4

+ 20 - 7
rtl/linux/i386/si_prc.inc

@@ -41,7 +41,7 @@ procedure PASCALMAIN; external name 'PASCALMAIN';
  ******************************************************************************}
  ******************************************************************************}
 
 
 var
 var
-  dlexitproc: pointer;
+  dlexitproc : pointer;
 
 
 {$ifdef FPC_PIC}
 {$ifdef FPC_PIC}
 function fpc_geteipasebxlocal : pointer; [external name 'fpc_geteipasebx'];
 function fpc_geteipasebxlocal : pointer; [external name 'fpc_geteipasebx'];
@@ -60,12 +60,9 @@ asm
   {$ifdef FPC_PIC}
   {$ifdef FPC_PIC}
         pushl %ebx
         pushl %ebx
         pushl %ecx
         pushl %ecx
-	
-	call fpc_geteipasebxlocal
-        addl  $_GLOBAL_OFFSET_TABLE_,%ebx
 
 
-	movl  dlexitproc@GOT(%ebx),%ecx
-	movl  %edx,(%ecx)
+        call fpc_geteipasebxlocal
+        addl  $_GLOBAL_OFFSET_TABLE_,%ebx
 
 
 	movl  operatingsystem_parameter_envp@GOT(%ebx),%ecx
 	movl  operatingsystem_parameter_envp@GOT(%ebx),%ecx
 	movl  %eax,(%ecx)
 	movl  %eax,(%ecx)
@@ -78,7 +75,6 @@ asm
 	popl  %ebx
 	popl  %ebx
 	movl  %ebx,(%edx)
 	movl  %ebx,(%edx)
   {$else FPC_PIC}
   {$else FPC_PIC}
-  	movl  %edx, dlexitproc
   	movl  %eax,operatingsystem_parameter_envp
   	movl  %eax,operatingsystem_parameter_envp
   	movl  %ecx,operatingsystem_parameter_argc
   	movl  %ecx,operatingsystem_parameter_argc
   	movl  %ebx,operatingsystem_parameter_argv
   	movl  %ebx,operatingsystem_parameter_argv
@@ -103,6 +99,23 @@ asm
   call    PASCALMAIN
   call    PASCALMAIN
 end;
 end;
 
 
+procedure _FPC_dynamic_proc_start; assembler; nostackframe; public name '_dynamic_start';
+asm
+  {$ifdef FPC_PIC}
+  pushl %ebx
+  call fpc_geteipasebxlocal
+  addl  $_GLOBAL_OFFSET_TABLE_,%ebx
+
+  movl  dlexitproc@GOT(%ebx),%ebx
+  movl  %edx,(%ebx)
+  popl  %ebx
+  {$else}
+  movl  %edx, dlexitproc
+  {$endif}
+  jmp _FPC_proc_start
+end;
+
+
 procedure _FPC_proc_haltproc; assembler; nostackframe; public name '_haltproc';
 procedure _FPC_proc_haltproc; assembler; nostackframe; public name '_haltproc';
 asm
 asm
 
 

+ 10 - 0
rtl/linux/mips/prt0.as

@@ -13,6 +13,13 @@
 */
 */
 
 
 	.section ".text"
 	.section ".text"
+	.align 4
+	.global _dynamic_start
+	.type _dynamic_start,#function
+_dynamic_start:
+        /* TODO: need to set __dl_fini here */
+       b _start
+
 	.align 4
 	.align 4
 	.global _start
 	.global _start
 	.type _start,#function
 	.type _start,#function
@@ -77,6 +84,8 @@ _start:
 .globl  _haltproc
 .globl  _haltproc
 .type   _haltproc,@function
 .type   _haltproc,@function
 _haltproc:
 _haltproc:
+        /* TODO: need to check whether __dl_fini is non-zero and call the function pointer in case */
+
         li      v0,4001
         li      v0,4001
         lui     a0,0x0
         lui     a0,0x0
         lw      a0,0(a0)
         lw      a0,0(a0)
@@ -87,6 +96,7 @@ _haltproc:
 	.size _start, .-_start
 	.size _start, .-_start
 
 
         .comm __stkptr,4
         .comm __stkptr,4
+        .comm __dl_fini,4
 
 
         .comm operatingsystem_parameter_envp,4
         .comm operatingsystem_parameter_envp,4
         .comm operatingsystem_parameter_argc,4
         .comm operatingsystem_parameter_argc,4

+ 15 - 0
rtl/linux/mipsel/prt0.as

@@ -14,6 +14,17 @@
         .set noat
         .set noat
 
 
 	.section ".text"
 	.section ".text"
+
+	.align 4
+	.global _dynamic_start
+	.type _dynamic_start,@function
+_dynamic_start:
+        /* TODO: check whether this code is correct */
+        lui     $a2,%hi(__dl_fini)
+        sw      $v0,%lo(__dl_fini)($a2)
+        b _start
+
+
 	.align 4
 	.align 4
 	.global _start
 	.global _start
 	.type _start,@function
 	.type _start,@function
@@ -29,6 +40,7 @@
     sp ($29)	The stack contains the arguments and environment:
     sp ($29)	The stack contains the arguments and environment:
  		0(%esp)			argc
  		0(%esp)			argc
  		4(%esp)			argv[0]
  		4(%esp)			argv[0]
+
  		...
  		...
  		(4*argc)(%esp)		NULL
  		(4*argc)(%esp)		NULL
  		(4*(argc+1))(%esp)	envp[0]
  		(4*(argc+1))(%esp)	envp[0]
@@ -75,6 +87,8 @@ _start:
 .globl  _haltproc
 .globl  _haltproc
 .type   _haltproc,@function
 .type   _haltproc,@function
 _haltproc:
 _haltproc:
+        /* TODO: need to check whether __dl_fini is non-zero and call the function pointer in case */
+
         li      $v0,4001
         li      $v0,4001
         lui     $a0,0x0
         lui     $a0,0x0
         lw      $a0,0($a0)
         lw      $a0,0($a0)
@@ -85,6 +99,7 @@ _haltproc:
 	.size _start, .-_start
 	.size _start, .-_start
 
 
         .comm __stkptr,4
         .comm __stkptr,4
+        .comm __dl_fini,4
 
 
         .comm operatingsystem_parameter_envp,4
         .comm operatingsystem_parameter_envp,4
         .comm operatingsystem_parameter_argc,4
         .comm operatingsystem_parameter_argc,4

+ 22 - 24
rtl/linux/powerpc/dllprt0.as

@@ -20,42 +20,32 @@
     .section ".text"
     .section ".text"
     .globl FPC_SHARED_LIB_START
     .globl FPC_SHARED_LIB_START
     .type  FPC_SHARED_LIB_START,@function
     .type  FPC_SHARED_LIB_START,@function
-
-    .globl  _start
-_start:
 FPC_SHARED_LIB_START:
 FPC_SHARED_LIB_START:
-    mr      26,1
-    /* Set up an initial stack frame, and clear the LR.  */
-    clrrwi   1,1,4
-    li       0,0
-    stwu     1,-16(1)
-    mtlr     0
-    stw      0,0(1)
-    lwz      3,0(26)       /* get argc */
+    mflr     0
+    stw      0,4(1)
+    stwu     1,-32(1)
+
+    /* store argument count (in r3)*/
     lis     11,operatingsystem_parameter_argc@ha
     lis     11,operatingsystem_parameter_argc@ha
     stw      3,operatingsystem_parameter_argc@l(11);
     stw      3,operatingsystem_parameter_argc@l(11);
-
-    addi     4,26,4        /* get argv */
+    /* store argument vector (in r4) */
     lis     11,operatingsystem_parameter_argv@ha
     lis     11,operatingsystem_parameter_argv@ha
     stw      4,operatingsystem_parameter_argv@l(11);
     stw      4,operatingsystem_parameter_argv@l(11);
-
-    addi    27,3,1        /* calculate argc + 1 into r27 */
-    slwi    27,27,2       /* calculate (argc + 1) * sizeof(char *) into r27 */
-    add      5,4,27       /* get address of env[0] */
+    /* store environment pointer (in r5) */
     lis     11,operatingsystem_parameter_envp@ha
     lis     11,operatingsystem_parameter_envp@ha
     stw      5,operatingsystem_parameter_envp@l(11);
     stw      5,operatingsystem_parameter_envp@l(11);
 
 
     lis     11,__stkptr@ha
     lis     11,__stkptr@ha
     stw      1,__stkptr@l(11);
     stw      1,__stkptr@l(11);
-    /* update library flag in RTL */
-    lis	   11,operatingsystem_islibrary@ha
-    li      6, 1
-    stb     6, operatingsystem_islibrary@l(11)
-
 
 
+    /* call library initialization */
     bl         PASCALMAIN
     bl         PASCALMAIN
 
 
-    b          _haltproc
+    /* return to the caller */
+    addi     1,1,32
+    lwz      0,4(1)
+    mtlr     0
+    blr
 
 
     .globl  _haltproc
     .globl  _haltproc
     .globl  FPC_SHARED_LIB_EXIT
     .globl  FPC_SHARED_LIB_EXIT
@@ -63,9 +53,17 @@ FPC_SHARED_LIB_START:
      .type   _haltproc,@function
      .type   _haltproc,@function
 FPC_SHARED_LIB_EXIT:
 FPC_SHARED_LIB_EXIT:
 _haltproc:
 _haltproc:
+    lis     11,operatingsystem_result@ha
+    lwz      3,operatingsystem_result@l(3)
+    li       0,234        /* exit group call */
+    sc
+
+    lis     11,operatingsystem_result@ha
+    lwz      3,operatingsystem_result@l(3)
     li       0,1          /* exit call */
     li       0,1          /* exit call */
     sc
     sc
-    b          _haltproc
+    /* we should not reach here. Crash horribly */
+    trap
 
 
 /* Define a symbol for the first piece of initialized data.  */
 /* Define a symbol for the first piece of initialized data.  */
     .section ".data"
     .section ".data"

+ 57 - 18
rtl/linux/powerpc/prt0.as

@@ -1,22 +1,32 @@
-/* Startup code for programs linked with GNU libc.
-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
+/*
+ * This file is part of the Free Pascal run time library.
+ * Copyright (c) 2011 by Thomas Schatzl,
+ * member of the Free Pascal development team.
+ *
+ * Startup code for normal programs, PowerPC version.
+ *
+ * See the file COPYING.FPC, included in this distribution,
+ * for details about the copyright.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
 
 
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
+/*
+ * Main program entry point for dynamic executables.
+ */
+    .section ".text"
+    .globl  _dynamic_start
+_dynamic_start:
+    lis     11,__dl_fini@ha
+    stw      7,__dl_fini@l(11)
 
 
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+    b _start
 
 
+/*
+ * Main program entry point for static executables.
+ */
     .section ".text"
     .section ".text"
     .globl  _start
     .globl  _start
 _start:
 _start:
@@ -27,6 +37,7 @@ _start:
     stwu     1,-16(1)
     stwu     1,-16(1)
     mtlr     0
     mtlr     0
     stw      0,0(1)
     stw      0,0(1)
+
     lwz      3,0(26)       /* get argc */
     lwz      3,0(26)       /* get argc */
     lis     11,operatingsystem_parameter_argc@ha
     lis     11,operatingsystem_parameter_argc@ha
     stw      3,operatingsystem_parameter_argc@l(11);
     stw      3,operatingsystem_parameter_argc@l(11);
@@ -46,14 +57,36 @@ _start:
 
 
     bl         PASCALMAIN
     bl         PASCALMAIN
 
 
-    b          _haltproc
+    /* we should not reach here. Crash horribly */
+    trap
 
 
     .globl  _haltproc
     .globl  _haltproc
     .type   _haltproc,@function
     .type   _haltproc,@function
 _haltproc:
 _haltproc:
+
+    lis     11,__dl_fini@ha
+    lwz     11,__dl_fini@l(11)
+
+    cmpwi   11, 0
+    beq     .LNoDlFiniCall
+
+    mtctr   11
+    bctrl
+
+.LNoDlFiniCall:
+
+    lis     11,operatingsystem_result@ha
+    lwz      3,operatingsystem_result@l(11)
+    li       0,234        /* exit group call */
+    sc
+
+    lis     11,operatingsystem_result@ha
+    lwz      3,operatingsystem_result@l(11)
     li       0,1          /* exit call */
     li       0,1          /* exit call */
     sc
     sc
-    b          _haltproc
+    /* we should not reach here. Crash horribly */
+    trap
+
 
 
 /* Define a symbol for the first piece of initialized data.  */
 /* Define a symbol for the first piece of initialized data.  */
     .section ".data"
     .section ".data"
@@ -63,6 +96,12 @@ data_start:
 
 
     .section ".bss"
     .section ".bss"
 
 
+    .type __dl_fini, @object
+    .size __dl_fini, 4
+    .global __dl_fini
+__dl_fini:
+    .skip 4
+
     .type __stkptr, @object
     .type __stkptr, @object
     .size __stkptr, 4
     .size __stkptr, 4
     .global __stkptr
     .global __stkptr

+ 15 - 12
rtl/linux/powerpc64/dllprt0.as

@@ -3,7 +3,7 @@
  * Copyright (c) 2005 by Thomas Schatzl,
  * Copyright (c) 2005 by Thomas Schatzl,
  * member of the Free Pascal development team.
  * member of the Free Pascal development team.
  *
  *
- * Startup code for normal programs, PowerPC64 version.
+ * Startup code for shared libraries, PowerPC64 version.
  *
  *
  * See the file COPYING.FPC, included in this distribution,
  * See the file COPYING.FPC, included in this distribution,
  * for details about the copyright.
  * for details about the copyright.
@@ -56,7 +56,7 @@
     std     2, 40(1)
     std     2, 40(1)
     mtctr   0
     mtctr   0
     ld      2, 8(11)
     ld      2, 8(11)
-    ld      11, 8(11)
+    ld      11, 16(11)
     bctr
     bctr
 .long 0
 .long 0
 .byte 0, 12, 128, 0, 0, 0, 0, 0
 .byte 0, 12, 128, 0, 0, 0, 0, 0
@@ -322,31 +322,29 @@ _restvr_31: addi r12,r0,-16
 
 
 /*
 /*
  * Main program entry point label (function), called by the loader
  * Main program entry point label (function), called by the loader
+ *
+ * The document "64-bit PowerPC ELF Application Binary Interface Supplement 1.9"
+ * pg. 24f specifies the register contents.
  */
  */
 FUNCTION_PROLOG FPC_SHARED_LIB_START
 FUNCTION_PROLOG FPC_SHARED_LIB_START
-
     mflr    0
     mflr    0
     std     0, 16(1)        /* save LR */
     std     0, 16(1)        /* save LR */
     stdu    1, -144(1)      /* save back chain, make frame */
     stdu    1, -144(1)      /* save back chain, make frame */
 
 
-    /* store argument count (in r3?)*/
+    /* store argument count (in r3)*/
     LOAD_64BIT_VAL 10, operatingsystem_parameter_argc
     LOAD_64BIT_VAL 10, operatingsystem_parameter_argc
     stw     3, 0(10)
     stw     3, 0(10)
-    /* store argument vector (in r4?) */
+    /* store argument vector (in r4) */
     LOAD_64BIT_VAL 10, operatingsystem_parameter_argv
     LOAD_64BIT_VAL 10, operatingsystem_parameter_argv
     std     4, 0(10)
     std     4, 0(10)
-    /* store environment pointer (in r5?) */
+    /* store environment pointer (in r5) */
     LOAD_64BIT_VAL 10, operatingsystem_parameter_envp
     LOAD_64BIT_VAL 10, operatingsystem_parameter_envp
     std     5, 0(10)
     std     5, 0(10)
 
 
-    /* update library flag in RTL */
-    LOAD_64BIT_VAL 8, operatingsystem_islibrary
-    li      6, 1
-    stb     6, 0(8)
-
     LOAD_64BIT_VAL 8, __stkptr
     LOAD_64BIT_VAL 8, __stkptr
     std     1,0(8)
     std     1,0(8)
 
 
+    /* call library initialization */
     bl      PASCALMAIN
     bl      PASCALMAIN
     nop
     nop
 
 
@@ -355,6 +353,8 @@ FUNCTION_PROLOG FPC_SHARED_LIB_START
     ld      0,16(1)   /* prepare for method return */
     ld      0,16(1)   /* prepare for method return */
     mtlr    0
     mtlr    0
     blr
     blr
+.long 0
+.byte 0, 12, 64, 0, 0, 0, 0, 0
 
 
 /* this routine is only called when the halt() routine of the RTL embedded in
 /* this routine is only called when the halt() routine of the RTL embedded in
    the shared library is called */
    the shared library is called */
@@ -370,7 +370,10 @@ FUNCTION_PROLOG FPC_SHARED_LIB_EXIT
     lwz     3, 0(3)
     lwz     3, 0(3)
     li      0, 1
     li      0, 1
     sc
     sc
-    b       .FPC_SHARED_LIB_EXIT
+    /* we should not reach here. Crash horribly */
+    trap
+.long 0
+.byte 0, 12, 64, 0, 0, 0, 0, 0
 
 
     /* Define a symbol for the first piece of initialized data.  */
     /* Define a symbol for the first piece of initialized data.  */
     .section ".data"
     .section ".data"

+ 76 - 27
rtl/linux/powerpc64/prt0.as

@@ -56,7 +56,7 @@
     std     2, 40(1)
     std     2, 40(1)
     mtctr   0
     mtctr   0
     ld      2, 8(11)
     ld      2, 8(11)
-    ld      11, 8(11)
+    ld      11, 16(11)
     bctr
     bctr
 .long 0
 .long 0
 .byte 0, 12, 128, 0, 0, 0, 0, 0
 .byte 0, 12, 128, 0, 0, 0, 0, 0
@@ -321,54 +321,97 @@ _restvr_31: addi r12,r0,-16
 */
 */
 
 
 /*
 /*
- * Main program entry point label (function), called by the loader
+ * Main program entry point for dynamic executables.
+ *
+ * r7 contains the function pointer that needs to be registered for calling at exit.
  */
  */
-FUNCTION_PROLOG _start
+FUNCTION_PROLOG _dynamic_start
+  LOAD_64BIT_VAL 11, __dl_fini
+  std      7,0(11)
+  LOAD_64BIT_VAL 11, _start
+  /* do not bother loading the actual function address of _start. We can directly jump to it */
+  /* set up GOT pointer from original start function */
+  ld       2,8(11)
+  /* and environment pointer */
+  ld      11,16(11)
+  b       _start
+.long 0
+.byte 0, 12, 64, 0, 0, 0, 0, 0
 
 
-    mr   26, 1            /* save stack pointer */
+/*
+ * Main program entry point for static executables
+ *
+ * The document "64-bit PowerPC ELF Application Binary Interface Supplement 1.9"
+ * pg. 24f specifies that argc/argv/envp are passed in registers r3/r4/r5 respectively,
+ * but that does not seem to be the case.
+ *
+ * However the stack layout and contents are the same as for other platforms, so
+ * use this.
+ */
+FUNCTION_PROLOG _start
+    mr     26,1            /* save stack pointer */
     /* Set up an initial stack frame, and clear the LR */
     /* Set up an initial stack frame, and clear the LR */
-    clrrdi  1, 1, 5       /* align r1 */
-    li      0, 0
+    clrrdi  1,1,5          /* align r1 */
+    li      0,0
     stdu    1,-128(1)
     stdu    1,-128(1)
     mtlr    0
     mtlr    0
-    std     0, 0(1)       /* r1 = pointer to NULL value */
+    std     0,0(1)        /* r1 = pointer to NULL value */
 
 
     /* store argument count (= 0(r1) )*/
     /* store argument count (= 0(r1) )*/
-    ld      3, 0(26)
-    LOAD_64BIT_VAL 10, operatingsystem_parameter_argc
-    stw     3, 0(10)
+    ld      3,0(26)
+    LOAD_64BIT_VAL 10,operatingsystem_parameter_argc
+    stw     3,0(10)
     /* calculate argument vector address and store (= 8(r1) + 8 ) */
     /* calculate argument vector address and store (= 8(r1) + 8 ) */
-    addi    4, 26, 8
-    LOAD_64BIT_VAL 10, operatingsystem_parameter_argv
-    std     4, 0(10)
+    addi    4,26,8
+    LOAD_64BIT_VAL 10,operatingsystem_parameter_argv
+    std     4,0(10)
     /* store environment pointer (= argv + (argc+1)* 8 ) */
     /* store environment pointer (= argv + (argc+1)* 8 ) */
-    addi    5, 3, 1
-    sldi    5, 5, 3
-    add     5, 4, 5
+    addi    5,3,1
+    sldi    5,5,3
+    add     5,4,5
     LOAD_64BIT_VAL 10, operatingsystem_parameter_envp
     LOAD_64BIT_VAL 10, operatingsystem_parameter_envp
-    std     5, 0(10)
+    std     5,0(10)
 
 
-    LOAD_64BIT_VAL 8, __stkptr
+    LOAD_64BIT_VAL 8,__stkptr
     std     1,0(8)
     std     1,0(8)
 
 
     bl      PASCALMAIN
     bl      PASCALMAIN
     nop
     nop
 
 
-    /* directly jump to exit procedure, not via the function pointer */
-    b       ._haltproc
+    /* we should not reach here. Crash horribly */
+    trap
 
 
 FUNCTION_PROLOG _haltproc
 FUNCTION_PROLOG _haltproc
-    /* exit group call */
+    mflr  0
+    std   0,16(1)
+    stdu  1,-144(1)
+
+    LOAD_64BIT_VAL 11,__dl_fini
+    ld    11,0(11)
+    cmpdi 11,0
+    beq .LNoCallDlFini
+
+    bl .ptrgl
+    ld      2,40(1)
+
+.LNoCallDlFini:
+
     LOAD_64BIT_VAL 3, operatingsystem_result
     LOAD_64BIT_VAL 3, operatingsystem_result
-    lwz     3, 0(3)
-    li      0, 234
+    lwz     3,0(3)
+    /* exit group call */
+    li      0,234
     sc
     sc
-    /* exit call */
+
     LOAD_64BIT_VAL 3, operatingsystem_result
     LOAD_64BIT_VAL 3, operatingsystem_result
-    lwz     3, 0(3)
-    li      0, 1
+    lwz     3,0(3)
+    /* exit call */
+    li      0,1
     sc
     sc
-    b       ._haltproc
+    /* we should not reach here. Crash horribly */
+    trap
+    /* do not bother cleaning up the stack frame, we should not reach here */
+.long 0
+.byte 0, 12, 64, 0, 0, 0, 0, 0
 
 
     /* Define a symbol for the first piece of initialized data.  */
     /* Define a symbol for the first piece of initialized data.  */
     .section ".data"
     .section ".data"
@@ -384,6 +427,12 @@ data_start:
 __stkptr:
 __stkptr:
     .skip 8
     .skip 8
 
 
+    .type __dl_fini, @object
+    .size __dl_fini, 8
+    .global __dl_fini
+__dl_fini:
+    .skip 8
+
     .type operatingsystem_parameters, @object
     .type operatingsystem_parameters, @object
     .size operatingsystem_parameters, 24
     .size operatingsystem_parameters, 24
 operatingsystem_parameters:
 operatingsystem_parameters:

+ 15 - 2
rtl/linux/sparc/prt0.as

@@ -19,6 +19,14 @@
    02111-1307 USA.  */
    02111-1307 USA.  */
 
 
 	.section ".text"
 	.section ".text"
+
+	.align 4
+	.global _dynamic_start
+	.type _dynamic_start,#function
+_dynamic_start:
+        /* TODO: need to set __dl_fini here */
+        b _start
+
 	.align 4
 	.align 4
 	.global _start
 	.global _start
 	.type _start,#function
 	.type _start,#function
@@ -49,7 +57,7 @@ _start:
 	or	%o1,%lo(operatingsystem_parameter_envp),%o1
 	or	%o1,%lo(operatingsystem_parameter_envp),%o1
 	st	%o2, [%o1]
 	st	%o2, [%o1]
 
 
-    /* Save initial stackpointer */
+        /* Save initial stackpointer */
 	sethi	%hi(__stkptr),%o1
 	sethi	%hi(__stkptr),%o1
 	or	%o1,%lo(__stkptr),%o1
 	or	%o1,%lo(__stkptr),%o1
 	st	%sp, [%o1]
 	st	%sp, [%o1]
@@ -57,11 +65,15 @@ _start:
   	/* Call the user program entry point.  */
   	/* Call the user program entry point.  */
   	call	PASCALMAIN
   	call	PASCALMAIN
   	nop
   	nop
+	/* Die very horribly if main returns.  */
+	unimp
 
 
 .globl  _haltproc
 .globl  _haltproc
 .type   _haltproc,@function
 .type   _haltproc,@function
 _haltproc:
 _haltproc:
-	mov	188, %g1			/* "exit_group" system call */
+        /* TODO: need to check whether __dl_fini is non-zero and call the function pointer in case */
+
+	mov	188, %g1		/* "exit_group" system call */
 	ta	0x10			/* dot the system call */
 	ta	0x10			/* dot the system call */
 	nop				/* delay slot */
 	nop				/* delay slot */
 	/* Die very horribly if exit returns.  */
 	/* Die very horribly if exit returns.  */
@@ -70,6 +82,7 @@ _haltproc:
 	.size _start, .-_start
 	.size _start, .-_start
 
 
         .comm __stkptr,4
         .comm __stkptr,4
+        .comm __dl_fini,4
 
 
         .comm operatingsystem_parameter_envp,4
         .comm operatingsystem_parameter_envp,4
         .comm operatingsystem_parameter_argc,4
         .comm operatingsystem_parameter_argc,4

+ 0 - 2
rtl/linux/x86_64/dllprt0.as

@@ -44,8 +44,6 @@ FPC_SHARED_LIB_START:
 	.globl _start
 	.globl _start
 	.type _start,@function
 	.type _start,@function
 _startlib:
 _startlib:
-#       movq %rdx,%r9                 /* Address of the shared library termination
-#               	                 function.  */
 	pushq	 %rbx
 	pushq	 %rbx
         movq     operatingsystem_parameter_argc@GOTPCREL(%rip),%rbx
         movq     operatingsystem_parameter_argc@GOTPCREL(%rip),%rbx
         movq     %rdi,(%rbx)
         movq     %rdi,(%rbx)

+ 20 - 4
rtl/linux/x86_64/prt0.as

@@ -16,8 +16,10 @@
 #
 #
 
 
 /* This is the canonical entry point, usually the first thing in the text
 /* This is the canonical entry point, usually the first thing in the text
-   segment.  The SVR4/i386 ABI (pages 3-31, 3-32) says that when the entry
-   point runs, most registers' values are unspecified, except for:
+   segment.  The document "System V Application Binary Interface AMD64
+   Architecture Processor Supplement Version 0.99.5" pg. 30 defines that
+   the entry point runs, most registers' values are unspecified, except
+   for:
 
 
    %rdx		Contains a function pointer to be registered with `atexit'.
    %rdx		Contains a function pointer to be registered with `atexit'.
 		This is how the dynamic linker arranges to have DT_FINI
 		This is how the dynamic linker arranges to have DT_FINI
@@ -34,12 +36,18 @@
 					NULL
 					NULL
 */
 */
 
 
+        .text
+	.globl _dynamic_start
+	.type _dynamic_start,@function
+_dynamic_start:
+        movq    __dl_fini@GOTPCREL(%rip),%rax
+        movq    %rdx,(%rax)
+        jmp _start
+
         .text
         .text
 	.globl _start
 	.globl _start
 	.type _start,@function
 	.type _start,@function
 _start:
 _start:
-#       movq    %rdx,%r9                 /* Address of the shared library termination
-#               	                 function.  */
 	popq    %rsi		      /* Pop the argument count.  */
 	popq    %rsi		      /* Pop the argument count.  */
         movq 	operatingsystem_parameter_argc@GOTPCREL(%rip),%rax
         movq 	operatingsystem_parameter_argc@GOTPCREL(%rip),%rax
         movq    %rsi,(%rax)
         movq    %rsi,(%rax)
@@ -62,6 +70,13 @@ _start:
         .globl  _haltproc
         .globl  _haltproc
         .type   _haltproc,@function
         .type   _haltproc,@function
 _haltproc:
 _haltproc:
+        movq    __dl_fini@GOTPCREL(%rip),%rax
+        movq    (%rax),%rax
+        testq   %rax,%rax
+        jz .LNoDlFiniCall
+        call    *%rax
+.LNoDlFiniCall:
+
         movq 	operatingsystem_result@GOTPCREL(%rip),%rax
         movq 	operatingsystem_result@GOTPCREL(%rip),%rax
         movzwl  (%rax),%edi
         movzwl  (%rax),%edi
         movl    $231,%eax                 /* exit_group call */
         movl    $231,%eax                 /* exit_group call */
@@ -78,6 +93,7 @@ __data_start:
 
 
 .bss
 .bss
         .comm __stkptr,8
         .comm __stkptr,8
+        .comm __dl_fini,8
 
 
         .comm operatingsystem_parameter_envp,8
         .comm operatingsystem_parameter_envp,8
         .comm operatingsystem_parameter_argc,8
         .comm operatingsystem_parameter_argc,8

+ 14 - 0
rtl/linux/x86_64/si_prc.inc

@@ -37,6 +37,9 @@ procedure PASCALMAIN; external name 'PASCALMAIN';
                           Process start/halt
                           Process start/halt
  ******************************************************************************}
  ******************************************************************************}
 
 
+var
+  dlexitproc: pointer;
+
 procedure _FPC_proc_start; assembler; nostackframe; public name '_start';
 procedure _FPC_proc_start; assembler; nostackframe; public name '_start';
   asm
   asm
     popq     %rsi                                  { Pop the argument count.  }
     popq     %rsi                                  { Pop the argument count.  }
@@ -54,9 +57,20 @@ procedure _FPC_proc_start; assembler; nostackframe; public name '_start';
     call    PASCALMAIN
     call    PASCALMAIN
   end;
   end;
 
 
+procedure _FPC_dynamic_proc_start; assembler; nostackframe; public name '_dynamic_start';
+  asm
+    movq %rdx,dlexitproc
+    jmp _FPC_proc_start
+  end;
 
 
 procedure _FPC_proc_haltproc; assembler; nostackframe; public name '_haltproc';
 procedure _FPC_proc_haltproc; assembler; nostackframe; public name '_haltproc';
   asm
   asm
+    movq    dlexitproc,%rdx
+    testq   %rdx,%rdx
+    jz      .Lhaltproc
+
+    call *%rdx
+
   .Lhaltproc:
   .Lhaltproc:
     movl    $231,%eax                             { exit_group call }
     movl    $231,%eax                             { exit_group call }
     movzwl    operatingsystem_result,%edi
     movzwl    operatingsystem_result,%edi