From: Artur Frenszek-Iwicki Date: Sat, 7 Jan 2023 12:07:32 +0000 (+0000) Subject: Fix missing TOC loads on ppc64el X-Git-Tag: archive/raspbian/3.2.2+dfsg-20+rpi1^2^2^2~3 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=46f9c301bbb7ec8bc602f1c8f0d58439757537b9;p=fpc.git Fix missing TOC loads on ppc64el Bug: https://gitlab.com/freepascal.org/fpc/source/-/issues/39542 Origin: vendor, https://src.fedoraproject.org/rpms/fpc/c/01634e7f70132cc0bc1cab278edc8449e73ac1f9 Last-Update: 2022-02-07 A backport of upstream commits: - https://gitlab.com/freepascal.org/fpc/source/-/commit/12f48c230bccd49f368be1e5a2855cb6c3a60c0f - https://gitlab.com/freepascal.org/fpc/source/-/commit/9314bbbf080418827eef94a8bc392ce0497bf72b - https://gitlab.com/freepascal.org/fpc/source/-/commit/2de72c854115908271912cd9b260a607c826eadb - https://gitlab.com/freepascal.org/fpc/source/-/commit/83c18df69a79fe1035a0cf0bc0897c60d1af0293 - https://gitlab.com/freepascal.org/fpc/source/-/commit/68b5ca633ca71a83c29b78cd3669bf15477cd94f Some modifications were made to make the changes apply cleanly to v3.2.2. Gbp-Pq: Name ppc64el-toc-fixes.patch --- diff --git a/fpcsrc/compiler/ncgvmt.pas b/fpcsrc/compiler/ncgvmt.pas index ab93c7fe..bd7fd46a 100644 --- a/fpcsrc/compiler/ncgvmt.pas +++ b/fpcsrc/compiler/ncgvmt.pas @@ -1222,14 +1222,25 @@ implementation tmps : string; pd : TProcdef; ImplIntf : TImplementedInterface; -{$ifdef cpuhighleveltarget} wrapperpd: tprocdef; wrapperinfo: pskpara_interface_wrapper; -{$else} - tmplist: tasmlist; - oldfileposinfo: tfileposinfo; -{$endif cpuhighleveltarget} + tmplist: tasmlist; + oldfileposinfo: tfileposinfo; + usehighlevelwrapper: Boolean; begin +{$if defined(cpuhighleveltarget)} + usehighlevelwrapper:=true; +{$else defined(cpuhighleveltarget)} + { on PPC systems that use a TOC the linker needs to be able to insert + an instruction to restore the TOC register after every branch + between code fragments that use a different TOC (which has to be + executed when that "branch" returns). So we can't use tail call + branches to routines potentially using a different TOC there } + if target_info.system in systems_ppc_toc then + usehighlevelwrapper:=true + else + usehighlevelwrapper:=false; +{$endif defined(cpuhighleveltarget)} for i:=0 to _class.ImplementedInterfaces.count-1 do begin ImplIntf:=TImplementedInterface(_class.ImplementedInterfaces[i]); @@ -1246,43 +1257,47 @@ implementation not is_objectpascal_helper(tprocdef(pd).struct) then tobjectdef(tprocdef(pd).struct).register_vmt_call(tprocdef(pd).extnumber); tmps:=CreateWrapperName(_Class,ImplIntf,j,pd); -{$ifdef cpuhighleveltarget} - new(wrapperinfo); - wrapperinfo^.pd:=pd; - wrapperinfo^.offset:=ImplIntf.ioffset; - { insert the wrapper procdef in the current unit's local - symbol table, but set the owning "struct" to the current - class (so self will have the correct type) } - wrapperpd:=create_procdef_alias(pd,tmps,tmps, - current_module.localsymtable,_class, - tsk_interface_wrapper,wrapperinfo); - include(wrapperpd.procoptions,po_noreturn); -{$else cpuhighleveltarget} - oldfileposinfo:=current_filepos; - if pd.owner.iscurrentunit then - current_filepos:=pd.fileinfo - else - begin - current_filepos.moduleindex:=current_module.unit_index; - current_filepos.fileindex:=1; - current_filepos.line:=1; - current_filepos.column:=1; - end; - { create wrapper code } - tmplist:=tasmlist.create; - new_section(tmplist,sec_code,tmps,target_info.alignment.procalign); - tmplist.Concat(tai_function_name.create(tmps)); - hlcg.init_register_allocators; - hlcg.g_intf_wrapper(tmplist,pd,tmps,ImplIntf.ioffset); - hlcg.done_register_allocators; - if ((cs_debuginfo in current_settings.moduleswitches) or - (cs_use_lineinfo in current_settings.globalswitches)) and - (target_dbg.id<>dbg_stabx) then - current_debuginfo.insertlineinfo(tmplist); - list.concatlist(tmplist); - tmplist.Free; - current_filepos:=oldfileposinfo; -{$endif cpuhighleveltarget} + + if usehighlevelwrapper then + begin + new(wrapperinfo); + wrapperinfo^.pd:=pd; + wrapperinfo^.offset:=ImplIntf.ioffset; + { insert the wrapper procdef in the current unit's local + symbol table, but set the owning "struct" to the current + class (so self will have the correct type) } + wrapperpd:=create_procdef_alias(pd,tmps,tmps, + current_module.localsymtable,_class, + tsk_interface_wrapper,wrapperinfo); + include(wrapperpd.implprocoptions,pio_thunk); + end + else + begin + oldfileposinfo:=current_filepos; + if pd.owner.iscurrentunit then + current_filepos:=pd.fileinfo + else + begin + current_filepos.moduleindex:=current_module.unit_index; + current_filepos.fileindex:=1; + current_filepos.line:=1; + current_filepos.column:=1; + end; + { create wrapper code } + tmplist:=tasmlist.create; + new_section(tmplist,sec_code,tmps,target_info.alignment.procalign); + tmplist.Concat(tai_function_name.create(tmps)); + hlcg.init_register_allocators; + hlcg.g_intf_wrapper(tmplist,pd,tmps,ImplIntf.ioffset); + hlcg.done_register_allocators; + if ((cs_debuginfo in current_settings.moduleswitches) or + (cs_use_lineinfo in current_settings.globalswitches)) and + (target_dbg.id<>dbg_stabx) then + current_debuginfo.insertlineinfo(tmplist); + list.concatlist(tmplist); + tmplist.Free; + current_filepos:=oldfileposinfo; + end; end; end; end; diff --git a/fpcsrc/compiler/powerpc64/cgcpu.pas b/fpcsrc/compiler/powerpc64/cgcpu.pas index 9b045061..0b7a58c1 100644 --- a/fpcsrc/compiler/powerpc64/cgcpu.pas +++ b/fpcsrc/compiler/powerpc64/cgcpu.pas @@ -337,10 +337,6 @@ begin reference_reset_base(tmpref, reg, 0, ctempposinvalid, sizeof(pint), []); a_load_ref_reg(list, OS_ADDR, OS_ADDR, tmpref, tempreg); - { save TOC pointer in stackframe } - reference_reset_base(tmpref, NR_STACK_POINTER_REG, get_rtoc_offset, ctempposinvalid, 8, []); - a_load_reg_ref(list, OS_ADDR, OS_ADDR, NR_RTOC, tmpref); - { move actual function pointer to CTR register } list.concat(taicpu.op_reg(A_MTCTR, tempreg)); @@ -1269,6 +1265,13 @@ begin end; end; + { save current RTOC for restoration after calls if necessary } + if pi_do_call in current_procinfo.flags then + begin + reference_reset_base(href,NR_STACK_POINTER_REG,get_rtoc_offset,ctempposinvalid,target_info.stackalign,[]); + a_load_reg_ref(list,OS_ADDR,OS_ADDR,NR_RTOC,href); + end; + { CR register not used by FPC atm } { keep R1 allocated??? } diff --git a/fpcsrc/compiler/ppcgen/cgppc.pas b/fpcsrc/compiler/ppcgen/cgppc.pas index 35e0d7b1..a71acf10 100644 --- a/fpcsrc/compiler/ppcgen/cgppc.pas +++ b/fpcsrc/compiler/ppcgen/cgppc.pas @@ -1055,6 +1055,7 @@ unit cgppc; (assigned(ref.symbol) and not assigned(ref.relsymbol)) then begin + include(current_procinfo.flags,pi_needs_got); tmpreg := load_got_symbol(list, ref.symbol.name, asmsym2indsymflags(ref.symbol)); if (ref.base = NR_NO) then ref.base := tmpreg diff --git a/fpcsrc/compiler/ppcgen/hlcgppc.pas b/fpcsrc/compiler/ppcgen/hlcgppc.pas index 4d747b3f..2a991708 100644 --- a/fpcsrc/compiler/ppcgen/hlcgppc.pas +++ b/fpcsrc/compiler/ppcgen/hlcgppc.pas @@ -183,11 +183,16 @@ implementation system_powerpc_darwin, system_powerpc64_darwin: list.concat(taicpu.op_sym(A_B,tcgppcgen(cg).get_darwin_call_stub(procdef.mangledname,false))); - else if use_dotted_functions then - {$note ts:todo add GOT change?? - think not needed :) } - list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol('.' + procdef.mangledname,AT_FUNCTION))) else - list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname,AT_FUNCTION))) + begin + if use_dotted_functions then + {$note ts:todo add GOT change?? - think not needed :) } + list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol('.' + procdef.mangledname,AT_FUNCTION))) + else + list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname,AT_FUNCTION))); + if (target_info.system in ([system_powerpc64_linux]+systems_aix)) then + list.concat(taicpu.op_none(A_NOP)); + end; end; List.concat(Tai_symbol_end.Createname(labelname)); end; diff --git a/fpcsrc/compiler/psub.pas b/fpcsrc/compiler/psub.pas index 6d04c694..40d8419d 100644 --- a/fpcsrc/compiler/psub.pas +++ b/fpcsrc/compiler/psub.pas @@ -2306,8 +2306,10 @@ implementation } if (not pd.forwarddef) and (pd.hasforward) and - (proc_get_importname(pd)<>'') then - call_through_new_name(pd,proc_get_importname(pd)) + (proc_get_importname(pd)<>'') then begin + call_through_new_name(pd,proc_get_importname(pd)) + include(pd.implprocoptions,pio_thunk); + end else {$endif cpuhighleveltarget} begin diff --git a/fpcsrc/compiler/symconst.pas b/fpcsrc/compiler/symconst.pas index fdc7a200..86529873 100644 --- a/fpcsrc/compiler/symconst.pas +++ b/fpcsrc/compiler/symconst.pas @@ -425,7 +425,17 @@ type { the routine contains no code } pio_empty, { the inline body of this routine is available } - pio_has_inlininginfo + pio_has_inlininginfo, + { inline is not possible (has assembler block, etc) } + pio_inline_not_possible, + { a nested routine accesses a local variable from this routine } + pio_nested_access, + { a stub/thunk } + pio_thunk, + { compiled with fastmath enabled } + pio_fastmath, + { inline is forbidden (calls get_frame) } + pio_inline_forbidden ); timplprocoptions = set of timplprocoption; diff --git a/fpcsrc/compiler/systems.pas b/fpcsrc/compiler/systems.pas index e1cce1d5..c322c60e 100644 --- a/fpcsrc/compiler/systems.pas +++ b/fpcsrc/compiler/systems.pas @@ -393,6 +393,16 @@ interface on the caller side rather than on the callee side } systems_caller_copy_addr_value_para = [system_aarch64_ios,system_aarch64_darwin,system_aarch64_linux]; + { all PPC systems that use a TOC register to address globals } + { TODO: not used by Darwin, but don't know about others (JM) } + systems_ppc_toc = [ + system_powerpc_linux, + system_powerpc64_linux, + system_powerpc_aix, + system_powerpc64_aix, + system_powerpc_macosclassic + ]; + { pointer checking (requires special code in FPC_CHECKPOINTER, and can never work for libc-based targets or any other program linking to an external library) diff --git a/fpcsrc/compiler/utils/ppuutils/ppudump.pp b/fpcsrc/compiler/utils/ppuutils/ppudump.pp index 3418e628..bb96d039 100644 --- a/fpcsrc/compiler/utils/ppuutils/ppudump.pp +++ b/fpcsrc/compiler/utils/ppuutils/ppudump.pp @@ -3087,7 +3087,12 @@ type const piopt : array[low(timplprocoption)..high(timplprocoption)] of tpiopt=( (mask:pio_empty; str:'IsEmpty'), - (mask:pio_has_inlininginfo; str:'HasInliningInfo') + (mask:pio_has_inlininginfo; str:'HasInliningInfo'), + (mask:pio_inline_not_possible; str:'InlineNotPossible'), + (mask:pio_nested_access; str:'NestedAccess'), + (mask:pio_thunk; str:'Thunk'), + (mask:pio_fastmath; str:'FastMath'), + (mask:pio_inline_forbidden; str:'InlineForbidden') ); var i: timplprocoption;