mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-21 18:29:27 +02:00
+ Generate unwind bytecode for function prologues on win64.
* For now placed actual processing of unwind info under {$ifdef TEST_WIN64_UNWIND}, because in the current state it doesn't add much value. git-svn-id: trunk@19200 -
This commit is contained in:
parent
dff5ac3b0a
commit
b997094755
@ -1238,6 +1238,7 @@ implementation
|
||||
|
||||
ait_seh_directive :
|
||||
begin
|
||||
{$ifdef TEST_WIN64_UNWIND}
|
||||
AsmWrite('.'+sehdirectivestr[tai_seh_directive(hp).kind]);
|
||||
case tai_seh_directive(hp).datatype of
|
||||
sd_none:;
|
||||
@ -1252,6 +1253,7 @@ implementation
|
||||
tostr(tai_seh_directive(hp).data.offset));
|
||||
end;
|
||||
AsmLn;
|
||||
{$endif TEST_WIN64_UNWIND}
|
||||
end;
|
||||
|
||||
else
|
||||
|
@ -1393,8 +1393,10 @@ Implementation
|
||||
ait_cutobject :
|
||||
if SmartAsm then
|
||||
break;
|
||||
{$ifdef TEST_WIN64_UNWIND}
|
||||
ait_seh_directive :
|
||||
tai_seh_directive(hp).generate_code(objdata);
|
||||
{$endif TEST_WIN64_UNWIND}
|
||||
end;
|
||||
hp:=Tai(hp.next);
|
||||
end;
|
||||
|
@ -466,7 +466,9 @@ interface
|
||||
{ dfa was generated for this proc }
|
||||
pi_dfaavailable,
|
||||
{ subroutine contains interprocedural used labels }
|
||||
pi_has_interproclabel
|
||||
pi_has_interproclabel,
|
||||
{ subroutine has unwind info (win64) }
|
||||
pi_has_unwind_info
|
||||
);
|
||||
tprocinfoflags=set of tprocinfoflag;
|
||||
|
||||
|
@ -95,6 +95,12 @@ unit procinfo;
|
||||
{ Holds the reference used to store all saved registers. }
|
||||
save_regs_ref : treference;
|
||||
|
||||
{ Last assembler instruction of procedure prologue }
|
||||
endprologue_ai : tlinkedlistitem;
|
||||
|
||||
{ Amount of stack adjustment after all alignments }
|
||||
final_localsize : longint;
|
||||
|
||||
{ Labels for TRUE/FALSE condition, BREAK and CONTINUE }
|
||||
CurrBreakLabel,
|
||||
CurrContinueLabel,
|
||||
@ -183,7 +189,6 @@ implementation
|
||||
CurrContinueLabel:=nil;
|
||||
CurrTrueLabel:=nil;
|
||||
CurrFalseLabel:=nil;
|
||||
maxpushedparasize:=0;
|
||||
if Assigned(parent) and (parent.procdef.parast.symtablelevel>=normal_function_level) then
|
||||
parent.addnestedproc(Self);
|
||||
end;
|
||||
|
@ -1174,6 +1174,9 @@ implementation
|
||||
{ Add save and restore of used registers }
|
||||
current_filepos:=entrypos;
|
||||
gen_save_used_regs(templist);
|
||||
{ Remember the last instruction of register saving block
|
||||
(may be =nil for e.g. assembler procedures) }
|
||||
current_procinfo.endprologue_ai:=templist.last;
|
||||
aktproccode.insertlistafter(headertai,templist);
|
||||
current_filepos:=exitpos;
|
||||
gen_restore_used_regs(aktproccode);
|
||||
|
@ -1018,7 +1018,9 @@ const
|
||||
(mask:pi_dfaavailable;
|
||||
str:' dfa was generated for this proc '),
|
||||
(mask:pi_has_interproclabel;
|
||||
str:' subroutine contains interprocedural used labels ')
|
||||
str:' subroutine contains interprocedural used labels '),
|
||||
(mask:pi_has_unwind_info;
|
||||
str:' unwinding info was generated for this proc ')
|
||||
);
|
||||
var
|
||||
procinfooptions : tprocinfoflags;
|
||||
|
@ -2175,11 +2175,23 @@ unit cgx86;
|
||||
inc(stackmisalignment,sizeof(pint));
|
||||
include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
|
||||
list.concat(Taicpu.op_reg(A_PUSH,tcgsize2opsize[OS_ADDR],NR_FRAME_POINTER_REG));
|
||||
if (target_info.system=system_x86_64_win64) then
|
||||
begin
|
||||
list.concat(cai_seh_directive.create_reg(ash_pushreg,NR_FRAME_POINTER_REG));
|
||||
include(current_procinfo.flags,pi_has_unwind_info);
|
||||
end;
|
||||
{ Return address and FP are both on stack }
|
||||
current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*sizeof(pint));
|
||||
current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(2*sizeof(pint)));
|
||||
list.concat(Taicpu.op_reg_reg(A_MOV,tcgsize2opsize[OS_ADDR],NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG));
|
||||
current_asmdata.asmcfi.cfa_def_cfa_register(list,NR_FRAME_POINTER_REG);
|
||||
{
|
||||
TODO: current framepointer handling is not compatible with Win64 at all:
|
||||
Win64 expects FP to point to the top or into the middle of local area.
|
||||
In FPC it points to the bottom, making it impossible to generate
|
||||
UWOP_SET_FPREG unwind code if local area is > 240 bytes.
|
||||
So for now pretend we never have a framepointer.
|
||||
}
|
||||
end;
|
||||
|
||||
{ allocate stackframe space }
|
||||
@ -2194,6 +2206,12 @@ unit cgx86;
|
||||
cg.g_stackpointer_alloc(list,localsize);
|
||||
if current_procinfo.framepointer=NR_STACK_POINTER_REG then
|
||||
current_asmdata.asmcfi.cfa_def_cfa_offset(list,localsize+sizeof(pint));
|
||||
current_procinfo.final_localsize:=localsize;
|
||||
if (target_info.system=system_x86_64_win64) then
|
||||
begin
|
||||
list.concat(cai_seh_directive.create_offset(ash_stackalloc,localsize));
|
||||
include(current_procinfo.flags,pi_has_unwind_info);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
@ -37,6 +37,7 @@ unit cgcpu;
|
||||
procedure init_register_allocators;override;
|
||||
procedure done_register_allocators;override;
|
||||
|
||||
procedure g_proc_entry(list : TAsmList; parasize:longint; nostackframe:boolean);override;
|
||||
procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
|
||||
procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
|
||||
|
||||
@ -49,7 +50,7 @@ unit cgcpu;
|
||||
implementation
|
||||
|
||||
uses
|
||||
globtype,globals,verbose,systems,cutils,
|
||||
globtype,globals,verbose,systems,cutils,cclasses,
|
||||
symsym,defutil,paramgr,fmodule,
|
||||
rgobj,tgobj,rgcpu;
|
||||
|
||||
@ -110,10 +111,71 @@ unit cgcpu;
|
||||
setlength(saved_mm_registers,0);
|
||||
end;
|
||||
|
||||
procedure tcgx86_64.g_proc_entry(list : TAsmList;parasize:longint;nostackframe:boolean);
|
||||
var
|
||||
hitem: tlinkedlistitem;
|
||||
r: integer;
|
||||
href: treference;
|
||||
templist: TAsmList;
|
||||
frame_offset: longint;
|
||||
begin
|
||||
hitem:=list.last;
|
||||
inherited g_proc_entry(list,parasize,nostackframe);
|
||||
|
||||
if not (pi_has_unwind_info in current_procinfo.flags) then
|
||||
exit;
|
||||
{ Generate unwind data for x86_64-win64 }
|
||||
list.insertafter(cai_seh_directive.create_name(ash_proc,current_procinfo.procdef.mangledname),hitem);
|
||||
templist:=TAsmList.Create;
|
||||
|
||||
{ We need to record postive offsets from RSP; if registers are saved
|
||||
at negative offsets from RBP we need to account for it. }
|
||||
if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
|
||||
frame_offset:=current_procinfo.final_localsize
|
||||
else
|
||||
frame_offset:=0;
|
||||
|
||||
{ There's no need to describe position of register saves precisely;
|
||||
since registers are not modified before they are saved, and saves do not
|
||||
change RSP, 'logically' all saves can happen at the end of prologue. }
|
||||
href:=current_procinfo.save_regs_ref;
|
||||
for r:=low(saved_standard_registers) to high(saved_standard_registers) do
|
||||
if saved_standard_registers[r] in rg[R_INTREGISTER].used_in_proc then
|
||||
begin
|
||||
templist.concat(cai_seh_directive.create_reg_offset(ash_savereg,
|
||||
newreg(R_INTREGISTER,saved_standard_registers[r],R_SUBWHOLE),
|
||||
href.offset+frame_offset));
|
||||
inc(href.offset,sizeof(aint));
|
||||
end;
|
||||
if uses_registers(R_MMREGISTER) then
|
||||
begin
|
||||
if (href.offset mod tcgsize2size[OS_VECTOR])<>0 then
|
||||
inc(href.offset,tcgsize2size[OS_VECTOR]-(href.offset mod tcgsize2size[OS_VECTOR]));
|
||||
|
||||
for r:=low(saved_mm_registers) to high(saved_mm_registers) do
|
||||
begin
|
||||
if saved_mm_registers[r] in rg[R_MMREGISTER].used_in_proc then
|
||||
begin
|
||||
templist.concat(cai_seh_directive.create_reg_offset(ash_savexmm,
|
||||
newreg(R_MMREGISTER,saved_mm_registers[r],R_SUBNONE),
|
||||
href.offset+frame_offset));
|
||||
inc(href.offset,tcgsize2size[OS_VECTOR]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
templist.concat(cai_seh_directive.create(ash_endprologue));
|
||||
if assigned(current_procinfo.endprologue_ai) then
|
||||
current_procinfo.aktproccode.insertlistbefore(current_procinfo.endprologue_ai,templist)
|
||||
else
|
||||
list.concatlist(templist);
|
||||
templist.free;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgx86_64.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
|
||||
var
|
||||
stacksize : longint;
|
||||
href : treference;
|
||||
begin
|
||||
{ Release PIC register }
|
||||
if cs_create_pic in current_settings.moduleswitches then
|
||||
@ -135,12 +197,24 @@ unit cgcpu;
|
||||
if (stacksize<>0) then
|
||||
cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
|
||||
end
|
||||
else if (target_info.system=system_x86_64_win64) then
|
||||
begin
|
||||
{ Comply with Win64 unwinding mechanism, which only recognizes
|
||||
'add $constant,%rsp' and 'lea offset(FPREG),%rsp' as belonging to
|
||||
the function epilog.
|
||||
Neither 'leave' nor even 'mov %FPREG,%rsp' are allowed. }
|
||||
reference_reset_base(href,current_procinfo.framepointer,0,sizeof(pint));
|
||||
list.concat(Taicpu.op_ref_reg(A_LEA,tcgsize2opsize[OS_ADDR],href,NR_STACK_POINTER_REG));
|
||||
list.concat(Taicpu.op_reg(A_POP,tcgsize2opsize[OS_ADDR],current_procinfo.framepointer));
|
||||
end
|
||||
else
|
||||
list.concat(Taicpu.op_none(A_LEAVE,S_NO));
|
||||
list.concat(tai_regalloc.dealloc(NR_FRAME_POINTER_REG,nil));
|
||||
end;
|
||||
|
||||
list.concat(Taicpu.Op_none(A_RET,S_NO));
|
||||
if (pi_has_unwind_info in current_procinfo.flags) then
|
||||
list.concat(cai_seh_directive.create(ash_endproc));
|
||||
end;
|
||||
|
||||
|
||||
|
@ -234,7 +234,7 @@ begin
|
||||
|
||||
FElements.Clear;
|
||||
|
||||
objdata.createsection(sec_pdata,FName^);
|
||||
objdata.createsection(sec_pdata,lower(FName^));
|
||||
pdatasym:=objdata.symboldefine('$pdata$'+FName^,AB_LOCAL,AT_DATA);
|
||||
objdata.writereloc(0,4,FFrameStartSym,RELOC_RVA);
|
||||
objdata.writereloc(FFrameStartSym.Size,4,FFrameStartSym,RELOC_RVA);
|
||||
@ -268,6 +268,8 @@ end;
|
||||
|
||||
procedure TWin64CFI.end_prologue(objdata:TObjData);
|
||||
begin
|
||||
if not assigned(FName) then
|
||||
internalerror(2011072312);
|
||||
FPrologueEndPos:=objdata.CurrObjSec.Size;
|
||||
end;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user