ソースを参照

* do not access local data via the GOT on x86_64, because
a) it's unnecessary
b) it's slower than "direct" RIP-relative accessing
c) it's not supported on darwin/x86_64 in certain cases
* never use absolute addressing on darwin/x86_64 (like on win64)
* when not generating PIC, make sure that a_loadaddr_ref_reg on x86_64
also uses RIP-relative addressing for darwin/x86_64 and win64

git-svn-id: trunk@13760 -

Jonas Maebe 16 年 前
コミット
ec8fee45fe
5 ファイル変更72 行追加18 行削除
  1. 11 4
      compiler/aasmbase.pas
  2. 2 1
      compiler/cgbase.pas
  3. 1 1
      compiler/x86/aasmcpu.pas
  4. 1 1
      compiler/x86/agx86att.pas
  5. 57 11
      compiler/x86/cgx86.pas

+ 11 - 4
compiler/aasmbase.pas

@@ -354,11 +354,18 @@ implementation
 *****************************************************************************}
 
     constructor TAsmLabel.Createlocal(AList:TFPHashObjectList;nr:longint;ltyp:TAsmLabelType);
+      var
+        asmtyp: TAsmsymtype;
       begin
-        if ltyp=alt_addr then
-          inherited Create(AList,target_asm.labelprefix+asmlabeltypeprefix[ltyp]+tostr(nr),AB_LOCAL,AT_ADDR)
-        else
-          inherited Create(AList,target_asm.labelprefix+asmlabeltypeprefix[ltyp]+tostr(nr),AB_LOCAL,AT_LABEL);
+        case ltyp of
+          alt_addr:
+            asmtyp:=AT_ADDR;
+          alt_data:
+            asmtyp:=AT_DATA;
+          else
+            asmtyp:=AT_LABEL;
+        end;
+        inherited Create(AList,target_asm.labelprefix+asmlabeltypeprefix[ltyp]+tostr(nr),AB_LOCAL,asmtyp);
         labelnr:=nr;
         labeltype:=ltyp;
         is_set:=false;

+ 2 - 1
compiler/cgbase.pas

