Pārlūkot izejas kodu

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 gadi atpakaļ
vecāks
revīzija
9ce34c63c9

+ 15 - 3
compiler/systems/t_linux.pas

@@ -330,6 +330,7 @@ Var
   s,s1,s2      : TCmdStr;
   found1,
   found2       : boolean;
+  linksToSharedLibFiles : boolean;
 begin
   result:=False;
 { set special options for some targets }
@@ -432,6 +433,13 @@ begin
 
       { 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) }
+      if (isdll) then
+       begin
+         Add('INPUT(');
+         Add(info.DynamicLinker);
+         Add(')');
+       end;
+      linksToSharedLibFiles := not SharedLibFiles.Empty;
 
       if not SharedLibFiles.Empty then
        begin
@@ -497,8 +505,13 @@ begin
           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}
 {$define LINKERSCRIPT_INCLUDED}
@@ -641,7 +654,6 @@ begin
           add('OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",');
           add('	      "elf32-littlearm")');
           add('OUTPUT_ARCH(arm)');
-          add('ENTRY(_start)');
           add('SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");');
           add('SECTIONS');
           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"
 .text
         .globl  _startlib
@@ -24,10 +39,6 @@ FPC_SHARED_LIB_START:
         ldr ip, =__stklen
         str sp, [ip]
 
-        ldr ip, =TC_SYSTEM_ISLIBRARY
-        mov a1, #1
-        str a1, [ip]
-
         /* call main and exit normally */
         bl PASCALMAIN
         ldmdb fp, {fp, sp, pc}
@@ -35,14 +46,18 @@ FPC_SHARED_LIB_START:
         .globl  _haltproc
         .type   _haltproc,#function
 _haltproc:
-        /* r0 contains exitcode */
+        /* reload exitcode */
+        ldr r0,=operatingsystem_result
+        ldr r0,[r0]
         swi 0x900001
         b _haltproc
 
         .globl  _haltproc_eabi
         .type   _haltproc_eabi,#function
 _haltproc_eabi:
-        /* r0 contains exitcode */
+        /* reload exitcode */
+        ldr r0,=operatingsystem_result
+        ldr r0,[r0]
         mov r7,#248
         swi 0x0
         b _haltproc_eabi

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

@@ -41,6 +41,14 @@
 					NULL
 */
 
+	.text
+	.globl _dynamic_start
+	.type _dynamic_start,#function
+_dynamic_start:
+         ldr ip,=__dl_fini
+         str a1,[ip]
+         b _start
+
 	.text
 	.globl _start
 	.type _start,#function
@@ -81,11 +89,20 @@ _haltproc:
 	.globl  _haltproc_eabi
         .type   _haltproc_eabi,#function
 _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
-        ldrb r0,[r0]
-        mov r7,#248
+        ldr r0,[r0]
+        mov r7,#248  /* exit group call */
 	swi 0x0
-	b _haltproc_eabi
+	b .Lloop
 
 	/* Define a symbol for the first piece of initialized data.  */
 	.data
@@ -96,6 +113,7 @@ __data_start:
 	data_start = __data_start
 
 .bss
+        .comm __dl_fini,4
         .comm __stkptr,4
 
         .comm operatingsystem_parameter_envp,4

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

@@ -41,7 +41,7 @@ procedure PASCALMAIN; external name 'PASCALMAIN';
  ******************************************************************************}
 
 var
-  dlexitproc: pointer;
+  dlexitproc : pointer;
 
 {$ifdef FPC_PIC}
 function fpc_geteipasebxlocal : pointer; [external name 'fpc_geteipasebx'];
@@ -60,12 +60,9 @@ asm
   {$ifdef FPC_PIC}
         pushl %ebx
         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  %eax,(%ecx)
@@ -78,7 +75,6 @@ asm
 	popl  %ebx
 	movl  %ebx,(%edx)
   {$else FPC_PIC}
-  	movl  %edx, dlexitproc
   	movl  %eax,operatingsystem_parameter_envp
   	movl  %ecx,operatingsystem_parameter_argc
   	movl  %ebx,operatingsystem_parameter_argv
@@ -103,6 +99,23 @@ asm
   call    PASCALMAIN
 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';
 asm
 

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

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

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

@@ -14,6 +14,17 @@
         .set noat
 
 	.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
 	.global _start
 	.type _start,@function
@@ -29,6 +40,7 @@
     sp ($29)	The stack contains the arguments and environment:
  		0(%esp)			argc
  		4(%esp)			argv[0]
+
  		...
  		(4*argc)(%esp)		NULL
  		(4*(argc+1))(%esp)	envp[0]
@@ -75,6 +87,8 @@ _start:
 .globl  _haltproc
 .type   _haltproc,@function
 _haltproc:
