mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-13 09:39:09 +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 :
|
ait_seh_directive :
|
||||||
begin
|
begin
|
||||||
|
{$ifdef TEST_WIN64_UNWIND}
|
||||||
AsmWrite('.'+sehdirectivestr[tai_seh_directive(hp).kind]);
|
AsmWrite('.'+sehdirectivestr[tai_seh_directive(hp).kind]);
|
||||||
case tai_seh_directive(hp).datatype of
|
case tai_seh_directive(hp).datatype of
|
||||||
sd_none:;
|
sd_none:;
|
||||||
@ -1252,6 +1253,7 @@ implementation
|
|||||||
tostr(tai_seh_directive(hp).data.offset));
|
tostr(tai_seh_directive(hp).data.offset));
|
||||||
end;
|
end;
|
||||||
AsmLn;
|
AsmLn;
|
||||||
|
{$endif TEST_WIN64_UNWIND}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -1393,8 +1393,10 @@ Implementation
|
|||||||
ait_cutobject :
|
ait_cutobject :
|
||||||
if SmartAsm then
|
if SmartAsm then
|
||||||
break;
|
break;
|
||||||
|
{$ifdef TEST_WIN64_UNWIND}
|
||||||
ait_seh_directive :
|
ait_seh_directive :
|
||||||
tai_seh_directive(hp).generate_code(objdata);
|
tai_seh_directive(hp).generate_code(objdata);
|
||||||
|
{$endif TEST_WIN64_UNWIND}
|
||||||
end;
|
end;
|
||||||
hp:=Tai(hp.next);
|
hp:=Tai(hp.next);
|
||||||
end;
|
end;
|
||||||
|
@ -466,7 +466,9 @@ interface
|
|||||||
{ dfa was generated for this proc }
|
{ dfa was generated for this proc }
|
||||||
pi_dfaavailable,
|
pi_dfaavailable,
|
||||||
{ subroutine contains interprocedural used labels }
|
{ subroutine contains interprocedural used labels }
|
||||||
pi_has_interproclabel
|
pi_has_interproclabel,
|
||||||
|
{ subroutine has unwind info (win64) }
|
||||||
|
pi_has_unwind_info
|
||||||
);
|
);
|
||||||
tprocinfoflags=set of tprocinfoflag;
|
tprocinfoflags=set of tprocinfoflag;
|
||||||
|
|
||||||
|
@ -95,6 +95,12 @@ unit procinfo;
|
|||||||
{ Holds the reference used to store all saved registers. }
|
{ Holds the reference used to store all saved registers. }
|
||||||
save_regs_ref : treference;
|
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 }
|
{ Labels for TRUE/FALSE condition, BREAK and CONTINUE }
|
||||||
CurrBreakLabel,
|
CurrBreakLabel,
|
||||||
CurrContinueLabel,
|
CurrContinueLabel,
|
||||||
@ -183,7 +189,6 @@ implementation
|
|||||||
CurrContinueLabel:=nil;
|
CurrContinueLabel:=nil;
|
||||||
CurrTrueLabel:=nil;
|
CurrTrueLabel:=nil;
|
||||||
CurrFalseLabel:=nil;
|
CurrFalseLabel:=nil;
|
||||||
maxpushedparasize:=0;
|
|
||||||
if Assigned(parent) and (parent.procdef.parast.symtablelevel>=normal_function_level) then
|
if Assigned(parent) and (parent.procdef.parast.symtablelevel>=normal_function_level) then
|
||||||
parent.addnestedproc(Self);
|
parent.addnestedproc(Self);
|
||||||
end;
|
end;
|
||||||
|
@ -1174,6 +1174,9 @@ implementation
|
|||||||
{ Add save and restore of used registers }
|
{ Add save and restore of used registers }
|
||||||
current_filepos:=entrypos;
|
current_filepos:=entrypos;
|
||||||
gen_save_used_regs(templist);
|
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);
|
aktproccode.insertlistafter(headertai,templist);
|
||||||
current_filepos:=exitpos;
|
current_filepos:=exitpos;
|
||||||
gen_restore_used_regs(aktproccode);
|
gen_restore_used_regs(aktproccode);
|
||||||
|
@ -1018,7 +1018,9 @@ const
|
|||||||
(mask:pi_dfaavailable;
|
(mask:pi_dfaavailable;
|
||||||
str:' dfa was generated for this proc '),
|
str:' dfa was generated for this proc '),
|
||||||
(mask:pi_has_interproclabel;
|
(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
|
var
|
||||||
procinfooptions : tprocinfoflags;
|
procinfooptions : tprocinfoflags;
|
||||||
|
@ -2175,11 +2175,23 @@ unit cgx86;
|
|||||||
inc(stackmisalignment,sizeof(pint));
|
inc(stackmisalignment,sizeof(pint));
|
||||||
include(rg[R_INTREGISTER].preserved_by_proc,RS_FRAME_POINTER_REG);
|
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));
|
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 }
|
{ Return address and FP are both on stack }
|
||||||
current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*sizeof(pint));
|
current_asmdata.asmcfi.cfa_def_cfa_offset(list,2*sizeof(pint));
|
||||||
current_asmdata.asmcfi.cfa_offset(list,NR_FRAME_POINTER_REG,-(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));
|
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);
|
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;
|
end;
|
||||||
|
|
||||||
{ allocate stackframe space }
|
{ allocate stackframe space }
|
||||||
@ -2194,6 +2206,12 @@ unit cgx86;
|
|||||||
cg.g_stackpointer_alloc(list,localsize);
|
cg.g_stackpointer_alloc(list,localsize);
|
||||||
if current_procinfo.framepointer=NR_STACK_POINTER_REG then
|
if current_procinfo.framepointer=NR_STACK_POINTER_REG then
|
||||||
current_asmdata.asmcfi.cfa_def_cfa_offset(list,localsize+sizeof(pint));
|
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;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -37,6 +37,7 @@ unit cgcpu;
|
|||||||
procedure init_register_allocators;override;
|
procedure init_register_allocators;override;
|
||||||
procedure done_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_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);override;
|
||||||
procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
|
procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ unit cgcpu;
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
globtype,globals,verbose,systems,cutils,
|
globtype,globals,verbose,systems,cutils,cclasses,
|
||||||
symsym,defutil,paramgr,fmodule,
|
symsym,defutil,paramgr,fmodule,
|
||||||
rgobj,tgobj,rgcpu;
|
rgobj,tgobj,rgcpu;
|
||||||
|
|
||||||
@ -110,10 +111,71 @@ unit cgcpu;
|
|||||||
setlength(saved_mm_registers,0);
|
setlength(saved_mm_registers,0);
|
||||||
end;
|
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);
|
procedure tcgx86_64.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean);
|
||||||
var
|
var
|
||||||
stacksize : longint;
|
stacksize : longint;
|
||||||
|
href : treference;
|
||||||
begin
|
begin
|
||||||
{ Release PIC register }
|
{ Release PIC register }
|
||||||
if cs_create_pic in current_settings.moduleswitches then
|
if cs_create_pic in current_settings.moduleswitches then
|
||||||
@ -135,12 +197,24 @@ unit cgcpu;
|
|||||||
if (stacksize<>0) then
|
if (stacksize<>0) then
|
||||||
cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
|
cg.a_op_const_reg(list,OP_ADD,OS_ADDR,stacksize,current_procinfo.framepointer);
|
||||||
end
|
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
|
else
|
||||||
list.concat(Taicpu.op_none(A_LEAVE,S_NO));
|
list.concat(Taicpu.op_none(A_LEAVE,S_NO));
|
||||||
list.concat(tai_regalloc.dealloc(NR_FRAME_POINTER_REG,nil));
|
list.concat(tai_regalloc.dealloc(NR_FRAME_POINTER_REG,nil));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
list.concat(Taicpu.Op_none(A_RET,S_NO));
|
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;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -234,7 +234,7 @@ begin
|
|||||||
|
|
||||||
FElements.Clear;
|
FElements.Clear;
|
||||||
|
|
||||||
objdata.createsection(sec_pdata,FName^);
|
objdata.createsection(sec_pdata,lower(FName^));
|
||||||
pdatasym:=objdata.symboldefine('$pdata$'+FName^,AB_LOCAL,AT_DATA);
|
pdatasym:=objdata.symboldefine('$pdata$'+FName^,AB_LOCAL,AT_DATA);
|
||||||
objdata.writereloc(0,4,FFrameStartSym,RELOC_RVA);
|
objdata.writereloc(0,4,FFrameStartSym,RELOC_RVA);
|
||||||
objdata.writereloc(FFrameStartSym.Size,4,FFrameStartSym,RELOC_RVA);
|
objdata.writereloc(FFrameStartSym.Size,4,FFrameStartSym,RELOC_RVA);
|
||||||
@ -268,6 +268,8 @@ end;
|
|||||||
|
|
||||||
procedure TWin64CFI.end_prologue(objdata:TObjData);
|
procedure TWin64CFI.end_prologue(objdata:TObjData);
|
||||||
begin
|
begin
|
||||||
|
if not assigned(FName) then
|
||||||
|
internalerror(2011072312);
|
||||||
FPrologueEndPos:=objdata.CurrObjSec.Size;
|
FPrologueEndPos:=objdata.CurrObjSec.Size;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user