@@ -68,7 +68,8 @@ interface
        trefaddr = (
          addr_no,
          addr_full,
-         addr_pic
+         addr_pic,
+         addr_pic_no_got
          {$IF defined(POWERPC) or defined(POWERPC64) or defined(SPARC)}
          ,
          addr_low,         // bits 48-63

+ 1 - 1
compiler/x86/aasmcpu.pas

@@ -931,7 +931,7 @@ implementation
                   if (ref^.refaddr=addr_no)
 {$ifdef x86_64}
                      or (
-                         (ref^.refaddr=addr_pic) and
+                         (ref^.refaddr in [addr_pic,addr_pic_no_got]) and
                          (ref^.base<>NR_NO)
                         )
 {$endif x86_64}

+ 1 - 1
compiler/x86/agx86att.pas

@@ -162,7 +162,7 @@ interface
           top_reg :
             owner.AsmWrite(gas_regname(o.reg));
           top_ref :
-            if o.ref^.refaddr in [addr_no,addr_pic] then
+            if o.ref^.refaddr in [addr_no,addr_pic,addr_pic_no_got] then
               WriteReference(o.ref^)
             else
               begin

+ 57 - 11
compiler/x86/cgx86.pas

@@ -386,13 +386,41 @@ unit cgx86;
           begin
             if cs_create_pic in current_settings.moduleswitches then
               begin
-                reference_reset_symbol(href,ref.symbol,0,sizeof(pint));
-                hreg:=getaddressregister(list);
-                href.refaddr:=addr_pic;
-                href.base:=NR_RIP;
-                list.concat(taicpu.op_ref_reg(A_MOV,S_Q,href,hreg));
+                if (ref.symbol.bind=AB_LOCAL) and
+                   (ref.symbol.typ=AT_DATA) then
+                  begin
+                    { Local data symbols don't have to go via the GOT (and in
+                      case of darwin must not in some cases), but they still
+                      have to be addressed using PIC (RIP-relative).
+                    }
+                    { unfortunately, RIP-based addresses don't support an index }
+                    if (ref.base<>NR_NO) or
+                       (ref.index<>NR_NO) then
+                      begin
+                        reference_reset_symbol(href,ref.symbol,0,sizeof(pint));
+                        hreg:=getaddressregister(list);
+                        href.refaddr:=addr_pic_no_got;
+                        href.base:=NR_RIP;
+                        list.concat(taicpu.op_ref_reg(A_LEA,S_Q,href,hreg));
+                        ref.symbol:=nil;
+                      end
+                    else
+                      begin
+                        ref.refaddr:=addr_pic_no_got;
+                        hreg:=NR_NO;
+                        ref.base:=NR_RIP;
+                      end;
+                  end
+                else
+                  begin
+                    reference_reset_symbol(href,ref.symbol,0,sizeof(pint));
+                    hreg:=getaddressregister(list);
+                    href.refaddr:=addr_pic;
+                    href.base:=NR_RIP;
+                    list.concat(taicpu.op_ref_reg(A_MOV,S_Q,href,hreg));
 
-                ref.symbol:=nil;
+                    ref.symbol:=nil;
+                  end;
 
                 if ref.base=NR_NO then
                   ref.base:=hreg
@@ -408,17 +436,21 @@ unit cgx86;
                   end;
               end
             else
-              { Always use RIP relative symbol addressing for Windows targets. }
-              if (target_info.system in system_all_windows) and (ref.base<>NR_RIP) then
+              { Always use RIP relative symbol addressing for Windows and Darwin targets. }
+              if (target_info.system in (system_all_windows+[system_x86_64_darwin])) and (ref.base<>NR_RIP) then
                 begin
                   if (ref.refaddr=addr_no) and (ref.base=NR_NO) and (ref.index=NR_NO) then
-                    { Set RIP relative addressing for simple symbol references }
-                    ref.base:=NR_RIP
+                    begin
+                      { Set RIP relative addressing for simple symbol references }
+                      ref.base:=NR_RIP;
+                      ref.refaddr:=addr_pic_no_got
+                    end
                   else
                     begin
                       { Use temp register to load calculated 64-bit symbol address for complex references }
                       reference_reset_symbol(href,ref.symbol,0,sizeof(pint));
                       href.base:=NR_RIP;
+                      href.refaddr:=addr_pic_no_got;
                       hreg:=GetAddressRegister(list);
                       list.concat(taicpu.op_ref_reg(A_LEA,S_Q,href,hreg));
                       ref.symbol:=nil;
@@ -874,7 +906,11 @@ unit cgx86;
                            list.concat(Taicpu.op_ref_reg(A_LEA,tcgsize2opsize[OS_ADDR],tmpref,r));
                          end;
                       end
-                    else if (cs_create_pic in current_settings.moduleswitches) then
+                    else if (cs_create_pic in current_settings.moduleswitches)
+{$ifdef x86_64}
+                             and not((ref.symbol.bind=AB_LOCAL) and (ref.symbol.typ=AT_DATA))
+{$endif x86_64}
+                            then
                       begin
 {$ifdef x86_64}
                         reference_reset_symbol(tmpref,ref.symbol,0,ref.alignment);
@@ -891,6 +927,16 @@ unit cgx86;
                         if offset<>0 then
                           a_op_const_reg(list,OP_ADD,OS_ADDR,offset,r);
                       end
+{$ifdef x86_64}
+                    else if (target_info.system in (system_all_windows+[system_x86_64_darwin])) then
+                      begin
+                        { Win64 and Darwin/x86_64 always require RIP-relative addressing }
+                        tmpref:=ref;
+                        tmpref.base:=NR_RIP;
+                        tmpref.refaddr:=addr_pic_no_got;
+                        list.concat(Taicpu.op_ref_reg(A_LEA,S_Q,tmpref,r));
+                      end
+{$endif x86_64}
                     else
                       begin
                         tmpref:=ref;