Skip to content

Commit 17b5fb7

Browse files
committed
Initial support for Go and Pascal calling conventions
1 parent b620423 commit 17b5fb7

7 files changed

Lines changed: 507 additions & 4 deletions

File tree

arch/x86/arch_x86.cpp

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3971,6 +3971,159 @@ class X86LinuxSystemCallConvention: public CallingConvention
39713971
};
39723972

39733973

3974+
class X86PascalCallingConvention : public X86BaseCallingConvention
3975+
{
3976+
public:
3977+
X86PascalCallingConvention(Architecture* arch) : X86BaseCallingConvention(arch, "pascal") {}
3978+
3979+
bool IsNonRegisterArgumentIndirect(BinaryView*, Type* type) override
3980+
{
3981+
return type && !type->IsFloat() && type->GetWidth() > 4;
3982+
}
3983+
3984+
bool IsStackAdjustedOnReturn() override
3985+
{
3986+
return true;
3987+
}
3988+
3989+
bool AreStackArgumentsPushedLeftToRight() override
3990+
{
3991+
return true;
3992+
}
3993+
3994+
Variable GetIndirectReturnValueLocation() override
3995+
{
3996+
// Return value pointer is always at the top of the stack (effectively the last parameter
3997+
// in a left-to-right convention)
3998+
return Variable::StackOffset(4);
3999+
}
4000+
4001+
std::optional<Variable> GetReturnedIndirectReturnValuePointer() override
4002+
{
4003+
return std::nullopt;
4004+
}
4005+
};
4006+
4007+
4008+
class X86PascalRegisterCallingConvention : public X86BaseCallingConvention
4009+
{
4010+
public:
4011+
X86PascalRegisterCallingConvention(Architecture* arch) : X86BaseCallingConvention(arch, "register") {}
4012+
4013+
vector<uint32_t> GetIntegerArgumentRegisters() override
4014+
{
4015+
return { XED_REG_EAX, XED_REG_EDX, XED_REG_ECX };
4016+
}
4017+
4018+
bool IsNonRegisterArgumentIndirect(BinaryView*, Type* type) override
4019+
{
4020+
return type && !type->IsFloat() && type->GetWidth() > 4;
4021+
}
4022+
4023+
bool AreStackArgumentsPushedLeftToRight() override
4024+
{
4025+
return true;
4026+
}
4027+
4028+
std::optional<Variable> GetReturnedIndirectReturnValuePointer() override
4029+
{
4030+
return std::nullopt;
4031+
}
4032+
};
4033+
4034+
4035+
class X86GoStackCallingConvention: public CallingConvention
4036+
{
4037+
public:
4038+
X86GoStackCallingConvention(Architecture* arch): CallingConvention(arch, "go-stack")
4039+
{
4040+
}
4041+
4042+
bool IsEligibleForHeuristics() override
4043+
{
4044+
// This convention cannot be detected by heuristics at this time and will cause issues
4045+
// with non-Go code.
4046+
return false;
4047+
}
4048+
4049+
uint32_t GetIntegerReturnValueRegister() override
4050+
{
4051+
return BN_INVALID_REGISTER;
4052+
}
4053+
4054+
vector<uint32_t> GetCallerSavedRegisters() override
4055+
{
4056+
return vector<uint32_t> { XED_REG_EAX, XED_REG_ECX, XED_REG_EDX, XED_REG_EBX, XED_REG_EBP };
4057+
}
4058+
4059+
RegisterValue GetIncomingFlagValue(uint32_t flag, Function*) override
4060+
{
4061+
RegisterValue result;
4062+
if (flag == IL_FLAG_D)
4063+
{
4064+
result.state = ConstantValue;
4065+
result.value = 0;
4066+
}
4067+
return result;
4068+
}
4069+
4070+
ValueLocation GetReturnValueLocation(BinaryView*, const ReturnValue&) override
4071+
{
4072+
// It is not possible for this API to determine the return value location on the stack at
4073+
// this point, return an invalid location and fall back to GetCallLayout.
4074+
return ValueLocation();
4075+
}
4076+
4077+
CallLayout GetCallLayout(BinaryView* view, const ReturnValue& returnValue, const vector<FunctionParameter>& params,
4078+
const std::optional<set<uint32_t>>& permittedRegs) override
4079+
{
4080+
CallLayout result;
4081+
result.parameters = GetParameterLocations(view, result.returnValue, params, permittedRegs);
4082+
4083+
if (returnValue.type.GetValue() && returnValue.type->GetClass() != VoidTypeClass)
4084+
{
4085+
if (returnValue.defaultLocation)
4086+
{
4087+
int64_t stackOffset = 4;
4088+
size_t i = 0;
4089+
for (auto it = result.parameters.begin(); it != result.parameters.end(); ++i, ++it)
4090+
{
4091+
if (i >= params.size())
4092+
continue;
4093+
if (!params[i].type.GetValue())
4094+
continue;
4095+
4096+
auto var = it->GetVariableForParameter(i);
4097+
if (!var.has_value())
4098+
continue;
4099+
if (var->type != StackVariableSourceType)
4100+
continue;
4101+
if (var->storage < stackOffset)
4102+
continue;
4103+
4104+
uint64_t width = params[i].type->GetWidth();
4105+
if (width < 4)
4106+
width = 4;
4107+
else if ((width % 4) != 0)
4108+
width += 4 - (width % 4);
4109+
4110+
stackOffset = var->storage + width;
4111+
}
4112+
4113+
result.returnValue = Variable::StackOffset(stackOffset);
4114+
}
4115+
else
4116+
{
4117+
result.returnValue = returnValue.location.GetValue();
4118+
}
4119+
}
4120+
4121+
result.registerStackAdjustments = GetRegisterStackAdjustments(view, result.returnValue, result.parameters);
4122+
return result;
4123+
}
4124+
};
4125+
4126+
39744127
class X64BaseCallingConvention: public CallingConvention
39754128
{
39764129
public:
@@ -4145,6 +4298,100 @@ class X64LinuxSystemCallConvention: public CallingConvention
41454298
};
41464299

