Browse Source

+ AIX symbol handling: load symbol address from the TOC
* fixed code dealing with symbol+offsets on 64 bit platforms in
case of offsets > 32 bit (and to use smallint() typecasts
instead of lo(), since the return value of lo() depends on
the type passed in)

git-svn-id: trunk@20793 -

Jonas Maebe 13 years ago
parent
commit
509df28361
1 changed files with 100 additions and 36 deletions
  1. 100 36
      compiler/ppcgen/cgppc.pas

+ 100 - 36
compiler/ppcgen/cgppc.pas

@@ -61,9 +61,13 @@ unit cgppc;
         procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
 
         procedure g_maybe_got_init(list: TAsmList); override;
+
+        function g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister; override;
         { Transform unsupported methods into Internal errors }
         procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override;
         procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
+
+        function get_aix_toc_sym(const symname: string; const flags: tindsymflags):tasmsymbol;
        protected
         function  get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
         procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tcgsize; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); override;
@@ -89,7 +93,7 @@ unit cgppc;
 
         function save_lr_in_prologue: boolean;
 
-        function load_got_symbol(list : TAsmList; symbol : string) : tregister;
+        function load_got_symbol(list : TAsmList; const symbol : string; const flags: tindsymflags) : tregister;
      end;
 
   const
@@ -251,6 +255,18 @@ unit cgppc;
       end;
 
 
+    function tcgppcgen.g_indirect_sym_load(list: TAsmList; const symname: string; const flags: tindsymflags): tregister;
+      begin
+        case target_info.system of
+          system_powerpc_aix,
+          system_powerpc64_aix:
+            result:=load_got_symbol(list,symname,flags);
+          else
+            result:=inherited;
+        end;
+      end;
+
+
     function tcgppcgen.get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
       var
         stubname: string;
@@ -351,13 +367,8 @@ unit cgppc;
                      tmpref.base := NR_RTOC;
                      list.concat(taicpu.op_reg_ref(A_LWZ,r,tmpref));
 
-                     if ref2.offset <> 0 then
-                       begin
-                         reference_reset(tmpref,ref2.alignment);
-                         tmpref.offset := ref2.offset;
-                         tmpref.base:= r;
-                         list.concat(taicpu.op_reg_ref(A_LA,r,tmpref));
-                       end;
+                     if ref2.offset<>0 then
+                       a_op_const_reg(list,OP_ADD,OS_ADDR,ref2.offset,r);
                    end;
 
                  if ref2.base <> NR_NO then
@@ -686,14 +697,14 @@ unit cgppc;
               href.offset := smallint(href.offset and $ffff);
             end;
           a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R11);
-          if (target_info.system = system_powerpc64_linux) then
+          if (target_info.system in ([system_powerpc64_linux]+systems_aix)) then
             begin
               reference_reset_base(href, NR_R11, 0, sizeof(pint));
               a_load_ref_reg(list, OS_ADDR, OS_ADDR, href, NR_R11);
             end;
           list.concat(taicpu.op_reg(A_MTCTR,NR_R11));
           list.concat(taicpu.op_none(A_BCTR));
-          if (target_info.system = system_powerpc64_linux) then
+          if (target_info.system in ([system_powerpc64_linux]+systems_aix)) then
             list.concat(taicpu.op_none(A_NOP));
         end;
 
@@ -747,24 +758,25 @@ unit cgppc;
       end;
 
 
-    function tcgppcgen.load_got_symbol(list: TAsmList; symbol : string) : tregister;
+    function tcgppcgen.load_got_symbol(list: TAsmList; const symbol : string; const flags: tindsymflags) : tregister;
     var
       l: tasmsymbol;
       ref: treference;
     begin
-      if (target_info.system <> system_powerpc64_linux) then
+      if target_info.system=system_powerpc64_linux then
+        l:=current_asmdata.getasmsymbol(symbol)
+      else if target_info.system in systems_aix then
+        l:=get_aix_toc_sym(symbol,flags)
+      else
         internalerror(2007102010);
