add StackFrame class
This commit is contained in:
parent
497be937d9
commit
31feec56a2
3 changed files with 162 additions and 64 deletions
26
sample/stackframe.cpp
Normal file
26
sample/stackframe.cpp
Normal 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");
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue