mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-02 13:53:19 +02:00
* generate ".abiversion 2" directive when targeting ppc64/ELFv2
* generate code to load the TOC register if it's required, and emit the the ".localentry" directive to indicate to the linker where the actual function body starts * support the ".localentry" directive in the ppc64 assembler reader o disable the fpc_qword_to_double() assembler implementation for ELFv2, because we can't manually insert the .localentry directive before the stack allocation code * perform indirect calls on ppc64 via R12 in ncgcal, as R12 needs to contain the function address on entry on ppc64/ELFv2 (and it's a volatile register, so there's no problem with always using it) git-svn-id: trunk@30198 -
This commit is contained in:
parent
8445381929
commit
fb27dff638
@ -359,7 +359,7 @@ interface
|
||||
ash_savereg,ash_savexmm,ash_pushframe
|
||||
);
|
||||
|
||||
TSymbolPairKind = (spk_set, spk_thumb_set);
|
||||
TSymbolPairKind = (spk_set, spk_thumb_set, spk_localentry);
|
||||
|
||||
|
||||
const
|
||||
@ -393,7 +393,7 @@ interface
|
||||
'.seh_savereg','.seh_savexmm','.seh_pushframe'
|
||||
);
|
||||
symbolpairkindstr: array[TSymbolPairKind] of string[11]=(
|
||||
'.set', '.thumb_set'
|
||||
'.set', '.thumb_set', '.localentry'
|
||||
);
|
||||
|
||||
type
|
||||
|
@ -1359,10 +1359,16 @@ implementation
|
||||
AsmWrite(#9);
|
||||
AsmWrite(symbolpairkindstr[tai_symbolpair(hp).kind]);
|
||||
AsmWrite(' ');
|
||||
if replaceforbidden then
|
||||
AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).sym^)+', '+ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).value^))
|
||||
if tai_symbolpair(hp).kind<>spk_localentry then
|
||||
s:=', '
|
||||
else
|
||||
AsmWriteLn(tai_symbolpair(hp).sym^+', '+tai_symbolpair(hp).value^);
|
||||
{ the .localentry directive has to specify the size from the
|
||||
start till here of the non-local entry code as second argument }
|
||||
s:=', .-';
|
||||
if replaceforbidden then
|
||||
AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).sym^)+s+ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).value^))
|
||||
else
|
||||
AsmWriteLn(tai_symbolpair(hp).sym^+s+tai_symbolpair(hp).value^);
|
||||
end;
|
||||
ait_weak:
|
||||
begin
|
||||
|
@ -28,7 +28,8 @@ interface
|
||||
uses
|
||||
cpubase,
|
||||
globtype,
|
||||
parabase,cgbase,cgutils,
|
||||
parabase,cgutils,
|
||||
aasmdata,cgbase,
|
||||
symdef,node,ncal;
|
||||
|
||||
type
|
||||
@ -97,6 +98,9 @@ interface
|
||||
procedure do_call_ref(ref: treference);virtual;
|
||||
|
||||
procedure load_block_invoke(toreg: tregister);virtual;
|
||||
|
||||
function get_call_reg(list: TAsmList): tregister; virtual;
|
||||
procedure unget_call_reg(list: TAsmList; reg: tregister); virtual;
|
||||
public
|
||||
procedure pass_generate_code;override;
|
||||
destructor destroy;override;
|
||||
@ -111,7 +115,7 @@ implementation
|
||||
cpuinfo,
|
||||
symconst,symbase,symtable,symtype,symsym,defutil,paramgr,
|
||||
pass_2,
|
||||
aasmbase,aasmtai,aasmdata,
|
||||
aasmbase,aasmtai,
|
||||
nbas,nmem,nld,ncnv,nutils,
|
||||
ncgutil,blockutl,
|
||||
cgobj,tgobj,hlcgobj,
|
||||
@ -471,6 +475,18 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function tcgcallnode.get_call_reg(list: TAsmList): tregister;
|
||||
begin
|
||||
result:=hlcg.getaddressregister(current_asmdata.CurrAsmList,procdefinition.address_type);
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgcallnode.unget_call_reg(list: TAsmList; reg: tregister);
|
||||
begin
|
||||
{ nothing to do by default }
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgcallnode.set_result_location(realresdef: tstoreddef);
|
||||
begin
|
||||
if realresdef.is_intregable or
|
||||
@ -947,7 +963,7 @@ implementation
|
||||
callref:=can_call_ref(href);
|
||||
if not callref then
|
||||
begin
|
||||
pvreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,proc_addr_voidptrdef);
|
||||
pvreg:=get_call_reg(current_asmdata.CurrAsmList);
|
||||
cg.a_load_ref_reg(current_asmdata.CurrAsmList,proc_addr_size,proc_addr_size,href,pvreg);
|
||||
end;
|
||||
|
||||
@ -977,7 +993,10 @@ implementation
|
||||
if callref then
|
||||
do_call_ref(href)
|
||||
else
|
||||
hlcg.a_call_reg(current_asmdata.CurrAsmList,tabstractprocdef(procdefinition),pvreg);
|
||||
begin
|
||||
hlcg.a_call_reg(current_asmdata.CurrAsmList,tabstractprocdef(procdefinition),pvreg);
|
||||
unget_call_reg(current_asmdata.CurrAsmList,pvreg);
|
||||
end;
|
||||
|
||||
extra_post_call_code;
|
||||
end
|
||||
|
@ -1167,7 +1167,33 @@ var
|
||||
|
||||
var
|
||||
href: treference;
|
||||
lab: tasmlabel;
|
||||
procmangledname: TSymStr;
|
||||
begin
|
||||
{ In ELFv2 the function is required to initialise the TOC register itself
|
||||
if necessary. Additionally, it has to mark the end of this TOC
|
||||
initialisation code with a .localfunc directive, which will be used as
|
||||
local entry code by the linker (when it knows the TOC value is the same
|
||||
for the caller and callee). It must load the TOC in a PIC-way, which it
|
||||
can do easily because R12 is guaranteed to hold the address of this function
|
||||
on entry. }
|
||||
if (target_info.abi=abi_powerpc_elfv2) and
|
||||
(pi_needs_got in current_procinfo.flags) and
|
||||
not nostackframe then
|
||||
begin
|
||||
current_asmdata.getlabel(lab,alt_addr);
|
||||
getcpuregister(list,NR_R12);
|
||||
getcpuregister(list,NR_R2);
|
||||
cg.a_label(list,lab);
|
||||
reference_reset_symbol(href,current_asmdata.RefAsmSymbol('.TOC.',AT_DATA),0,sizeof(PInt));
|
||||
href.relsymbol:=lab;
|
||||
href.refaddr:=addr_higha;
|
||||
list.concat(taicpu.op_reg_reg_ref(a_addis,NR_R2,NR_R12,href));
|
||||
href.refaddr:=addr_low;
|
||||
list.concat(taicpu.op_reg_reg_ref(a_addi,NR_R2,NR_R2,href));
|
||||
procmangledname:=current_procinfo.procdef.mangledname;
|
||||
list.concat(tai_symbolpair.create(spk_localentry,procmangledname,procmangledname));
|
||||
end;
|
||||
calcFirstUsedFPR(firstregfpu, fprcount);
|
||||
calcFirstUsedGPR(firstreggpr, gprcount);
|
||||
|
||||
|
@ -26,6 +26,7 @@ unit nppccal;
|
||||
interface
|
||||
|
||||
uses
|
||||
aasmdata, cgbase,
|
||||
symdef, node, ncal, ncgcal;
|
||||
|
||||
type
|
||||
@ -34,6 +35,11 @@ type
|
||||
end;
|
||||
|
||||
tppccallnode = class(tcgcallnode)
|
||||
protected
|
||||
function get_call_reg(list: TAsmList): tregister; override;
|
||||
procedure unget_call_reg(list: TAsmList; reg: tregister); override;
|
||||
public
|
||||
function pass_1: tnode; override;
|
||||
procedure do_syscall; override;
|
||||
end;
|
||||
|
||||
@ -43,12 +49,40 @@ uses
|
||||
globtype, systems,
|
||||
cutils, verbose, globals,
|
||||
symconst, symbase, symsym, symtable, defutil, paramgr, parabase,
|
||||
cgbase, pass_2,
|
||||
cpuinfo, cpubase, aasmbase, aasmtai,aasmdata, aasmcpu,
|
||||
pass_2,
|
||||
cpuinfo, cpubase, aasmbase, aasmtai, aasmcpu,
|
||||
nmem, nld, ncnv,
|
||||
ncgutil, cgutils, cgobj, tgobj, regvars, rgobj, rgcpu,
|
||||
cgcpu, cpupi, procinfo;
|
||||
|
||||
|
||||
function tppccallnode.get_call_reg(list: TAsmList): tregister;
|
||||
begin
|
||||
{ on the ppc64/ELFv2 abi, all indirect calls must go via R12, so that the
|
||||
called function can use R12 as PIC base register }
|
||||
cg.getcpuregister(list,NR_R12);
|
||||
result:=NR_R12;
|
||||
end;
|
||||
|
||||
|
||||
procedure tppccallnode.unget_call_reg(list: TAsmList; reg: tregister);
|
||||
begin
|
||||
cg.ungetcpuregister(list,NR_R12);
|
||||
end;
|
||||
|
||||
function tppccallnode.pass_1: tnode;
|
||||
begin
|
||||
result:=inherited;
|
||||
if assigned(result) then
|
||||
exit;
|
||||
{ for ELFv2, we must load the TOC/GOT register in case this routine may
|
||||
call an external routine (because the lookup of the target address is
|
||||
TOC-based). Maybe needs to be extended to non-ELFv2 too }
|
||||
if target_info.abi=abi_powerpc_elfv2 then
|
||||
include(current_procinfo.flags,pi_needs_got);
|
||||
end;
|
||||
|
||||
|
||||
procedure tppccallnode.do_syscall;
|
||||
begin
|
||||
{ no MorphOS style syscalls supported. Only implemented to avoid abstract
|
||||
|
@ -39,6 +39,8 @@ type
|
||||
procedure ReadAt(oper: tppcoperand);
|
||||
procedure ReadSym(oper: tppcoperand);
|
||||
procedure ConvertCalljmp(instr: tppcinstruction);
|
||||
function is_targetdirective(const s: string): boolean; override;
|
||||
procedure HandleTargetDirective; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -773,6 +775,44 @@ begin
|
||||
instr.Operands[1].opr.symbol:=current_asmdata.DefineAsmSymbol('.'+instr.Operands[1].opr.symbol.name,instr.Operands[1].opr.symbol.bind,AT_FUNCTION);
|
||||
end;
|
||||
|
||||
function tppcattreader.is_targetdirective(const s: string): boolean;
|
||||
begin
|
||||
if (target_info.abi=abi_powerpc_elfv2) and
|
||||
(s='.localentry') then
|
||||
result:=true
|
||||
else
|
||||
result:=inherited;
|
||||
end;
|
||||
|
||||
procedure tppcattreader.HandleTargetDirective;
|
||||
var
|
||||
symname,
|
||||
symval : String;
|
||||
val : aint;
|
||||
symtyp : TAsmsymtype;
|
||||
begin
|
||||
if (target_info.abi=abi_powerpc_elfv2) and
|
||||
(actasmpattern='.localentry') then
|
||||
begin
|
||||
{ .localentry funcname, .-funcname }
|
||||
consume(AS_TARGET_DIRECTIVE);
|
||||
BuildConstSymbolExpression(true,false,false, val,symname,symtyp);
|
||||
Consume(AS_COMMA);
|
||||
{ we need a '.', but these are parsed as identifiers -> if the current
|
||||
pattern is different from a '.' try to consume AS_DOT so we'll get
|
||||
the correct error message, otherwise consume this '.' identifier }
|
||||
if actasmpattern<>'.' then
|
||||
Consume(AS_DOT)
|
||||
else
|
||||
Consume(AS_ID);
|
||||
Consume(AS_MINUS);
|
||||
BuildConstSymbolExpression(true,false,false, val,symval,symtyp);
|
||||
curList.concat(tai_symbolpair.create(spk_localentry,symname,symval));
|
||||
end
|
||||
else
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure tppcattreader.handleopcode;
|
||||
var
|
||||
instr: tppcinstruction;
|
||||
|
@ -411,6 +411,8 @@ unit agppcgas;
|
||||
var
|
||||
i : longint;
|
||||
begin
|
||||
if target_info.abi = abi_powerpc_elfv2 then
|
||||
AsmWriteln(#9'.abiversion 2');
|
||||
for i:=0 to 31 do
|
||||
AsmWriteln(#9'.set'#9'r'+tostr(i)+','+tostr(i));
|
||||
for i:=0 to 31 do
|
||||
|
@ -74,7 +74,11 @@ asm
|
||||
fcfid f0,f0 // convert to fpu int
|
||||
end;
|
||||
|
||||
{$ifndef aix}
|
||||
{ we wouls have to generate the .localfunc directive for ELFv2, and moreover it
|
||||
must appear at the start right after setting up the TOC pointer, but the local
|
||||
variables will cause the code generator to already insert the stack allocation
|
||||
before that... -> disable this routine for ELFv2 }
|
||||
{$if not defined(aix) and (not defined(linux) or (defined(_ELF_CALL) and (_ELF_CALL = 1))) }
|
||||
|
||||
{$define FPC_SYSTEM_HAS_QWORD_TO_DOUBLE}
|
||||
function fpc_qword_to_double(q: qword): double; compilerproc;assembler;
|
||||
|
Loading…
Reference in New Issue
Block a user