Skip to content

Commit 75c242c

Browse files
committed
Initial support for Go and Pascal calling conventions
1 parent eddefff commit 75c242c

8 files changed

Lines changed: 522 additions & 21 deletions

File tree

arch/arm64/arch_arm64.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2678,7 +2678,7 @@ class Arm64CallingConvention : public CallingConvention
26782678
}
26792679

26802680

2681-
bool AreNonRegisterArgumentsIndirect() override
2681+
bool IsNonRegisterArgumentIndirect(Type*) override
26822682
{
26832683
return true;
26842684
}

arch/x86/arch_x86.cpp

Lines changed: 256 additions & 1 deletion
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(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(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(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(const ReturnValue& returnValue, const vector<FunctionParameter>& params,
4078+
const std::optional<set<uint32_t>>& permittedRegs) override
4079+
{
4080+
CallLayout result;
4081+
result.parameters = GetParameterLocations(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(result.returnValue, result.parameters);
4122+
return result;
4123+
}
4124+
};
4125+
4126+
39744127
class X64BaseCallingConvention: public CallingConvention
39754128
{
39764129
public:
@@ -4103,7 +4256,7 @@ class X64WindowsCallingConvention: public X64BaseCallingConvention
41034256
|| type->GetWidth() == 8;
41044257
}
41054258

4106-
bool AreNonRegisterArgumentsIndirect() override
4259+
bool IsNonRegisterArgumentIndirect(Type*) override
41074260
{
41084261
return true;
41094262
}
@@ -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(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(const ReturnValue& returnValue, const vector<FunctionParameter>& params,
4346+
const std::optional<set<uint32_t>>& permittedRegs) override
4347+
{
4348+
CallLayout result;
4349+
result.parameters = GetParameterLocations(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(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: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17907,8 +17907,9 @@ namespace BinaryNinja {
1790717907
static bool GetReturnedIndirectReturnValuePointerCallback(void* ctxt, BNVariable* outVar);
1790817908

1790917909
static bool IsArgumentTypeRegisterCompatibleCallback(void* ctxt, BNType* type);
17910-
static bool AreNonRegisterArgumentsIndirectCallback(void* ctxt);
17910+
static bool IsNonRegisterArgumentIndirectCallback(void* ctxt, BNType* type);
1791117911
static bool AreStackArgumentsNaturallyAlignedCallback(void* ctxt);
17912+
static bool AreStackArgumentsPushedLeftToRightCallback(void* ctxt);
1791217913

1791317914
static void GetCallLayoutCallback(void* ctxt, BNReturnValue* returnValue, BNFunctionParameter* params,
1791417915
size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs, size_t permittedRegCount,
@@ -17921,6 +17922,9 @@ namespace BinaryNinja {
1792117922
BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs,
1792217923
size_t permittedRegCount, size_t* outLocationCount);
1792317924
static void FreeParameterLocationsCallback(void* ctxt, BNValueLocation* locations, size_t count);
17925+
static BNVariable* GetParameterOrderingForVariablesCallback(
17926+
void* ctxt, BNVariable* vars, BNType** types, size_t paramCount, size_t* outCount);
17927+
static void FreeVariableListCallback(void* ctxt, BNVariable* vars, size_t count);
1792417928
static int64_t GetStackAdjustmentForLocationsCallback(
1792517929
void* ctxt, BNValueLocation* returnValue, BNValueLocation* locations, BNType** types, size_t paramCount);
1792617930
static size_t GetRegisterStackAdjustmentsCallback(void* ctxt, BNValueLocation* returnValue,
@@ -17977,15 +17981,17 @@ namespace BinaryNinja {
1797717981

1797817982
virtual bool IsArgumentTypeRegisterCompatible(Type* type);
1797917983
bool DefaultIsArgumentTypeRegisterCompatible(Type* type);
17980-
virtual bool AreNonRegisterArgumentsIndirect();
17984+
virtual bool IsNonRegisterArgumentIndirect(Type* type);
1798117985
virtual bool AreStackArgumentsNaturallyAligned();
17986+
virtual bool AreStackArgumentsPushedLeftToRight();
1798217987

1798317988
virtual CallLayout GetCallLayout(const ReturnValue& returnValue, const std::vector<FunctionParameter>& params,
1798417989
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
1798517990
virtual ValueLocation GetReturnValueLocation(const ReturnValue& returnValue);
1798617991
virtual std::vector<ValueLocation> GetParameterLocations(const std::optional<ValueLocation>& returnValue,
1798717992
const std::vector<FunctionParameter>& params,
1798817993
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
17994+
virtual std::vector<Variable> GetParameterOrderingForVariables(const std::map<Variable, Ref<Type>>& params);
1798917995
virtual int64_t GetStackAdjustmentForLocations(const std::optional<ValueLocation>& returnValue,
1799017996
const std::vector<ValueLocation>& locations, const std::vector<Ref<Type>>& types);
1799117997
virtual std::map<uint32_t, int32_t> GetRegisterStackAdjustments(
@@ -17997,6 +18003,7 @@ namespace BinaryNinja {
1799718003
std::vector<ValueLocation> GetDefaultParameterLocations(const std::optional<ValueLocation>& returnValue,
1799818004
const std::vector<FunctionParameter>& params,
1799918005
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
18006+
std::vector<Variable> GetDefaultParameterOrderingForVariables(const std::map<Variable, Ref<Type>>& params);
1800018007
int64_t GetDefaultStackAdjustmentForLocations(const std::optional<ValueLocation>& returnValue,
1800118008
const std::vector<ValueLocation>& locations, const std::vector<Ref<Type>>& types);
1800218009
std::map<uint32_t, int32_t> GetDefaultRegisterStackAdjustments(
@@ -18041,15 +18048,18 @@ namespace BinaryNinja {
1804118048
virtual std::optional<Variable> GetReturnedIndirectReturnValuePointer() override;
1804218049

1804318050
virtual bool IsArgumentTypeRegisterCompatible(Type* type) override;
18044-
virtual bool AreNonRegisterArgumentsIndirect() override;
18051+
virtual bool IsNonRegisterArgumentIndirect(Type* type) override;
1804518052
virtual bool AreStackArgumentsNaturallyAligned() override;
18053+
virtual bool AreStackArgumentsPushedLeftToRight() override;
1804618054

1804718055
virtual CallLayout GetCallLayout(const ReturnValue& returnValue, const std::vector<FunctionParameter>& params,
1804818056
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt) override;
1804918057
virtual ValueLocation GetReturnValueLocation(const ReturnValue& returnValue) override;
1805018058
virtual std::vector<ValueLocation> GetParameterLocations(const std::optional<ValueLocation>& returnValue,
1805118059
const std::vector<FunctionParameter>& params,
1805218060
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt) override;
18061+
virtual std::vector<Variable> GetParameterOrderingForVariables(
18062+
const std::map<Variable, Ref<Type>>& params) override;
1805318063
virtual int64_t GetStackAdjustmentForLocations(const std::optional<ValueLocation>& returnValue,
1805418064
const std::vector<ValueLocation>& locations, const std::vector<Ref<Type>>& types) override;
1805518065
virtual std::map<uint32_t, int32_t> GetRegisterStackAdjustments(

0 commit comments

Comments
 (0)