win64: add tiny unwind data for setjmp/longjmp

This enables native unwind semantics with longjmp on
win64 by putting an entry into the .pdata section for
each compiled fuction.

Also, the function now use a fixed stack and store arguments
into X(%rsp) rather than using push.
master
grischka 2009-12-19 22:40:28 +01:00
parent 88a3ccab9f
commit 50b040ef83
7 changed files with 322 additions and 110 deletions

View File

@ -426,6 +426,10 @@ static void gen_disp32(ExprValue *pe)
elimination in the linker */ elimination in the linker */
gen_le32(pe->v + sym->jnext - ind - 4); gen_le32(pe->v + sym->jnext - ind - 4);
} else { } else {
if (sym && sym->type.t == VT_VOID) {
sym->type.t = VT_FUNC;
sym->type.ref = NULL;
}
gen_addrpc32(VT_SYM, sym, pe->v); gen_addrpc32(VT_SYM, sym, pe->v);
} }
} }

7
tcc.h
View File

@ -521,6 +521,10 @@ struct TCCState {
/* PE info */ /* PE info */
int pe_subsystem; int pe_subsystem;
unsigned long pe_file_align; unsigned long pe_file_align;
struct pe_uw {
Section *pdata;
int sym_1, sym_2, offs_1;
} pe_unwind;
#endif #endif
#ifndef TCC_TARGET_PE #ifndef TCC_TARGET_PE
@ -1167,6 +1171,9 @@ ST_FUNC int pe_output_file(TCCState * s1, const char *filename);
ST_FUNC int pe_dllimport(int r, SValue *sv, void (*fn)(int r, SValue *sv)); ST_FUNC int pe_dllimport(int r, SValue *sv, void (*fn)(int r, SValue *sv));
/* tiny_impdef.c */ /* tiny_impdef.c */
ST_FUNC char *get_export_names(FILE *fp); ST_FUNC char *get_export_names(FILE *fp);
#ifdef TCC_TARGET_X86_64
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
#endif
#endif #endif
/* ------------ tccrun.c ----------------- */ /* ------------ tccrun.c ----------------- */

62
tccpe.c
View File

@ -289,6 +289,7 @@ enum {
sec_data , sec_data ,
sec_bss , sec_bss ,
sec_idata , sec_idata ,
sec_pdata ,
sec_other , sec_other ,
sec_rsrc , sec_rsrc ,
sec_stab , sec_stab ,
@ -301,6 +302,7 @@ static const DWORD pe_sec_flags[] = {
0xC0000040, /* ".data" , */ 0xC0000040, /* ".data" , */
0xC0000080, /* ".bss" , */ 0xC0000080, /* ".bss" , */
0x40000040, /* ".idata" , */ 0x40000040, /* ".idata" , */
0x40000040, /* ".pdata" , */
0xE0000060, /* < other > , */ 0xE0000060, /* < other > , */
0x40000040, /* ".rsrc" , */ 0x40000040, /* ".rsrc" , */
0x42000802, /* ".stab" , */ 0x42000802, /* ".stab" , */
@ -634,6 +636,10 @@ static int pe_write(struct pe_info *pe)
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size);
break; break;
case sec_pdata:
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size);
break;
case sec_stab: case sec_stab:
break; break;
} }
@ -1037,6 +1043,8 @@ static int pe_section_class(Section *s)
return sec_rsrc; return sec_rsrc;
if (0 == strcmp(name, ".iedat")) if (0 == strcmp(name, ".iedat"))
return sec_idata; return sec_idata;
if (0 == strcmp(name, ".pdata"))
return sec_pdata;
return sec_other; return sec_other;
} else if (type == SHT_NOBITS) { } else if (type == SHT_NOBITS) {
if (flags & SHF_WRITE) if (flags & SHF_WRITE)
@ -1086,7 +1094,7 @@ static int pe_assign_addresses (struct pe_info *pe)
#ifdef PE_MERGE_DATA #ifdef PE_MERGE_DATA
if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) { if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
/* append .bss to .data */ /* append .bss to .data */
s->sh_addr = addr = ((addr-1) | 15) + 1; s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1;
addr += s->data_offset; addr += s->data_offset;
si[-1].sh_size = addr - si[-1].sh_addr; si[-1].sh_size = addr - si[-1].sh_addr;
continue; continue;
@ -1162,7 +1170,7 @@ static void pe_relocate_rva (struct pe_info *pe, Section *s)
ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index; ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
addr = sym->st_value; addr = sym->st_value;
} }
// printf("reloc rva %08x %08x\n", (DWORD)rel->r_offset, addr); // printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name);
*(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase; *(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase;
} }
} }
@ -1623,6 +1631,56 @@ ST_FUNC int pe_dllimport(int r, SValue *sv, void (*fn)(int r, SValue *sv))
return 1; return 1;
} }
/* ------------------------------------------------------------- */
#ifdef TCC_TARGET_X86_64
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
{
static const char uw_info[] = {
0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
0x04, // UBYTE Size of prolog
0x02, // UBYTE Count of unwind codes
0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled)
// USHORT * n Unwind codes array
// 0x0b, 0x01, 0xff, 0xff, // stack size
0x04, 0x03, // set frame ptr (mov rsp -> rbp)
0x01, 0x50 // push reg (rbp)
};
struct pe_uw *pe_uw = &tcc_state->pe_unwind;
Section *uw, *pd;
WORD *p1;
DWORD *p2;
unsigned o2;
uw = data_section;
pd = pe_uw->pdata;
if (NULL == pd)
{
pe_uw->pdata = pd = find_section(tcc_state, ".pdata");
pe_uw->pdata->sh_addralign = 4;
section_ptr_add(uw, -uw->data_offset & 3);
pe_uw->offs_1 = uw->data_offset;
p1 = section_ptr_add(uw, sizeof uw_info);
/* use one common entry for all functions */
memcpy(p1, uw_info, sizeof uw_info);
pe_uw->sym_1 = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL);
pe_uw->sym_2 = put_elf_sym(symtab_section, 0, 0, 0, 0, uw->sh_num, NULL);
}
o2 = pd->data_offset;
p2 = section_ptr_add(pd, 3 * sizeof (DWORD));
/* record this function */
p2[0] = start;
p2[1] = end;
p2[2] = pe_uw->offs_1;
/* put relocations on it */
put_elf_reloc(symtab_section, pd, o2, R_X86_64_RELATIVE, pe_uw->sym_1);
put_elf_reloc(symtab_section, pd, o2+4, R_X86_64_RELATIVE, pe_uw->sym_1);
put_elf_reloc(symtab_section, pd, o2+8, R_X86_64_RELATIVE, pe_uw->sym_2);
}
#endif
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
#define PE_STDSYM(n,s) n #define PE_STDSYM(n,s) n

