Skip to content

Commit

Permalink
st0 impl?
Browse files Browse the repository at this point in the history
  • Loading branch information
altalk23 committed Feb 25, 2024
1 parent 9dc223d commit 047031e
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 2 deletions.
21 changes: 21 additions & 0 deletions src/assembler/X86Assembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,24 @@ void X86Assembler::mov(X86Register reg, std::string const& label) {
this->write8(0x05 | regIdx(reg) << 3);
this->label32(label);
}

void X86Assembler::fstps(X86Pointer ptr) {
// 32 bit fstp
this->write8(0xD9);
this->encodeModRM(ptr, 3);
}
void X86Assembler::flds(X86Pointer ptr) {
// 32 bit fld
this->write8(0xD9);
this->encodeModRM(ptr, 0);
}
void X86Assembler::fstpd(X86Pointer ptr) {
// 64 bit fstp
this->write8(0xDD);
this->encodeModRM(ptr, 3);
}
void X86Assembler::fldd(X86Pointer ptr) {
// 64 bit fld
this->write8(0xDD);
this->encodeModRM(ptr, 0);
}
5 changes: 5 additions & 0 deletions src/assembler/X86Assembler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,10 @@ namespace tulip::hook {
void mov(X86Pointer ptr, X86Register reg);
void mov(X86Register reg, X86Register reg2);
void mov(X86Register reg, std::string const& label);

void fstps(X86Pointer ptr);
void flds(X86Pointer ptr);
void fstpd(X86Pointer ptr);
void fldd(X86Pointer ptr);
};
}
54 changes: 52 additions & 2 deletions src/convention/WindowsConvention.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ enum class Register {
XMM1,
XMM2,
XMM3,
ST0,
};
using Stack = size_t;
using Location = std::variant<Stack, Register>;
Expand All @@ -37,6 +38,16 @@ class PushParameter final {
};

static Location returnLocation(AbstractFunction const& function) {
// other
switch (function.m_return.m_kind) {
default:
case AbstractTypeKind::Primitive: return Register::EAX;
case AbstractTypeKind::FloatingPoint: return Register::ST0;
case AbstractTypeKind::Other: return Stack(0x4);
}
}

static Location optimizedReturnLocation(AbstractFunction const& function) {
// other
switch (function.m_return.m_kind) {
default:
Expand All @@ -50,6 +61,8 @@ class PushParameters final {
private:
std::vector<PushParameter> m_params;
Location m_returnValueLocation;
AbstractType m_returnType;

// size of the original function's stack
size_t m_originalStackSize = 0x0;
// size of our converted function's stack
Expand Down Expand Up @@ -93,6 +106,7 @@ class PushParameters final {
public:
static PushParameters fromCdecl(X86Assembler& a, AbstractFunction const& function) {
auto res = PushParameters(a);
res.m_returnType = function.m_return;

// structs are returned as pointer through first parameter
res.m_returnValueLocation = returnLocation(function);
Expand Down Expand Up @@ -120,6 +134,7 @@ class PushParameters final {

static PushParameters fromThiscall(X86Assembler& a, AbstractFunction const& function) {
auto res = PushParameters(a);
res.m_returnType = function.m_return;

// structs are returned as pointer through first parameter
res.m_returnValueLocation = returnLocation(function);
Expand Down Expand Up @@ -150,6 +165,7 @@ class PushParameters final {

static PushParameters fromFastcall(X86Assembler& a, AbstractFunction const& function) {
auto res = PushParameters(a);
res.m_returnType = function.m_return;
size_t registersUsed = 0;

// structs are returned as pointer through first parameter
Expand Down Expand Up @@ -184,7 +200,8 @@ class PushParameters final {
size_t registersUsed = 0;

// structs are returned as pointer through first parameter
res.m_returnValueLocation = returnLocation(function);
res.m_returnType = function.m_return;
res.m_returnValueLocation = optimizedReturnLocation(function);
if (std::holds_alternative<Stack>(res.m_returnValueLocation)) {
res.push(AbstractType::from<void*>(), Register::ECX);
registersUsed = 1;
Expand Down Expand Up @@ -242,7 +259,8 @@ class PushParameters final {
size_t registersUsed = 0;

// structs are returned as pointer through first parameter
res.m_returnValueLocation = returnLocation(function);
res.m_returnType = function.m_return;
res.m_returnValueLocation = optimizedReturnLocation(function);
if (std::holds_alternative<Stack>(res.m_returnValueLocation)) {
res.push(AbstractType::from<void*>());
}
Expand Down Expand Up @@ -386,6 +404,22 @@ class PushParameters final {
// clean up stack from the ones we added
a.add(ESP, m_resultStackSize);

// in the original(gd) function, the return for floats is in xmm0
if (std::holds_alternative<Register>(m_returnValueLocation) && std::get<Register>(m_returnValueLocation) == Register::XMM0) {
// move the st0 into xmm0
auto size = m_returnType.m_size;
a.sub(ESP, size);
if (size == 4) {
a.fstps(m[ESP]);
a.movss(XMM0, m[ESP]);
}
else {
a.fstpd(m[ESP]);
a.movsd(XMM0, m[ESP]);
}
a.add(ESP, size);
}

// if the function is caller cleaned, then generateOriginalCleanup
// or the original GD function cleans it up
if (m_isCallerCleanup) {
Expand Down Expand Up @@ -435,6 +469,22 @@ class PushParameters final {
}

void generateOriginalCleanup() {
// in the default(geode) function, the return for floats is in st0
if (std::holds_alternative<Register>(m_returnValueLocation) && std::get<Register>(m_returnValueLocation) == Register::XMM0) {
// move the xmm into st0
auto size = m_returnType.m_size;
a.sub(ESP, size);
if (size == 4) {
a.movss(m[ESP], XMM0);
a.flds(m[ESP]);
}
else {
a.movsd(m[ESP], XMM0);
a.fldd(m[ESP]);
}
a.add(ESP, size);
}

if (m_isCallerCleanup) {
// for mat: comment this to make your tests work
a.add(ESP, m_originalStackSize);
Expand Down

0 comments on commit 047031e

Please sign in to comment.