-      l:=current_asmdata.getasmsymbol(symbol);
       reference_reset_symbol(ref,l,0,sizeof(pint));
-      ref.base := NR_R2;
-      ref.refaddr := addr_pic;
-
-      result := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
-      {$IFDEF EXTDEBUG}
-      list.concat(tai_comment.create(strpnew('loading got reference for ' + symbol)));
-      {$ENDIF EXTDEBUG}
-    //  cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,result);
+      ref.base:=NR_RTOC;
+      if target_info.system in systems_aix then
+        ref.refaddr:=addr_pic_no_got
+      else
+        ref.refaddr:=addr_pic;
 
+      result := getaddressregister(list);
 {$ifdef cpu64bitaddr}
       list.concat(taicpu.op_reg_ref(A_LD, result, ref));
 {$else cpu64bitaddr}
@@ -773,6 +785,34 @@ unit cgppc;
     end;
 
 
+  function tcgppcgen.get_aix_toc_sym(const symname: string; const flags: tindsymflags): tasmsymbol;
+    var
+      nlsymname: string;
+      newsymname: ansistring;
+    begin
+      { all global symbol accesses always must be done via the TOC }
+      nlsymname:='LC..'+symname;
+      result:=current_asmdata.getasmsymbol(nlsymname);
+      if not assigned(result) then
+        begin
+          new_section(current_asmdata.AsmLists[al_picdata],sec_toc,'',sizeof(pint));
+          result:=current_asmdata.DefineAsmSymbol(nlsymname,AB_LOCAL,AT_DATA);
+          current_asmdata.asmlists[al_picdata].concat(tai_symbol.create(result,0));
+          { do not assign the result of these statements to result: the access
+            must be done via the LC..symname symbol; these are just to define
+            the symbol that's being accessed as either weak or not }
+          if not(is_weak in flags) then
+            current_asmdata.RefAsmSymbol(symname)
+          else if is_data in flags then
+            current_asmdata.WeakRefAsmSymbol(symname)
+          else
+            current_asmdata.WeakRefAsmSymbol('.'+symname);
+          newsymname:=ReplaceForbiddenChars(symname);
+          current_asmdata.asmlists[al_picdata].concat(tai_directive.Create(asd_toc_entry,newsymname+'[TC],'+newsymname));
+        end;
+    end;
+
+
     function tcgppcgen.fixref(list: TAsmList; var ref: treference): boolean;
       var
         tmpreg: tregister;
@@ -780,7 +820,7 @@ unit cgppc;
         result := false;
 
         { Avoid recursion. }
-        if (ref.refaddr = addr_pic) then
+        if (ref.refaddr in [addr_pic,addr_pic_no_got]) then
           exit;
 
         {$IFDEF EXTDEBUG}
@@ -796,7 +836,7 @@ unit cgppc;
                ((cs_create_pic in current_settings.moduleswitches) and
                 (ref.symbol.bind in [AB_COMMON,AB_GLOBAL,AB_PRIVATE_EXTERN])) then
               begin
-                tmpreg := g_indirect_sym_load(list,ref.symbol.name,ref.symbol.bind=AB_WEAK_EXTERNAL);
+                tmpreg := g_indirect_sym_load(list,ref.symbol.name,asmsym2indsymflags(ref.symbol));
                 ref.symbol:=nil;
               end
             else
@@ -819,11 +859,12 @@ unit cgppc;
           end;
 
         { if we have to create PIC, add the symbol to the TOC/GOT }
-        if (target_info.system = system_powerpc64_linux) and
-           (cs_create_pic in current_settings.moduleswitches) and
+        if (((target_info.system = system_powerpc64_linux) and
+             (cs_create_pic in current_settings.moduleswitches)) or
+            (target_info.system in systems_aix)) and
            (assigned(ref.symbol)) then
           begin
-            tmpreg := load_got_symbol(list, ref.symbol.name);
+            tmpreg := load_got_symbol(list, ref.symbol.name, asmsym2indsymflags(ref.symbol));
             if (ref.base = NR_NO) then
               ref.base := tmpreg
             else if (ref.index = NR_NO) then
@@ -871,6 +912,9 @@ unit cgppc;
 
       var
         tmpreg: tregister;
+{$ifdef cpu64bitaddr}
+        tmpreg2: tregister;
+{$endif cpu64bitaddr}
         tmpref: treference;
         largeOffset: Boolean;
 
@@ -878,38 +922,57 @@ unit cgppc;
         tmpreg := NR_NO;
         largeOffset:= hasLargeOffset(ref);
 
-        if target_info.system = system_powerpc_macos then
+        if target_info.system in ([system_powerpc_macos]+systems_aix) then
           begin
 
-            if assigned(ref.symbol) then
+            if assigned(ref.symbol) and
+               (ref.refaddr<>addr_pic_no_got) then
               begin {Load symbol's value}
                 tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
 
                 reference_reset(tmpref,sizeof(pint));
                 tmpref.symbol := ref.symbol;
                 tmpref.base := NR_RTOC;
+                tmpref.refaddr := addr_pic_no_got;
 
                 if macos_direct_globals then
                   list.concat(taicpu.op_reg_ref(A_LA,tmpreg,tmpref))
                 else
+{$ifdef cpu64bitaddr}
+                  list.concat(taicpu.op_reg_ref(A_LD,tmpreg,tmpref));
+{$else cpu64bitaddr}
                   list.concat(taicpu.op_reg_ref(A_LWZ,tmpreg,tmpref));
+{$endif cpu64bitaddr}
               end;
 
             if largeOffset then
               begin {Add hi part of offset}
                 reference_reset(tmpref,ref.alignment);
 
-                if Smallint(Lo(ref.offset)) < 0 then
-                  tmpref.offset := Hi(ref.offset) + 1 {Compensate when lo part is negative}
-                else
-                  tmpref.offset := Hi(ref.offset);
+{$ifdef cpu64bitaddr}
+                if (ref.offset < low(longint)) or
+                   (ref.offset > high(longint)) then
+                  begin
+                    { load upper 32 bits of the offset, adjusted for adding
+                      the lower 32 bits later }
+                    tmpreg2:=getintregister(list,OS_ADDR);
+                    a_load_const_reg(list,OS_ADDR,(ref.offset and $ffffffff00000000) + ord(longint(ref.offset)<0),tmpreg2);
+                    if tmpreg=NR_NO then
+                      tmpreg:=tmpreg2
+                    else
+                      a_op_reg_reg(list,OP_ADD,OS_ADDR,tmpreg2,tmpreg);
+                    ref.offset:=longint(ref.offset);
+                  end;
+{$endif cpu64bitaddr}
+                {Compensate when lo part is negative}
+                tmpref.offset := Smallint(ref.offset >> 16) + ord(Smallint(ref.offset) < 0);
 
                 if (tmpreg <> NR_NO) then
-                  list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg, tmpreg,tmpref))
+                  list.concat(taicpu.op_reg_reg_const(A_ADDIS,tmpreg, tmpreg,tmpref.offset))
                 else
                   begin
-                    tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
-                    list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
+                    tmpreg := getintregister(list,OS_ADDR);
+                    list.concat(taicpu.op_reg_const(A_LIS,tmpreg,tmpref.offset));
                   end;
               end;
 
@@ -924,7 +987,7 @@ unit cgppc;
                 ref.symbol:= nil;
                 ref.base:= tmpreg;
                 if largeOffset then
-                  ref.offset := Smallint(Lo(ref.offset));
+                  ref.offset := Smallint(ref.offset);
 
                 list.concat(taicpu.op_reg_ref(op,reg,ref));
                 //list.concat(tai_comment.create(strpnew('*** a_load_store indirect global')));
@@ -937,6 +1000,7 @@ unit cgppc;
             if assigned(ref.symbol) or
                largeOffset then
               begin
+                // TODO: offsets > 32 bit
                 tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
                 reference_reset(tmpref,ref.alignment);
                 tmpref.symbol := ref.symbol;