add StackFrame class

This commit is contained in:
MITSUNARI Shigeo 2013-04-16 15:57:11 +09:00
parent 497be937d9
commit 31feec56a2
3 changed files with 162 additions and 64 deletions

26
sample/stackframe.cpp Normal file
View file

@ -0,0 +1,26 @@
#define XBYAK_NO_OP_NAMES
#include <xbyak/xbyak_util.h>
#ifdef XBYAK32
#error "this sample is for only 64-bit mode"
#endif
struct Code : public Xbyak::CodeGenerator {
Code()
{
Xbyak::util::StackFrame sf(this, 4);
mov(rax, sf.p(0));
add(rax, sf.p(1));
add(rax, sf.p(2));
add(rax, sf.p(3));
ret();
}
};
int main()
{
Code c;
int (*f)(int, int, int, int) = c.getCode<int(*) (int, int, int, int)>();
printf("%d\n", f(3, 5, 2, 9));
puts("ok");
}

View file

@ -126,8 +126,8 @@ enum Error {
ERR_CANT_ALLOC, ERR_CANT_ALLOC,
ERR_ONLY_T_NEAR_IS_SUPPORTED_IN_AUTO_GROW, ERR_ONLY_T_NEAR_IS_SUPPORTED_IN_AUTO_GROW,
ERR_BAD_PROTECT_MODE, ERR_BAD_PROTECT_MODE,
ERR_BAD_GPNUM, ERR_BAD_PNUM,
ERR_BAD_GTNUM, ERR_BAD_TNUM,
ERR_INTERNAL ERR_INTERNAL
}; };
@ -159,8 +159,8 @@ inline const char *ConvertErrorToString(Error err)
"can't alloc", "can't alloc",
"T_SHORT is not supported in AutoGrow", "T_SHORT is not supported in AutoGrow",
"bad protect mode", "bad protect mode",
"bad gpNum", "bad pNum",
"bad gtNum", "bad tNum",
"internal error", "internal error",
}; };
if (err < 0 || err > ERR_INTERNAL) return 0; if (err < 0 || err > ERR_INTERNAL) return 0;

View file