+        /* TODO: need to check whether __dl_fini is non-zero and call the function pointer in case */
+
         li      $v0,4001
         lui     $a0,0x0
         lw      $a0,0($a0)
@@ -85,6 +99,7 @@ _haltproc:
 	.size _start, .-_start
 
         .comm __stkptr,4
+        .comm __dl_fini,4
 
         .comm operatingsystem_parameter_envp,4
         .comm operatingsystem_parameter_argc,4

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

@@ -20,42 +20,32 @@
     .section ".text"
     .globl FPC_SHARED_LIB_START
     .type  FPC_SHARED_LIB_START,@function
-
-    .globl  _start
-_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
     stw      3,operatingsystem_parameter_argc@l(11);
-
-    addi     4,26,4        /* get argv */
+    /* store argument vector (in r4) */
     lis     11,operatingsystem_parameter_argv@ha
     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
     stw      5,operatingsystem_parameter_envp@l(11);
 
     lis     11,__stkptr@ha
     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
 
-    b          _haltproc
+    /* return to the caller */
+    addi     1,1,32
+    lwz      0,4(1)
+    mtlr     0
+    blr
 
     .globl  _haltproc
     .globl  FPC_SHARED_LIB_EXIT
@@ -63,9 +53,17 @@ FPC_SHARED_LIB_START:
      .type   _haltproc,@function
 FPC_SHARED_LIB_EXIT:
 _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 */
     sc
-    b          _haltproc
+    /* we should not reach here. Crash horribly */
+    trap
 
 /* Define a symbol for the first piece of initialized 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"
     .globl  _start
 _start:
@@ -27,6 +37,7 @@ _start:
     stwu     1,-16(1)
     mtlr     0
     stw      0,0(1)
+
     lwz      3,0(26)       /* get argc */
     lis     11,operatingsystem_parameter_argc@ha
     stw      3,operatingsystem_parameter_argc@l(11);
@@ -46,14 +57,36 @@ _start:
 
     bl         PASCALMAIN
 
-    b          _haltproc
+    /* we should not reach here. Crash horribly */
+    trap
 
     .globl  _haltproc
     .type   _haltproc,@function
 _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 */
     sc
-    b          _haltproc
+    /* we should not reach here. Crash horribly */
+    trap
+
 
 /* Define a symbol for the first piece of initialized data.  */
     .section ".data"
@@ -63,6 +96,12 @@ data_start:
 
     .section ".bss"
 
+    .type __dl_fini, @object
+    .size __dl_fini, 4
+    .global __dl_fini
+__dl_fini:
+    .skip 4
+
     .type __stkptr, @object
     .size __stkptr, 4
     .global __stkptr

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

@@ -3,7 +3,7 @@
  * Copyright (c) 2005 by Thomas Schatzl,
  * 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,
  * for details about the copyright.
@@ -56,7 +56,7 @@
     std     2, 40(1)
     mtctr   0
     ld      2, 8(11)
-    ld      11, 8(11)
+    ld      11, 16(11)
     bctr
 .long 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
+ *
+ * The document "64-bit PowerPC ELF Application Binary Interface Supplement 1.9"
+ * pg. 24f specifies the register contents.
  */
 FUNCTION_PROLOG FPC_SHARED_LIB_START
-
     mflr    0
     std     0, 16(1)        /* save LR */
     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
     stw     3, 0(10)
-    /* store argument vector (in r4?) */
+    /* store argument vector (in r4) */
     LOAD_64BIT_VAL 10, operatingsystem_parameter_argv
     std     4, 0(10)
-    /* store environment pointer (in r5?) */
+    /* store environment pointer (in r5) */
     LOAD_64BIT_VAL 10, operatingsystem_parameter_envp
     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
     std     1,0(8)
 
+    /* call library initialization */
     bl      PASCALMAIN
     nop
 
@@ -355,6 +353,8 @@ FUNCTION_PROLOG FPC_SHARED_LIB_START
     ld      0,16(1)   /* prepare for method return */
     mtlr    0
     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
    the shared library is called */
@@ -370,7 +370,10 @@ FUNCTION_PROLOG FPC_SHARED_LIB_EXIT
     lwz     3, 0(3)
     li      0, 1
     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.  */
     .section ".data"

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

@@ -56,7 +56,7 @@
     std     2, 40(1)
     mtctr   0
     ld      2, 8(11)
-    ld      11, 8(11)
+    ld      11, 16(11)
     bctr
 .long 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 */
-    clrrdi  1, 1, 5       /* align r1 */
-    li      0, 0
+    clrrdi  1,1,5          /* align r1 */
+    li      0,0
     stdu    1,-128(1)
     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) )*/
-    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 ) */
-    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 ) */
-    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
-    std     5, 0(10)
+    std     5,0(10)
 
-    LOAD_64BIT_VAL 8, __stkptr
+    LOAD_64BIT_VAL 8,__stkptr
     std     1,0(8)
 
     bl      PASCALMAIN
     nop
 