41474300

4301+
class X64GoStackCallingConvention: public CallingConvention
4302+
{
4303+
public:
4304+
X64GoStackCallingConvention(Architecture* arch): CallingConvention(arch, "go-stack")
4305+
{
4306+
}
4307+
4308+
bool IsEligibleForHeuristics() override
4309+
{
4310+
// This convention cannot be detected by heuristics at this time and will cause issues
4311+
// with non-Go code.
4312+
return false;
4313+
}
4314+
4315+
uint32_t GetIntegerReturnValueRegister() override
4316+
{
4317+
return BN_INVALID_REGISTER;
4318+
}
4319+
4320+
vector<uint32_t> GetCallerSavedRegisters() override
4321+
{
4322+
return vector<uint32_t> { XED_REG_RAX, XED_REG_RCX, XED_REG_RDX, XED_REG_RBX, XED_REG_RBP,
4323+
XED_REG_R8, XED_REG_R9, XED_REG_R10, XED_REG_R11, XED_REG_R12, XED_REG_R13, XED_REG_R14,
4324+
XED_REG_R15 };
4325+
}
4326+
4327+
RegisterValue GetIncomingFlagValue(uint32_t flag, Function*) override
4328+
{
4329+
RegisterValue result;
4330+
if (flag == IL_FLAG_D)
4331+
{
4332+
result.state = ConstantValue;
4333+
result.value = 0;
4334+
}
4335+
return result;
4336+
}
4337+
4338+
ValueLocation GetReturnValueLocation(BinaryView*, const ReturnValue&) override
4339+
{
4340+
// It is not possible for this API to determine the return value location on the stack at
4341+
// this point, return an invalid location and fall back to GetCallLayout.
4342+
return ValueLocation();
4343+
}
4344+
4345+
CallLayout GetCallLayout(BinaryView* view, const ReturnValue& returnValue, const vector<FunctionParameter>& params,
4346+
const std::optional<set<uint32_t>>& permittedRegs) override
4347+
{
4348+
CallLayout result;
4349+
result.parameters = GetParameterLocations(view, result.returnValue, params, permittedRegs);
4350+
4351+
if (returnValue.type.GetValue() && returnValue.type->GetClass() != VoidTypeClass)
4352+
{
4353+
if (returnValue.defaultLocation)
4354+
{
4355+
int64_t stackOffset = 8;
4356+
size_t i = 0;
4357+
for (auto it = result.parameters.begin(); it != result.parameters.end(); ++i, ++it)
4358+
{
4359+
if (i >= params.size())
4360+
continue;
4361+
if (!params[i].type.GetValue())
4362+
continue;
4363+
4364+
auto var = it->GetVariableForParameter(i);
4365+
if (!var.has_value())
4366+
continue;
4367+
if (var->type != StackVariableSourceType)
4368+
continue;
4369+
if (var->storage < stackOffset)
4370+
continue;
4371+
4372+
uint64_t width = params[i].type->GetWidth();
4373+
if (width < 8)
4374+
width = 8;
4375+
else if ((width % 8) != 0)
4376+
width += 8 - (width % 8);
4377+
4378+
stackOffset = var->storage + width;
4379+
}
4380+
4381+
result.returnValue = Variable::StackOffset(stackOffset);
4382+
}
4383+
else
4384+
{
4385+
result.returnValue = returnValue.location.GetValue();
4386+
}
4387+
}
4388+
4389+
result.registerStackAdjustments = GetRegisterStackAdjustments(view, result.returnValue, result.parameters);
4390+
return result;
4391+
}
4392+
};
4393+
4394+
41484395
class x86MachoRelocationHandler: public RelocationHandler
41494396
{
41504397
public:
@@ -5052,6 +5299,12 @@ extern "C"
50525299
x86->RegisterCallingConvention(conv);
50535300
conv = new X86LinuxSystemCallConvention(x86);
50545301
x86->RegisterCallingConvention(conv);
5302+
conv = new X86PascalCallingConvention(x86);
5303+
x86->RegisterCallingConvention(conv);
5304+
conv = new X86PascalRegisterCallingConvention(x86);
5305+
x86->RegisterCallingConvention(conv);
5306+
conv = new X86GoStackCallingConvention(x86);
5307+
x86->RegisterCallingConvention(conv);
50555308

50565309
x86->RegisterRelocationHandler("Mach-O", new x86MachoRelocationHandler());
50575310
x86->RegisterRelocationHandler("KCView", new x86MachoRelocationHandler());
@@ -5069,6 +5322,8 @@ extern "C"
50695322
x64->RegisterCallingConvention(conv);
50705323
conv = new X64LinuxSystemCallConvention(x64);
50715324
x64->RegisterCallingConvention(conv);
5325+
conv = new X64GoStackCallingConvention(x64);
5326+
x64->RegisterCallingConvention(conv);
50725327

50735328
x64->RegisterRelocationHandler("Mach-O", new x64MachoRelocationHandler());
50745329
x64->RegisterRelocationHandler("KCView", new x64MachoRelocationHandler());

binaryninjaapi.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17935,6 +17935,7 @@ namespace BinaryNinja {
1793517935
static bool IsArgumentTypeRegisterCompatibleCallback(void* ctxt, BNBinaryView* view, BNType* type);
1793617936
static bool IsNonRegisterArgumentIndirectCallback(void* ctxt, BNBinaryView* view, BNType* type);
1793717937
static bool AreStackArgumentsNaturallyAlignedCallback(void* ctxt);
17938+
static bool AreStackArgumentsPushedLeftToRightCallback(void* ctxt);
1793817939

1793917940
static void GetCallLayoutCallback(void* ctxt, BNBinaryView* view, BNReturnValue* returnValue,
1794017941
BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs,
@@ -17947,6 +17948,9 @@ namespace BinaryNinja {
1794717948
BNValueLocation* returnValue, BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs,
1794817949
uint32_t* permittedRegs, size_t permittedRegCount, size_t* outLocationCount);
1794917950
static void FreeParameterLocationsCallback(void* ctxt, BNValueLocation* locations, size_t count);
17951+
static BNVariable* GetParameterOrderingForVariablesCallback(
17952+
void* ctxt, BNBinaryView* view, BNVariable* vars, BNType** types, size_t paramCount, size_t* outCount);
17953+
static void FreeVariableListCallback(void* ctxt, BNVariable* vars, size_t count);
1795017954
static int64_t GetStackAdjustmentForLocationsCallback(void* ctxt, BNBinaryView* view,
1795117955
BNValueLocation* returnValue, BNValueLocation* locations, BNType** types, size_t paramCount);
1795217956
static size_t GetRegisterStackAdjustmentsCallback(void* ctxt, BNBinaryView* view, BNValueLocation* returnValue,
@@ -18005,6 +18009,7 @@ namespace BinaryNinja {
1800518009
bool DefaultIsArgumentTypeRegisterCompatible(Type* type);
1800618010
virtual bool IsNonRegisterArgumentIndirect(BinaryView* view, Type* type);
1800718011
virtual bool AreStackArgumentsNaturallyAligned();
18012+
virtual bool AreStackArgumentsPushedLeftToRight();
1800818013

1800918014
virtual CallLayout GetCallLayout(BinaryView* view, const ReturnValue& returnValue,
1801018015
const std::vector<FunctionParameter>& params,
@@ -18013,6 +18018,8 @@ namespace BinaryNinja {
1801318018
virtual std::vector<ValueLocation> GetParameterLocations(BinaryView* view,
1801418019
const std::optional<ValueLocation>& returnValue, const std::vector<FunctionParameter>& params,
1801518020
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
18021+
virtual std::vector<Variable> GetParameterOrderingForVariables(
18022+
BinaryView* view, const std::map<Variable, Ref<Type>>& params);
1801618023
virtual int64_t GetStackAdjustmentForLocations(BinaryView* view,
1801718024
const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& locations,
1801818025
const std::vector<Ref<Type>>& types);
@@ -18026,6 +18033,7 @@ namespace BinaryNinja {
1802618033
std::vector<ValueLocation> GetDefaultParameterLocations(BinaryView* view,
1802718034
const std::optional<ValueLocation>& returnValue, const std::vector<FunctionParameter>& params,
1802818035
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
18036+
std::vector<Variable> GetDefaultParameterOrderingForVariables(const std::map<Variable, Ref<Type>>& params);
1802918037
int64_t GetDefaultStackAdjustmentForLocations(const std::optional<ValueLocation>& returnValue,
1803018038
const std::vector<ValueLocation>& locations, const std::vector<Ref<Type>>& types);
1803118039
std::map<uint32_t, int32_t> GetDefaultRegisterStackAdjustments(
@@ -18072,6 +18080,7 @@ namespace BinaryNinja {
1807218080
virtual bool IsArgumentTypeRegisterCompatible(BinaryView* view, Type* type) override;
1807318081
virtual bool IsNonRegisterArgumentIndirect(BinaryView* view, Type* type) override;
1807418082
virtual bool AreStackArgumentsNaturallyAligned() override;
18083+
virtual bool AreStackArgumentsPushedLeftToRight() override;
1807518084

1807618085
virtual CallLayout GetCallLayout(BinaryView* view, const ReturnValue& returnValue,
1807718086
const std::vector<FunctionParameter>& params,
@@ -18080,6 +18089,8 @@ namespace BinaryNinja {
1808018089
virtual std::vector<ValueLocation> GetParameterLocations(BinaryView* view,
1808118090
const std::optional<ValueLocation>& returnValue, const std::vector<FunctionParameter>& params,
1808218091
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt) override;
18092+
virtual std::vector<Variable> GetParameterOrderingForVariables(
18093+
BinaryView* view, const std::map<Variable, Ref<Type>>& params) override;
1808318094
virtual int64_t GetStackAdjustmentForLocations(BinaryView* view,
1808418095
const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& locations,
1808518096
const std::vector<Ref<Type>>& types) override;

binaryninjacore.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,7 +1155,10 @@ extern "C"
11551155
ILTransparentCopy = 0x1000,
11561156

11571157
// Instruction is defining an implicit trait of the calling convention
1158-
MLILCallingConventionImplicit = 0x2000
1158+
MLILCallingConventionImplicit = 0x2000,
1159+
1160+
// Function call returns its result onto the caller's stack
1161+
ILStackReturn = 0x4000,
11591162
};
11601163

11611164
BN_ENUM(uint8_t, BNIntrinsicClass)
@@ -2957,6 +2960,7 @@ extern "C"
29572960
bool (*isArgumentTypeRegisterCompatible)(void* ctxt, BNBinaryView* view, BNType* type);
29582961
bool (*isNonRegisterArgumentIndirect)(void* ctxt, BNBinaryView* view, BNType* type);
29592962
bool (*areStackArgumentsNaturallyAligned)(void* ctxt);
2963+
bool (*areStackArgumentsPushedLeftToRight)(void* ctxt);
29602964

29612965
void (*getIncomingVariableForParameterVariable)(
29622966
void* ctxt, const BNVariable* var, BNFunction* func, BNVariable* result);
@@ -2976,6 +2980,9 @@ extern "C"
29762980
BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs,
29772981
size_t permittedRegCount, size_t* outLocationCount);
29782982
void (*freeParameterLocations)(void* ctxt, BNValueLocation* locations, size_t count);
2983+
BNVariable* (*getParameterOrderingForVariables)(
2984+
void* ctxt, BNBinaryView* view, BNVariable* vars, BNType** types, size_t paramCount, size_t* outCount);
2985+
void (*freeVariableList)(void* ctxt, BNVariable* vars, size_t count);
29792986
int64_t (*getStackAdjustmentForLocations)(void* ctxt, BNBinaryView* view, BNValueLocation* returnValue,
29802987
BNValueLocation* locations, BNType** types, size_t paramCount);
29812988
size_t (*getRegisterStackAdjustments)(void* ctxt, BNBinaryView* view, BNValueLocation* returnValue,
@@ -7779,9 +7786,10 @@ extern "C"
77797786
size_t* outCount);
77807787
BINARYNINJACOREAPI void BNFreeValueLocationList(BNValueLocation* locations, size_t count);
77817788

7782-
BINARYNINJACOREAPI BNVariable* BNGetParameterOrderingForVariables(
7783-
BNCallingConvention* cc, const BNVariable* paramVars, const BNType** paramTypes,
7784-
size_t paramCount, size_t* count);
7789+
BINARYNINJACOREAPI BNVariable* BNGetParameterOrderingForVariables(BNCallingConvention* cc, BNBinaryView* view,
7790+
const BNVariable* paramVars, const BNType** paramTypes, size_t paramCount, size_t* count);
7791+
BINARYNINJACOREAPI BNVariable* BNGetDefaultParameterOrderingForVariables(BNCallingConvention* cc,
7792+
const BNVariable* paramVars, const BNType** paramTypes, size_t paramCount, size_t* count);
77857793
BINARYNINJACOREAPI int64_t BNGetStackAdjustmentForLocations(BNCallingConvention* cc, BNBinaryView* view,
77867794
BNValueLocation* returnValue, const BNValueLocation* paramLocations, const BNType** paramTypes,
77877795
size_t paramCount);
@@ -7815,6 +7823,7 @@ extern "C"
78157823
BINARYNINJACOREAPI bool BNDefaultIsArgumentTypeRegisterCompatible(BNCallingConvention* cc, BNType* type);
78167824
BINARYNINJACOREAPI bool BNIsNonRegisterArgumentIndirect(BNCallingConvention* cc, BNBinaryView* view, BNType* type);
78177825
BINARYNINJACOREAPI bool BNAreStackArgumentsNaturallyAligned(BNCallingConvention* cc);
7826+
BINARYNINJACOREAPI bool BNAreStackArgumentsPushedLeftToRight(BNCallingConvention* cc);
78187827

78197828
BINARYNINJACOREAPI BNCallingConvention* BNGetArchitectureDefaultCallingConvention(BNArchitecture* arch);
78207829
BINARYNINJACOREAPI BNCallingConvention* BNGetArchitectureCdeclCallingConvention(BNArchitecture* arch);

0 commit comments

Comments
 (0)