ソースを参照

Merged revisions 8518,8566-8567,8591 via svnmerge from
svn+ssh://[email protected]/FPC/svn/fpc/trunk

........
r8518 | tom_at_work | 2007-09-16 23:32:29 +0200 (Sun, 16 Sep 2007) | 1 line

* remove additional dot for import name of external function. Makes tprocext compile and run for powerpc64 (stub still not fully working, due to missing GOT loading in stub).
........
r8566 | tom_at_work | 2007-09-19 22:41:39 +0200 (Wed, 19 Sep 2007) | 2 lines

* improve powerpc64/linux stub for external procedures in units: also consider GOT change in call to this external procedure
* refactored above mentioned stub code generation, allowing the CG to define a cpu specific method for this task by overriding new g_external_wrapper() method
........
r8567 | tom_at_work | 2007-09-19 22:55:47 +0200 (Wed, 19 Sep 2007) | 1 line

* constantified hardcoded minimum stackframe size required by the (powerpc64/linux) ABI
........
r8591 | tom_at_work | 2007-09-21 02:05:51 +0200 (Fri, 21 Sep 2007) | 1 line

* linker script: keep got and toc sections together; allows use of -Cg (PIC) in large programs (e.g. compiler) on powerpc64/linux
........

git-svn-id: branches/fixes_2_2@8893 -

Jonas Maebe 18 年 前
コミット
ca6a248758

+ 10 - 0
compiler/cgobj.pas

@@ -474,6 +474,11 @@ unit cgobj;
           procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: aint);virtual;
 
           function g_indirect_sym_load(list:TAsmList;const symname: string): tregister;virtual;
+          { generate a stub which only purpose is to pass control the given external method, 
+          setting up any additional environment before doing so (if required).
+
+          The default implementation issues a jump instruction to the external name. }
+          procedure g_external_wrapper(list : TAsmList; procdef: tprocdef; const externalname: string); virtual;
         protected
           procedure get_subsetref_load_info(const sref: tsubsetreference; out loadsize: tcgsize; out extra_load: boolean);
           procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tcgsize; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); virtual;
@@ -3702,6 +3707,11 @@ implementation
       end;
 
 
+    procedure tcg.g_external_wrapper(list : TAsmList; procdef: tprocdef; const externalname: string);
+      begin
+        a_jmp_name(list,externalname);
+      end;
+
     procedure tcg.a_call_name_static(list : TAsmList;const s : string);
       begin
         a_call_name(list,s);

+ 1 - 26
compiler/ncgutil.pas

@@ -2168,11 +2168,6 @@ implementation
 ****************************************************************************}
 
     procedure gen_external_stub(list:TAsmList;pd:tprocdef;const externalname:string);
-{$ifdef x86}
-      var
-        ref : treference;
-        sym : tasmsymbol;
-{$endif x86}
       begin
         { add the procedure to the al_procedures }
         maybe_new_object_file(list);
@@ -2183,27 +2178,7 @@ implementation
         else
           list.concat(Tai_symbol.createname(pd.mangledname,AT_FUNCTION,0));
 
-{$ifdef x86}
-        { fix this for other CPUs as well }
-        sym:=current_asmdata.RefAsmSymbol(externalname);
-        reference_reset_symbol(ref,sym,0);
-
-
-        { create pic'ed? }
-        if cs_create_pic in current_settings.moduleswitches then
-          begin
-            { it could be that we're called from a procedure not having the
-              got loaded
-            }
-            gen_got_load(list);
-            ref.refaddr:=addr_pic;
-          end
-        else
-          ref.refaddr:=addr_full;
-        list.concat(taicpu.op_ref(A_JMP,S_NO,ref));
-{$else x86}
-        cg.a_jmp_name(list,externalname);
-{$endif x86}
+        cg.g_external_wrapper(list,pd,externalname);
       end;
 
 {****************************************************************************

+ 47 - 0
compiler/powerpc64/cgcpu.pas

@@ -99,6 +99,8 @@ type
     procedure g_concatcopy(list: TAsmList; const source, dest: treference;
       len: aint); override;
 
+    procedure g_external_wrapper(list: TAsmList; pd: TProcDef; const externalname: string); override;
+
   private
 
     procedure a_load_regconst_subsetreg_intern(list : TAsmList; fromsize, subsetsize: tcgsize; fromreg: tregister; const sreg: tsubsetregister; slopt: tsubsetloadopt); override;
@@ -1868,6 +1870,51 @@ begin
 
 end;
 
+procedure tcgppc.g_external_wrapper(list: TAsmList; pd: TProcDef; const externalname: string);
+var
+  href : treference;
+begin
+  if (target_info.system <> system_powerpc64_linux) then begin
+    inherited;
+    exit;
+  end;
+
+  { for ppc64/linux emit correct code which sets up a stack frame and then calls the
+  external method normally to ensure that the GOT/TOC will be loaded correctly if 
+  required.
+
+  It's not really advantageous to use cg methods here because they are too specialized.
+
+  I.e. the resulting code sequence looks as follows:
+
+  mflr r0
+  std r0, 16(r1)
+  stdu r1, -112(r1)
+  bl <external_method>
+  nop
+  addi r1, r1, 112
+  ld r0, 16(r1)
+  mtlr r0
+  blr
+
+  }
+  list.concat(taicpu.op_reg(A_MFLR, NR_R0));
+  reference_reset_base(href, NR_STACK_POINTER_REG, 16);
+  list.concat(taicpu.op_reg_ref(A_STD, NR_R0, href));
+  reference_reset_base(href, NR_STACK_POINTER_REG, -MINIMUM_STACKFRAME_SIZE);
+  list.concat(taicpu.op_reg_ref(A_STDU, NR_STACK_POINTER_REG, href));
+
+  list.concat(taicpu.op_sym(A_BL, current_asmdata.RefAsmSymbol(externalname)));
+  list.concat(taicpu.op_none(A_NOP));
+
+  list.concat(taicpu.op_reg_reg_const(A_ADDI, NR_STACK_POINTER_REG, NR_STACK_POINTER_REG, MINIMUM_STACKFRAME_SIZE));
+
+  reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_ELF);
+  list.concat(taicpu.op_reg_ref(A_LD, NR_R0, href));
+  list.concat(taicpu.op_reg(A_MTLR, NR_R0));
+  list.concat(taicpu.op_none(A_BLR));
+end;
+
 {***************** This is private property, keep out! :) *****************}
 
 procedure tcgppc.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);

