diff --git a/compiler/aasmbase.pas b/compiler/aasmbase.pas index cf648f10ef..6e264158f6 100644 --- a/compiler/aasmbase.pas +++ b/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; diff --git a/compiler/cgbase.pas b/compiler/cgbase.pas index 668b484ddb..abf4bc1a44 100644 --- a/compiler/cgbase.pas +++ b/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 diff --git a/compiler/x86/aasmcpu.pas b/compiler/x86/aasmcpu.pas index 258378b2ff..3daa9abc56 100644 --- a/compiler/x86/aasmcpu.pas +++ b/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} diff --git a/compiler/x86/agx86att.pas b/compiler/x86/agx86att.pas index 338e5773c5..5afea7aff3 100644 --- a/compiler/x86/agx86att.pas +++ b/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 diff --git a/compiler/x86/cgx86.pas b/compiler/x86/cgx86.pas index d49e51f81b..1cde985369 100644 --- a/compiler/x86/cgx86.pas +++ b/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;