diff --git a/compiler/cgobj.pas b/compiler/cgobj.pas index 2d21e277f0..c45b677b49 100644 --- a/compiler/cgobj.pas +++ b/compiler/cgobj.pas @@ -484,7 +484,7 @@ unit cgobj; procedure g_external_wrapper(list : TAsmList; procdef: tprocdef; const externalname: string); virtual; { initialize the pic/got register } - procedure g_maybe_got_init(list: TAsmList); virtual; + function g_maybe_got_init(list: TAsmList; force: boolean): tregister; 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; @@ -3832,8 +3832,9 @@ implementation end; - procedure tcg.g_maybe_got_init(list: TAsmList); + function tcg.g_maybe_got_init(list: TAsmList; force: boolean): tregister; begin + result:=NR_NO; end; diff --git a/compiler/i386/cgcpu.pas b/compiler/i386/cgcpu.pas index dcb5eb6b7b..9bd9f2c3cb 100644 --- a/compiler/i386/cgcpu.pas +++ b/compiler/i386/cgcpu.pas @@ -52,7 +52,7 @@ unit cgcpu; procedure g_exception_reason_save_const(list : TAsmList; const href : treference; a: aint);override; procedure g_exception_reason_load(list : TAsmList; const href : treference);override; procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override; - procedure g_maybe_got_init(list: TAsmList); override; + function g_maybe_got_init(list: TAsmList; force: boolean): tregister; override; end; tcg64f386 = class(tcg64f32) @@ -494,12 +494,13 @@ unit cgcpu; end; - procedure tcg386.g_maybe_got_init(list: TAsmList); + function tcg386.g_maybe_got_init(list: TAsmList; force: boolean): tregister; begin { allocate PIC register } if (cs_create_pic in current_settings.moduleswitches) and (tf_pic_uses_got in target_info.flags) and - (pi_needs_got in current_procinfo.flags) then + (force or + (pi_needs_got in current_procinfo.flags)) then begin if (target_info.system<>system_i386_darwin) then begin @@ -507,11 +508,14 @@ unit cgcpu; cg.a_call_name_static(list,'fpc_geteipasebx'); list.concat(taicpu.op_sym_ofs_reg(A_ADD,S_L,current_asmdata.RefAsmSymbol('_GLOBAL_OFFSET_TABLE_'),0,NR_PIC_OFFSET_REG)); list.concat(tai_regalloc.alloc(NR_PIC_OFFSET_REG,nil)); - { ecx could be used in leaf procedures } - current_procinfo.got:=NR_EBX; + { ecx could be used for a parameter register } + result:=NR_EBX; end else begin + { is not called for darwin/i386 for external stubs } + if not assigned(current_procinfo) then + internalerror(2009072801); { can't use ecx, since that one may overwrite a parameter } current_module.requires_ebx_pic_helper:=true; cg.a_call_name_static(list,'fpc_geteipasebx'); @@ -520,6 +524,7 @@ unit cgcpu; { got is already set by ti386procinfo.allocate_got_register } list.concat(tai_regalloc.dealloc(NR_EBX,nil)); a_load_reg_reg(list,OS_ADDR,OS_ADDR,NR_EBX,current_procinfo.got); + result:=current_procinfo.got; end; end; end; diff --git a/compiler/ppcgen/cgppc.pas b/compiler/ppcgen/cgppc.pas index 8ea958d6ad..14380cf54d 100644 --- a/compiler/ppcgen/cgppc.pas +++ b/compiler/ppcgen/cgppc.pas @@ -62,7 +62,7 @@ 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_maybe_got_init(list: TAsmList; force: boolean): tregister; override; 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; @@ -204,16 +204,19 @@ unit cgppc; end; - procedure tcgppcgen.g_maybe_got_init(list: TAsmList); + function tcgppcgen.g_maybe_got_init(list: TAsmList; force: boolean): tregister; var instr: taicpu; cond: tasmcond; savedlr: boolean; begin + if not assigned(current_procinfo) then + internalerror(2009072802); if not(po_assembler in current_procinfo.procdef.procoptions) then begin if (cs_create_pic in current_settings.moduleswitches) and - (pi_needs_got in current_procinfo.flags) then + (force or + (pi_needs_got in current_procinfo.flags)) then case target_info.system of system_powerpc_darwin, system_powerpc64_darwin: @@ -237,6 +240,7 @@ unit cgppc; { procedures) } not(pi_do_call in current_procinfo.flags) then list.concat(taicpu.op_reg_reg(A_MTSPR,NR_LR,NR_R0)); + result:=current_procinfo.got; end; end; end; diff --git a/compiler/psub.pas b/compiler/psub.pas index d4e69b72d7..d69792fbdc 100644 --- a/compiler/psub.pas +++ b/compiler/psub.pas @@ -1026,7 +1026,7 @@ implementation cg.set_regalloc_live_range_direction(rad_backwards_reinit); current_filepos:=entrypos; { load got if necessary } - cg.g_maybe_got_init(templist); + current_procinfo.got:=cg.g_maybe_got_init(templist,false); aktproccode.insertlistafter(headertai,templist); diff --git a/compiler/x86/cgx86.pas b/compiler/x86/cgx86.pas index 2e79d7d666..621bbe7ce1 100644 --- a/compiler/x86/cgx86.pas +++ b/compiler/x86/cgx86.pas @@ -2124,11 +2124,24 @@ unit cgx86; { darwin/x86_64's assembler doesn't want @PLT after call symbols } (target_info.system<>system_x86_64_darwin) then begin + ref.refaddr:=addr_pic; +{$ifdef i386} { it could be that we're called from a procedure not having the - got loaded + got loaded. Since all volatile registers can contain parameters, + we have to use the stack. } - g_maybe_got_init(list); - ref.refaddr:=addr_pic + list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EBX)); + ref.base:=g_maybe_got_init(list,true); + if (ref.base<>NR_EBX) then + internalerror(2009072801); + list.concat(taicpu.op_ref_reg(A_MOV,S_L,ref,NR_EBX)); + reference_reset_base(ref,NR_ESP,0,sizeof(pint)); + { restore ebx to its original value, and place target address + on the stack } + list.concat(taicpu.op_reg_ref(A_XCHG,S_L,NR_EBX,ref)); + list.concat(taicpu.op_none(A_RET)); + exit; +{$endif i386} end else ref.refaddr:=addr_full;