|
@@ -36,7 +36,7 @@ unit cgcpu;
|
|
|
tcgx86_64 = class(tcgx86)
|
|
|
procedure init_register_allocators;override;
|
|
|
|
|
|
- procedure g_proc_entry(list : TAsmList; parasize:longint; nostackframe:boolean);override;
|
|
|
+ procedure g_proc_entry(list : TAsmList;localsize: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_local_unwind(list: TAsmList; l: TAsmLabel);override;
|
|
@@ -109,7 +109,7 @@ unit cgcpu;
|
|
|
end;
|
|
|
|
|
|
|
|
|
- procedure tcgx86_64.g_proc_entry(list : TAsmList;parasize:longint;nostackframe:boolean);
|
|
|
+ procedure tcgx86_64.g_proc_entry(list : TAsmList;localsize:longint;nostackframe:boolean);
|
|
|
var
|
|
|
hitem: tlinkedlistitem;
|
|
|
r: integer;
|
|
@@ -117,13 +117,86 @@ unit cgcpu;
|
|
|
templist: TAsmList;
|
|
|
frame_offset: longint;
|
|
|
suppress_endprologue: boolean;
|
|
|
+ stackmisalignment: longint;
|
|
|
+ para: tparavarsym;
|
|
|
begin
|
|
|
hitem:=list.last;
|
|
|
{ pi_has_unwind_info may already be set at this point if there are
|
|
|
SEH directives in assembler body. In this case, .seh_endprologue
|
|
|
is expected to be one of those directives, and not generated here. }
|
|
|
suppress_endprologue:=(pi_has_unwind_info in current_procinfo.flags);
|
|
|
- inherited g_proc_entry(list,parasize,nostackframe);
|
|
|
+
|
|
|
+ { save old framepointer }
|
|
|
+ if not nostackframe then
|
|
|
+ begin
|
|
|
+ { return address }
|
|
|
+ stackmisalignment := sizeof(pint);
|
|
|
+ list.concat(tai_regalloc.alloc(current_procinfo.framepointer,nil));
|
|
|
+ if current_procinfo.framepointer=NR_STACK_POINTER_REG then
|
|
|
+ CGmessage(cg_d_stackframe_omited)
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ { push <frame_pointer> }
|
|
|
+ inc(stackmisalignment,sizeof(pint));
|
|
|
+ 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)));
|
|
|
+ if current_procinfo.procdef.proctypeoption<>potype_exceptfilter then
|
|
|
+ list.concat(Taicpu.op_reg_reg(A_MOV,tcgsize2opsize[OS_ADDR],NR_STACK_POINTER_REG,NR_FRAME_POINTER_REG))
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ { load framepointer from hidden $parentfp parameter }
|
|
|
+ para:=tparavarsym(current_procinfo.procdef.paras[0]);
|
|
|
+ if not (vo_is_parentfp in para.varoptions) then
|
|
|
+ InternalError(201201142);
|
|
|
+ if (para.paraloc[calleeside].location^.loc<>LOC_REGISTER) or
|
|
|
+ (para.paraloc[calleeside].location^.next<>nil) then
|
|
|
+ InternalError(201201143);
|
|
|
+ list.concat(Taicpu.op_reg_reg(A_MOV,tcgsize2opsize[OS_ADDR],
|
|
|
+ para.paraloc[calleeside].location^.register,NR_FRAME_POINTER_REG));
|
|
|
+ { Need only as much stack space as necessary to do the calls.
|
|
|
+ Exception filters don't have own local vars, and temps are 'mapped'
|
|
|
+ to the parent procedure.
|
|
|
+ maxpushedparasize is already aligned at least on x86_64. }
|
|
|
+ localsize:=current_procinfo.maxpushedparasize;
|
|
|
+ end;
|
|
|
+ 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 }
|
|
|
+ if (localsize<>0) or
|
|
|
+ ((target_info.stackalign>sizeof(pint)) and
|
|
|
+ (stackmisalignment <> 0) and
|
|
|
+ ((pi_do_call in current_procinfo.flags) or
|
|
|
+ (po_assembler in current_procinfo.procdef.procoptions))) then
|
|
|
+ begin
|
|
|
+ if target_info.stackalign>sizeof(pint) then
|
|
|
+ localsize := align(localsize+stackmisalignment,target_info.stackalign)-stackmisalignment;
|
|
|
+ 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
|
|
|
+ if localsize<>0 then
|
|
|
+ list.concat(cai_seh_directive.create_offset(ash_stackalloc,localsize));
|
|
|
+ include(current_procinfo.flags,pi_has_unwind_info);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
|
|
|
if not (pi_has_unwind_info in current_procinfo.flags) then
|
|
|
exit;
|