@ -233,70 +233,142 @@ private:
int count_; int count_;
}; };
#ifdef XBYAK32 #ifdef XBYAK64
struct StackFrame {
namespace local { enum { UseRCX = 1, UseRDX = 2 };
#ifdef _WIN32 #ifdef XBYAK64_WIN
#define XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(x) static inline __declspec(naked) void set_eip_to_ ## x() { \ static const int noSaveNum = 6;
__asm { mov x, dword ptr [esp] } __asm { ret } \ #else
static const int noSaveNum = 8;
#endif
Xbyak::CodeGenerator *code_;
int pNum_;
int tNum_;
int useReg_;
int saveNum_;
int P_;
bool makeEpilog_;
Xbyak::Reg64 pTbl_[4];
Xbyak::Reg64 tTbl_[10];
const Xbyak::Reg64& p(int pos) const
{
if (pos < 0 || pos >= pNum_) throw ERR_BAD_PARAMETER;
return pTbl_[pos];
}
const Xbyak::Reg64& t(int pos) const
{
if (pos < 0 || pos >= tNum_) throw ERR_BAD_PARAMETER;
return tTbl_[pos];
}
/*
make stack frame
@param sf [in] this
@param pNum [in] num of global parameter
@param tNum [in] num of temporary register
@param numQword [in] local stack size
@param useReg [in] reserve rcx, rdx if necessary
you can use
rax
gp0, ..., gp(pNum - 1)
gt0, ..., gt(tNum-1)
rsp[0..8 * numQrod - 1]
*/
StackFrame(Xbyak::CodeGenerator *code, int pNum, int tNum = 0, int numQword = 0, int useReg = 0)
: code_(code)
, pNum_(pNum)
, tNum_(tNum)
, useReg_(useReg)
, saveNum_(0)
, P_(0)
, makeEpilog_(true)
{
using namespace Xbyak;
if (pNum > 4) throw ERR_BAD_PNUM;
const int allRegNum = pNum + tNum + (useReg & UseRCX) + (useReg & UseRDX);
if (allRegNum > 14) throw ERR_BAD_TNUM;
const Reg64& rsp = code->rsp;
const AddressFrame& ptr = code->ptr;
saveNum_ = std::max(0, allRegNum - noSaveNum);
const int *tbl = getOrderTbl() + noSaveNum;
P_ = 8 * (saveNum_ + numQword);
if (P_ > 0) code->sub(rsp, P_);
#ifdef XBYAK64
for (int i = 0; i < std::min(saveNum_, 4); i++) {
code->mov(ptr [rsp + P_ + (i + 1) * 8], Reg64(tbl[i]));
}
for (int i = 4; i < saveNum_; i++) {
code->mov(ptr [rsp + P_ - 8 * (saveNum_ - i)], Reg64(tbl[i]));
} }
#else #else
#define XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(x) static inline void set_eip_to_ ## x() { \ for (int i = 0; i < saveNum_; i++) {
__asm__ volatile("movl (%esp), %" #x); \ code->mov(ptr [rsp + P_ - 8 * (saveNum_ - i)], Reg64(tbl[i]));
} }
#endif #endif
int pos = 0;
XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(eax) for (int i = 0; i < pNum; i++) {
XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(ecx) pTbl_[i] = Xbyak::Reg64(getRegIdx(pos));
XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(edx) }
XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(ebx) for (int i = 0; i < tNum; i++) {
XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(esi) tTbl_[i] = Xbyak::Reg64(getRegIdx(pos));
XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(edi) }
XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG(ebp) }
void disableEpilog() { makeEpilog_ = false; }
#undef XBYAK_LOCAL_DEFINE_SET_EIP_TO_REG void close(bool callRet = true)
} // end of local {
using namespace Xbyak;
/** const Reg64& rsp = code_->rsp;
get eip to out register const AddressFrame& ptr = code_->ptr;
@note out is not esp const int *tbl = getOrderTbl() + noSaveNum;
*/ #ifdef XBYAK64_WIN
template<class T> for (int i = 0; i < std::min(saveNum_, 4); i++) {
void setEipTo(T *self, const Xbyak::Reg32& out) code_->mov(Reg64(tbl[i]), ptr [rsp + P_ + (i + 1) * 8]);
{ }
#if 0 for (int i = 4; i < saveNum_; i++) {
self->call("@f"); code_->mov(Reg64(tbl[i]), ptr [rsp + P_ - 8 * (saveNum_ - i)]);
self->L("@@"); }
self->pop(out);
#else #else
int idx = out.getIdx(); for (int i = 0; i <=saveNum_; i++) {
switch (idx) { code_->mov(Reg64(tbl[i]), ptr [rsp + P_ - 8 * (saveNum_ - i)]);
case Xbyak::Operand::EAX:
self->call(CastTo<void*>(local::set_eip_to_eax));
break;
case Xbyak::Operand::ECX:
self->call(CastTo<void*>(local::set_eip_to_ecx));
break;
case Xbyak::Operand::EDX:
self->call(CastTo<void*>(local::set_eip_to_edx));
break;
case Xbyak::Operand::EBX:
self->call(CastTo<void*>(local::set_eip_to_ebx));
break;
case Xbyak::Operand::ESI:
self->call(CastTo<void*>(local::set_eip_to_esi));
break;
case Xbyak::Operand::EDI:
self->call(CastTo<void*>(local::set_eip_to_edi));
break;
case Xbyak::Operand::EBP:
self->call(CastTo<void*>(local::set_eip_to_ebp));
break;
default:
assert(0);
} }
#endif #endif
} if (P_ > 0) code_->add(rsp, P_);
if (callRet) code_->ret();
}
const int *getOrderTbl() const
{
using namespace Xbyak;
static const int tbl[] = {
#ifdef XBYAK64_WIN
Operand::RCX, Operand::RDX, Operand::R8, Operand::R9, Operand::R10, Operand::R11, Operand::RDI, Operand::RSI,
#else
Operand::RDI, Operand::RSI, Operand::RDX, Operand::RCX, Operand::R8, Operand::R9, Operand::R10, Operand::R11,
#endif
Operand::RBX, Operand::RBP, Operand::R12, Operand::R13, Operand::R14, Operand::R15
};
return &tbl[0];
}
int getRegIdx(int& pos) const
{
assert(pos < 14);
using namespace Xbyak;
const int *tbl = getOrderTbl();
int r = tbl[pos++];
if (useReg_ & UseRCX) {
if (r == Operand::RCX) { return Operand::R10; }
if (r == Operand::R10) { return tbl[pos++]; }
}
if (useReg_ & UseRDX) {
if (r == Operand::RDX) { return Operand::R11; }
if (r == Operand::R11) { return tbl[pos++]; }
}
return r;
}
~StackFrame()
{
if (makeEpilog_) close();
}
};
#endif #endif
} } // end of util } } // end of util