#include <ctype.h>
#include "globals.h"
#include "memalloc.h"
#include "parser.h"
#include "segment.h"
#include "extern.h"
#include "equate.h"
#include "fixup.h"
#include "label.h"
#include "input.h"
#include "lqueue.h"
#include "tokenize.h"
#include "expreval.h"
#include "types.h"
#include "condasm.h"
#include "macro.h"
#include "proc.h"
#include "fastpass.h"
#include "listing.h"
#include "posndir.h"
#include "myassert.h"
#include "reswords.h"
#if AMD64_SUPPORT
#include "win64seh.h"
#endif
#ifdef __I86__
#define NUMQUAL (long)
#else
#define NUMQUAL
#endif
#define STACKPROBE 0
extern const char szDgroup[];
extern uint_32 list_pos;
extern unsigned char regsize[6];
struct dsym *CurrProc;
int procidx;
int CurrProcLine;
int XYZMMsize;
static struct proc_info *ProcStack;
enum proc_status ProcStatus;
#if AMD64_SUPPORT
static bool endprolog_found;
static uint_8 unw_segs_defined;
static UNWIND_INFO unw_info;
static UNWIND_CODE unw_code[258];
#endif
#if AMD64_SUPPORT
struct asym *sym_ReservedStack;
#endif
static const enum special_token ms32_regs16[] = { T_AX, T_DX, T_BX };
static const enum special_token ms32_regs32[] = { T_ECX,T_EDX };
static const enum special_token delphi_regs32[] = { T_EAX, T_EDX, T_ECX, };
static const int ms32_maxreg[] = {
sizeof(ms32_regs16) / sizeof(ms32_regs16[0]),
sizeof(ms32_regs32) / sizeof(ms32_regs32[0]),
};
static const int delphi_maxreg[] = {
sizeof(delphi_regs32) / sizeof(delphi_regs32[0]),
sizeof(delphi_regs32) / sizeof(delphi_regs32[0]),
};
#if OWFC_SUPPORT
static const enum special_token watc_regs8[] = { T_AL, T_DL, T_BL, T_CL };
static const enum special_token watc_regs16[] = { T_AX, T_DX, T_BX, T_CX };
static const enum special_token watc_regs32[] = { T_EAX, T_EDX, T_EBX, T_ECX };
static const enum special_token watc_regs_qw[] = { T_AX, T_BX, T_CX, T_DX };
#endif
#if AMD64_SUPPORT
static const enum special_token ms64_regs[] = { T_RCX, T_RDX, T_R8, T_R9 };
static const enum special_token sysV64_regs[] = { T_RDI, T_RSI, T_RDX, T_RCX, T_R8, T_R9 };
static const enum special_token sysV64_regs32[] = { T_EDI, T_ESI, T_EDX, T_ECX, T_R8D, T_R9D };
static const enum special_token sysV64_regs16[] = { T_DI, T_SI, T_DX, T_CX, T_R8W, T_R9W };
static const enum special_token sysV64_regs8[] = { T_DIL, T_SIL, T_DL, T_CL, T_R8B, T_R9B };
static const enum special_token sysV64_regsXMM[] = { T_XMM0, T_XMM1, T_XMM2, T_XMM3, T_XMM4, T_XMM5, T_XMM6, T_XMM7 };
static const enum special_token sysV64_regsYMM[] = { T_YMM0, T_YMM1, T_YMM2, T_YMM3, T_YMM4, T_YMM5, T_YMM6, T_YMM7 };
static const enum special_token sysV64_regsZMM[] = { T_ZMM0, T_ZMM1, T_ZMM2, T_ZMM3, T_ZMM4, T_ZMM5, T_ZMM6, T_ZMM7 };
static const uint_16 win64_nvgpr = 0xF0E8;
static const uint_16 win64_nvxmm = 0xFFC0;
static const int sysv_maxreg[] = {
sizeof(sysV64_regs) / sizeof(sysV64_regs[0]),
sizeof(sysV64_regs) / sizeof(sysV64_regs[0]),
};
#endif
struct fastcall_conv {
int(*paramcheck)(struct dsym *, struct dsym *, int *);
void(*handlereturn)(struct dsym *, char *buffer);
};
struct vectorcall_conv {
int(*paramcheck)(struct dsym *, struct dsym *, int *);
void(*handlereturn)(struct dsym *, char *buffer);
};
struct sysvcall_conv {
int(*paramcheck)(struct dsym *, struct dsym *, int *, int *);
void(*handlereturn)(struct dsym *, char *buffer);
};
struct delphicall_conv {
int(*paramcheck)(struct dsym *, struct dsym *, int *);
void(*handlereturn)(struct dsym *, char *buffer);
};
static int ms32_pcheck(struct dsym *, struct dsym *, int *);
static void ms32_return(struct dsym *, char *);
#if OWFC_SUPPORT
static int watc_pcheck(struct dsym *, struct dsym *, int *);
static void watc_return(struct dsym *, char *);
#endif
#if AMD64_SUPPORT
static int ms64_pcheck(struct dsym *, struct dsym *, int *);
static void ms64_return(struct dsym *, char *);
#endif
#if SYSV_SUPPORT
static int sysv_pcheck(struct dsym *, struct dsym *, int *, int *);
static void sysv_return(struct dsym *, char *);
#endif
#if DELPHI_SUPPORT
static int delphi_pcheck(struct dsym *, struct dsym *, int *);
static void delphi_return(struct dsym *, char *);
#endif
static void check_proc_fpo(struct proc_info *);
static const struct fastcall_conv fastcall_tab[] = {
{ ms32_pcheck, ms32_return },
#if OWFC_SUPPORT
{ watc_pcheck, watc_return },
#endif
#if AMD64_SUPPORT
{ ms64_pcheck, ms64_return }
#endif
};
static const struct vectorcall_conv vectorcall_tab[] = {
{ ms32_pcheck, ms32_return },
#if OWFC_SUPPORT
{ watc_pcheck, watc_return },
#endif
#if AMD64_SUPPORT
{ ms64_pcheck, ms64_return }
#endif
};
static const struct sysvcall_conv sysvcall_tab[] = {
{ ms32_pcheck, ms32_return },
#if OWFC_SUPPORT
{ watc_pcheck, watc_return },
#endif
#if SYSV_SUPPORT
{ sysv_pcheck, sysv_return }
#endif
};
static const struct delphicall_conv delphicall_tab[] = {
{ delphi_pcheck, delphi_return },
#if OWFC_SUPPORT
{ watc_pcheck, watc_return },
#endif
#if AMD64_SUPPORT
{ ms64_pcheck, ms64_return }
#endif
};
const enum special_token stackreg[] = { T_SP, T_ESP,
#if AMD64_SUPPORT
T_RSP
#endif
};
#if STACKBASESUPP==0
const enum special_token basereg[] = {
T_BP, T_EBP,
#if AMD64_SUPPORT
T_RBP
#endif
};
#else
uint_32 StackAdj;
int_32 StackAdjHigh;
#endif
#if AMD64_SUPPORT
static const char * const fmtstk0[] = {
"sub %r, %d",
"%r %d",
#if STACKPROBE
"mov %r, %d",
#endif
};
static const char * const fmtstk1[] = {
"sub %r, %d + %s",
"%r %d + %s",
#if STACKPROBE
"mov %r, %d + %s",
#endif
};
static const char * const fmtstk2[] = {
"lea %r, [%r + %d]",
};
static const char * const fmtstk3[] = {
"lea %r, [%r + %d + %s]",
};
#endif
#define ROUND_UP( i, r ) (((i)+((r)-1)) & ~((r)-1))
static void SetLocalOffsets_RSP(struct proc_info *info);
static void SetLocalOffsets_RBP(struct proc_info *info);
static void pop_register(uint_16 *regist);
static void WriteSEHData(struct dsym *proc);
static void SetLocalOffsets_RBP_SYSV(struct proc_info* info);
#if OWFC_SUPPORT
static int watc_pcheck(struct dsym *proc, struct dsym *paranode, int *used)
{
static char regname[64];
static char regist[32];
int newflg;
int shift;
int firstreg;
uint_8 Ofssize = GetSymOfssize(&proc->sym);
int size = SizeFromMemtype(paranode->sym.mem_type, paranode->sym.Ofssize, paranode->sym.type);
if (proc->e.procinfo->has_vararg)
return(0);
if (size != 1 && size != 2 && size != 4 && size != 8)
return(0);
if (size == 8) {
newflg = Ofssize ? 3 : 15;
shift = Ofssize ? 2 : 4;
}
else if (size == 4 && Ofssize == USE16) {
newflg = 3;
shift = 2;
}
else {
newflg = 1;
shift = 1;
}
for (firstreg = 0; firstreg < 4 && (newflg & *used); newflg <<= shift, firstreg += shift);
if (firstreg >= 4)
return(0);
paranode->sym.state = SYM_TMACRO;
switch (size) {
case 1:
paranode->sym.regist[0] = watc_regs8[firstreg];
break;
case 2:
paranode->sym.regist[0] = watc_regs16[firstreg];
break;
case 4:
if (Ofssize) {
paranode->sym.regist[0] = watc_regs32[firstreg];
}
else {
paranode->sym.regist[0] = watc_regs16[firstreg];
paranode->sym.regist[1] = watc_regs16[firstreg + 1];
}
break;
case 8:
if (Ofssize) {
paranode->sym.regist[0] = watc_regs32[firstreg];
paranode->sym.regist[1] = watc_regs32[firstreg + 1];
}
else {
for (firstreg = 0, regname[0] = NULLC; firstreg < 4; firstreg++) {
GetResWName(watc_regs_qw[firstreg], regname + strlen(regname));
if (firstreg != 3)
strcat(regname, "::");
}
}
}
if (paranode->sym.regist[1]) {
sprintf(regname, "%s::%s",
GetResWName(paranode->sym.regist[1], regist),
GetResWName(paranode->sym.regist[0], NULL));
}
else if (paranode->sym.regist[0]) {
GetResWName(paranode->sym.regist[0], regname);
}
*used |= newflg;
paranode->sym.string_ptr = LclAlloc(strlen(regname) + 1);
strcpy(paranode->sym.string_ptr, regname);
DebugMsg(("watc_pcheck(%s.%s): size=%u ptr=%u far=%u reg=%s\n", proc->sym.name, paranode->sym.name, size, paranode->sym.is_ptr, paranode->sym.isfar, regname));
return(1);
}
static void watc_return(struct dsym *proc, char *buffer)
{
int value;
value = 4 * CurrWordSize;
if (proc->e.procinfo->has_vararg == FALSE && proc->e.procinfo->parasize > value)
sprintf(buffer + strlen(buffer), "%d%c", proc->e.procinfo->parasize - value, ModuleInfo.radix != 10 ? 't' : NULLC);
return;
}
#endif
static int ms32_pcheck(struct dsym *proc, struct dsym *paranode, int *used)
{
char regname[32];
int size = SizeFromMemtype(paranode->sym.mem_type, paranode->sym.Ofssize, paranode->sym.type);
if (size > CurrWordSize || *used >= ms32_maxreg[ModuleInfo.Ofssize] || paranode->sym.mem_type == MT_REAL4 || paranode->sym.mem_type == MT_REAL8)
return(0);
paranode->sym.state = SYM_TMACRO;
paranode->sym.regist[0] = ModuleInfo.Ofssize ? ms32_regs32[*used] : ms32_regs16[*used];
GetResWName(ModuleInfo.Ofssize ? ms32_regs32[*used] : ms32_regs16[*used], regname);
if (paranode->sym.mem_type == MT_WORD || paranode->sym.mem_type == MT_SWORD)
{
if (_stricmp(regname, "ECX") == 0)
strcpy(regname, "cx");
else if (_stricmp(regname, "EDX") == 0)
strcpy(regname, "dx");
}
else if (paranode->sym.mem_type == MT_BYTE || paranode->sym.mem_type == MT_SBYTE)
{
if (_stricmp(regname, "ECX") == 0)
strcpy(regname, "cl");
else if (_stricmp(regname, "EDX") == 0)
strcpy(regname, "dl");
}
paranode->sym.string_ptr = LclAlloc(strlen(regname) + 1);
strcpy(paranode->sym.string_ptr, regname);
(*used)++;
return(1);
}
static void ms32_return(struct dsym *proc, char *buffer)
{
if (proc->e.procinfo->parasize > (ms32_maxreg[ModuleInfo.Ofssize] * CurrWordSize))
sprintf(buffer + strlen(buffer), "%d%c", proc->e.procinfo->parasize - (ms32_maxreg[ModuleInfo.Ofssize] * CurrWordSize), ModuleInfo.radix != 10 ? 't' : NULLC);
return;
}
static int delphi_pcheck(struct dsym *proc, struct dsym *paranode, int *used)
{
char regname[32];
int size = SizeFromMemtype(paranode->sym.mem_type, paranode->sym.Ofssize, paranode->sym.type);
int stack_size = size;
if (paranode->sym.mem_type == MT_REAL4 || paranode->sym.mem_type == MT_REAL8)
{
if (stack_size < CurrWordSize) stack_size = CurrWordSize;
proc->e.procinfo->ReservedStack += stack_size;
return (0);
}
if (size > CurrWordSize || *used >= delphi_maxreg[ModuleInfo.Ofssize])
{
if (stack_size < CurrWordSize) stack_size = CurrWordSize;
proc->e.procinfo->ReservedStack += stack_size;
return(0);
}
paranode->sym.state = SYM_TMACRO;
GetResWName(delphi_regs32[*used], regname);
if (paranode->sym.mem_type == MT_WORD || paranode->sym.mem_type == MT_SWORD)
{
if (_stricmp(regname, "EAX") == 0)
strcpy(regname, "ax");
else if (_stricmp(regname, "EDX") == 0)
strcpy(regname, "dx");
else if (_stricmp(regname, "ECX") == 0)
strcpy(regname, "cx");
}
else if (paranode->sym.mem_type == MT_BYTE || paranode->sym.mem_type == MT_SBYTE)
{
if (_stricmp(regname, "EAX") == 0)
strcpy(regname, "al");
else if (_stricmp(regname, "EDX") == 0)
strcpy(regname, "dl");
else if (_stricmp(regname, "ECX") == 0)
strcpy(regname, "cl");
}
paranode->sym.string_ptr = LclAlloc(strlen(regname) + 1);
strcpy(paranode->sym.string_ptr, regname);
(*used)++;
return(1);
}
static void delphi_return(struct dsym *proc, char *buffer)
{
if (proc->e.procinfo->parasize > (delphi_maxreg[ModuleInfo.Ofssize] * CurrWordSize))
sprintf(buffer + strlen(buffer), "%d%c", proc->e.procinfo->parasize - (delphi_maxreg[ModuleInfo.Ofssize] * CurrWordSize), ModuleInfo.radix != 10 ? 't' : NULLC);
return;
}
#if AMD64_SUPPORT
static int ms64_pcheck(struct dsym *proc, struct dsym *paranode, int *used)
{
return(0);
}
static void ms64_return(struct dsym *proc, char *buffer)
{
return;
}
#endif
static void pushitem(void *stk, void *elmt)
{
void **stack = stk;
struct qnode *node;
node = LclAlloc(sizeof(struct qnode));
node->next = *stack;
node->elmt = elmt;
*stack = node;
}
static void *popitem(void *stk)
{
void **stack = stk;
struct qnode *node;
void *elmt;
node = (struct qnode *)(*stack);
*stack = node->next;
elmt = (void *)node->elmt;
LclFree(node);
return(elmt);
}
static void push_proc(struct dsym *proc)
{
if (Parse_Pass == PASS_1)
SymGetLocal((struct asym *)proc);
pushitem(&ProcStack, proc);
return;
}
static struct dsym *pop_proc(void)
{
if (ProcStack == NULL)
return(NULL);
return((struct dsym *)popitem(&ProcStack));
}
ret_code LocalDir(int i, struct asm_tok tokenarray[])
{
char *name;
struct dsym *local;
struct dsym *curr;
struct proc_info *info;
struct qualified_type ti;
if (Parse_Pass != PASS_1)
return(NOT_ERROR);
DebugMsg1(("LocalDir(%u) entry\n", i));
if (!(ProcStatus & PRST_PROLOGUE_NOT_DONE) || CurrProc == NULL) {
return(EmitError(PROC_MACRO_MUST_PRECEDE_LOCAL));
}
info = CurrProc->e.procinfo;
#if STACKBASESUPP
if (GetRegNo(info->basereg) == 4) {
info->fpo = TRUE;
ProcStatus |= PRST_FPO;
}
#endif
i++;
do {
if (tokenarray[i].token != T_ID) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
name = tokenarray[i].string_ptr;
DebugMsg1(("LocalDir: item=%s\n", tokenarray[i].tokpos));
ti.symtype = NULL;
ti.is_ptr = 0;
ti.ptr_memtype = MT_EMPTY;
if (SIZE_DATAPTR & (1 << ModuleInfo.model))
ti.is_far = TRUE;
else
ti.is_far = FALSE;
ti.Ofssize = ModuleInfo.Ofssize;
#if 0#endif
local = (struct dsym *)SymLCreate(name);
if (!local) {
DebugMsg(("LocalDir: SymLCreate( %s ) failed\n", name));
return(ERROR);
}
if (ModuleInfo.win64_flags & W64F_SMART) local->sym.isparam = FALSE; local->sym.state = SYM_STACK;
local->sym.isdefined = TRUE;
local->sym.total_length = 1;
switch (ti.Ofssize) {
case USE16:
local->sym.mem_type = MT_WORD;
ti.size = sizeof(uint_16);
break;
#if AMD64_SUPPORT
#endif
default:
local->sym.mem_type = MT_DWORD;
ti.size = sizeof(uint_32);
break;
}
i++;
if (tokenarray[i].token == T_OP_SQ_BRACKET) {
int j;
struct expr opndx;
i++;
for (j = i; j < Token_Count; j++)
if (tokenarray[j].token == T_COMMA ||
tokenarray[j].token == T_COLON)
break;
if (ERROR == EvalOperand(&i, tokenarray, j, &opndx, 0))
return(ERROR);
if (opndx.kind != EXPR_CONST) {
EmitError(CONSTANT_EXPECTED);
opndx.value = 1;
}
local->sym.total_length = opndx.value;
local->sym.isarray = TRUE;
if (tokenarray[i].token == T_CL_SQ_BRACKET) {
i++;
}
else {
EmitError(EXPECTED_CL_SQ_BRACKET);
}
}
if (tokenarray[i].token == T_COLON) {
i++;
if (GetQualifiedType(&i, tokenarray, &ti) == ERROR)
return(ERROR);
local->sym.mem_type = ti.mem_type;
if (ti.mem_type == MT_TYPE) {
local->sym.type = ti.symtype;
}
else {
local->sym.target_type = ti.symtype;
}
DebugMsg1(("LocalDir: memtype=%X, type=%s, size=%u*%u\n",
local->sym.mem_type,
ti.symtype ? ti.symtype->name : "NULL",
ti.size, local->sym.total_length));
}
local->sym.is_ptr = ti.is_ptr;
local->sym.isfar = ti.is_far;
local->sym.Ofssize = ti.Ofssize;
local->sym.ptr_memtype = ti.ptr_memtype;
local->sym.total_size = ti.size * local->sym.total_length;
if (info->locallist == NULL) {
info->locallist = local;
}
else {
for (curr = info->locallist; curr->nextlocal; curr = curr->nextlocal);
curr->nextlocal = local;
}
if (tokenarray[i].token != T_FINAL)
if (tokenarray[i].token == T_COMMA) {
if ((i + 1) < Token_Count)
i++;
}
else {
return(EmitErr(EXPECTING_COMMA, tokenarray[i].tokpos));
}
} while (i < Token_Count);
return(NOT_ERROR);
}
#if STACKBASESUPP
void UpdateStackBase(struct asym *sym, struct expr *opnd)
{
if (opnd) {
StackAdj = opnd->uvalue;
StackAdjHigh = opnd->hvalue;
}
sym->value = StackAdj;
sym->value3264 = StackAdjHigh;
}
void UpdateProcStatus(struct asym *sym, struct expr *opnd)
{
sym->value = (CurrProc ? ProcStatus : 0);
}
#endif
static ret_code ParseParams(struct dsym *proc, int i, struct asm_tok tokenarray[], bool IsPROC)
{
char *name;
struct asym *sym;
int cntParam;
int offset = 0;
int fcint = 0;
int vecint = 0;
struct qualified_type ti;
bool is_vararg;
bool init_done;
struct dsym *paranode;
struct dsym *paracurr;
int curr;
if (proc->sym.langtype == LANG_C ||
proc->sym.langtype == LANG_SYSCALL ||
proc->sym.langtype == LANG_DELPHICALL ||
(proc->sym.langtype == LANG_FASTCALL && ModuleInfo.Ofssize != USE64) ||
(proc->sym.langtype == LANG_VECTORCALL && ModuleInfo.Ofssize != USE64) ||
(proc->sym.langtype == LANG_SYSVCALL && ModuleInfo.Ofssize != USE64) ||
proc->sym.langtype == LANG_STDCALL)
for (paracurr = proc->e.procinfo->paralist; paracurr && paracurr->nextparam; paracurr = paracurr->nextparam);
else
paracurr = proc->e.procinfo->paralist;
init_done = proc->sym.isproc;
for (cntParam = 0; tokenarray[i].token != T_FINAL; cntParam++) {
if (tokenarray[i].token == T_ID) {
name = tokenarray[i++].string_ptr;
}
else if (IsPROC == FALSE && tokenarray[i].token == T_COLON) {
if (paracurr)
name = paracurr->sym.name;
else
name = "";
}
else {
DebugMsg(("ParseParams: name missing/invalid for parameter %u, i=%u\n", cntParam + 1, i));
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
ti.symtype = NULL;
ti.is_ptr = 0;
ti.ptr_memtype = MT_EMPTY;
if (SIZE_DATAPTR & (1 << ModuleInfo.model))
ti.is_far = TRUE;
else
ti.is_far = FALSE;
ti.Ofssize = ModuleInfo.Ofssize;
ti.size = CurrWordSize;
is_vararg = FALSE;
if (tokenarray[i].token != T_COLON) {
if (IsPROC == FALSE) {
return(EmitError(COLON_EXPECTED));
}
switch (ti.Ofssize) {
case USE16:
ti.mem_type = MT_WORD; break;
#if AMD64_SUPPORT
#endif
default:
ti.mem_type = MT_DWORD; break;
}
}
else {
i++;
if ((tokenarray[i].token == T_RES_ID) && (tokenarray[i].tokval == T_VARARG)) {
switch (proc->sym.langtype) {
case LANG_NONE:
case LANG_BASIC:
case LANG_FORTRAN:
case LANG_PASCAL:
case LANG_STDCALL:
return(EmitError(VARARG_REQUIRES_C_CALLING_CONVENTION));
}
if (tokenarray[i + 1].token != T_FINAL)
EmitError(VARARG_PARAMETER_MUST_BE_LAST);
else
is_vararg = TRUE;
ti.mem_type = MT_EMPTY;
ti.size = 0;
i++;
}
else {
if (GetQualifiedType(&i, tokenarray, &ti) == ERROR)
return(ERROR);
}
}
if ((IsPROC) && (sym = SymSearch(name)) && sym->state != SYM_UNDEFINED) {
DebugMsg(("ParseParams: %s defined already, state=%u, local=%u\n", sym->name, sym->state, sym->scoped));
return(EmitErr(SYMBOL_REDEFINITION, name));
}
if (paracurr) {
struct asym *to;
struct asym *tn;
char oo;
char on;
for (tn = ti.symtype; tn && tn->type; tn = tn->type);
if (paracurr->sym.mem_type == MT_TYPE)
to = paracurr->sym.type;
else
to = (paracurr->sym.mem_type == MT_PTR ? paracurr->sym.target_type : NULL);
for (; to && to->type; to = to->type);
oo = (paracurr->sym.Ofssize != USE_EMPTY) ? paracurr->sym.Ofssize : ModuleInfo.Ofssize;
on = (ti.Ofssize != USE_EMPTY) ? ti.Ofssize : ModuleInfo.Ofssize;
if (ti.mem_type != paracurr->sym.mem_type ||
(ti.mem_type == MT_TYPE && tn != to) ||
(ti.mem_type == MT_PTR &&
(ti.is_far != paracurr->sym.isfar ||
on != oo ||
ti.ptr_memtype != paracurr->sym.ptr_memtype ||
tn != to))) {
if (ti.mem_type == MT_PTR && paracurr->sym.state == SYM_STACK &&
(paracurr->sym.mem_type == MT_QWORD && CurrWordSize == 8) ||
(paracurr->sym.mem_type == MT_OWORD && CurrWordSize == 8) ||
(paracurr->sym.mem_type == MT_YMMWORD && CurrWordSize == 8) ||
(paracurr->sym.mem_type == MT_ZMMWORD && CurrWordSize == 8) ||
(paracurr->sym.mem_type == MT_DWORD && CurrWordSize == 4) ||
(paracurr->sym.mem_type == MT_OWORD && CurrWordSize == 4) ||
(paracurr->sym.mem_type == MT_YMMWORD && CurrWordSize == 4) ||
(paracurr->sym.mem_type == MT_ZMMWORD && CurrWordSize == 4))
{
}
else if (paracurr->sym.mem_type == MT_PTR && paracurr->sym.state == SYM_STACK &&
(ti.mem_type == MT_QWORD && CurrWordSize == 8) ||
(ti.mem_type == MT_OWORD && CurrWordSize == 8) ||
(ti.mem_type == MT_YMMWORD && CurrWordSize == 8) ||
(ti.mem_type == MT_ZMMWORD && CurrWordSize == 8) ||
(ti.mem_type == MT_DWORD && CurrWordSize == 4) ||
(ti.mem_type == MT_OWORD && CurrWordSize == 4) ||
(ti.mem_type == MT_YMMWORD && CurrWordSize == 4) ||
(ti.mem_type == MT_ZMMWORD && CurrWordSize == 4))
{
}
else
{
DebugMsg(("ParseParams: old-new memtype=%X-%X type=%X(%s)-%X(%s) far=%u-%u ind=%u-%u ofss=%d-%d pmt=%X-%X\n",
paracurr->sym.mem_type, ti.mem_type,
(paracurr->sym.mem_type == MT_TYPE) ? paracurr->sym.type : paracurr->sym.target_type,
(paracurr->sym.mem_type == MT_TYPE) ? paracurr->sym.type->name : paracurr->sym.target_type ? paracurr->sym.target_type->name : "",
ti.symtype, ti.symtype ? ti.symtype->name : "",
paracurr->sym.isfar, ti.is_far,
paracurr->sym.is_ptr, ti.is_ptr,
paracurr->sym.Ofssize, ti.Ofssize,
paracurr->sym.ptr_memtype, ti.ptr_memtype));
EmitErr(CONFLICTING_PARAMETER_DEFINITION, name);
}
}
if (IsPROC) {
DebugMsg1(("ParseParams: calling SymAddLocal(%s, %s)\n", paracurr->sym.name, name));
SymAddLocal(¶curr->sym, name);
}
if (proc->sym.langtype == LANG_C ||
proc->sym.langtype == LANG_SYSCALL ||
proc->sym.langtype == LANG_DELPHICALL ||
(proc->sym.langtype == LANG_FASTCALL && ti.Ofssize != USE64) ||
(proc->sym.langtype == LANG_VECTORCALL && ti.Ofssize != USE64) ||
(proc->sym.langtype == LANG_SYSVCALL && ti.Ofssize != USE64) ||
proc->sym.langtype == LANG_STDCALL) {
struct dsym *l;
for (l = proc->e.procinfo->paralist;
l && (l->nextparam != paracurr);
l = l->nextparam);
paracurr = l;
}
else
paracurr = paracurr->nextparam;
}
else if (init_done == TRUE) {
DebugMsg(("ParseParams: different param count\n"));
return(EmitErr(CONFLICTING_PARAMETER_DEFINITION, ""));
}
else {
if (IsPROC) {
paranode = (struct dsym *)SymLCreate(name);
}
else
paranode = (struct dsym *)SymAlloc("");
if (paranode == NULL) {
DebugMsg(("ParseParams: SymLCreate(%s) failed\n", name));
return(ERROR);
}
paranode->sym.isdefined = TRUE;
paranode->sym.mem_type = ti.mem_type;
if (ti.mem_type == MT_TYPE) {
paranode->sym.type = ti.symtype;
if (proc->sym.langtype == LANG_VECTORCALL) {
proc->e.procinfo->vecregsize[cntParam] = ti.symtype->max_mbr_size;
proc->e.procinfo->vecregs[cntParam] = ti.size / ti.symtype->max_mbr_size;
proc->e.procinfo->vsize += ti.size;
ti.size = MT_QWORD;
}
}
else {
paranode->sym.target_type = ti.symtype;
if (proc->sym.langtype == LANG_VECTORCALL) {
if (ti.mem_type == MT_REAL4 || ti.mem_type == MT_REAL8 ||
ti.mem_type == MT_OWORD || ti.mem_type == MT_YMMWORD || ti.mem_type == MT_ZMMWORD) {
proc->e.procinfo->vecregsize[cntParam] = ti.size;
proc->e.procinfo->vecregs[cntParam] = 1;
if (ti.size >= 16) proc->e.procinfo->vsize += ti.size;
ti.size = MT_QWORD;
}
}
}
paranode->sym.isfar = ti.is_far;
paranode->sym.Ofssize = ti.Ofssize;
paranode->sym.is_ptr = ti.is_ptr;
paranode->sym.ptr_memtype = ti.ptr_memtype;
paranode->sym.is_vararg = is_vararg;
if (proc->sym.langtype == LANG_FASTCALL && fastcall_tab[ModuleInfo.fctype].paramcheck(proc, paranode, &fcint))
{
}
else if (proc->sym.langtype == LANG_VECTORCALL && vectorcall_tab[ModuleInfo.fctype].paramcheck(proc, paranode, &fcint))
{
}
else if (proc->sym.langtype == LANG_SYSVCALL && sysvcall_tab[ModuleInfo.fctype].paramcheck(proc, paranode, &fcint, &vecint))
{
}
else if (proc->sym.langtype == LANG_DELPHICALL && delphicall_tab[ModuleInfo.fctype].paramcheck(proc, paranode, &fcint))
{
}
else
{
paranode->sym.state = SYM_STACK;
}
paranode->sym.total_length = 1;
paranode->sym.total_size = ti.size;
if (paranode->sym.is_vararg == FALSE)
{
if (proc->sym.langtype == LANG_VECTORCALL)
{
switch (CurrWordSize)
{
case 8:
switch (ti.mem_type)
{
case MT_OWORD:
proc->e.procinfo->parasize += ROUND_UP(ti.size, IsPROC ? 2 * CurrWordSize : 2 * (2 << proc->sym.seg_ofssize));
break;
case MT_YMMWORD:
proc->e.procinfo->parasize += ROUND_UP(ti.size, IsPROC ? 4 * CurrWordSize : 4 * (2 << proc->sym.seg_ofssize));
break;
case MT_ZMMWORD:
proc->e.procinfo->parasize += ROUND_UP(ti.size, IsPROC ? 8 * CurrWordSize : 8 * (2 << proc->sym.seg_ofssize));
break;
default:
proc->e.procinfo->parasize += ROUND_UP(ti.size, IsPROC ? CurrWordSize : (2 << proc->sym.seg_ofssize));
break;
}
break;
case 4:
switch (ti.mem_type)
{
case MT_OWORD:
proc->e.procinfo->parasize += ROUND_UP(ti.size, IsPROC ? 4 * CurrWordSize : 4 * (2 << proc->sym.seg_ofssize));
break;
case MT_YMMWORD:
proc->e.procinfo->parasize += ROUND_UP(ti.size, IsPROC ? 8 * CurrWordSize : 8 * (2 << proc->sym.seg_ofssize));
break;
case MT_ZMMWORD:
proc->e.procinfo->parasize += ROUND_UP(ti.size, IsPROC ? 16 * CurrWordSize : 16 * (2 << proc->sym.seg_ofssize));
break;
default:
proc->e.procinfo->parasize += ROUND_UP(ti.size, IsPROC ? CurrWordSize : (2 << proc->sym.seg_ofssize));
break;
}
break;
default:
proc->e.procinfo->parasize += ROUND_UP(ti.size, IsPROC ? CurrWordSize : (2 << proc->sym.seg_ofssize));
break;
}
}
else
{
proc->e.procinfo->parasize += ROUND_UP(ti.size, IsPROC ? CurrWordSize : (2 << proc->sym.seg_ofssize));
}
}
switch (proc->sym.langtype) {
case LANG_BASIC:
case LANG_FORTRAN:
case LANG_PASCAL:
left_to_right:
paranode->nextparam = NULL;
if (proc->e.procinfo->paralist == NULL) {
proc->e.procinfo->paralist = paranode;
}
else {
for (paracurr = proc->e.procinfo->paralist;; paracurr = paracurr->nextparam) {
if (paracurr->nextparam == NULL) {
break;
}
}
paracurr->nextparam = paranode;
paracurr = NULL;
}
break;
case LANG_FASTCALL:
case LANG_VECTORCALL:
case LANG_DELPHICALL:
#if AMD64_SUPPORT
case LANG_SYSVCALL:
if (ti.Ofssize == USE64)
goto left_to_right;
#endif
if (ti.Ofssize == USE16 && ModuleInfo.fctype == FCT_MSC)
goto left_to_right;
else if (ti.Ofssize == USE32 && ModuleInfo.fctype == FCT_DELPHI && proc->sym.langtype == LANG_DELPHICALL)
goto left_to_right;
default:
paranode->nextparam = proc->e.procinfo->paralist;
proc->e.procinfo->paralist = paranode;
break;
}
}
if (tokenarray[i].token != T_FINAL) {
if (tokenarray[i].token != T_COMMA) {
DebugMsg(("ParseParams: error, cntParam=%u, found %s\n", cntParam, tokenarray[i].tokpos));
return(EmitErr(EXPECTING_COMMA, tokenarray[i].tokpos));
}
i++;
}
}
if (init_done == TRUE) {
if (paracurr) {
DebugMsg(("ParseParams: a param is left over, cntParam=%u\n", cntParam));
return(EmitErr(CONFLICTING_PARAMETER_DEFINITION, ""));
}
}
if (IsPROC) {
if (proc->e.procinfo->fpo || (proc->e.procinfo->parasize == 0 && proc->e.procinfo->locallist == NULL) && proc->e.procinfo->basereg == T_RSP)
offset = ((2 + (proc->sym.mem_type == MT_FAR ? 1 : 0)) * CurrWordSize);
else if (proc->e.procinfo->basereg == T_RBP && (ModuleInfo.win64_flags & W64F_AUTOSTACKSP) && (ModuleInfo.win64_flags & W64F_SAVEREGPARAMS))
{
offset = ((2 + (proc->sym.mem_type == MT_FAR ? 1 : 0)) * CurrWordSize);
}
else if (proc->e.procinfo->basereg == T_RBP && !(ModuleInfo.win64_flags & W64F_AUTOSTACKSP) && (ModuleInfo.win64_flags & W64F_SAVEREGPARAMS))
{
offset = ((2 + (proc->sym.mem_type == MT_FAR ? 1 : 0)) * CurrWordSize);
}
else if (proc->e.procinfo->basereg == T_RBP)
offset = ((2 + (proc->sym.mem_type == MT_FAR ? 1 : 0)) * CurrWordSize);
else
offset = ((2 + (proc->sym.mem_type == MT_FAR ? 1 : 0)) * CurrWordSize);
#if AMD64_SUPPORT
if (ModuleInfo.Ofssize == USE64) {
if (proc->sym.langtype == LANG_FASTCALL || proc->sym.langtype == LANG_VECTORCALL || proc->sym.langtype == LANG_SYSVCALL)
{
for (paranode = proc->e.procinfo->paralist; paranode; paranode = paranode->nextparam)
if (paranode->sym.state == SYM_TMACRO)
;
else {
paranode->sym.offset = offset;
proc->e.procinfo->stackparam = TRUE;
offset += ROUND_UP(paranode->sym.total_size, CurrWordSize);
if(ModuleInfo.basereg[ModuleInfo.Ofssize] == T_RSP)
paranode->sym.isparam = TRUE;
}
}
}
else
#endif
for (; cntParam; cntParam--)
{
for (curr = 1, paranode = proc->e.procinfo->paralist; curr < cntParam; paranode = paranode->nextparam, curr++);
DebugMsg1(("ParseParams: parm=%s, ofs=%u, size=%d\n", paranode->sym.name, offset, paranode->sym.total_size));
if (paranode->sym.state == SYM_TMACRO)
;
else
{
paranode->sym.offset = offset;
proc->e.procinfo->stackparam = TRUE;
offset += ROUND_UP(paranode->sym.total_size, CurrWordSize);
}
}
}
return (NOT_ERROR);
}
ret_code ParseProc(struct dsym *proc, int i, struct asm_tok tokenarray[], bool IsPROC, enum lang_type langtype)
{
char *token;
uint_16 *regist;
enum memtype newmemtype;
uint_8 newofssize;
uint_8 oldofssize;
#if FASTPASS
bool oldpublic = proc->sym.ispublic;
#endif
enum returntype ret_type;
bool defRet = FALSE;
struct asym *sym = NULL;
if (IsPROC) {
proc->e.procinfo->isexport = ModuleInfo.procs_export;
if (ModuleInfo.procs_private == FALSE)
proc->sym.ispublic = TRUE;
#if STACKBASESUPP
if (GetRegNo(proc->e.procinfo->basereg) != 5) {
proc->e.procinfo->pe_type = 0;
}
else
#endif
if (Options.masm_compat_gencode) {
proc->e.procinfo->pe_type = (ModuleInfo.Ofssize > USE16 ||
(ModuleInfo.curr_cpu & P_CPU_MASK) == P_286 ||
(ModuleInfo.curr_cpu & P_CPU_MASK) >= P_586) ? 1 : 0;
}
else {
proc->e.procinfo->pe_type = ((ModuleInfo.curr_cpu & P_CPU_MASK) == P_286 ||
#if AMD64_SUPPORT
(ModuleInfo.curr_cpu & P_CPU_MASK) == P_64 ||
#endif
(ModuleInfo.curr_cpu & P_CPU_MASK) == P_386) ? 1 : 0;
}
}
#if MANGLERSUPP
if (tokenarray[i].token == T_STRING && IsPROC) {
SetMangler(&proc->sym, LANG_NONE, tokenarray[i].string_ptr);
i++;
}
#endif
if (tokenarray[i].token == T_STYPE &&
tokenarray[i].tokval >= T_NEAR && tokenarray[i].tokval <= T_FAR32) {
uint_8 Ofssize = GetSflagsSp(tokenarray[i].tokval);
if (IsPROC) {
if ((ModuleInfo.Ofssize >= USE32 && Ofssize == USE16) ||
(ModuleInfo.Ofssize == USE16 && Ofssize == USE32)) {
EmitError(DISTANCE_INVALID);
}
}
newmemtype = GetMemtypeSp(tokenarray[i].tokval);
newofssize = ((Ofssize != USE_EMPTY) ? Ofssize : ModuleInfo.Ofssize);
i++;
}
else {
newmemtype = ((SIZE_CODEPTR & (1 << ModuleInfo.model)) ? MT_FAR : MT_NEAR);
newofssize = ModuleInfo.Ofssize;
}
if (proc->sym.state == SYM_TYPE)
oldofssize = proc->sym.seg_ofssize;
else
oldofssize = GetSymOfssize(&proc->sym);
if (proc->sym.mem_type != MT_EMPTY &&
(proc->sym.mem_type != newmemtype ||
oldofssize != newofssize)) {
DebugMsg(("ParseProc: error, memtype changed, old-new memtype=%X-%X, ofssize=%X-%X\n", proc->sym.mem_type, newmemtype, proc->sym.Ofssize, newofssize));
if (proc->sym.mem_type == MT_NEAR || proc->sym.mem_type == MT_FAR)
EmitError(PROC_AND_PROTO_CALLING_CONV_CONFLICT);
else {
return(EmitErr(SYMBOL_REDEFINITION, proc->sym.name));
}
}
else {
proc->sym.mem_type = newmemtype;
if (IsPROC == FALSE)
proc->sym.seg_ofssize = newofssize;
}
langtype = ModuleInfo.langtype;
GetLangType(&i, tokenarray, &langtype);
if (proc->sym.langtype != LANG_NONE && proc->sym.langtype != langtype) {
DebugMsg(("ParseProc: error, language changed, %u - %u\n", proc->sym.langtype, langtype));
EmitError(PROC_AND_PROTO_CALLING_CONV_CONFLICT);
}
else
proc->sym.langtype = langtype;
ret_type = 0xff;
if (proc->e.procinfo->ret_type == 0xff)
{
if (ModuleInfo.Ofssize == USE16)
proc->e.procinfo->ret_type = RT_WORD;
if (ModuleInfo.Ofssize == USE32)
proc->e.procinfo->ret_type = RT_DWORD;
if (ModuleInfo.Ofssize == USE64)
proc->e.procinfo->ret_type = RT_QWORD;
defRet = TRUE;
}
proc->e.procinfo->isleaf = TRUE;
if (tokenarray[i + 1].tokval == T_VOIDARG)
{
i += 3;
}
else if (tokenarray[i].token == T_OP_BRACKET && tokenarray[i+2].token == T_CL_BRACKET && tokenarray[i+1].token == T_ID )
{
sym = SymLookup(tokenarray[i + 1].string_ptr);
while (sym)
{
switch (sym->mem_type)
{
case MT_EMPTY:
if (sym->state == SYM_TYPE)
{
if (sym->total_size == 16)
ret_type = RT_XMM;
else if (sym->total_size == 32)
ret_type = RT_YMM;
else if (sym->total_size == 64)
ret_type = RT_ZMM;
}
break;
case MT_BYTE:
ret_type = RT_BYTE;
break;
case MT_SBYTE:
ret_type = RT_SBYTE;
break;
case MT_WORD:
ret_type = RT_WORD;
break;
case MT_SWORD:
ret_type = RT_SWORD;
break;
case MT_DWORD:
ret_type = RT_DWORD;
break;
case MT_SDWORD:
ret_type = RT_SDWORD;
break;
case MT_QWORD:
ret_type = RT_QWORD;
break;
case MT_SQWORD:
ret_type = RT_SQWORD;
break;
case MT_FLOAT:
ret_type = RT_FLOAT;
break;
case MT_OWORD:
ret_type = RT_XMM;
break;
case MT_PTR:
ret_type = RT_PTR;
break;
case MT_YMMWORD:
ret_type = RT_YMM;
break;
case MT_ZMMWORD:
ret_type = RT_ZMM;
break;
case MT_REAL4:
ret_type = RT_REAL4;
break;
case MT_REAL8:
ret_type = RT_REAL8;
break;
case MT_REAL10:
ret_type = RT_REAL10;
break;
}
if (sym->target_type && sym->mem_type != MT_EMPTY)
sym = sym->target_type;
else
break;
}
i+=3;
}
else if (tokenarray[i].token == T_OP_BRACKET && tokenarray[i + 2].token == T_CL_BRACKET &&
(tokenarray[i+1].token == T_STYPE || (tokenarray[i+1].token == T_BINARY_OPERATOR && tokenarray[i+1].tokval == T_PTR)) )
{
switch (tokenarray[i+1].tokval)
{
case T_PTR:
ret_type = RT_PTR;
break;
case T_REAL4:
ret_type = RT_REAL4;
break;
case T_REAL8:
ret_type = RT_REAL8;
break;
case T_BYTE:
ret_type = RT_BYTE;
break;
case T_WORD:
ret_type = RT_WORD;
break;
case T_DWORD:
ret_type = RT_DWORD;
break;
case T_QWORD:
ret_type = RT_QWORD;
break;
case T_SBYTE:
ret_type = RT_SBYTE;
break;
case T_SWORD:
ret_type = RT_SWORD;
break;
case T_SDWORD:
ret_type = RT_SDWORD;
break;
case T_SQWORD:
ret_type = RT_SQWORD;
break;
case T_XMMWORD:
ret_type = RT_XMM;
break;
case T_YMMWORD:
ret_type = RT_YMM;
break;
case T_ZMMWORD:
ret_type = RT_ZMM;
break;
default:
ret_type = RT_NONE;
break;
}
i+=3;
}
else
{
ret_type = proc->e.procinfo->ret_type;
}
if (proc->e.procinfo->ret_type != 0xff && !defRet)
{
if (ret_type != proc->e.procinfo->ret_type)
EmitError(PROC_AND_PROTO_CALLING_CONV_CONFLICT);
}
proc->e.procinfo->ret_type = ret_type;
if (tokenarray[i].token == T_ID || tokenarray[i].token == T_DIRECTIVE) {
token = tokenarray[i].string_ptr;
if (_stricmp(token, "PRIVATE") == 0) {
if (IsPROC) {
proc->sym.ispublic = FALSE;
#if FASTPASS
proc->sym.scoped = TRUE;
if (oldpublic) {
SkipSavedState();
}
#endif
proc->e.procinfo->isexport = FALSE;
}
i++;
}
else if (IsPROC && (_stricmp(token, "PUBLIC") == 0)) {
proc->sym.ispublic = TRUE;
proc->e.procinfo->isexport = FALSE;
i++;
}
else if (_stricmp(token, "EXPORT") == 0) {
DebugMsg1(("ParseProc(%s): EXPORT detected\n", proc->sym.name));
if (IsPROC) {
proc->sym.ispublic = TRUE;
proc->e.procinfo->isexport = TRUE;
if (ModuleInfo.Ofssize == USE16 && proc->sym.mem_type == MT_NEAR)
EmitErr(EXPORT_MUST_BE_FAR, proc->sym.name);
}
i++;
}
}
if (IsPROC && tokenarray[i].token == T_STRING && tokenarray[i].string_delim == '<') {
int idx = Token_Count + 1;
int max;
if (ModuleInfo.prologuemode == PEM_NONE)
;
else if (ModuleInfo.prologuemode == PEM_MACRO) {
proc->e.procinfo->prologuearg = LclAlloc(tokenarray[i].stringlen + 1);
strcpy(proc->e.procinfo->prologuearg, tokenarray[i].string_ptr);
}
else {
max = Tokenize(tokenarray[i].string_ptr, idx, tokenarray, TOK_RESCAN);
for (; idx < max; idx++) {
if (tokenarray[idx].token == T_ID) {
if (_stricmp(tokenarray[idx].string_ptr, "FORCEFRAME") == 0) {
proc->e.procinfo->forceframe = TRUE;
#if AMD64_SUPPORT
}
else if (ModuleInfo.Ofssize != USE64 && (_stricmp(tokenarray[idx].string_ptr, "LOADDS") == 0)) {
#else
}
else if (_stricmp(tokenarray[idx].string_ptr, "LOADDS") == 0) {
#endif
if (ModuleInfo.model == MODEL_FLAT) {
EmitWarn(2, LOADDS_IGNORED_IN_FLAT_MODEL);
}
else
proc->e.procinfo->loadds = TRUE;
}
else {
return(EmitErr(UNKNOWN_DEFAULT_PROLOGUE_ARGUMENT, tokenarray[idx].string_ptr));
}
if (tokenarray[idx + 1].token == T_COMMA && tokenarray[idx + 2].token != T_FINAL)
idx++;
}
else {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[idx].string_ptr));
}
}
}
i++;
}
#if AMD64_SUPPORT
if (ModuleInfo.basereg[ModuleInfo.Ofssize] == T_RSP || ModuleInfo.basereg[ModuleInfo.Ofssize] == T_RBP)
{
if (ModuleInfo.prologuemode == PEM_DEFAULT && IsPROC && ModuleInfo.frame_auto == 1)
proc->e.procinfo->isframe = TRUE;
}
if (ModuleInfo.Ofssize == USE64 &&
IsPROC &&
tokenarray[i].token == T_RES_ID &&
tokenarray[i].tokval == T_FRAME) {
if (Options.output_format != OFORMAT_COFF && Options.output_format != OFORMAT_ELF && Options.output_format != OFORMAT_BIN && Options.output_format != OFORMAT_MAC
#if PE_SUPPORT
&& ModuleInfo.sub_format != SFORMAT_PE
#endif
) {
return(EmitErr(NOT_SUPPORTED_WITH_CURR_FORMAT, GetResWName(T_FRAME, NULL)));
}
i++;
if (tokenarray[i].token == T_COLON) {
struct asym *sym;
i++;
if (tokenarray[i].token != T_ID) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
sym = SymSearch(tokenarray[i].string_ptr);
if (sym == NULL) {
sym = SymCreate(tokenarray[i].string_ptr);
sym->state = SYM_UNDEFINED;
sym->used = TRUE;
sym_add_table(&SymTables[TAB_UNDEF], (struct dsym *)sym);
}
else if (sym->state != SYM_UNDEFINED &&
sym->state != SYM_INTERNAL &&
sym->state != SYM_EXTERNAL) {
return(EmitErr(SYMBOL_REDEFINITION, sym->name));
}
proc->e.procinfo->exc_handler = sym;
i++;
}
else
proc->e.procinfo->exc_handler = NULL;
proc->e.procinfo->isframe = TRUE;
}
#endif
if (tokenarray[i].token == T_ID && _stricmp(tokenarray[i].string_ptr, "USES") == 0) {
int cnt;
int j;
if (!IsPROC) {
DebugMsg(("ParseProc: USES found in PROTO\n"));
EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr);
}
i++;
for (cnt = 0, j = i; tokenarray[j].token == T_REG; j++, cnt++);
if (cnt == 0) {
DebugMsg(("ParseProc: no registers for regslist\n"));
EmitErr(SYNTAX_ERROR_EX, tokenarray[i - 1].tokpos);
}
else {
regist = LclAlloc((cnt + 1) * sizeof(uint_16));
proc->e.procinfo->regslist = regist;
*regist++ = cnt;
for (; tokenarray[i].token == T_REG; i++) {
if (SizeFromRegister(tokenarray[i].tokval) == 1) {
EmitError(INVALID_USE_OF_REGISTER);
}
*regist++ = tokenarray[i].tokval;
}
}
}
if (tokenarray[i].token == T_STYPE || tokenarray[i].token == T_RES_ID || tokenarray[i].token == T_DIRECTIVE) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
if (tokenarray[i].token == T_COMMA)
i++;
DebugMsg1(("ParseProc(%s): i=%u, Token_Count=%u, CurrWordSize=%u\n", proc->sym.name, i, Token_Count, CurrWordSize));
if (i >= Token_Count) {
if (proc->e.procinfo->paralist != NULL)
EmitErr(CONFLICTING_PARAMETER_DEFINITION, "");
}
else if (proc->sym.langtype == LANG_NONE) {
EmitError(LANG_MUST_BE_SPECIFIED);
}
else {
if (tokenarray[Token_Count - 1].token == T_RES_ID &&
tokenarray[Token_Count - 1].tokval == T_VARARG)
proc->e.procinfo->has_vararg = TRUE;
if (ERROR == ParseParams(proc, i, tokenarray, IsPROC))
; }
proc->sym.isdefined = TRUE;
proc->sym.isproc = TRUE;
DebugMsg1(("ParseProc(%s): memtype=%Xh parasize=%u\n", proc->sym.name, proc->sym.mem_type, proc->e.procinfo->parasize));
return(NOT_ERROR);
}
struct asym *CreateProc(struct asym *sym, const char *name, enum sym_state state)
{
if (sym == NULL)
sym = (*name ? SymCreate(name) : SymAlloc(name));
else
sym_remove_table((sym->state == SYM_UNDEFINED) ? &SymTables[TAB_UNDEF] : &SymTables[TAB_EXT], (struct dsym *)sym);
if (sym) {
struct proc_info *info;
sym->state = state;
if (state != SYM_INTERNAL) {
sym->seg_ofssize = ModuleInfo.Ofssize;
}
info = LclAlloc(sizeof(struct proc_info));
((struct dsym *)sym)->e.procinfo = info;
info->regslist = NULL;
info->paralist = NULL;
info->locallist = NULL;
info->labellist = NULL;
info->parasize = 0;
info->localsize = 0;
info->prologuearg = NULL;
info->flags = 0;
info->ret_type = 0xff;
switch (sym->state) {
case SYM_INTERNAL:
if (SymTables[TAB_PROC].head == NULL)
SymTables[TAB_PROC].head = (struct dsym *)sym;
else {
SymTables[TAB_PROC].tail->nextproc = (struct dsym *)sym;
}
SymTables[TAB_PROC].tail = (struct dsym *)sym;
procidx++;
if (Options.line_numbers) {
sym->debuginfo = LclAlloc(sizeof(struct debug_info));
sym->debuginfo->file = get_curr_srcfile();
}
break;
case SYM_EXTERNAL:
sym->weak = TRUE;
sym_add_table(&SymTables[TAB_EXT], (struct dsym *)sym);
break;
}
}
return(sym);
}
void DeleteProc(struct dsym *proc)
{
struct dsym *curr;
struct dsym *next;
DebugMsg(("DeleteProc(%s) enter\n", proc->sym.name));
if (proc->sym.state == SYM_INTERNAL) {
for (curr = proc->e.procinfo->labellist; curr; ) {
next = curr->e.nextll;
DebugMsg(("DeleteProc(%s): free %s [next=%p]\n", proc->sym.name, curr->sym.name, curr->next));
SymFree(&curr->sym);
curr = next;
}
if (proc->e.procinfo->regslist)
LclFree(proc->e.procinfo->regslist);
if (proc->e.procinfo->prologuearg)
LclFree(proc->e.procinfo->prologuearg);
if (Options.line_numbers && proc->sym.state == SYM_INTERNAL)
LclFree(proc->sym.debuginfo);
#if FASTMEM==0 || defined(DEBUG_OUT)
}
else {
for (curr = proc->e.procinfo->paralist; curr; ) {
next = curr->nextparam;
DebugMsg(("DeleteProc(%s): free %p (%s) [next=%p]\n", proc->sym.name, curr, curr->sym.name, curr->next));
SymFree(&curr->sym);
curr = next;
}
#endif
}
LclFree(proc->e.procinfo);
return;
}
ret_code ProcDir(int i, struct asm_tok tokenarray[])
{
struct asym *sym;
unsigned int ofs;
char *name;
bool oldpubstate;
bool is_global;
struct asym* cline;
struct asym* procline;
struct asym* procname;
cline = SymFind("@Line");
procline = SymFind("@ProcLine");
procline->value = cline->value;
DebugMsg1(("ProcDir enter, curr ofs=%X\n", GetCurrOffset()));
if (i != 1) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
if (CurrSeg == NULL) {
return(EmitError(MUST_BE_IN_SEGMENT_BLOCK));
}
name = tokenarray[0].string_ptr;
if (CurrProc != NULL) {
procname = SymFind("@ProcName");
procname->string_ptr = CurrProc->sym.name;
if (CurrProc->e.procinfo->paralist ||
#if AMD64_SUPPORT
CurrProc->e.procinfo->isframe ||
#endif
CurrProc->e.procinfo->locallist ||
CurrProc->e.procinfo->regslist) {
return(EmitErr(CANNOT_NEST_PROCEDURES, name));
}
push_proc(CurrProc);
}
if (ModuleInfo.procalign) {
AlignCurrOffset(ModuleInfo.procalign);
}
i++;
sym = SymSearch(name);
if (Parse_Pass == PASS_1) {
oldpubstate = sym ? sym->ispublic : FALSE;
if (sym == NULL || sym->state == SYM_UNDEFINED) {
sym = CreateProc(sym, name, SYM_INTERNAL);
is_global = FALSE;
}
else if (sym->state == SYM_EXTERNAL && sym->weak == TRUE) {
is_global = TRUE;
if (sym->isproc == TRUE) {
procidx++;
if (Options.line_numbers) {
sym->debuginfo = LclAlloc(sizeof(struct debug_info));
sym->debuginfo->file = get_curr_srcfile();
}
}
else {
sym = CreateProc(sym, name, SYM_INTERNAL);
}
}
else {
return(EmitErr(SYMBOL_REDEFINITION, sym->name));
}
SetSymSegOfs(sym);
SymClearLocal();
#if STACKBASESUPP
((struct dsym *)sym)->e.procinfo->basereg = ModuleInfo.basereg[ModuleInfo.Ofssize];
#endif
CurrProc = (struct dsym *)sym;
if (ParseProc((struct dsym *)sym, i, tokenarray, TRUE, ModuleInfo.langtype) == ERROR) {
CurrProc = NULL;
return(ERROR);
}
if (is_global && Options.masm8_proc_visibility)
sym->ispublic = TRUE;
if (sym->state == SYM_EXTERNAL && sym->isproc == TRUE) {
sym_ext2int(sym);
if (SymTables[TAB_PROC].head == NULL)
SymTables[TAB_PROC].head = (struct dsym *)sym;
else {
SymTables[TAB_PROC].tail->nextproc = (struct dsym *)sym;
}
SymTables[TAB_PROC].tail = (struct dsym *)sym;
}
#if STACKBASESUPP
if (CurrProc->e.procinfo->paralist && GetRegNo(CurrProc->e.procinfo->basereg) == 4)
CurrProc->e.procinfo->fpo = TRUE;
#endif
if (sym->ispublic == TRUE && oldpubstate == FALSE)
AddPublicData(sym);
((struct dsym *)sym)->next = (struct dsym *)CurrSeg->e.seginfo->label_list;
CurrSeg->e.seginfo->label_list = sym;
}
else {
procidx++;
sym->isdefined = TRUE;
SymSetLocal(sym);
ofs = GetCurrOffset();
if (ofs != sym->offset) {
sym->offset = ofs;
ModuleInfo.PhaseError = TRUE;
}
CurrProc = (struct dsym *)sym;
if (CurrProc->e.procinfo->isframe &&
CurrProc->e.procinfo->exc_handler &&
CurrProc->e.procinfo->exc_handler->state == SYM_UNDEFINED) {
EmitErr(SYMBOL_NOT_DEFINED, CurrProc->e.procinfo->exc_handler->name);
}
}
#if STACKBASESUPP
ProcStatus = PRST_PROLOGUE_NOT_DONE | (CurrProc->e.procinfo->fpo ? PRST_FPO : 0);
StackAdj = 0;
StackAdjHigh = 0;
#else
ProcStatus = PRST_PROLOGUE_NOT_DONE;
#endif
#if AMD64_SUPPORT
if (CurrProc->e.procinfo->isframe) {
endprolog_found = FALSE;
memset(&unw_info, 0, sizeof(unw_info));
if (CurrProc->e.procinfo->exc_handler)
unw_info.Flags = UNW_FLAG_FHANDLER;
}
#endif
sym->asmpass = Parse_Pass;
if (ModuleInfo.list)
LstWrite(LSTTYPE_LABEL, 0, NULL);
if (Options.line_numbers) {
if (Options.debug_symbols == 4)
AddLinnumDataRef(get_curr_srcfile(), GetLineNumber());
else
AddLinnumDataRef(get_curr_srcfile(), Options.output_format == OFORMAT_COFF ? 0 : GetLineNumber());
}
BackPatch(sym);
return(NOT_ERROR);
}
ret_code CopyPrototype(struct dsym *proc, struct dsym *src)
{
struct dsym *curr;
struct dsym *newl;
struct dsym *oldl;
if (src->sym.isproc == FALSE)
return(ERROR);
memcpy(proc->e.procinfo, src->e.procinfo, sizeof(struct proc_info));
proc->sym.mem_type = src->sym.mem_type;
proc->sym.langtype = src->sym.langtype;
#if MANGLERSUPP
proc->sym.mangler = src->sym.mangler;
#endif
proc->sym.ispublic = src->sym.ispublic;
proc->sym.seg_ofssize = src->sym.seg_ofssize;
proc->sym.isproc = TRUE;
proc->e.procinfo->paralist = NULL;
for (curr = src->e.procinfo->paralist; curr; curr = curr->nextparam) {
newl = LclAlloc(sizeof(struct dsym));
memcpy(newl, curr, sizeof(struct dsym));
newl->nextparam = NULL;
if (proc->e.procinfo->paralist == NULL)
proc->e.procinfo->paralist = newl;
else {
for (oldl = proc->e.procinfo->paralist; oldl->nextparam; oldl = oldl->nextparam);
oldl->nextparam = newl;
}
}
DebugMsg1(("CopyPrototype(%s,src=%s): ofssize=%u\n",
proc->sym.name, src->sym.name, src->sym.seg_ofssize));
return(NOT_ERROR);
}
static void ProcFini(struct dsym *proc)
{
struct asym* procline = NULL;
struct dsym *curr;
if (proc->sym.segment == &CurrSeg->sym) {
proc->sym.total_size = GetCurrOffset() - proc->sym.offset;
}
else {
DebugMsg1(("ProcFini(%s): unmatched block nesting error, proc->seg=%s, CurrSeg=%s\n",
proc->sym.name, proc->sym.segment->name, CurrSeg ? CurrSeg->sym.name : "NULL"));
EmitErr(UNMATCHED_BLOCK_NESTING, proc->sym.name);
proc->sym.total_size = CurrProc->sym.segment->offset - proc->sym.offset;
}
if (Options.warning_level > 2 && Parse_Pass == PASS_1) {
for (curr = proc->e.procinfo->paralist; curr; curr = curr->nextparam) {
if (curr->sym.used == FALSE)
EmitWarn(3, PROCEDURE_ARGUMENT_OR_LOCAL_NOT_REFERENCED, curr->sym.name);
}
for (curr = proc->e.procinfo->locallist; curr; curr = curr->nextlocal) {
if (curr->sym.used == FALSE)
EmitWarn(3, PROCEDURE_ARGUMENT_OR_LOCAL_NOT_REFERENCED, curr->sym.name);
}
}
#if AMD64_SUPPORT
if (Parse_Pass == PASS_1 &&
ModuleInfo.fctype == FCT_WIN64 &&
(ModuleInfo.win64_flags & W64F_AUTOSTACKSP)) {
proc->e.procinfo->ReservedStack = sym_ReservedStack->value;
DebugMsg1(("ProcFini(%s): localsize=%u ReservedStack=%u\n", proc->sym.name, proc->e.procinfo->localsize, proc->e.procinfo->ReservedStack));
#if STACKBASESUPP
if (proc->e.procinfo->fpo) {
if (proc->e.procinfo->ReservedStack > 0)
{
for (curr = proc->e.procinfo->locallist; curr; curr = curr->nextlocal) {
DebugMsg1(("ProcFini(%s): FPO, offset for %s %8d -> %8d\n", proc->sym.name, curr->sym.name, curr->sym.offset, curr->sym.offset + proc->e.procinfo->ReservedStack));
curr->sym.offset += proc->e.procinfo->ReservedStack;
}
for (curr = proc->e.procinfo->paralist; curr; curr = curr->nextparam) {
DebugMsg1(("ProcFini(%s): FPO, offset for %s %8d -> %8d\n", proc->sym.name, curr->sym.name, curr->sym.offset, curr->sym.offset + proc->e.procinfo->ReservedStack));
curr->sym.offset += proc->e.procinfo->ReservedStack;
}
}
}
#endif
}
if (proc->e.procinfo->isframe)
{
#if FASTPASS
LstSetPosition();
#endif
if(proc->sym.langtype != LANG_SYSVCALL)
WriteSEHData(proc);
}
#endif
if (ModuleInfo.list)
LstWrite(LSTTYPE_LABEL, 0, NULL);
if (Parse_Pass == PASS_1) {
if (ProcStatus & PRST_PROLOGUE_NOT_DONE) {
if (ModuleInfo.basereg[USE64] == T_RSP) {
SetLocalOffsets_RSP(CurrProc->e.procinfo);
}
else if (proc->sym.langtype == LANG_SYSVCALL) {
SetLocalOffsets_RBP_SYSV(CurrProc->e.procinfo);
}
else {
SetLocalOffsets_RBP(CurrProc->e.procinfo);
}
}
SymGetLocal((struct asym *)CurrProc);
}
procline = SymFind("@ProcLine");
procline->value = 0;
CurrProc = pop_proc();
if (CurrProc)
SymSetLocal((struct asym *)CurrProc);
ProcStatus = 0;
if (sym_ReservedStack)
sym_ReservedStack->value = 0;
}
ret_code EndpDir(int i, struct asm_tok tokenarray[])
{
struct asym* procline;
DebugMsg1(("EndpDir(%s) enter, curr ofs=% " I32_SPEC "X, CurrProc=%s\n", tokenarray[0].string_ptr, GetCurrOffset(), CurrProc ? CurrProc->sym.name : "NULL"));
if (i != 1 || tokenarray[2].token != T_FINAL) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].tokpos));
}
if (CurrProc &&
(SymCmpFunc(CurrProc->sym.name, tokenarray[0].string_ptr, CurrProc->sym.name_size + 1) == 0)) {
procline = SymFind("@ProcLine");
procline->value = 0;
ProcFini(CurrProc);
}
else {
return(EmitErr(UNMATCHED_BLOCK_NESTING, tokenarray[0].string_ptr));
}
return(NOT_ERROR);
}
#if AMD64_SUPPORT
static void WriteSEHData(struct dsym *proc)
{
struct dsym *xdata;
char *segname = ".xdata";
int i;
int simplespec;
uint_8 olddotname;
uint_32 xdataofs = 0;
char segnamebuff[12];
char buffer[128];
if (Options.output_format == OFORMAT_ELF || Options.output_format == OFORMAT_BIN || Options.output_format == OFORMAT_MAC)
return;
if (endprolog_found == FALSE) {
EmitErr(MISSING_ENDPROLOG, proc->sym.name);
}
if (unw_segs_defined)
AddLineQueueX("%s %r", segname, T_SEGMENT);
else {
AddLineQueueX("%s %r align(%u) flat read 'DATA'", segname, T_SEGMENT, 8);
AddLineQueue("$xdatasym label near");
}
xdataofs = 0;
xdata = (struct dsym *)SymSearch(segname);
if (xdata) {
xdataofs = xdata->sym.max_offset;
}
AddLineQueueX("db %ut + (0%xh shl 3), %ut, %ut, 0%xh + (0%xh shl 4)",
UNW_VERSION, unw_info.Flags, unw_info.SizeOfProlog,
unw_info.CountOfCodes, unw_info.FrameRegister, unw_info.FrameOffset);
if (unw_info.CountOfCodes) {
char *pfx = "dw";
buffer[0] = NULLC;
for (i = unw_info.CountOfCodes; i; i--) {
sprintf(buffer + strlen(buffer), "%s 0%xh", pfx, unw_code[i - 1].FrameOffset);
pfx = ",";
if (i == 1 || strlen(buffer) > 72) {
AddLineQueue(buffer);
buffer[0] = NULLC;
pfx = "dw";
}
}
}
AddLineQueueX("%r 4", T_ALIGN);
if (proc->e.procinfo->exc_handler) {
AddLineQueueX("dd %r %s", T_IMAGEREL, proc->e.procinfo->exc_handler->name);
AddLineQueueX("dd 0"); }
AddLineQueueX("%s %r", segname, T_ENDS);
if (0 == strcmp(SimGetSegName(SIM_CODE), proc->sym.segment->name)) {
segname = ".pdata";
simplespec = (unw_segs_defined & 1);
unw_segs_defined = 3;
}
else {
segname = segnamebuff;
sprintf(segname, ".pdata$%04u", GetSegIdx(proc->sym.segment));
simplespec = 0;
unw_segs_defined |= 2;
}
if (simplespec)
AddLineQueueX("%s %r", segname, T_SEGMENT);
else
AddLineQueueX("%s %r align(%u) flat read 'DATA'", segname, T_SEGMENT, 4);
AddLineQueueX("dd %r %s, %r %s+0%xh, %r $xdatasym+0%xh",
T_IMAGEREL, proc->sym.name,
T_IMAGEREL, proc->sym.name, proc->sym.total_size,
T_IMAGEREL, xdataofs);
AddLineQueueX("%s %r", segname, T_ENDS);
olddotname = ModuleInfo.dotname;
ModuleInfo.dotname = TRUE;
RunLineQueue();
ModuleInfo.dotname = olddotname;
return;
}
ret_code ExcFrameDirective(int i, struct asm_tok tokenarray[])
{
struct expr opndx;
int token;
unsigned int size;
uint_8 oldcodes = unw_info.CountOfCodes;
uint_8 reg;
uint_8 ofs;
UNWIND_CODE *puc;
DebugMsg1(("ExcFrameDirective(%s) enter\n", tokenarray[i].string_ptr));
if (Options.output_format != OFORMAT_COFF && Options.output_format != OFORMAT_ELF && Options.output_format != OFORMAT_BIN && Options.output_format != OFORMAT_MAC
#if PE_SUPPORT
&& ModuleInfo.sub_format != SFORMAT_PE
#endif
) {
return(EmitErr(NOT_SUPPORTED_WITH_CURR_FORMAT, GetResWName(tokenarray[i].tokval, NULL)));
}
if (CurrProc == NULL || endprolog_found == TRUE) {
return(EmitError(ENDPROLOG_FOUND_BEFORE_EH_DIRECTIVES));
}
if (CurrProc->e.procinfo->isframe == FALSE) {
return(EmitError(MISSING_FRAME_IN_PROC));
}
puc = &unw_code[unw_info.CountOfCodes];
ofs = GetCurrOffset() - CurrProc->sym.offset;
token = tokenarray[i].tokval;
i++;
switch (token) {
case T_DOT_ALLOCSTACK:
if (ERROR == EvalOperand(&i, tokenarray, Token_Count, &opndx, 0))
return(ERROR);
if (opndx.kind == EXPR_ADDR && opndx.sym->state == SYM_UNDEFINED)
;
else if (opndx.kind != EXPR_CONST) {
return(EmitError(CONSTANT_EXPECTED));
}
if (opndx.hvalue) {
return(EmitConstError(&opndx));
}
if (opndx.uvalue == 0) {
return(EmitError(NONZERO_VALUE_EXPECTED));
}
if (opndx.value & 7) {
return(EmitError(BAD_ALIGNMENT_FOR_OFFSET_IN_UNWIND_CODE));
}
if (opndx.uvalue > 16 * 8) {
if (opndx.uvalue >= 65536 * 8) {
puc->FrameOffset = (opndx.uvalue >> 16);
puc++;
puc->FrameOffset = opndx.uvalue & 0xFFFF;
puc++;
unw_info.CountOfCodes += 2;
puc->OpInfo = 1;
DebugMsg1(("ExcFrameDirective: UWOP_ALLOC_LARGE, operation info 1, size=%Xh\n", opndx.value));
}
else {
puc->FrameOffset = (opndx.uvalue >> 3);
puc++;
unw_info.CountOfCodes++;
puc->OpInfo = 0;
DebugMsg1(("ExcFrameDirective: UWOP_ALLOC_LARGE, operation info 0, size=%Xh\n", opndx.value));
}
puc->UnwindOp = UWOP_ALLOC_LARGE;
}
else {
puc->UnwindOp = UWOP_ALLOC_SMALL;
puc->OpInfo = ((opndx.uvalue - 8) >> 3);
DebugMsg1(("ExcFrameDirective: UWOP_ALLOC_SMALL, size=%Xh\n", opndx.value));
}
puc->CodeOffset = ofs;
unw_info.CountOfCodes++;
break;
case T_DOT_ENDPROLOG:
opndx.value = GetCurrOffset() - CurrProc->sym.offset;
if (opndx.uvalue > 255) {
return(EmitError(SIZE_OF_PROLOG_TOO_BIG));
}
unw_info.SizeOfProlog = (uint_8)opndx.uvalue;
endprolog_found = TRUE;
break;
case T_DOT_PUSHFRAME:
puc->CodeOffset = ofs;
puc->UnwindOp = UWOP_PUSH_MACHFRAME;
puc->OpInfo = 0;
if (tokenarray[i].token == T_ID && (_stricmp(tokenarray[i].string_ptr, "CODE") == 0)) {
puc->OpInfo = 1;
i++;
}
unw_info.CountOfCodes++;
break;
case T_DOT_PUSHREG:
if (tokenarray[i].token != T_REG || !(GetValueSp(tokenarray[i].tokval) & OP_R64)) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
puc->CodeOffset = ofs;
puc->UnwindOp = UWOP_PUSH_NONVOL;
puc->OpInfo = GetRegNo(tokenarray[i].tokval);
unw_info.CountOfCodes++;
i++;
break;
case T_DOT_SAVEREG:
case T_DOT_SAVEXMM128:
case T_DOT_SAVEYMM256:
case T_DOT_SAVEZMM512:
case T_DOT_SETFRAME:
if (tokenarray[i].token != T_REG) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
if (token == T_DOT_SAVEXMM128) {
if (!(GetValueSp(tokenarray[i].tokval) & OP_XMM)) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
}
else if (token == T_DOT_SAVEYMM256) {
if (!(GetValueSp(tokenarray[i].tokval) & OP_YMM)) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
}
else if (token == T_DOT_SAVEZMM512) {
if (!(GetValueSp(tokenarray[i].tokval) & OP_ZMM)) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
}
else {
if (!(GetValueSp(tokenarray[i].tokval) & OP_R64)) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
}
reg = GetRegNo(tokenarray[i].tokval);
if (token == T_DOT_SAVEREG)
size = 8;
else
size = 16;
i++;
if (tokenarray[i].token != T_COMMA) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
i++;
if (ERROR == EvalOperand(&i, tokenarray, Token_Count, &opndx, 0))
return(ERROR);
if (opndx.kind == EXPR_ADDR && opndx.sym->state == SYM_UNDEFINED)
;
else if (opndx.kind != EXPR_CONST) {
return(EmitError(CONSTANT_EXPECTED));
}
if (opndx.value & (size - 1)) {
return(EmitError(BAD_ALIGNMENT_FOR_OFFSET_IN_UNWIND_CODE));
}
switch (token) {
case T_DOT_SAVEREG:
puc->OpInfo = reg;
if (opndx.value > 65536 * size) {
puc->FrameOffset = (opndx.value >> 19);
puc++;
puc->FrameOffset = (opndx.value >> 3);
puc++;
puc->UnwindOp = UWOP_SAVE_NONVOL_FAR;
unw_info.CountOfCodes += 3;
}
else {
puc->FrameOffset = (opndx.value >> 3);
puc++;
puc->UnwindOp = UWOP_SAVE_NONVOL;
unw_info.CountOfCodes += 2;
}
puc->CodeOffset = ofs;
puc->OpInfo = reg;
break;
case T_DOT_SAVEXMM128:
case T_DOT_SAVEYMM256:
if (opndx.value > 65536 * size) {
puc->FrameOffset = (opndx.value >> 20);
puc++;
puc->FrameOffset = (opndx.value >> 4);
puc++;
puc->UnwindOp = UWOP_SAVE_XMM128_FAR;
unw_info.CountOfCodes += 3;
}
else {
puc->FrameOffset = (opndx.value >> 4);
puc++;
puc->UnwindOp = UWOP_SAVE_XMM128;
unw_info.CountOfCodes += 2;
}
puc->CodeOffset = ofs;
puc->OpInfo = reg;
break;
case T_DOT_SAVEZMM512:
if (opndx.value > 65536 * size) {
puc->FrameOffset = (opndx.value >> 20);
puc++;
puc->FrameOffset = (opndx.value >> 4);
puc++;
puc->UnwindOp = UWOP_SAVE_XMM128_FAR;
unw_info.CountOfCodes += 3;
}
else {
puc->FrameOffset = (opndx.value >> 4);
puc++;
puc->UnwindOp = UWOP_SAVE_XMM128;
unw_info.CountOfCodes += 2;
}
puc->CodeOffset = ofs;
puc->OpInfo = reg;
break;
case T_DOT_SETFRAME:
if (opndx.uvalue > 240) {
return(EmitConstError(&opndx));
}
unw_info.FrameRegister = reg;
unw_info.FrameOffset = (opndx.uvalue >> 4);
puc->CodeOffset = ofs;
puc->UnwindOp = UWOP_SET_FPREG;
puc->OpInfo = reg;
unw_info.CountOfCodes++;
break;
}
break;
}
if (tokenarray[i].token != T_FINAL) {
return(EmitErr(SYNTAX_ERROR_EX, tokenarray[i].string_ptr));
}
if (oldcodes > unw_info.CountOfCodes) {
return(EmitErr(TOO_MANY_UNWIND_CODES_IN_FRAME_PROC));
}
return(NOT_ERROR);
}
#endif
void ProcCheckOpen(void)
{
while (CurrProc != NULL) {
DebugMsg1(("ProcCheckOpen: unmatched block nesting error, CurrProc=%s\n", CurrProc->sym.name));
EmitErr(UNMATCHED_BLOCK_NESTING, CurrProc->sym.name);
ProcFini(CurrProc);
}
}
static ret_code write_userdef_prologue(struct asm_tok tokenarray[])
{
int len;
int i;
struct proc_info *info;
char *p;
bool is_exitm;
struct dsym *dir;
int flags = CurrProc->sym.langtype;
uint_16 *regs;
char reglst[128];
char buffer[MAX_LINE_LEN];
#if FASTPASS
if (Parse_Pass > PASS_1 && UseSavedState)
return(NOT_ERROR);
#endif
info = CurrProc->e.procinfo;
#if AMD64_SUPPORT
if (CurrProc->sym.langtype == LANG_FASTCALL && ModuleInfo.fctype == FCT_WIN64)
flags = 0;
#endif
if (CurrProc->sym.langtype == LANG_C ||
CurrProc->sym.langtype == LANG_SYSCALL ||
CurrProc->sym.langtype == LANG_SYSVCALL ||
CurrProc->sym.langtype == LANG_FASTCALL)
flags |= 0x10;
flags |= (CurrProc->sym.mem_type == MT_FAR ? 0x20 : 0);
flags |= (CurrProc->sym.ispublic ? 0 : 0x40);
flags |= (info->isexport ? 0x80 : 0);
dir = (struct dsym *)SymSearch(ModuleInfo.proc_prologue);
if (dir == NULL || dir->sym.state != SYM_MACRO || dir->sym.isfunc != TRUE) {
return(EmitError(PROLOGUE_MUST_BE_MACRO_FUNC));
}
if (Options.preprocessor_stdout)
printf("option prologue:none\n");
p = reglst;
if (info->regslist) {
regs = info->regslist;
for (len = *regs++; len; len--, regs++) {
GetResWName(*regs, p);
p += strlen(p);
if (len > 1)
*p++ = ',';
}
}
*p = NULLC;
sprintf(buffer, " (%s, 0%XH, 0%XH, 0%XH, <<%s>>, <%s>)",
CurrProc->sym.name, flags, info->parasize, info->localsize,
reglst, info->prologuearg ? info->prologuearg : "");
i = Token_Count + 1;
Token_Count = Tokenize(buffer, i, tokenarray, TOK_RESCAN);
RunMacro(dir, i, tokenarray, buffer, 0, &is_exitm);
Token_Count = i - 1;
DebugMsg(("write_userdef_prologue: macro %s returned >%s<\n", ModuleInfo.proc_prologue, buffer));
if (Parse_Pass == PASS_1) {
struct dsym *curr;
len = atoi(buffer) - info->localsize;
for (curr = info->locallist; curr; curr = curr->nextlocal) {
curr->sym.offset -= len;
}
}
return (NOT_ERROR);
}
#if AMD64_SUPPORT
static void win64_SaveRegParams_RSP(struct proc_info *info)
{
int i;
struct dsym *param;
if (ModuleInfo.win64_flags & W64F_SMART) {
uint_16 *regist;
info->home_taken = 0;
memset(info->home_used, 0, 6);
if (info->regslist)
regist = info->regslist;
if (CurrProc->sym.langtype == LANG_VECTORCALL) {
for (i = 0, param = info->paralist; param && (i < 6); i++) {
if (param->sym.is_vararg == FALSE) {
if ((param->sym.mem_type & MT_FLOAT) && param->sym.used) {
if (param->sym.mem_type == MT_REAL8)
AddLineQueueX("%s qword ptr[%r+%u], %r", MOVE_DOUBLE(), T_RSP, 8 + i * 8, T_XMM0 + i);
else if (param->sym.mem_type == MT_REAL4)
AddLineQueueX("%s dword ptr[%r+%u], %r", MOVE_SINGLE(), T_RSP, 8 + i * 8, T_XMM0 + i);
info->home_used[i] = 1;
++info->home_taken;
}
else if ((param->sym.mem_type == MT_TYPE) && param->sym.used)
{
info->home_used[i] = 1;
++info->home_taken;
info->vecused = TRUE;
}
else {
if (((param->sym.mem_type != MT_TYPE) && param->sym.used) &&
(param->sym.mem_type <= MT_QWORD) && param->sym.used) {
if (i < 4) {
AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, ms64_regs[i]);
info->home_used[i] = 1;
++info->home_taken;
}
}
}
param = param->nextparam;
}
else {
AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, ms64_regs[i]);
info->home_used[i] = 1;
++info->home_taken;
}
}
}
else {
for (i = 0, param = info->paralist; param && (i < 4); i++) {
if (param->sym.is_vararg == FALSE) {
if (param->sym.mem_type & MT_FLOAT && param->sym.total_size == 10) {
if (Parse_Pass == PASS_1)
EmitWarn(2, REAL10_BY_VALUE);
}
if (param->sym.mem_type & MT_FLOAT && param->sym.total_size == 4 && param->sym.used) {
AddLineQueueX("%s [%r+%u], %r", MOVE_SIMD_DWORD(), T_RSP, 8 + i * 8, T_XMM0 + i);
info->home_used[i] = 1;
++info->home_taken;
}
else if (param->sym.mem_type & MT_FLOAT && param->sym.total_size == 8 && param->sym.used) {
AddLineQueueX("%s [%r+%u], %r", MOVE_SIMD_QWORD(), T_RSP, 8 + i * 8, T_XMM0 + i);
info->home_used[i] = 1;
++info->home_taken;
}
else {
if (param->sym.used) { AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, ms64_regs[i]);
info->home_used[i] = 1;
++info->home_taken;
}
}
param = param->nextparam;
}
else {
AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, ms64_regs[i]);
info->home_used[i] = 1;
++info->home_taken;
}
}
}
}
else {
for (i = 0, param = info->paralist; param && (i < 4); i++) {
if (param->sym.is_vararg == FALSE) {
if (param->sym.mem_type & MT_FLOAT)
AddLineQueueX("%s [%r+%u], %r", MOVE_SIMD_QWORD(), T_RSP, 8 + i * 8, T_XMM0 + i);
else
AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, ms64_regs[i]);
param = param->nextparam;
}
else {
AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, ms64_regs[i]);
}
}
}
return;
}
static void win64_StoreRegHome(struct proc_info *info)
{
int i = 0;
int cnt;
int grcount = 0;
int sizestd = 0;
int freeshadow = 4;
uint_16 *regist;
info->stored_reg = 0;
if (info->regslist) {
for (regist = info->regslist, cnt = *regist++; cnt; cnt--, regist++, i++) {
if ((GetValueSp(*regist) & OP_YMM) || (GetValueSp(*regist) & OP_XMM) || (GetValueSp(*regist) & OP_ZMM))
continue;
else ++grcount; }
freeshadow -= info->home_taken; if (freeshadow) { if (grcount == 1) memset(info->home_used, 1, 4); else if (grcount == 2 && freeshadow >= 2) { for (i = 0; i<4; i++) {
if (info->home_used[i] == 0) break; }
for (++i; i<4; i++) info->home_used[i] = 1;
}
else if (grcount == 3) { if (freeshadow == 1) memset(info->home_used, 1, 4); if (freeshadow >= 3) { for (i = 0; i<4; i++) { if (info->home_used[i] == 0) break; }
for (++i; i<4; i++) {
if (info->home_used[i] == 0) break; }
for (++i; i<4; i++)
info->home_used[i] = 1; }
}
else if (grcount == 4 && freeshadow == 4) { info->home_used[3] = 1; } else if (grcount > 4) { freeshadow = grcount - freeshadow; if (!(freeshadow & 1)) { for (i = 0; i<4; i++) { if (info->home_used[i] == 0) break; }
info->home_used[i] = 1; }
}
}
for (i = 0, regist = info->regslist, cnt = *regist++; cnt; cnt--, regist++, i++) {
if ((GetValueSp(*regist) & OP_YMM) || (GetValueSp(*regist) & OP_XMM) || (GetValueSp(*regist) & OP_ZMM)) {
i--;
continue;
}
else {
sizestd += 8;
if (i < 4)
{
if (info->home_used[i] == 0) {
AddLineQueueX("mov [%r+%u], %r", T_RSP, NUMQUAL sizestd, *regist);
AddLineQueueX("%r %r, %u", T_DOT_SAVEREG, *regist, NUMQUAL sizestd);
info->stored_reg++;
}
else {
cnt++; regist--;
}
}
}
}
}
return;
}
static enum special_token GetWin64SubReg(enum special_token srcReg,int type)
{
if (type == 0)
{
if (srcReg == T_RCX)
return(T_CL);
if (srcReg == T_RDX)
return(T_DL);
if (srcReg == T_R8)
return(T_R8B);
if (srcReg == T_R9)
return(T_R9B);
}
else if (type == 1)
{
if (srcReg == T_RCX)
return(T_CX);
if (srcReg == T_RDX)
return(T_DX);
if (srcReg == T_R8)
return(T_R8W);
if (srcReg == T_R9)
return(T_R9W);
}
else if (type == 2)
{
if (srcReg == T_RCX)
return(T_ECX);
if (srcReg == T_RDX)
return(T_EDX);
if (srcReg == T_R8)
return(T_R8D);
if (srcReg == T_R9)
return(T_R9D);
}
return(srcReg);
}
static int win64_SaveRegParams_RBP(struct proc_info *info)
{
int i;
struct dsym *param;
int saved = 0;
for (i = 0, param = info->paralist; param && (i < 4); i++)
{
if (param->sym.is_vararg == FALSE)
{
if (param->sym.mem_type & MT_FLOAT && param->sym.total_size == 4 && param->sym.used) {
AddLineQueueX("%s [%r+%u], %r", MOVE_SINGLE(), T_RSP, 8 + i * 8, T_XMM0 + i);
saved++;
}
else if (param->sym.mem_type & MT_FLOAT && param->sym.total_size == 8 && param->sym.used) {
AddLineQueueX("%s [%r+%u], %r", MOVE_DOUBLE(), T_RSP, 8 + i * 8, T_XMM0 + i);
saved++;
}
else if (param->sym.used)
{
if (param->sym.mem_type == MT_BYTE || param->sym.mem_type == MT_SBYTE) {
AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, GetWin64SubReg(ms64_regs[i], 0));
saved++;
}
else if (param->sym.mem_type == MT_WORD || param->sym.mem_type == MT_SWORD) {
AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, GetWin64SubReg(ms64_regs[i], 1));
saved++;
}
else if (param->sym.mem_type == MT_DWORD || param->sym.mem_type == MT_SDWORD) {
AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, GetWin64SubReg(ms64_regs[i], 2));
saved++;
}
else {
AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, ms64_regs[i]);
saved++;
}
}
param = param->nextparam;
}
else
{
AddLineQueueX("mov [%r+%u], %r", T_RSP, 8 + i * 8, ms64_regs[i]);
saved++;
}
}
return saved;
}
static void write_win64_default_prologue_RBP(struct proc_info *info)
{
uint_16 *regist;
const char * const *ppfmt;
int i;
int cnt;
int cntxmm;
int resstack = ((ModuleInfo.win64_flags & W64F_AUTOSTACKSP) ? sym_ReservedStack->value : 0);
int stackadj = 0;
int subAmt = 0;
int saved = 0;
check_proc_fpo(info);
info->pushed_reg = 0;
if (ModuleInfo.win64_flags & W64F_SAVEREGPARAMS)
saved = win64_SaveRegParams_RBP(info);
if ((info->isframe && ModuleInfo.frame_auto) || !info->isframe)
{
if (info->fpo)
{
}
else if (!info->fpo || info->forceframe)
{
if (info->isframe && ModuleInfo.frame_auto && saved == 0)
AddLineQueueX("db 48h"); AddLineQueueX("push %r", info->basereg);
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX("%r %r", T_DOT_PUSHREG, info->basereg);
}
cntxmm = 0;
if (info->regslist) {
regist = info->regslist;
for (cnt = *regist++; cnt; cnt--, regist++) {
if (GetValueSp(*regist) & OP_XMM) {
cntxmm += 1; }
else if (GetValueSp(*regist) & OP_YMM) {
cntxmm += 2; }
else if (GetValueSp(*regist) & OP_ZMM) {
cntxmm += 4; }
else {
info->pushed_reg += 1;
AddLineQueueX("push %r", *regist);
if ((1 << GetRegNo(*regist)) & win64_nvgpr) {
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX("%r %r", T_DOT_PUSHREG, *regist);
}
}
}
}
}
if (!info->isframe && cntxmm > 0)
{
EmitError(PROC_USES_XMM);
return;
}
if (ModuleInfo.win64_flags & W64F_STACKALIGN16 || ModuleInfo.win64_flags & W64F_AUTOSTACKSP || ModuleInfo.frame_auto)
{
if (info->fpo)
{
if (info->pushed_reg % 2 == 0 && info->localsize % 16 == 0)
stackadj = 8;
else if (info->pushed_reg % 2 == 0 && info->localsize % 16 != 0)
stackadj = 0;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 == 0)
stackadj = 0;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 != 0)
stackadj = 8;
}
else
{
if (info->pushed_reg % 2 == 0 && info->localsize % 16 == 0)
stackadj = 0;
else if (info->pushed_reg % 2 == 0 && info->localsize % 16 != 0)
stackadj = 8;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 == 0)
stackadj = 8;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 != 0)
stackadj = 0;
}
}
if ((info->isframe && ModuleInfo.frame_auto) || !info->isframe)
{
if (!info->fpo || info->stackparam || info->has_vararg || ModuleInfo.win64_flags & W64F_STACKALIGN16 || ModuleInfo.win64_flags & W64F_AUTOSTACKSP)
{
DebugMsg1(("write_win64_default_prologue_RBP: localsize=%u resstack=%u\n", info->localsize, resstack));
ppfmt = (resstack ? fmtstk1 : fmtstk0);
#if STACKPROBE
if (info->localsize + stackadj + resstack > 0x1000) {
AddLineQueueX(*(ppfmt + 2), T_RAX, NUMQUAL info->localsize + stackadj, sym_ReservedStack->name);
AddLineQueue("externdef __chkstk:PROC");
AddLineQueue("call __chkstk");
AddLineQueueX("mov %r, %r", T_RSP, T_RAX);
}
else
#endif
if (info->localsize + stackadj + resstack > 0)
{
subAmt = info->localsize + stackadj + sym_ReservedStack->value;
if (Options.frameflags)
{
if (resstack)
AddLineQueueX("lea %r, [%r-(%d+%s)]", T_RSP, T_RSP, NUMQUAL info->localsize + stackadj, sym_ReservedStack->name);
else
AddLineQueueX("lea %r, [%r-%d]", T_RSP, T_RSP, NUMQUAL info->localsize + stackadj, sym_ReservedStack->name);
}
else
{
AddLineQueueX(*(ppfmt + 0), T_RSP, NUMQUAL info->localsize + stackadj, sym_ReservedStack->name);
}
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX(*(ppfmt + 1), T_DOT_ALLOCSTACK, NUMQUAL info->localsize + stackadj, sym_ReservedStack->name);
}
}
else if (stackadj + info->localsize > 0 && ModuleInfo.frame_auto)
{
subAmt = info->localsize + stackadj;
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r-%d]", T_RSP, T_RSP, NUMQUAL stackadj + info->localsize);
}
else
{
AddLineQueueX("sub %r, %d", T_RSP, NUMQUAL stackadj + info->localsize);
}
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX("%r %d", T_DOT_ALLOCSTACK, NUMQUAL stackadj + info->localsize);
}
}
if (cntxmm) {
regist = info->regslist;
i = (info->localsize - cntxmm * 16) & ~(16 - 1);
if (regist) {
for (cnt = *regist++; cnt; cnt--, regist++) {
if (resstack) { if (GetValueSp(*regist) & OP_XMM) {
AddLineQueueX("%s [%r+%u+%s], %r", MOVE_ALIGNED_INT(), T_RSP, NUMQUAL i, sym_ReservedStack->name, *regist);
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX("%r %r, %u+%s", T_DOT_SAVEXMM128, *regist, NUMQUAL i, sym_ReservedStack->name);
i += 16;
}
else if (GetValueSp(*regist) & OP_YMM) {
AddLineQueueX("%s [%r+%u+%s], %r", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL i, sym_ReservedStack->name, *regist);
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX("%r %r, %u+%s", T_DOT_SAVEYMM256, *regist, NUMQUAL i, sym_ReservedStack->name);
i += 32;
}
else if (GetValueSp(*regist) & OP_ZMM) {
AddLineQueueX("%s [%r+%u+%s], %r", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL i, sym_ReservedStack->name, *regist);
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX("%r %r, %u+%s", T_DOT_SAVEZMM512, *regist, NUMQUAL i, sym_ReservedStack->name);
i += 64;
}
}
else { if (GetValueSp(*regist) & OP_XMM) {
AddLineQueueX("%s [%r+%u], %r", MOVE_ALIGNED_INT(), T_RSP, NUMQUAL i, *regist);
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX("%r %r, %u", T_DOT_SAVEXMM128, *regist, NUMQUAL i);
i += 16;
}
else if (GetValueSp(*regist) & OP_YMM) {
AddLineQueueX("%s [%r+%u], %r", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL i, *regist);
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX("%r %r, %u", T_DOT_SAVEYMM256, *regist, NUMQUAL i);
i += 32;
}
else if (GetValueSp(*regist) & OP_ZMM) {
AddLineQueueX("%s [%r+%u+%s], %r", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL i, *regist);
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX("%r %r, %u+%s", T_DOT_SAVEZMM512, *regist, NUMQUAL i);
i += 64;
}
}
}
}
}
if ((info->isframe && ModuleInfo.frame_auto) || !info->isframe)
{
if (info->fpo)
{
}
else if (!info->fpo || info->forceframe)
{
if (info->frameofs != 0)
AddLineQueueX("lea %r, [%r + %d]", info->basereg, T_RSP, info->frameofs);
else
AddLineQueueX("mov %r, %r", info->basereg, T_RSP);
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX( "%r %r, %d", T_DOT_SETFRAME, info->basereg, info->frameofs );
}
if (info->isframe && ModuleInfo.frame_auto)
AddLineQueueX("%r", T_DOT_ENDPROLOG);
}
return;
}
static void write_win64_default_prologue_RSP(struct proc_info *info)
{
uint_16 *regist;
const char * const *ppfmt;
int cntxmm;
unsigned char xyused[6];
unsigned char xreg;
unsigned char xsize;
unsigned char ymmflag = 0;
unsigned char zmmflag = 0;
int vsize = 0;
int vectstart = 0;
int n;
int m;
int i;
int j;
int cnt;
int stackSize;
int resstack = ((ModuleInfo.win64_flags & W64F_AUTOSTACKSP) ? sym_ReservedStack->value : 0);
int pushed = 0;
if (Parse_Pass == PASS_1)
{
info->vsize = 0;
info->xmmsize = 0;
}
memset(xyused, 0, 6);
info->vecused = 0;
XYZMMsize = 16;
if (ModuleInfo.win64_flags & W64F_SAVEREGPARAMS)
win64_SaveRegParams_RSP(info);
if (ModuleInfo.win64_flags & W64F_SMART)
win64_StoreRegHome(info);
#if STACKBASESUPP
info->pushed_reg = 0;
if (info->regslist != 0)
pushed = *(info->regslist);
#endif
cntxmm = 0;
if (info->regslist) {
n = 0;
regist = info->regslist;
for (cnt = *regist++; cnt; cnt--, regist++) {
if (GetValueSp(*regist) & OP_XMM) {
cntxmm += 1;
}
else if (GetValueSp(*regist) & OP_YMM) {
cntxmm += 1;
ymmflag = 1;
}
else if (GetValueSp(*regist) & OP_ZMM) {
cntxmm += 1;
zmmflag = 1;
}
else {
if (n < info->stored_reg) n++;
else {
info->pushed_reg += 1;
AddLineQueueX("push %r", *regist);
if ((1 << GetRegNo(*regist)) & win64_nvgpr) {
AddLineQueueX("%r %r", T_DOT_PUSHREG, *regist);
}
}
}
}
}
if (zmmflag) XYZMMsize = 64;
else
if (ymmflag) XYZMMsize = 32;
else XYZMMsize = 16;
if (ModuleInfo.win64_flags & W64F_HABRAN)
{
if (!(info->locallist) && !(resstack)) info->localsize = 0;
if ((info->localsize == 0) && (cntxmm))
{
CurrProc->e.procinfo->xmmsize = cntxmm * XYZMMsize;
if ((info->pushed_reg & 1) == 0)
info->localsize = 8;
}
}
if ((info->locallist + resstack) || info->vecused || CurrProc->e.procinfo->xmmsize) {
DebugMsg1(("write_win64_default_prologue_RSP: localsize=%u resstack=%u\n", info->localsize, resstack));
if (ModuleInfo.win64_flags & W64F_HABRAN) {
if (((info->pushed_reg & 1) && (info->localsize & 0xF)) ||
((!(info->pushed_reg & 1)) && (!(info->localsize & 0xF))) && (!(info->pushed_reg & 1)) && (!(cntxmm)))
{
info->localsize += 8;
if (CurrProc->sym.langtype == LANG_VECTORCALL) {
vectstart = 0;
}
}
}
ppfmt = (resstack ? fmtstk1 : fmtstk0);
#if STACKPROBE
if (info->localsize + resstack > 0x1000) {
AddLineQueueX(*(ppfmt + 2), T_RAX, NUMQUAL info->localsize, sym_ReservedStack->name);
AddLineQueue("externdef __chkstk:PROC");
AddLineQueue("call __chkstk");
AddLineQueueX("mov %r, %r", T_RSP, T_RAX);
}
else
#endif
stackSize = info->localsize + info->vsize + info->xmmsize;
if ((stackSize & 7) != 0) stackSize = (stackSize + 7)&(-8);
if (Options.frameflags)
{
if(resstack)
AddLineQueueX("lea %r, [%r-(%d+%s)]", T_RSP, T_RSP, NUMQUAL stackSize, sym_ReservedStack->name);
else
AddLineQueueX("lea %r, [%r-%d]", T_RSP, T_RSP, NUMQUAL stackSize, sym_ReservedStack->name);
}
else
{
AddLineQueueX(*(ppfmt + 0), T_RSP, NUMQUAL stackSize, sym_ReservedStack->name);
}
AddLineQueueX(*(ppfmt + 1), T_DOT_ALLOCSTACK, NUMQUAL stackSize, sym_ReservedStack->name);
if (cntxmm) {
int cnt;
regist = info->regslist;
i = 0; if (regist)
{
for (cnt = *regist++; cnt; cnt--, regist++)
{
if ((GetValueSp(*regist) & OP_XMM) || (GetValueSp(*regist) & OP_YMM) || (GetValueSp(*regist) & OP_ZMM)) {
if (resstack) {
if (GetValueSp(*regist) & OP_XMM) {
AddLineQueueX("%s [%r+%u+%s], %r", MOVE_ALIGNED_INT(), T_RSP, NUMQUAL i, sym_ReservedStack->name, *regist);
AddLineQueueX("%r %r, %u+%s", T_DOT_SAVEXMM128, *regist, NUMQUAL i, sym_ReservedStack->name);
i += 16; }
else if (GetValueSp(*regist) & OP_YMM) {
AddLineQueueX("vmovdqu [%r+%u+%s], %r", T_RSP, NUMQUAL i, sym_ReservedStack->name, *regist);
AddLineQueueX("%r %r, %u+%s", T_DOT_SAVEYMM256, *regist, NUMQUAL i, sym_ReservedStack->name);
i += 32; }
else if (GetValueSp(*regist) & OP_ZMM) {
AddLineQueueX("vmovdqu [%r+%u+%s], %r", T_RSP, NUMQUAL i, sym_ReservedStack->name, *regist);
AddLineQueueX("%r %r, %u+%s", T_DOT_SAVEZMM512, *regist, NUMQUAL i, sym_ReservedStack->name);
i += 64; }
}
else {
if (GetValueSp(*regist) & OP_XMM) {
AddLineQueueX("%s [%r+%u], %r", MOVE_ALIGNED_INT(), T_RSP, NUMQUAL i, *regist);
AddLineQueueX("%r %r, %u", T_DOT_SAVEXMM128, *regist, NUMQUAL i);
i += 16; }
else if (GetValueSp(*regist) & OP_YMM) {
AddLineQueueX("vmovdqu [%r+%u], %r", T_RSP, NUMQUAL i, *regist);
AddLineQueueX("%r %r, %u", T_DOT_SAVEYMM256, *regist, NUMQUAL i);
i += 32; }
else if (GetValueSp(*regist) & OP_ZMM) {
AddLineQueueX("vmovdqu [%r+%u+%s], %r", T_RSP, NUMQUAL i, *regist);
AddLineQueueX("%r %r, %u+%s", T_DOT_SAVEZMM512, *regist, NUMQUAL i);
i += 64; }
}
}
}
}
}
if (CurrProc->sym.langtype == LANG_VECTORCALL) {
vectstart = info->localsize + info->xmmsize & ~(16 - 1);
if (info->vecused) {
if (info->vecregs) {
for (n = 0, m = 0, xsize = 0; n < 6; n++) {
xreg = info->vecregs[n];
if (xreg == 1 && info->vecregsize[n] < 16)
continue; else if (xreg)
{
AddLineQueueX("lea %r,[%r + %d]", T_RAX, T_RSP, vectstart + xsize);
stackSize = info->localsize + resstack + info->vsize + info->xmmsize + 8 + info->pushed_reg * 8 + n * 8;
if ((stackSize & 7) != 0) stackSize = (stackSize + 7)&(-8);
AddLineQueueX("mov [%r + %d], %r", T_RSP, stackSize, T_RAX);
xsize += info->vecregsize[n] * xreg;
}
else if (info->vregs[n] != 0 && xreg == 0 && n < 4)
{
struct dsym *pp = info->paralist;
int j = 0;
for (j = 0; j < n; j++)
{
if (pp) pp = pp->nextparam;
}
if (pp)
{
if (pp->sym.ttype)
{
if (pp->sym.ttype->e.structinfo->isHFA == 1 || pp->sym.ttype->e.structinfo->isHVA == 1 || pp->sym.ttype->e.structinfo->stype == MM128 || pp->sym.ttype->e.structinfo->stype == MM256)
{
stackSize = info->localsize + resstack + info->vsize + info->xmmsize + 8 + info->pushed_reg * 8 + n * 8;
if ((stackSize & 7) != 0) stackSize = (stackSize + 7)&(-8);
AddLineQueueX("mov [%r + %d], %r", T_RSP, stackSize, ms64_regs[n]);
xsize += info->vecregsize[n] * xreg;
}
}
}
}
}
for (i = 0; i < 6; i++) {
if (info->vecregs[i] == 1) xyused[i] = 1;
else if ((info->vecregs[i] >= 1) && (xyused[i] != 1))
xyused[i] = 0;
}
for (n = 0, m = 0; n < 6; n++) {
xreg = info->vecregs[n]; xsize = info->vecregsize[n]; m += xreg;
if (m > 6) break; if (xreg == 1 && info->vecregsize[n] < 16)
continue; else if (xreg) {
switch (xsize) {
case 4:
for (i = 0, j = 0; i < xreg; i++) {
while (xyused[j] != 0) j++;
AddLineQueueX("%s dword ptr [rsp+%d],%r", MOVE_SINGLE(), vsize + vectstart, T_XMM0 + j);
xyused[j] = 1;
vsize += 4;
}
break;
case 8:
if (xreg <= 3) {
for (i = 0, j = 0; i < xreg; i++) {
while (xyused[j] != 0) j++;
AddLineQueueX("%s qword ptr [rsp+%d],%r", MOVE_DOUBLE(), vsize + vectstart, T_XMM0 + j);
xyused[j] = 1;
vsize += 8;
}
}
else {
AddLineQueueX("vmovups ymmword ptr [rsp+%d],%r", vsize + vectstart, T_YMM0 + n);
vsize += 64;
xyused[n] = 1;
}
break;
case 16:
if (xreg == 1) {
AddLineQueueX("%s oword ptr [rsp+%d],%r", MOVE_UNALIGNED_FLOAT(), vsize + vectstart, T_XMM0 + n);
xyused[n] = 1;
vsize += 16;
}
else {
for (i = 0, j = 0; i < xreg; i++) {
while (xyused[j] != 0) j++;
AddLineQueueX("%s oword ptr [rsp+%d],%r", MOVE_UNALIGNED_FLOAT(), vsize + vectstart, T_XMM0 + j);
xyused[j] = 1;
vsize += 16;
}
}
break;
case 32:
if (xreg == 1) {
AddLineQueueX("vmovups ymmword ptr [rsp+%d],%r", vsize + vectstart, T_YMM0 + n);
xyused[n] = 1;
vsize += 32;
}
else {
for (i = 0, j = 0; i < xreg; i++) {
while (xyused[j] != 0) j++;
AddLineQueueX("vmovups ymmword ptr [rsp+%d],%r", vsize + vectstart, T_YMM0 + j);
xyused[j] = 1;
vsize += 32;
}
}
break;
case 64:
if (xreg == 1) {
AddLineQueueX("vmovups zmmword ptr [rsp+%d],%r", vsize + vectstart + xsize, T_ZMM0 + n);
xyused[n] = 1;
vsize += 64;
}
else {
for (i = 0, j = 0; i < xreg; i++) {
while (xyused[j] != 0) j++;
AddLineQueueX("vmovups zmmword ptr [rsp+%d],%r", vsize + vectstart + xsize, T_ZMM0 + j);
xyused[j] = 1;
vsize += 64;
}
}
break;
}
}
}
}
}
}
}
else if (info->localsize > 0)
{
stackSize = info->localsize;
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r-%d]", stackreg[ModuleInfo.Ofssize], stackreg[ModuleInfo.Ofssize], stackSize);
}
else
{
AddLineQueueX("sub %r, %d", stackreg[ModuleInfo.Ofssize], stackSize);
}
}
AddLineQueueX("%r", T_DOT_ENDPROLOG);
return;
}
static void check_proc_fpo(struct proc_info *info)
{
struct dsym *paracurr;
int usedParams = 0;
int usedLocals = 0;
for (paracurr = info->paralist; paracurr; paracurr = paracurr->nextparam)
usedParams++;
for (paracurr = info->locallist; paracurr; paracurr = paracurr->nextlocal)
usedLocals++;
if (info->exc_handler && ModuleInfo.basereg[ModuleInfo.Ofssize] == T_RBP)
{
info->fpo = FALSE;
return;
}
if (ModuleInfo.basereg[ModuleInfo.Ofssize] == T_RSP || ModuleInfo.basereg[ModuleInfo.Ofssize] == T_ESP)
{
info->fpo = TRUE;
return;
}
if (info->forceframe == TRUE)
{
info->fpo = FALSE;
return;
}
if (!ModuleInfo.frame_auto && info->isframe)
{
info->fpo = TRUE;
return;
}
if (!info->isframe && (usedParams>0 || usedLocals>0))
{
info->fpo = FALSE;
return;
}
if (usedLocals > 0 || usedParams > 0 || Parse_Pass == PASS_1)
{
info->fpo = FALSE;
return;
}
if (usedLocals == 0 && usedParams == 0)
info->fpo = TRUE;
return;
}
static void write_win64_default_epilogue_RBP(struct proc_info *info)
{
int resstack = ((ModuleInfo.win64_flags & W64F_AUTOSTACKSP) ? sym_ReservedStack->value : 0);
int stackadj = 0;
const char * const *ppfmt;
uint_16 restoreReg;
if (info->fpo)
{
if (info->pushed_reg % 2 == 0 && info->localsize % 16 == 0)
stackadj = 8;
else if (info->pushed_reg % 2 == 0 && info->localsize % 16 != 0)
stackadj = 0;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 == 0)
stackadj = 0;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 != 0)
stackadj = 8;
}
else
{
if (info->pushed_reg % 2 == 0 && info->localsize % 16 == 0)
stackadj = 0;
else if (info->pushed_reg % 2 == 0 && info->localsize % 16 != 0)
stackadj = 8;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 == 0)
stackadj = 8;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 != 0)
stackadj = 0;
}
if ((info->isframe && ModuleInfo.frame_auto) || !info->isframe)
{
if (info->regslist)
{
uint_16 *regs;
int cnt;
int i;
for (regs = info->regslist, cnt = *regs++, i = 0; cnt; cnt--, regs++)
if (GetValueSp(*regs) & OP_XMM)
i++;
else if (GetValueSp(*regs) & OP_YMM)
i += 2;
else if (GetValueSp(*regs) & OP_ZMM)
i += 4;
if (i)
{
i = (info->localsize - i * 16) & ~(16 - 1);
if (info->fpo)
restoreReg = stackreg[ModuleInfo.Ofssize];
else
restoreReg = info->basereg;
for (regs = info->regslist, cnt = *regs++; cnt; cnt--, regs++) {
if (GetValueSp(*regs) & OP_XMM) {
DebugMsg1(("write_win64_default_epilogue(%s): restore %s, offset=%d\n", CurrProc->sym.name, GetResWName(*regs, NULL), i));
if (ModuleInfo.win64_flags & W64F_AUTOSTACKSP)
AddLineQueueX("%s %r, [%r + %d + %s]", MOVE_ALIGNED_INT(), *regs, restoreReg, NUMQUAL i - info->frameofs, sym_ReservedStack->name);
else
AddLineQueueX("%s %r, [%r + %d]", MOVE_ALIGNED_INT(), *regs, restoreReg, NUMQUAL i - info->frameofs);
i += 16;
}
if (GetValueSp(*regs) & OP_YMM) {
DebugMsg1(("write_win64_default_epilogue(%s): restore %s, offset=%d\n", CurrProc->sym.name, GetResWName(*regs, NULL), i));
if (ModuleInfo.win64_flags & W64F_AUTOSTACKSP)
AddLineQueueX("%s %r, [%r + %d + %s]", MOVE_UNALIGNED_INT(), *regs, restoreReg, NUMQUAL i - info->frameofs, sym_ReservedStack->name);
else
AddLineQueueX("%s %r, [%r + %d]", MOVE_UNALIGNED_INT(), *regs, restoreReg, NUMQUAL i - info->frameofs);
i += 32;
}
if (GetValueSp(*regs) & OP_ZMM) {
DebugMsg1(("write_win64_default_epilogue(%s): restore %s, offset=%d\n", CurrProc->sym.name, GetResWName(*regs, NULL), i));
if (ModuleInfo.win64_flags & W64F_AUTOSTACKSP)
AddLineQueueX("%s %r, [%r + %d + %s]", MOVE_UNALIGNED_INT(), *regs, restoreReg, NUMQUAL i - info->frameofs, sym_ReservedStack->name);
else
AddLineQueueX("%s %r, [%r + %d]", MOVE_UNALIGNED_INT(), *regs, restoreReg, NUMQUAL i - info->frameofs);
i += 64;
}
}
}
}
}
if ( (info->isframe && ModuleInfo.frame_auto) || !info->isframe )
{
if (!info->fpo || info->stackparam || info->has_vararg || ModuleInfo.win64_flags & W64F_STACKALIGN16 || ModuleInfo.win64_flags & W64F_AUTOSTACKSP)
{
if (!info->fpo)
{
ppfmt = (resstack ? fmtstk3 : fmtstk2);
if (info->localsize + stackadj + resstack > 0)
{
AddLineQueueX(*(ppfmt + 0), T_RSP, info->basereg, NUMQUAL stackadj + info->localsize - info->frameofs, sym_ReservedStack->name);
}
else
AddLineQueueX("mov %r, %r", T_RSP, info->basereg);
}
else if (info->localsize + stackadj + resstack > 0)
{
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r+(%d+%s)]", T_RSP, T_RSP, NUMQUAL stackadj + info->localsize, sym_ReservedStack->name);
}
else
{
AddLineQueueX("add %r, %d + %s", T_RSP, NUMQUAL stackadj + info->localsize, sym_ReservedStack->name);
}
}
}
else if (stackadj + info->localsize > 0 && ModuleInfo.frame_auto)
{
if (!info->fpo)
AddLineQueueX("lea %r, [%r + %d]", T_RSP, info->basereg, NUMQUAL stackadj + info->localsize - info->frameofs);
else
{
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r+%d]", T_RSP, T_RSP, NUMQUAL stackadj + info->localsize);
}
else
{
AddLineQueueX("add %r, %d", T_RSP, NUMQUAL stackadj + info->localsize);
}
}
}
pop_register(CurrProc->e.procinfo->regslist);
if (!info->fpo)
AddLineQueueX("pop %r", info->basereg);
}
return;
}
static void write_win64_default_epilogue_RSP(struct proc_info *info)
{
int anysize;
int stackSize;
int resstack = ((ModuleInfo.win64_flags & W64F_AUTOSTACKSP) ? sym_ReservedStack->value : 0);
if (info->regslist) {
uint_16 *regs;
int cnt;
int i;
for (regs = info->regslist, cnt = *regs++, i = 0; cnt; cnt--, regs++)
if ((GetValueSp(*regs) & OP_XMM) || (GetValueSp(*regs) & OP_YMM) || (GetValueSp(*regs) & OP_ZMM))
i++;
DebugMsg1(("write_win64_default_epilogue_RSP(%s): %u xmm registers to restore\n", CurrProc->sym.name, i));
if (i) {
i = 0; for (regs = info->regslist, cnt = *regs++; cnt; cnt--, regs++) {
if ((GetValueSp(*regs) & OP_XMM) || (GetValueSp(*regs) & OP_YMM) || (GetValueSp(*regs) & OP_ZMM)) {
DebugMsg1(("write_win64_default_epilogue_RSP(%s): restore %s, offset=%d\n", CurrProc->sym.name, GetResWName(*regs, NULL), i));
if (resstack)
{
if (GetValueSp(*regs) & OP_XMM)
{
AddLineQueueX("%s %r, [%r + %u + %s]", MOVE_ALIGNED_INT(), *regs, stackreg[ModuleInfo.Ofssize], NUMQUAL i, sym_ReservedStack->name);
i += 16;
}
else if (GetValueSp(*regs) & OP_YMM)
{
AddLineQueueX("vmovdqu %r, [%r + %u + %s]", *regs, stackreg[ModuleInfo.Ofssize], NUMQUAL i, sym_ReservedStack->name);
i += 32;
}
}
else
{
if (GetValueSp(*regs) & OP_XMM)
{
AddLineQueueX("%s %r, [%r + %u]", MOVE_ALIGNED_INT(), *regs, stackreg[ModuleInfo.Ofssize], NUMQUAL i);
i += 16;
}
if (GetValueSp(*regs) & OP_YMM)
{
AddLineQueueX("vmovdqu %r, [%r + %u]", *regs, stackreg[ModuleInfo.Ofssize], NUMQUAL i);
i += 32;
}
}
}
}
}
}
if (ModuleInfo.fctype == FCT_WIN64 && (ModuleInfo.win64_flags & W64F_AUTOSTACKSP)) {
anysize = info->localsize + sym_ReservedStack->value + info->xmmsize;
if (info->vecused) anysize += info->vsize;
if (anysize)
{
stackSize = info->localsize + info->vsize + info->xmmsize;
if ((stackSize & 7) != 0) stackSize = (stackSize + 7)&(-8);
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r+(%d+%s)]", stackreg[ModuleInfo.Ofssize], stackreg[ModuleInfo.Ofssize], NUMQUAL stackSize, sym_ReservedStack->name);
}
else
{
AddLineQueueX("add %r, %d + %s", stackreg[ModuleInfo.Ofssize], NUMQUAL stackSize, sym_ReservedStack->name);
}
}
}
else if (info->localsize > 0)
{
stackSize = info->localsize;
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r+%d]", stackreg[ModuleInfo.Ofssize], stackreg[ModuleInfo.Ofssize], stackSize);
}
else
{
AddLineQueueX("add %r, %d", stackreg[ModuleInfo.Ofssize], stackSize);
}
}
pop_register(CurrProc->e.procinfo->regslist);
#if STACKBASESUPP
if (ModuleInfo.win64_flags & W64F_SMART) {
if (info->regslist) {
uint_16 *regist = info->regslist;
int cnt;
if (ModuleInfo.win64_flags) {
int i = 0;
int gprzize = 0;
for (cnt = *regist++; cnt; cnt--, regist++)
{
if ((GetValueSp(*regist) & OP_XMM) || (GetValueSp(*regist) & OP_YMM) || (GetValueSp(*regist) & OP_ZMM))
continue;
else {
gprzize += 8;
if (gprzize <= 0x20)
{
if (info->home_used[i] == 0) {
AddLineQueueX("mov %r, [%r+%u]", *regist, stackreg[ModuleInfo.Ofssize], NUMQUAL gprzize);
}
else {
cnt++; regist--;
}
i++;
}
}
}
}
}
}
if (GetRegNo(info->basereg) != 4 && (info->parasize != 0 || info->locallist != NULL))
AddLineQueueX("pop %r", info->basereg);
#else
AddLineQueueX("pop %r", basereg[ModuleInfo.Ofssize]);
#endif
return;
}
static void SetLocalOffsets_RBP(struct proc_info *info)
{
struct dsym *curr = NULL;
int cntxmm = 0;
int cntstd = 0;
int start = 0;
int rspalign = TRUE;
int align = CurrWordSize;
int cnt = 0;
uint_16 *regs = NULL;
int stackAdj = 0;
int paramBase = 0;
int curOfs = 0;
int resstack = ((ModuleInfo.win64_flags & W64F_AUTOSTACKSP) ? sym_ReservedStack->value : 0);
if (ModuleInfo.win64_flags & W64F_STACKALIGN16)
align = 16;
check_proc_fpo(info);
if (info->regslist)
{
for (regs = info->regslist, cnt = *regs++; cnt; cnt--, regs++)
{
if (GetValueSp(*regs) & OP_XMM)
cntxmm++;
else if (GetValueSp(*regs) & OP_YMM)
cntxmm += 2;
else if (GetValueSp(*regs) & OP_ZMM)
cntxmm += 4;
else
cntstd++;
}
}
info->localsize = (16 * cntxmm);
for (curr = info->locallist; curr; curr = curr->nextlocal)
{
uint_32 totalsize = curr->sym.total_size;
if (totalsize >= 16)
totalsize = ROUND_UP(totalsize, 16);
else if (totalsize >= 8 && totalsize < 16)
totalsize = ROUND_UP(totalsize, 8);
else if (totalsize >= 4 && totalsize < 8)
totalsize = ROUND_UP(totalsize, 4);
info->localsize += totalsize;
}
info->localsize = ROUND_UP(info->localsize, 16);
info->frameofs = 0;
if (!info->fpo)
{
info->frameofs = (info->localsize >> 1) + resstack;
info->frameofs = ROUND_UP(info->frameofs, 16);
if (info->frameofs > 128) info->frameofs = 128;
}
if (info->fpo)
{
if (info->pushed_reg % 2 == 0 && info->localsize % 16 == 0)
stackAdj = 8;
else if (info->pushed_reg % 2 == 0 && info->localsize % 16 != 0)
stackAdj = 0;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 == 0)
stackAdj = 0;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 != 0)
stackAdj = 8;
}
else
{
if (info->pushed_reg % 2 == 0 && info->localsize % 16 == 0)
stackAdj = 0;
else if (info->pushed_reg % 2 == 0 && info->localsize % 16 != 0)
stackAdj = 8;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 == 0)
stackAdj = 8;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 != 0)
stackAdj = 0;
}
curOfs = info->localsize + resstack - (16 * cntxmm) - info->frameofs;
for (curr = info->locallist; curr; curr = curr->nextlocal)
{
uint_32 totalsize = curr->sym.total_size;
if (totalsize >= 16)
{
totalsize = ROUND_UP(totalsize, 16);
curr->sym.offset = curOfs - totalsize;
curOfs -= totalsize;
}
}
for (curr = info->locallist; curr; curr = curr->nextlocal)
{
uint_32 totalsize = curr->sym.total_size;
if (totalsize >= 8 && totalsize < 16)
{
totalsize = ROUND_UP(totalsize, 8);
curr->sym.offset = curOfs - totalsize;
curOfs -= totalsize;
}
}
for (curr = info->locallist; curr; curr = curr->nextlocal)
{
uint_32 totalsize = curr->sym.total_size;
if (totalsize >= 4 && totalsize < 8)
{
totalsize = ROUND_UP(totalsize, 4);
curr->sym.offset = curOfs - totalsize;
curOfs -= totalsize;
}
}
for (curr = info->locallist; curr; curr = curr->nextlocal)
{
uint_32 totalsize = curr->sym.total_size;
if (totalsize < 4)
{
curr->sym.offset = curOfs - totalsize;
curOfs -= totalsize;
}
}
if (info->fpo)
{
paramBase = (CurrWordSize * cntstd) + 8 + info->localsize + stackAdj + resstack - info->frameofs;
for (curr = info->paralist; curr; curr = curr->nextparam)
curr->sym.offset = paramBase + ((cnt++)*CurrWordSize);
}
else
{
paramBase = (CurrWordSize * cntstd) + 16 + info->localsize + stackAdj + resstack - info->frameofs;
for (curr = info->paralist; curr; curr = curr->nextparam)
curr->sym.offset = paramBase + ((cnt++)*CurrWordSize);
}
}
static void SetLocalOffsets_RSP(struct proc_info *info)
{
struct dsym *curr;
int cntxmm = 0;
int cntstd = 0;
int start = 0;
uint_16 *regist;
int cnt;
unsigned char xmmflag = 1;
unsigned char ymmflag = 0;
unsigned localadj;
unsigned paramadj;
int rspalign = FALSE;
int align = CurrWordSize;
unsigned char zmmflag = 0;
regist = info->regslist;
rspalign = TRUE;
if (info->regslist) {
for (cnt = *regist++; cnt; cnt--, regist++) {
if (GetValueSp(*regist) & OP_XMM)
xmmflag = 1;
else if (GetValueSp(*regist) & OP_YMM)
ymmflag = 1;
else if (GetValueSp(*regist) & OP_ZMM)
zmmflag = 1;
}
}
if (ymmflag) XYZMMsize = 32;
else XYZMMsize = 16;
if (info->fpo || rspalign) {
if (info->regslist) {
int cnt;
uint_16 *regs;
for (regs = info->regslist, cnt = *regs++; cnt; cnt--, regs++)
if ((GetValueSp(*regs) & OP_XMM) || (GetValueSp(*regs) & OP_YMM) || (GetValueSp(*regs) & OP_ZMM))
cntxmm++;
else
cntstd++;
}
if (info->parasize == 0 && info->locallist == NULL)
start = CurrWordSize;
cntstd = info->pushed_reg;
if (rspalign && cntxmm) {
if (!(cntstd & 1)) info->localsize += 8;
info->localsize += XYZMMsize * cntxmm;
}
DebugMsg1(("SetLocalOffsets_RSP(%s): cntxmm=%u cntstd=%u start=%u align=%u localsize=%u\n", CurrProc->sym.name, cntxmm, cntstd, start, align, info->localsize));
}
for (curr = info->locallist; curr; curr = curr->nextlocal)
{
uint_32 itemsize = (curr->sym.total_size == 0 ? 0 : curr->sym.total_size / curr->sym.total_length);
int n = 0;
if (curr->sym.isarray) n = curr->sym.total_size & 0x7;
if (itemsize < 16)
info->localsize = ROUND_UP(info->localsize, itemsize);
if (ModuleInfo.win64_flags & W64F_STACKALIGN16 && curr->sym.total_size > CurrWordSize)
info->localsize = ROUND_UP(info->localsize, 16);
curr->sym.offset = info->localsize;
info->localsize += curr->sym.total_size + n;
if (itemsize > align)
info->localsize = ROUND_UP(info->localsize, align);
else if (itemsize)
info->localsize = ROUND_UP(info->localsize, itemsize);
DebugMsg1(("SetLocalOffsets_RSP(%s): offset of %s (size=%u) set to %d\n", CurrProc->sym.name, curr->sym.name, curr->sym.total_size, curr->sym.offset));
}
if (!(cntstd & 1) && ((info->localsize & 15) == 0)) info->localsize += 8;
if (rspalign)
info->localsize = ROUND_UP(info->localsize, 8);
DebugMsg1(("SetLocalOffsets_RSP(%s): localsize=%u after processing locals\n", CurrProc->sym.name, info->localsize));
if (info->fpo) {
if (rspalign) {
localadj = info->localsize;
paramadj = info->localsize - CurrWordSize - start;
}
else
{
localadj = info->localsize + cntstd * CurrWordSize;
paramadj = info->localsize + cntstd * CurrWordSize - CurrWordSize;
}
}
}
#endif
#if SYSV_SUPPORT
static int sysv_pcheck(struct dsym *proc, struct dsym *paranode, int *used, int *vecused)
{
char regname[32];
int size = SizeFromMemtype(paranode->sym.mem_type, paranode->sym.Ofssize, paranode->sym.type);
paranode->sym.string_ptr = NULL;
if ((paranode->sym.mem_type == MT_REAL4) || (paranode->sym.mem_type == MT_REAL8) || (paranode->sym.mem_type == MT_TYPE && _stricmp(paranode->sym.type->name, "__m128") == 0) || paranode->sym.mem_type == MT_OWORD)
{
if (*vecused >= 8)
{
paranode->sym.string_ptr = NULL;
return(0);
}
paranode->sym.state = SYM_TMACRO;
GetResWName(sysV64_regsXMM[*vecused], regname);
paranode->sym.tokval = sysV64_regsXMM[*vecused];
paranode->sym.total_size = 0;
paranode->sym.string_ptr = LclAlloc(strlen(regname) + 1);
strcpy(paranode->sym.string_ptr, regname);
(*vecused)++;
proc->e.procinfo->firstVEC = *vecused;
return(1);
}
if ((paranode->sym.mem_type == MT_TYPE && _stricmp(paranode->sym.type->name, "__m256") == 0) || paranode->sym.mem_type == MT_YMMWORD)
{
if (*vecused >= 8)
{
paranode->sym.string_ptr = NULL;
return(0);
}
paranode->sym.state = SYM_TMACRO;
GetResWName(sysV64_regsYMM[*vecused], regname);
paranode->sym.tokval = sysV64_regsYMM[*vecused];
paranode->sym.total_size = 0;
paranode->sym.string_ptr = LclAlloc(strlen(regname) + 1);
strcpy(paranode->sym.string_ptr, regname);
(*vecused)++;
proc->e.procinfo->firstVEC = *vecused;
return(1);
}
if ((paranode->sym.mem_type == MT_TYPE && _stricmp(paranode->sym.type->name, "__m512") == 0) || paranode->sym.mem_type == MT_ZMMWORD)
{
if (*vecused >= 8)
{
paranode->sym.string_ptr = NULL;
return(0);
}
paranode->sym.state = SYM_TMACRO;
GetResWName(sysV64_regsZMM[*vecused], regname);
paranode->sym.tokval = sysV64_regsZMM[*vecused];
paranode->sym.total_size = 0;
paranode->sym.string_ptr = LclAlloc(strlen(regname) + 1);
strcpy(paranode->sym.string_ptr, regname);
(*vecused)++;
proc->e.procinfo->firstVEC = *vecused;
return(1);
}
if (paranode->sym.mem_type == MT_TYPE)
{
EmitErr(INVOKE_ARGUMENT_NOT_SUPPORTED);
return(0);
}
if (size > CurrWordSize || *used >= 6 || paranode->sym.is_vararg)
{
paranode->sym.string_ptr = NULL;
return(0);
}
paranode->sym.state = SYM_TMACRO;
switch (size)
{
case 8:
GetResWName(sysV64_regs[*used], regname);
paranode->sym.total_size = 8;
paranode->sym.tokval = sysV64_regs[*used];
break;
case 4:
GetResWName(sysV64_regs32[*used], regname);
paranode->sym.total_size = 4;
paranode->sym.tokval = sysV64_regs32[*used];
break;
case 2:
GetResWName(sysV64_regs16[*used], regname);
paranode->sym.total_size = 2;
paranode->sym.tokval = sysV64_regs16[*used];
break;
case 1:
GetResWName(sysV64_regs8[*used], regname);
paranode->sym.total_size = 1;
paranode->sym.tokval = sysV64_regs8[*used];
break;
}
paranode->sym.string_ptr = LclAlloc(strlen(regname) + 1);
strcpy(paranode->sym.string_ptr, regname);
(*used)++;
proc->e.procinfo->firstGPR = *used;
return(1);
}
static void sysv_return(struct dsym *proc, char *buffer)
{
return;
}
static void write_sysv_default_prologue_RBP(struct proc_info *info)
{
uint_16 *regist;
int i = 0;
int cnt;
int cntxmm;
int stackadj = 0;
int resstack = ((ModuleInfo.win64_flags & W64F_AUTOSTACKSP) ? sym_ReservedStack->value : 0);
info->pushed_reg = 0;
stackadj += 8;
if (!info->fpo && GetRegNo(info->basereg) != 4 && (info->parasize != 0 || info->locallist != NULL))
{
AddLineQueueX("push %r", info->basereg);
AddLineQueueX("mov %r, %r", info->basereg, T_RSP);
stackadj -= 8;
}
cntxmm = 0;
if (info->regslist)
{
regist = info->regslist;
for (cnt = *regist++; cnt; cnt--, regist++)
{
if (GetValueSp(*regist) & OP_XMM)
cntxmm += 1; else if (GetValueSp(*regist) & OP_YMM)
cntxmm += 2; else if (GetValueSp(*regist) & OP_ZMM)
cntxmm += 4; else
{
info->pushed_reg += 1;
AddLineQueueX("push %r", *regist);
}
}
}
if (info->fpo)
{
if (info->pushed_reg % 2 == 0 && info->pushed_reg > 0)
stackadj += 8;
else if (info->pushed_reg % 2 == 0)
stackadj += 0;
}
else
{
if (info->pushed_reg % 2 == 0)
stackadj += 0;
else
stackadj += 8;
}
if ((info->localsize + resstack) > 0)
{
DebugMsg1(("write_sysv_default_prologue_RBP: localsize=%u\n", info->localsize));
if (ModuleInfo.redzone == 1 && (info->localsize + resstack) < 128 && resstack == 0)
;
else
{
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r-%d]", T_RSP, T_RSP, NUMQUAL(info->localsize + stackadj + resstack));
}
else
{
AddLineQueueX("sub %r, %d", T_RSP, NUMQUAL(info->localsize + stackadj + resstack));
}
}
}
else if (stackadj > 0 && !info->isleaf)
{
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r-%d]", T_RSP, T_RSP, NUMQUAL(stackadj + resstack));
}
else
{
AddLineQueueX("sub %r, %d", T_RSP, NUMQUAL(stackadj + resstack));
}
info->stackAdj = stackadj;
}
if (cntxmm)
{
regist = info->regslist;
i = (info->localsize + resstack - cntxmm * 16) & ~(16 - 1);
if (regist)
{
for (cnt = *regist++; cnt; cnt--, regist++)
{
if (GetValueSp(*regist) & OP_XMM) {
AddLineQueueX("%s [%r+%u], %r", MOVE_ALIGNED_INT(), T_RSP, NUMQUAL i, *regist);
i += 16;
}
else if (GetValueSp(*regist) & OP_YMM) {
AddLineQueueX("%s [%r+%u], %r", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL i, *regist);
i += 32;
}
else if (GetValueSp(*regist) & OP_ZMM) {
AddLineQueueX("%s [%r+%u+%s], %r", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL i, *regist);
i += 64;
}
}
}
}
return;
}
static void write_sysv_default_epilogue_RBP(struct proc_info *info)
{
int resstack = ((ModuleInfo.win64_flags & W64F_AUTOSTACKSP) ? sym_ReservedStack->value : 0);
int stackadj = 8;
if (!info->fpo && GetRegNo(info->basereg) != 4 && (info->parasize != 0 || info->locallist != NULL))
{
stackadj -= 8;
}
if (info->fpo)
{
if (info->pushed_reg % 2 == 0 && info->pushed_reg != 0)
stackadj += 8;
else if (info->pushed_reg != 0)
stackadj += 0;
}
else
{
if (info->pushed_reg % 2 == 0 && info->pushed_reg != 0)
stackadj += 0;
else if (info->pushed_reg != 0)
stackadj += 8;
}
if (info->regslist)
{
uint_16 *regs;
int cnt;
int i;
for (regs = info->regslist, cnt = *regs++, i = 0; cnt; cnt--, regs++)
if (GetValueSp(*regs) & OP_XMM)
i++;
else if (GetValueSp(*regs) & OP_YMM)
i += 2;
else if (GetValueSp(*regs) & OP_ZMM)
i += 4;
DebugMsg1(("write_sysv_default_epilogue(%s): %u xmm registers to restore\n", CurrProc->sym.name, i));
if (i)
{
i = (info->localsize - i * 16) & ~(16 - 1);
for (regs = info->regslist, cnt = *regs++; cnt; cnt--, regs++)
{
if (GetValueSp(*regs) & OP_XMM)
{
AddLineQueueX("%s %r, [%r + %u]", MOVE_ALIGNED_INT(), *regs, stackreg[ModuleInfo.Ofssize], NUMQUAL i);
i += 16;
}
if (GetValueSp(*regs) & OP_YMM)
{
AddLineQueueX("%s %r, [%r + %u]", MOVE_UNALIGNED_INT(), *regs, stackreg[ModuleInfo.Ofssize], NUMQUAL i);
i += 32;
}
if (GetValueSp(*regs) & OP_ZMM)
{
AddLineQueueX("%s %r, [%r + %u]", MOVE_UNALIGNED_INT(), *regs, stackreg[ModuleInfo.Ofssize], NUMQUAL i);
i += 64;
}
}
}
}
if (ModuleInfo.redzone == 1 && (info->localsize + resstack < 128) && resstack == 0)
;
else if (info->localsize > 0)
{
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r+%d]", stackreg[ModuleInfo.Ofssize], stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize + stackadj);
}
else
{
AddLineQueueX("add %r, %d", stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize + stackadj);
}
}
else if (stackadj > 0 && !info->isleaf)
{
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r+%d]", stackreg[ModuleInfo.Ofssize], stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize + stackadj);
}
else
{
AddLineQueueX("add %r, %d", stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize + stackadj);
}
}
pop_register(CurrProc->e.procinfo->regslist);
#if STACKBASESUPP
if (!info->fpo && GetRegNo(info->basereg) != 4 && (info->parasize != 0 || info->locallist != NULL))
AddLineQueueX("pop %r", info->basereg);
#else
AddLineQueueX("pop %r", basereg[ModuleInfo.Ofssize]);
#endif
return;
}
static void SetLocalOffsets_RBP_SYSV(struct proc_info *info)
{
struct dsym *curr;
int cntxmm = 0;
int cntstd = 0;
int start = 0;
int rspalign = TRUE;
int align = CurrWordSize;
align = 16;
check_proc_fpo(info);
#if AMD64_SUPPORT || STACKBASESUPP
if (info->fpo || rspalign) {
if (info->regslist) {
int cnt;
uint_16 *regs;
for (regs = info->regslist, cnt = *regs++; cnt; cnt--, regs++)
if (GetValueSp(*regs) & OP_XMM)
cntxmm++;
else if (GetValueSp(*regs) & OP_YMM)
cntxmm += 2;
else if (GetValueSp(*regs) & OP_ZMM)
cntxmm += 4;
else
cntstd++;
}
if ((info->fpo || (info->parasize == 0 && info->locallist == NULL)))
start = 0;
#if AMD64_SUPPORT
if (rspalign)
{
info->localsize = start + (cntstd * CurrWordSize);
if (cntxmm)
{
info->localsize += 16 * cntxmm;
}
}
#endif
DebugMsg1(("SetLocalOffsets_RBP(%s): cntxmm=%u cntstd=%u start=%u align=%u localsize=%u\n", CurrProc->sym.name, cntxmm, cntstd, start, align, info->localsize));
}
#endif
for (curr = info->locallist; curr; curr = curr->nextlocal) {
uint_32 itemsize = (curr->sym.total_size == 0 ? 0 : curr->sym.total_size / curr->sym.total_length);
info->localsize += curr->sym.total_size;
if (itemsize > align) {
if (itemsize == 32)
info->localsize = ROUND_UP(info->localsize, 32);
else if (itemsize == 16)
info->localsize = ROUND_UP(info->localsize, 16);
else
info->localsize = ROUND_UP(info->localsize, align);
}
else if (itemsize)
info->localsize = ROUND_UP(info->localsize, itemsize);
curr->sym.offset = -info->localsize; DebugMsg1(("SetLocalOffsets_RBP(%s): offset of %s (size=%u) set to %d\n", CurrProc->sym.name, curr->sym.name, curr->sym.total_size, curr->sym.offset));
}
info->localsize = ROUND_UP(info->localsize, CurrWordSize);
DebugMsg1(("SetLocalOffsets_RBP(%s): localsize=%u after processing locals\n", CurrProc->sym.name, info->localsize));
#if STACKBASESUPP
if (info->fpo) {
unsigned localadj;
unsigned paramadj;
#if AMD64_SUPPORT
if (rspalign) {
localadj = (info->localsize + 8);
paramadj = (info->localsize + 8) - CurrWordSize - start;
}
else {
#endif
localadj = (info->localsize + 8) + cntstd * CurrWordSize;
paramadj = (info->localsize + 8) + cntstd * CurrWordSize - CurrWordSize;
#if AMD64_SUPPORT
}
#endif
DebugMsg1(("SetLocalOffsets_RBP(%s): FPO, adjusting offsets\n", CurrProc->sym.name));
for (curr = info->locallist; curr; curr = curr->nextlocal) {
DebugMsg1(("SetLocalOffsets_RBP(%s): FPO, offset for %s %4d -> %4d\n", CurrProc->sym.name, curr->sym.name, curr->sym.offset, curr->sym.offset + localadj));
curr->sym.offset += localadj;
}
for (curr = info->paralist; curr; curr = curr->nextparam) {
DebugMsg1(("SetLocalOffsets_RBP(%s): FPO, offset for %s %4d -> %4d\n", CurrProc->sym.name, curr->sym.name, curr->sym.offset, curr->sym.offset + paramadj));
curr->sym.offset += paramadj;
}
}
#endif
#if AMD64_SUPPORT
if (rspalign) {
info->localsize -= cntstd * 8;
info->localsize = ROUND_UP(info->localsize, align);
DebugMsg1(("SetLocalOffsets_RBP(%s): final localsize=%u\n", CurrProc->sym.name, info->localsize));
}
#endif
}
#endif
static ret_code write_generic_prologue(struct proc_info *info)
{
uint_16 *regist;
int cnt;
int resstack = 0;
int stackadj = 0;
regist = info->regslist;
check_proc_fpo(info);
if (info->fpo)
{
if (info->pushed_reg % 2 == 0 && info->localsize % 16 == 0)
stackadj = 8;
else if (info->pushed_reg % 2 == 0 && info->localsize % 16 != 0)
stackadj = 0;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 == 0)
stackadj = 0;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 != 0)
stackadj = 8;
}
else
{
if (info->pushed_reg % 2 == 0 && info->localsize % 16 == 0)
stackadj = 0;
else if (info->pushed_reg % 2 == 0 && info->localsize % 16 != 0)
stackadj = 8;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 == 0)
stackadj = 8;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 != 0)
stackadj = 0;
}
if (info->forceframe == FALSE && info->localsize == 0 &&
info->stackparam == FALSE && info->has_vararg == FALSE &&
resstack == 0 && info->regslist == NULL && !info->fpo)
return(NOT_ERROR);
if (info->fpo && stackadj > 0 && CurrProc->sym.langtype == LANG_FASTCALL && !info->isleaf)
{
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r-%d]", T_RSP, T_RSP, stackadj);
}
else
{
AddLineQueueX("sub %r, %d", T_RSP, stackadj);
}
}
if (ModuleInfo.Ofssize == USE64 && ModuleInfo.fctype == FCT_WIN64 && (ModuleInfo.win64_flags & W64F_SAVEREGPARAMS))
{
if (CurrProc->sym.langtype == LANG_FASTCALL && ModuleInfo.basereg[ModuleInfo.Ofssize] == T_RSP)
win64_SaveRegParams_RSP(info);
else if (CurrProc->sym.langtype == LANG_FASTCALL && ModuleInfo.basereg[ModuleInfo.Ofssize] == T_RBP)
win64_SaveRegParams_RBP(info);
}
if (info->locallist || info->stackparam || info->has_vararg || info->forceframe)
{
if (!info->fpo) {
AddLineQueueX("push %r", info->basereg);
AddLineQueueX("mov %r, %r", info->basereg, stackreg[ModuleInfo.Ofssize]);
}
}
if (resstack)
{
if (regist) {
for (cnt = *regist++; cnt; cnt--, regist++)
AddLineQueueX("push %r", *regist);
regist = NULL;
}
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r-(%d+%s)]", stackreg[ModuleInfo.Ofssize], stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize, sym_ReservedStack->name);
}
else
{
AddLineQueueX("sub %r, %d + %s", stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize, sym_ReservedStack->name);
}
}
else
{
if (info->localsize)
{
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r-%d]", stackreg[ModuleInfo.Ofssize], stackreg[ModuleInfo.Ofssize], info->localsize);
}
else
{
if (Options.masm_compat_gencode || info->localsize <= 128)
AddLineQueueX("add %r, %d", stackreg[ModuleInfo.Ofssize], NUMQUAL - info->localsize);
else
AddLineQueueX("sub %r, %d", stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize);
}
}
}
if (info->loadds) {
AddLineQueueX("push %r", T_DS);
AddLineQueueX("mov %r, %s", T_AX, szDgroup);
AddLineQueueX("mov %r, %r", T_DS, ModuleInfo.Ofssize ? T_EAX : T_AX);
}
if (regist) {
for (cnt = *regist++; cnt; cnt--, regist++) {
AddLineQueueX("push %r", *regist);
}
}
}
static ret_code write_default_prologue(void)
{
struct proc_info *info;
uint_8 oldlinenumbers;
int resstack = 0;
bool OldState = FALSE;
info = CurrProc->e.procinfo;
if (ModuleInfo.Ofssize == USE64 && ModuleInfo.fctype == FCT_WIN64 && (ModuleInfo.win64_flags & W64F_AUTOSTACKSP))
resstack = sym_ReservedStack->value;
if (ModuleInfo.Ofssize == USE64)
{
if (ModuleInfo.basereg[USE64] == T_RSP)
write_win64_default_prologue_RSP(info);
else if ((ModuleInfo.basereg[USE64] == T_RBP) && CurrProc->sym.langtype == LANG_FASTCALL && info->isframe)
write_win64_default_prologue_RBP(info);
else if ((ModuleInfo.basereg[USE64] == T_RBP) && CurrProc->sym.langtype == LANG_FASTCALL)
write_generic_prologue(info);
else if ((ModuleInfo.basereg[USE64] == T_RBP) && CurrProc->sym.langtype == LANG_SYSVCALL)
write_sysv_default_prologue_RBP(info);
goto runqueue;
return(NOT_ERROR);
}
else
{
write_generic_prologue(info);
}
runqueue:
if (ModuleInfo.list && UseSavedState)
if (Parse_Pass == PASS_1)
info->prolog_list_pos = list_pos;
else
list_pos = info->prolog_list_pos;
oldlinenumbers = Options.line_numbers;
Options.line_numbers = FALSE;
OldState = UseSavedState;
UseSavedState = FALSE;
RunLineQueue();
UseSavedState = OldState;
Options.line_numbers = oldlinenumbers;
if (ModuleInfo.list && UseSavedState && (Parse_Pass > PASS_1))
LineStoreCurr->list_pos = list_pos;
return(NOT_ERROR);
}
static void SetLocalOffsets(struct proc_info *info)
{
struct dsym *curr;
int cntxmm = 0;
int cntstd = 0;
int start = 0;
int rspalign = FALSE;
int align = CurrWordSize;
if (info->isframe || (ModuleInfo.fctype == FCT_WIN64 && (ModuleInfo.win64_flags & W64F_AUTOSTACKSP))) {
rspalign = TRUE;
if (ModuleInfo.win64_flags & W64F_STACKALIGN16)
align = 16;
}
if (info->fpo || rspalign) {
if (info->regslist) {
int cnt;
uint_16 *regs;
for (regs = info->regslist, cnt = *regs++; cnt; cnt--, regs++)
if (GetValueSp(*regs) & OP_XMM)
cntxmm++;
else
cntstd++;
}
if ((info->fpo || (info->parasize == 0 && info->locallist == NULL)))
start = CurrWordSize;
if (rspalign) {
info->localsize = start + cntstd * CurrWordSize;
if (cntxmm) {
info->localsize += 16 * cntxmm;
info->localsize = ROUND_UP(info->localsize, 16);
}
}
}
for (curr = info->locallist; curr; curr = curr->nextlocal) {
uint_32 itemsize = (curr->sym.total_size == 0 ? 0 : curr->sym.total_size / curr->sym.total_length);
info->localsize += curr->sym.total_size;
if (itemsize > align)
info->localsize = ROUND_UP(info->localsize, align);
else if (itemsize) {
if ((CurrWordSize == 4) && (itemsize == 3)) itemsize = CurrWordSize;
info->localsize = ROUND_UP(info->localsize, itemsize);
}
curr->sym.offset = -info->localsize;
}
info->localsize = ROUND_UP(info->localsize, CurrWordSize);
if (rspalign) {
info->localsize = ROUND_UP(info->localsize, 16);
}
if (info->fpo) {
unsigned localadj;
unsigned paramadj;
if (rspalign) {
localadj = info->localsize;
paramadj = info->localsize - CurrWordSize - start;
}
else {
localadj = info->localsize + cntstd * CurrWordSize;
paramadj = info->localsize + cntstd * CurrWordSize - CurrWordSize;
}
for (curr = info->locallist; curr; curr = curr->nextlocal) {
curr->sym.offset += localadj;
}
if (info->stored_reg != 1) {
info->stored_reg = 1;
for (curr = info->paralist; curr; curr = curr->nextparam) {
curr->sym.offset += paramadj;
}
}
}
if (rspalign) {
info->localsize -= cntstd * 8 + start;
}
}
void write_prologue(struct asm_tok tokenarray[])
{
struct dsym *curr;
int align = CurrWordSize;
ProcStatus &= ~PRST_PROLOGUE_NOT_DONE;
CurrProc->e.procinfo->prologueDone = FALSE;
if (Parse_Pass == PASS_1)
CurrProc->e.procinfo->fpo = FALSE;
if (ModuleInfo.basereg[USE64] == T_RSP)
CurrProc->e.procinfo->fpo = TRUE;
if (ModuleInfo.fctype == FCT_WIN64 && (ModuleInfo.win64_flags & W64F_AUTOSTACKSP))
{
sym_ReservedStack->value = (Parse_Pass == PASS_1 ? 4 * sizeof(uint_64) : CurrProc->e.procinfo->ReservedStack);
if (Parse_Pass == PASS_1)
{
sym_ReservedStack->value = 0;
}
}
if (ModuleInfo.prologuemode == PEM_NONE && CurrProc->e.procinfo->forceframe == FALSE && (CurrProc->e.procinfo->basereg == T_ESP))
{
CurrProc->e.procinfo->fpo = TRUE;
if (CurrProc->e.procinfo->localsize > 0)
AddLineQueueX("sub esp,%d", CurrProc->e.procinfo->localsize);
RunLineQueue();
}
if (ModuleInfo.Ofssize == USE64)
{
if (ModuleInfo.basereg[USE64] == T_RSP)
{
if (Parse_Pass == PASS_1)
SetLocalOffsets_RSP(CurrProc->e.procinfo);
}
else
{
CurrProc->e.procinfo->localsize = 0;
if ((Options.output_format == OFORMAT_COFF || Options.output_format == OFORMAT_BIN) && CurrProc->e.procinfo->isframe)
SetLocalOffsets_RBP(CurrProc->e.procinfo);
else if ((Options.output_format == OFORMAT_ELF || Options.output_format == OFORMAT_MAC) && Options.sub_format == SFORMAT_64BIT)
SetLocalOffsets_RBP_SYSV(CurrProc->e.procinfo);
else
SetLocalOffsets(CurrProc->e.procinfo);
}
}
else
{
if (Parse_Pass > PASS_1)
CurrProc->e.procinfo->localsize = 0; SetLocalOffsets(CurrProc->e.procinfo);
}
ProcStatus |= PRST_INSIDE_PROLOGUE;
if (ModuleInfo.prologuemode == PEM_DEFAULT)
write_default_prologue();
else if (ModuleInfo.prologuemode == PEM_MACRO)
write_userdef_prologue(tokenarray);
ProcStatus &= ~PRST_INSIDE_PROLOGUE;
CurrProc->e.procinfo->prologueDone = TRUE;
CurrProc->e.procinfo->size_prolog = GetCurrOffset() - CurrProc->sym.offset;
return;
}
static void pop_register(uint_16 *regist)
{
int cnt;
if (regist == NULL)
return;
cnt = *regist;
regist += cnt;
if (ModuleInfo.win64_flags & W64F_SMART)
{
for (cnt = CurrProc->e.procinfo->pushed_reg; cnt; cnt--, regist--) {
if ((GetValueSp(*regist) & OP_XMM) || (GetValueSp(*regist) & OP_YMM) || (GetValueSp(*regist) & OP_ZMM))
{
cnt++;
continue;
}
AddLineQueueX("pop %r", *regist);
}
}
else {
for (; cnt; cnt--, regist--) {
if ((GetValueSp(*regist) & OP_XMM) || (GetValueSp(*regist) & OP_YMM) || (GetValueSp(*regist) & OP_ZMM))
continue;
AddLineQueueX("pop %r", *regist);
}
}
}
static void write_generic_epilogue(struct proc_info *info)
{
int resstack = 0;
int stackadj = 0;
check_proc_fpo(info);
if (ModuleInfo.Ofssize == USE64 && ModuleInfo.fctype == FCT_WIN64 && (ModuleInfo.win64_flags & W64F_AUTOSTACKSP))
{
resstack = sym_ReservedStack->value;
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r+(%d+%s)]", stackreg[ModuleInfo.Ofssize], stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize, sym_ReservedStack->name);
}
else if (resstack)
{
AddLineQueueX("add %r, %d + %s", stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize, sym_ReservedStack->name);
}
}
pop_register(CurrProc->e.procinfo->regslist);
if (info->loadds)
AddLineQueueX("pop %r", T_DS);
if (info->fpo)
{
if (info->pushed_reg % 2 == 0 && info->localsize % 16 == 0)
stackadj = 8;
else if (info->pushed_reg % 2 == 0 && info->localsize % 16 != 0)
stackadj = 0;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 == 0)
stackadj = 0;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 != 0)
stackadj = 8;
}
else
{
if (info->pushed_reg % 2 == 0 && info->localsize % 16 == 0)
stackadj = 0;
else if (info->pushed_reg % 2 == 0 && info->localsize % 16 != 0)
stackadj = 8;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 == 0)
stackadj = 8;
else if (info->pushed_reg % 2 != 0 && info->localsize % 16 != 0)
stackadj = 0;
}
if (ModuleInfo.Ofssize == USE64 && stackadj > 0 && info->fpo && !info->isleaf)
{
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r+%d]", T_RSP, stackadj);
}
else
{
AddLineQueueX("add %r, %d", T_RSP, stackadj);
}
}
if ((info->locallist == NULL) && info->stackparam == FALSE && info->has_vararg == FALSE && resstack == 0 && info->forceframe == FALSE)
return;
if (!(info->locallist || info->stackparam || info->has_vararg || info->forceframe))
;
else
{
if (info->pe_type && !info->fpo)
{
AddLineQueue("leave");
}
else
{
if (info->fpo)
{
if (ModuleInfo.Ofssize == USE64 && ModuleInfo.fctype == FCT_WIN64 && (ModuleInfo.win64_flags & W64F_AUTOSTACKSP))
;
else
{
if (Options.frameflags)
{
AddLineQueueX("lea %r, [%r+%d]", stackreg[ModuleInfo.Ofssize], stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize);
}
else if (info->localsize)
{
AddLineQueueX("add %r, %d", stackreg[ModuleInfo.Ofssize], NUMQUAL info->localsize);
}
}
return;
}
else
{
if (info->localsize != 0)
{
AddLineQueueX("mov %r, %r", stackreg[ModuleInfo.Ofssize], info->basereg);
}
AddLineQueueX("pop %r", info->basereg);
}
}
}
}
static void write_default_epilogue(void)
{
struct proc_info *info;
info = CurrProc->e.procinfo;
if (ModuleInfo.Ofssize == USE64)
{
if (ModuleInfo.basereg[USE64] == T_RSP && (CurrProc->sym.langtype == LANG_FASTCALL || CurrProc->sym.langtype == LANG_VECTORCALL))
write_win64_default_epilogue_RSP(info);
else if (ModuleInfo.basereg[USE64] == T_RBP && CurrProc->sym.langtype == LANG_FASTCALL && info->isframe)
write_win64_default_epilogue_RBP(info);
else if (ModuleInfo.basereg[USE64] == T_RBP && CurrProc->sym.langtype == LANG_FASTCALL)
write_generic_epilogue(info);
else if (ModuleInfo.basereg[USE64] == T_RBP && CurrProc->sym.langtype == LANG_SYSVCALL)
write_sysv_default_epilogue_RBP(info);
}
else
write_generic_epilogue(info);
return;
}
static ret_code write_userdef_epilogue(bool flag_iret, struct asm_tok tokenarray[])
{
uint_16 *regs;
int i;
char *p;
bool is_exitm;
struct proc_info *info;
int flags = CurrProc->sym.langtype;
struct dsym *dir;
char reglst[128];
char buffer[MAX_LINE_LEN];
dir = (struct dsym *)SymSearch(ModuleInfo.proc_epilogue);
if (dir == NULL ||
dir->sym.state != SYM_MACRO ||
dir->sym.isfunc == TRUE) {
return(EmitErr(EPILOGUE_MUST_BE_MACRO_PROC, ModuleInfo.proc_epilogue));
}
info = CurrProc->e.procinfo;
#if AMD64_SUPPORT
if (CurrProc->sym.langtype == LANG_FASTCALL && ModuleInfo.fctype == FCT_WIN64)
flags = 0;
#endif
if (CurrProc->sym.langtype == LANG_C ||
CurrProc->sym.langtype == LANG_SYSCALL ||
CurrProc->sym.langtype == LANG_FASTCALL ||
CurrProc->sym.langtype == LANG_SYSVCALL)
flags |= 0x10;
flags |= (CurrProc->sym.mem_type == MT_FAR ? 0x20 : 0);
flags |= (CurrProc->sym.ispublic ? 0 : 0x40);
flags |= (info->isexport ? 0x80 : 0);
flags |= flag_iret ? 0x100 : 0;
p = reglst;
if (info->regslist) {
int cnt = *info->regslist;
regs = info->regslist + cnt;
for (; cnt; regs--, cnt--) {
GetResWName(*regs, p);
p += strlen(p);
if (cnt != 1)
*p++ = ',';
}
}
*p = NULLC;
sprintf(buffer, "%s, 0%XH, 0%XH, 0%XH, <<%s>>, <%s>",
CurrProc->sym.name, flags, info->parasize, info->localsize,
reglst, info->prologuearg ? info->prologuearg : "");
i = Token_Count + 1;
Tokenize(buffer, i, tokenarray, TOK_RESCAN);
if (Options.preprocessor_stdout)
printf("option epilogue:none\n");
RunMacro(dir, i, tokenarray, NULL, 0, &is_exitm);
Token_Count = i - 1;
return(NOT_ERROR);
}
ret_code RetInstr(int i, struct asm_tok tokenarray[], int count)
{
struct proc_info *info;
bool is_iret = FALSE;
char *p;
#ifdef DEBUG_OUT
ret_code rc;
#endif
char buffer[MAX_LINE_LEN];
#if AMD64_SUPPORT
if (tokenarray[i].tokval == T_IRET || tokenarray[i].tokval == T_IRETD || tokenarray[i].tokval == T_IRETQ)
#else
if (tokenarray[i].tokval == T_IRET || tokenarray[i].tokval == T_IRETD)
#endif
is_iret = TRUE;
if (ModuleInfo.epiloguemode == PEM_MACRO) {
#if FASTPASS
if (UseSavedState) {
if (Parse_Pass > PASS_1) {
DebugMsg(("RetInstr() exit\n"));
return(ParseLine(tokenarray));
}
*(LineStoreCurr->line) = ';';
}
#endif
#ifdef DEBUG_OUT
rc = write_userdef_epilogue(is_iret, tokenarray);
DebugMsg(("RetInstr() exit\n"));
return(rc);
#else
return(write_userdef_epilogue(is_iret, tokenarray));
#endif
}
if (ModuleInfo.list) {
LstWrite(LSTTYPE_DIRECTIVE, GetCurrOffset(), NULL);
}
if (tokenarray[0].tokval == T_BND)
{
strcpy(buffer, "bnd ");
strcpy(buffer + 4, tokenarray[i].string_ptr);
}
else
strcpy(buffer, tokenarray[i].string_ptr);
p = buffer + strlen(buffer);
if (ModuleInfo.epiloguemode == PEM_DEFAULT)
write_default_epilogue();
info = CurrProc->e.procinfo;
if (ModuleInfo.epiloguemode == PEM_NONE && CurrProc->e.procinfo->forceframe == FALSE && (CurrProc->e.procinfo->basereg == T_ESP))
{
if (ModuleInfo.Ofssize == USE64 && CurrProc->e.procinfo->localsize > 0)
AddLineQueueX("add rsp,%d", CurrProc->e.procinfo->localsize);
else if (CurrProc->e.procinfo->localsize > 0)
AddLineQueueX("add esp,%d", CurrProc->e.procinfo->localsize);
RunLineQueue();
}
if (is_iret == FALSE)
{
if (CurrProc->e.procinfo->basereg == T_ESP || CurrProc->e.procinfo->basereg == T_RSP)
{
if (CurrProc->sym.mem_type == MT_FAR)
*p++ = 'f';
else if ((*(p - 1)) != 'n')
*p++ = 'n';
}
else
{
if (CurrProc->sym.mem_type == MT_FAR)
*p++ = 'f';
else
*p++ = 'n';
}
}
i++;
if (info->parasize || (count != i))
*p++ = ' ';
*p = NULLC;
if (is_iret == FALSE && count == i) {
if (ModuleInfo.epiloguemode != PEM_NONE) {
switch (CurrProc->sym.langtype) {
case LANG_BASIC:
case LANG_FORTRAN:
case LANG_PASCAL:
if (info->parasize != 0) {
sprintf(p, "%d%c", info->parasize, ModuleInfo.radix != 10 ? 't' : NULLC);
}
break;
case LANG_FASTCALL:
fastcall_tab[ModuleInfo.fctype].handlereturn(CurrProc, buffer);
break;
case LANG_VECTORCALL:
vectorcall_tab[ModuleInfo.fctype].handlereturn(CurrProc, buffer);
break;
case LANG_SYSVCALL:
sysvcall_tab[ModuleInfo.fctype].handlereturn(CurrProc, buffer);
break;
case LANG_STDCALL:
if (!info->has_vararg && info->parasize != 0) {
sprintf(p, "%d%c", info->parasize, ModuleInfo.radix != 10 ? 't' : NULLC);
}
break;
case LANG_DELPHICALL:
if (info->ReservedStack > 0) {
sprintf(p, "%d%c", info->ReservedStack, ModuleInfo.radix != 10 ? 't' : NULLC);
}
break;
}
}
}
else {
strcpy(p, tokenarray[i].tokpos);
}
AddLineQueue(buffer);
RunLineQueue();
return(NOT_ERROR);
}
void ProcInit(void)
{
ProcStack = NULL;
CurrProc = NULL;
procidx = 1;
ProcStatus = 0;
ModuleInfo.prologuemode = PEM_DEFAULT;
ModuleInfo.epiloguemode = PEM_DEFAULT;
ModuleInfo.invoke_exprparm = (Options.strict_masm_compat ? EXPF_NOUNDEF : 0);
ModuleInfo.basereg[USE16] = T_BP;
ModuleInfo.basereg[USE32] = T_EBP;
ModuleInfo.basereg[USE64] = T_RBP;
unw_segs_defined = 0;
}