-    /* directly jump to exit procedure, not via the function pointer */
-    b       ._haltproc
+    /* we should not reach here. Crash horribly */
+    trap
 
 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
-    lwz     3, 0(3)
-    li      0, 234
+    lwz     3,0(3)
+    /* exit group call */
+    li      0,234
     sc
-    /* exit call */
+
     LOAD_64BIT_VAL 3, operatingsystem_result
-    lwz     3, 0(3)
-    li      0, 1
+    lwz     3,0(3)
+    /* exit call */
+    li      0,1
     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.  */
     .section ".data"
@@ -384,6 +427,12 @@ data_start:
 __stkptr:
     .skip 8
 
+    .type __dl_fini, @object
+    .size __dl_fini, 8
+    .global __dl_fini
+__dl_fini:
+    .skip 8
+
     .type operatingsystem_parameters, @object
     .size operatingsystem_parameters, 24
 operatingsystem_parameters:

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

@@ -19,6 +19,14 @@
    02111-1307 USA.  */
 
 	.section ".text"
+
+	.align 4
+	.global _dynamic_start
+	.type _dynamic_start,#function
+_dynamic_start:
+        /* TODO: need to set __dl_fini here */
+        b _start
+
 	.align 4
 	.global _start
 	.type _start,#function
@@ -49,7 +57,7 @@ _start:
 	or	%o1,%lo(operatingsystem_parameter_envp),%o1
 	st	%o2, [%o1]
 
-    /* Save initial stackpointer */
+        /* Save initial stackpointer */
 	sethi	%hi(__stkptr),%o1
 	or	%o1,%lo(__stkptr),%o1
 	st	%sp, [%o1]
@@ -57,11 +65,15 @@ _start:
   	/* Call the user program entry point.  */
   	call	PASCALMAIN
   	nop
+	/* Die very horribly if main returns.  */
+	unimp
 
 .globl  _haltproc
 .type   _haltproc,@function
 _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 */
 	nop				/* delay slot */
 	/* Die very horribly if exit returns.  */
@@ -70,6 +82,7 @@ _haltproc:
 	.size _start, .-_start
 
         .comm __stkptr,4
+        .comm __dl_fini,4
 
         .comm operatingsystem_parameter_envp,4
         .comm operatingsystem_parameter_argc,4

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

@@ -44,8 +44,6 @@ FPC_SHARED_LIB_START:
 	.globl _start
 	.type _start,@function
 _startlib:
-#       movq %rdx,%r9                 /* Address of the shared library termination
-#               	                 function.  */
 	pushq	 %rbx
         movq     operatingsystem_parameter_argc@GOTPCREL(%rip),%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
-   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'.
 		This is how the dynamic linker arranges to have DT_FINI
@@ -34,12 +36,18 @@
 					NULL
 */
 
+        .text
+	.globl _dynamic_start
+	.type _dynamic_start,@function
+_dynamic_start:
+        movq    __dl_fini@GOTPCREL(%rip),%rax
+        movq    %rdx,(%rax)
+        jmp _start
+
         .text
 	.globl _start
 	.type _start,@function
 _start:
-#       movq    %rdx,%r9                 /* Address of the shared library termination
-#               	                 function.  */
 	popq    %rsi		      /* Pop the argument count.  */
         movq 	operatingsystem_parameter_argc@GOTPCREL(%rip),%rax
         movq    %rsi,(%rax)
@@ -62,6 +70,13 @@ _start:
         .globl  _haltproc
         .type   _haltproc,@function
 _haltproc:
+        movq    __dl_fini@GOTPCREL(%rip),%rax
+        movq    (%rax),%rax
+        testq   %rax,%rax
+        jz .LNoDlFiniCall
+        call    *%rax
+.LNoDlFiniCall:
+
         movq 	operatingsystem_result@GOTPCREL(%rip),%rax
         movzwl  (%rax),%edi
         movl    $231,%eax                 /* exit_group call */
@@ -78,6 +93,7 @@ __data_start:
 
 .bss
         .comm __stkptr,8
+        .comm __dl_fini,8
 
         .comm operatingsystem_parameter_envp,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
  ******************************************************************************}
 
+var
+  dlexitproc: pointer;
+
 procedure _FPC_proc_start; assembler; nostackframe; public name '_start';
   asm
     popq     %rsi                                  { Pop the argument count.  }
@@ -54,9 +57,20 @@ procedure _FPC_proc_start; assembler; nostackframe; public name '_start';
     call    PASCALMAIN
   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';
   asm
+    movq    dlexitproc,%rdx
+    testq   %rdx,%rdx
+    jz      .Lhaltproc
+
+    call *%rdx
+
   .Lhaltproc:
     movl    $231,%eax                             { exit_group call }
     movzwl    operatingsystem_result,%edi