View File

@ -78,6 +78,13 @@ int tcc_run(TCCState *s1, int argc, char **argv)
return ret; return ret;
} }
#endif #endif
#ifdef TCC_TARGET_PE
{
unsigned char *p = tcc_get_symbol(s1, "tinyc_no_getbp");
if (p) *p = 0;
}
#endif
return (*prog_main)(argc, argv); return (*prog_main)(argc, argv);
} }

View File

@ -58,7 +58,7 @@ typedef unsigned __int64 uintptr_t;
#define _AMD64_ 1 #define _AMD64_ 1
#define __x86_64 1 #define __x86_64 1
#define USE_MINGW_SETJMP_TWO_ARGS #define USE_MINGW_SETJMP_TWO_ARGS
#define mingw_getsp tinyc_getsp #define mingw_getsp tinyc_getbp
#else #else
typedef __int32 intptr_t; typedef __int32 intptr_t;
typedef unsigned __int32 uintptr_t; typedef unsigned __int32 uintptr_t;

View File

@ -57,11 +57,19 @@ P0:
jmp *8(%rax) jmp *8(%rax)
/* ---------------------------------------------- */ /* ---------------------------------------------- */
/* avoid msvcrt unwind stuff for setjmp/longjmp */ /* setjmp/longjmp support */
.globl tinyc_getsp .globl tinyc_no_getbp
tinyc_getsp: tinyc_no_getbp:
.byte 0x90
.globl tinyc_getbp
tinyc_getbp:
xor %rax,%rax xor %rax,%rax
cmp %al,tinyc_no_getbp(%rax)
je t1
mov %rbp,%rax
t1:
ret ret
/* ---------------------------------------------- */ /* ---------------------------------------------- */