+ 3 - 0
compiler/powerpc64/cpubase.pas

@@ -378,6 +378,9 @@ const
   { the size of the "red zone" which must not be changed by asynchronous calls
    in the stack frame and can be used for storing temps }
   RED_ZONE_SIZE = 288;
+  
+  { minimum size of the stack frame if one exists }
+  MINIMUM_STACKFRAME_SIZE = 112;
 
   {*****************************************************************************
                                     Helpers

+ 2 - 2
compiler/powerpc64/cpupi.pas

@@ -74,8 +74,8 @@ begin
     { the ABI specification says that it is required to always allocate space for 8 * 8 bytes
       for registers R3-R10 and stack header if there's a stack frame, but GCC doesn't do that,
       so we don't that too. Uncomment the next three lines if this is required }
-    if (cs_profile in init_settings.moduleswitches) and (ofs < 112) then begin
-      ofs := 112;
+    if (cs_profile in init_settings.moduleswitches) and (ofs < MINIMUM_STACKFRAME_SIZE) then begin
+      ofs := MINIMUM_STACKFRAME_SIZE;
     end;
     tg.setfirsttemp(ofs);
   end else begin

+ 1 - 1
compiler/psub.pas

@@ -1535,7 +1535,7 @@ implementation
                    begin
                      s:=proc_get_importname(pd);
                      if s<>'' then
-                       gen_external_stub(current_asmdata.asmlists[al_procedures],pd,{$IFDEF POWERPC64}'.'+{$ENDIF}s);
+                       gen_external_stub(current_asmdata.asmlists[al_procedures],pd,s);
                    end;
 
                  { Import DLL specified? }

+ 2 - 2
compiler/systems/t_linux.pas

@@ -610,8 +610,8 @@ begin
        the same address within the page on the next page up.}
       add('  . = ALIGN (0x1000) - ((0x1000 - .) & (0x1000 - 1));');
       add('  .dynamic        : { *(.dynamic) }');
-      add('  .got            : { *(.got) }');
-      add('  .got.plt        : { *(.got.plt) }');
+      add('  .got            : { *(.got .toc) }');
+      add('  .got.plt        : { *(.got.plt .toc.plt) }');
       add('  .data           :');
       add('  {');
       add('    *(.data .data.* .gnu.linkonce.d.*)');

+ 26 - 3
compiler/x86/cgx86.pas

@@ -32,7 +32,7 @@ unit cgx86;
        cgbase,cgutils,cgobj,
        aasmbase,aasmtai,aasmdata,aasmcpu,
        cpubase,cpuinfo,rgobj,rgx86,rgcpu,
-       symconst,symtype;
+       symconst,symtype,symdef;
 
     type
       tcgx86 = class(tcg)
@@ -108,6 +108,8 @@ unit cgx86;
 
         procedure g_overflowcheck(list: TAsmList; const l:tlocation;def:tdef);override;
 
+        procedure g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string); override;
+
         procedure make_simple_ref(list:TAsmList;var ref: treference);
       protected
         procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
@@ -150,8 +152,8 @@ unit cgx86;
 
     uses
        globals,verbose,systems,cutils,
-       symdef,defutil,paramgr,procinfo,
-       tgobj,
+       defutil,paramgr,procinfo,
+       tgobj,ncgutil,
        fmodule;
 
     const
@@ -1979,5 +1981,26 @@ unit cgx86;
          a_label(list,hl);
       end;
 
+    procedure tcgx86.g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string);
+      var
+        ref : treference;
+        sym : tasmsymbol;
+      begin
+        sym:=current_asmdata.RefAsmSymbol(externalname);
+        reference_reset_symbol(ref,sym,0);
+
+        { create pic'ed? }
+        if cs_create_pic in current_settings.moduleswitches then
+          begin
+            { it could be that we're called from a procedure not having the
+              got loaded
+            }
+            gen_got_load(list);
+            ref.refaddr:=addr_pic;
+          end
+        else
+          ref.refaddr:=addr_full;
+        list.concat(taicpu.op_ref(A_JMP,S_NO,ref));
+      end;
 
 end.