View File

@ -527,16 +527,6 @@ void store(int r, SValue *v)
} }
} }
static void gadd_sp(int val)
{
if (val == (char)val) {
o(0xc48348);
g(val);
} else {
oad(0xc48148, val); /* add $xxx, %rsp */
}
}
/* 'is_jmp' is '1' if it is a jump */ /* 'is_jmp' is '1' if it is a jump */
static void gcall_or_jmp(int is_jmp) static void gcall_or_jmp(int is_jmp)
{ {
@ -564,16 +554,238 @@ static void gcall_or_jmp(int is_jmp)
} }
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
#define REGN 4 #define REGN 4
static const uint8_t arg_regs[] = { static const uint8_t arg_regs[] = {
TREG_RCX, TREG_RDX, TREG_R8, TREG_R9 TREG_RCX, TREG_RDX, TREG_R8, TREG_R9
}; };
static int func_scratch;
/* Generate function call. The function address is pushed first, then
all the parameters in call order. This functions pops all the
parameters and the function address. */
void gen_offs_sp(int b, int r, int d)
{
if (d == (char)d) {
o(b | 0x4000 | (r << 11));
g(d);
} else {
o(b | 0x8000 | (r << 11));
gen_le32(d);
}
}
void gfunc_call(int nb_args)
{
int size, align, r, args_size, i, d, j, bt;
int nb_reg_args, gen_reg;
/* calculate the number of integer/float arguments */
nb_reg_args = 0;
for(i = 0; i < nb_args; i++) {
bt = (vtop[-i].type.t & VT_BTYPE);
if (bt != VT_STRUCT && bt != VT_LDOUBLE)
nb_reg_args++;
}
args_size = (nb_reg_args < REGN ? REGN : nb_reg_args) * PTR_SIZE;
save_regs(0); /* save used temporary registers */
/* for struct arguments, we need to call memcpy and the function
call breaks register passing arguments we are preparing.
So, we process arguments which will be passed by stack first. */
for(i = 0; i < nb_args; i++) {
SValue *sv = &vtop[-i];
bt = (sv->type.t & VT_BTYPE);
if (bt == VT_STRUCT) {
size = type_size(&sv->type, &align);
/* align to stack align size */
size = (size + 15) & ~16;
/* generate structure store */
r = get_reg(RC_INT);
o(0x48);
gen_offs_sp(0x24048d, r, args_size);
args_size += size;
/* generate memcpy call */
vset(&sv->type, r | VT_LVAL, 0);
*++vtop = *sv;
vstore();
--vtop;
} else if (bt == VT_LDOUBLE) {
gv(RC_ST0);
gen_offs_sp(0x243cdb, 0, args_size);
args_size += 16;
}
}
if (func_scratch < args_size)
func_scratch = args_size;
gen_reg = nb_reg_args;
for(i = 0; i < nb_args; i++) {
bt = (vtop->type.t & VT_BTYPE);
if (bt == VT_STRUCT || bt == VT_LDOUBLE) {
; /* done */
} else if (is_sse_float(vtop->type.t)) {
gv(RC_FLOAT); /* only one float register */
j = --gen_reg;
if (j >= REGN) {
o(0x0f66),
/* movq %xmm0, j*8(%rsp) */
gen_offs_sp(0x2444d6, 0, j*8);
} else {
d = arg_regs[j];
/* movaps %xmm0, %xmmN */
o(0x280f);
o(0xc0 + (j << 3));
/* mov %xmm0, %rxx */
o(0x66);
o(0x7e0f48 + (d >= 8));
o(0xc0 + (d & 7));
}
} else {
r = gv(RC_INT);
j = --gen_reg;
if (j >= REGN) {
o(0x48);
gen_offs_sp(0x244489, r, j*8);
} else {
d = arg_regs[j];
if (d != r) {
o(0x8948 + (d >= 8));
o(0xc0 + r*8 + (d & 7));
}
}
}
vtop--;
}
gcall_or_jmp(0);
vtop--;
}
#define FUNC_PROLOG_SIZE 11
/* generate function prolog of type 't' */
void gfunc_prolog(CType *func_type)
{
int addr, align, size, reg_param_index, bt;
Sym *sym;
CType *type;
func_ret_sub = 0;
func_scratch = 0;
loc = 0;
addr = PTR_SIZE * 2;
ind += FUNC_PROLOG_SIZE;
func_sub_sp_offset = ind;
reg_param_index = 0;
sym = func_type->ref;
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
reg_param_index++;
addr += PTR_SIZE;
}
/* define parameters */
while ((sym = sym->next) != NULL) {
type = &sym->type;
bt = type->t & VT_BTYPE;
if (bt == VT_STRUCT || bt == VT_LDOUBLE)
continue;
if (reg_param_index < REGN) {
/* save arguments passed by register */
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
}
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
reg_param_index++;
addr += PTR_SIZE;
}
while (reg_param_index < REGN) {
if (func_type->ref->c == FUNC_ELLIPSIS)
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
reg_param_index++;
addr += PTR_SIZE;
}
sym = func_type->ref;
while ((sym = sym->next) != NULL) {
type = &sym->type;
bt = type->t & VT_BTYPE;
if (bt == VT_STRUCT || bt == VT_LDOUBLE) {
size = type_size(type, &align);
size = (size + 15) & -16;
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
addr += size;
}
}
}
/* generate function epilog */
void gfunc_epilog(void)
{
int v, saved_ind;
o(0xc9); /* leave */
if (func_ret_sub == 0) {
o(0xc3); /* ret */
} else {
o(0xc2); /* ret n */
g(func_ret_sub);
g(func_ret_sub >> 8);
}
saved_ind = ind;
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
/* align local size to word & save local variables */
v = (func_scratch + -loc + 15) & -16;
pe_add_unwind_data(ind, saved_ind, v);
if (v >= 4096) {
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
oad(0xb8, v); /* mov stacksize, %eax */
oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
greloc(cur_text_section, sym, ind-4, R_X86_64_PC32);
o(0x90); /* fill for FUNC_PROLOG_SIZE = 11 bytes */
} else {
o(0xe5894855); /* push %rbp, mov %rsp, %rbp */
o(0xec8148); /* sub rsp, stacksize */
gen_le32(v);
}
ind = saved_ind;
}
#else #else
static void gadd_sp(int val)
{
if (val == (char)val) {
o(0xc48348);
g(val);
} else {
oad(0xc48148, val); /* add $xxx, %rsp */
}
}
#define REGN 6 #define REGN 6
static const uint8_t arg_regs[REGN] = { static const uint8_t arg_regs[REGN] = {
TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9 TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9
}; };
#endif
/* Generate function call. The function address is pushed first, then /* Generate function call. The function address is pushed first, then
all the parameters in call order. This functions pops all the all the parameters in call order. This functions pops all the
@ -593,11 +805,9 @@ void gfunc_call(int nb_args)
args_size += type_size(&vtop->type, &align); args_size += type_size(&vtop->type, &align);
} else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE) { } else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE) {
args_size += 16; args_size += 16;
#ifndef TCC_TARGET_PE
} else if (is_sse_float(vtop[-i].type.t)) { } else if (is_sse_float(vtop[-i].type.t)) {
nb_sse_args++; nb_sse_args++;
if (nb_sse_args > 8) args_size += 8; if (nb_sse_args > 8) args_size += 8;
#endif
} else { } else {
nb_reg_args++; nb_reg_args++;
if (nb_reg_args > REGN) args_size += 8; if (nb_reg_args > REGN) args_size += 8;
@ -611,10 +821,6 @@ void gfunc_call(int nb_args)
gen_reg = nb_reg_args; gen_reg = nb_reg_args;
sse_reg = nb_sse_args; sse_reg = nb_sse_args;
#ifdef TCC_TARGET_PE
save_regs(0); /* save used temporary registers */
#endif
/* adjust stack to align SSE boundary */ /* adjust stack to align SSE boundary */
if (args_size &= 8) { if (args_size &= 8) {
o(0x50); /* push $rax */ o(0x50); /* push $rax */
@ -650,13 +856,8 @@ void gfunc_call(int nb_args)
g(0x00); g(0x00);
args_size += size; args_size += size;
} else if (is_sse_float(vtop->type.t)) { } else if (is_sse_float(vtop->type.t)) {
#ifdef TCC_TARGET_PE
int j = --gen_reg;
if (j >= REGN) {
#else
int j = --sse_reg; int j = --sse_reg;
if (j >= 8) { if (j >= 8) {
#endif
gv(RC_FLOAT); gv(RC_FLOAT);
o(0x50); /* push $rax */ o(0x50); /* push $rax */
/* movq %xmm0, (%rsp) */ /* movq %xmm0, (%rsp) */
@ -688,42 +889,6 @@ void gfunc_call(int nb_args)
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT || if ((vtop->type.t & VT_BTYPE) == VT_STRUCT ||
(vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { (vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
} else if (is_sse_float(vtop->type.t)) { } else if (is_sse_float(vtop->type.t)) {
#ifdef TCC_TARGET_PE
int j = --gen_reg;
if (j < REGN) {
int d = arg_regs[j];
gv(RC_FLOAT); /* only one float register */
/* movaps %xmm0, %xmmN */
o(0x280f);
o(0xc0 + (j << 3));
o(0x50);
o(0xd60f66); /* movq %xmm0, (%rsp) */
o(0x2404 + (j << 3));
if (d < 8) {
o(0x58 + d); /* pop d */
} else {
o(0x58);
o(0xc08949 + d - 8);
}
}
} else {
int j = --gen_reg;
/* simple type */
/* XXX: implicit cast ? */
if (j < REGN) {
int d = arg_regs[j];
r = gv(RC_INT);
if (d != r) {
if (d < 8) {
o(0x8948); /* mov */
o(0xc0 + r * 8 + d);
} else {
o(0x8949); /* mov */
o(0xc0 + r * 8 + d - 8);
}
}
}
#else
int j = --sse_reg; int j = --sse_reg;
if (j < 8) { if (j < 8) {
gv(RC_FLOAT); /* only one float register */ gv(RC_FLOAT); /* only one float register */
@ -750,16 +915,10 @@ void gfunc_call(int nb_args)
o(0xc0 + r * 8 + j - 4); o(0xc0 + r * 8 + j - 4);
} }
} }
#endif
} }
vtop--; vtop--;
} }
#ifdef TCC_TARGET_PE
/* allocate scratch space */
gadd_sp(-8*REGN);
args_size += 8*REGN;
#else
save_regs(0); /* save used temporary registers */ save_regs(0); /* save used temporary registers */
/* Copy R10 and R11 into RDX and RCX, respectively */ /* Copy R10 and R11 into RDX and RCX, respectively */
@ -771,13 +930,13 @@ void gfunc_call(int nb_args)
} }
oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */ oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */
#endif
gcall_or_jmp(0); gcall_or_jmp(0);
if (args_size) if (args_size)
gadd_sp(args_size); gadd_sp(args_size);
vtop--; vtop--;
} }
#define FUNC_PROLOG_SIZE 11 #define FUNC_PROLOG_SIZE 11
static void push_arg_reg(int i) { static void push_arg_reg(int i) {
@ -793,15 +952,13 @@ void gfunc_prolog(CType *func_type)
Sym *sym; Sym *sym;
CType *type; CType *type;
func_ret_sub = 0;
sym = func_type->ref; sym = func_type->ref;
addr = PTR_SIZE * 2; addr = PTR_SIZE * 2;
loc = 0; loc = 0;
ind += FUNC_PROLOG_SIZE; ind += FUNC_PROLOG_SIZE;
func_sub_sp_offset = ind; func_sub_sp_offset = ind;
func_ret_sub = 0;
#ifndef TCC_TARGET_PE
if (func_type->ref->c == FUNC_ELLIPSIS) { if (func_type->ref->c == FUNC_ELLIPSIS) {
int seen_reg_num, seen_sse_num, seen_stack_size; int seen_reg_num, seen_sse_num, seen_stack_size;
seen_reg_num = seen_sse_num = 0; seen_reg_num = seen_sse_num = 0;
@ -857,7 +1014,6 @@ void gfunc_prolog(CType *func_type)
push_arg_reg(REGN-1-i); push_arg_reg(REGN-1-i);
} }
} }
#endif
sym = func_type->ref; sym = func_type->ref;
param_index = 0; param_index = 0;
@ -880,7 +1036,6 @@ void gfunc_prolog(CType *func_type)
type = &sym->type; type = &sym->type;
size = type_size(type, &align); size = type_size(type, &align);
size = (size + 3) & ~3; size = (size + 3) & ~3;
#ifndef TCC_TARGET_PE
if (is_sse_float(type->t)) { if (is_sse_float(type->t)) {
if (sse_param_index < 8) { if (sse_param_index < 8) {
/* save arguments passed by register */ /* save arguments passed by register */
@ -893,21 +1048,12 @@ void gfunc_prolog(CType *func_type)
addr += size; addr += size;
} }
sse_param_index++; sse_param_index++;
} else
#endif } else if ((type->t & VT_BTYPE) == VT_STRUCT ||
if ((type->t & VT_BTYPE) == VT_STRUCT ||
(type->t & VT_BTYPE) == VT_LDOUBLE) { (type->t & VT_BTYPE) == VT_LDOUBLE) {
param_addr = addr; param_addr = addr;
addr += size; addr += size;
} else { } else {
#ifdef TCC_TARGET_PE
if (reg_param_index < REGN) {
/* save arguments passed by register */
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
}
param_addr = addr;
addr += 8;
#else
if (reg_param_index < REGN) { if (reg_param_index < REGN) {
/* save arguments passed by register */ /* save arguments passed by register */
push_arg_reg(reg_param_index); push_arg_reg(reg_param_index);
@ -916,21 +1062,12 @@ void gfunc_prolog(CType *func_type)
param_addr = addr; param_addr = addr;
addr += 8; addr += 8;
} }
#endif
reg_param_index++; reg_param_index++;
} }
sym_push(sym->v & ~SYM_FIELD, type, sym_push(sym->v & ~SYM_FIELD, type,
VT_LOCAL | VT_LVAL, param_addr); VT_LOCAL | VT_LVAL, param_addr);
param_index++; param_index++;
} }
#ifdef TCC_TARGET_PE
if (func_type->ref->c == FUNC_ELLIPSIS) {
for (i = reg_param_index; i < REGN; ++i) {
gen_modrm64(0x89, arg_regs[i], VT_LOCAL, NULL, addr);
addr += 8;
}
}
#endif
} }
/* generate function epilog */ /* generate function epilog */
@ -950,23 +1087,14 @@ void gfunc_epilog(void)
v = (-loc + 15) & -16; v = (-loc + 15) & -16;
saved_ind = ind; saved_ind = ind;
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
#ifdef TCC_TARGET_PE o(0xe5894855); /* push %rbp, mov %rsp, %rbp */
if (v >= 4096) { o(0xec8148); /* sub rsp, stacksize */
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); gen_le32(v);
oad(0xb8, v); /* mov stacksize, %eax */
oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
greloc(cur_text_section, sym, ind-4, R_X86_64_PC32);
o(0x90); /* fill for FUNC_PROLOG_SIZE = 11 bytes */
} else
#endif
{
o(0xe5894855); /* push %rbp, mov %rsp, %rbp */
o(0xec8148); /* sub rsp, stacksize */
gen_le32(v);
}
ind = saved_ind; ind = saved_ind;
} }
#endif /* not PE */
/* generate a jump to a label */ /* generate a jump to a label */
int gjmp(int t) int gjmp(int t)
{ {