Skip to content

Commit 90ef728

Browse files
committed
Initial support for Go and Pascal calling conventions
1 parent 0348704 commit 90ef728

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
@@ -3967,6 +3967,159 @@ class X86LinuxSystemCallConvention: public CallingConvention
39673967
};
39683968

39693969

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

4102-
bool AreNonRegisterArgumentsIndirect() override
4255+
bool IsNonRegisterArgumentIndirect(Type*) override
41034256
{
41044257
return true;
41054258
}
@@ -4141,6 +4294,100 @@ class X64LinuxSystemCallConvention: public CallingConvention
41414294
};
41424295

41434296

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

50525305
x86->RegisterRelocationHandler("Mach-O", new x86MachoRelocationHandler());
50535306
x86->RegisterRelocationHandler("KCView", new x86MachoRelocationHandler());
@@ -5065,6 +5318,8 @@ extern "C"
50655318
x64->RegisterCallingConvention(conv);
50665319
conv = new X64LinuxSystemCallConvention(x64);
50675320
x64->RegisterCallingConvention(conv);
5321+
conv = new X64GoStackCallingConvention(x64);
5322+
x64->RegisterCallingConvention(conv);
50685323

50695324
x64->RegisterRelocationHandler("Mach-O", new x64MachoRelocationHandler());
50705325
x64->RegisterRelocationHandler("KCView", new x64MachoRelocationHandler());

binaryninjaapi.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17858,8 +17858,9 @@ namespace BinaryNinja {
1785817858
static bool GetReturnedIndirectReturnValuePointerCallback(void* ctxt, BNVariable* outVar);
1785917859

1786017860
static bool IsArgumentTypeRegisterCompatibleCallback(void* ctxt, BNType* type);
17861-
static bool AreNonRegisterArgumentsIndirectCallback(void* ctxt);
17861+
static bool IsNonRegisterArgumentIndirectCallback(void* ctxt, BNType* type);
1786217862
static bool AreStackArgumentsNaturallyAlignedCallback(void* ctxt);
17863+
static bool AreStackArgumentsPushedLeftToRightCallback(void* ctxt);
1786317864

1786417865
static void GetCallLayoutCallback(void* ctxt, BNReturnValue* returnValue, BNFunctionParameter* params,
1786517866
size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs, size_t permittedRegCount,
@@ -17872,6 +17873,9 @@ namespace BinaryNinja {
1787217873
BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs,
1787317874
size_t permittedRegCount, size_t* outLocationCount);
1787417875
static void FreeParameterLocationsCallback(void* ctxt, BNValueLocation* locations, size_t count);
17876+
static BNVariable* GetParameterOrderingForVariablesCallback(
17877+
void* ctxt, BNVariable* vars, BNType** types, size_t paramCount, size_t* outCount);
17878+
static void FreeVariableListCallback(void* ctxt, BNVariable* vars, size_t count);
1787517879
static int64_t GetStackAdjustmentForLocationsCallback(
1787617880
void* ctxt, BNValueLocation* returnValue, BNValueLocation* locations, BNType** types, size_t paramCount);
1787717881
static size_t GetRegisterStackAdjustmentsCallback(void* ctxt, BNValueLocation* returnValue,
@@ -17928,15 +17932,17 @@ namespace BinaryNinja {
1792817932

1792917933
virtual bool IsArgumentTypeRegisterCompatible(Type* type);
1793017934
bool DefaultIsArgumentTypeRegisterCompatible(Type* type);
17931-
virtual bool AreNonRegisterArgumentsIndirect();
17935+
virtual bool IsNonRegisterArgumentIndirect(Type* type);
1793217936
virtual bool AreStackArgumentsNaturallyAligned();
17937+
virtual bool AreStackArgumentsPushedLeftToRight();
1793317938

1793417939
virtual CallLayout GetCallLayout(const ReturnValue& returnValue, const std::vector<FunctionParameter>& params,
1793517940
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
1793617941
virtual ValueLocation GetReturnValueLocation(const ReturnValue& returnValue);
1793717942
virtual std::vector<ValueLocation> GetParameterLocations(const std::optional<ValueLocation>& returnValue,
1793817943
const std::vector<FunctionParameter>& params,
1793917944
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
17945+
virtual std::vector<Variable> GetParameterOrderingForVariables(const std::map<Variable, Ref<Type>>& params);
1794017946
virtual int64_t GetStackAdjustmentForLocations(const std::optional<ValueLocation>& returnValue,
1794117947
const std::vector<ValueLocation>& locations, const std::vector<Ref<Type>>& types);
1794217948
virtual std::map<uint32_t, int32_t> GetRegisterStackAdjustments(
@@ -17948,6 +17954,7 @@ namespace BinaryNinja {
1794817954
std::vector<ValueLocation> GetDefaultParameterLocations(const std::optional<ValueLocation>& returnValue,
1794917955
const std::vector<FunctionParameter>& params,
1795017956
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
17957+
std::vector<Variable> GetDefaultParameterOrderingForVariables(const std::map<Variable, Ref<Type>>& params);
1795117958
int64_t GetDefaultStackAdjustmentForLocations(const std::optional<ValueLocation>& returnValue,
1795217959
const std::vector<ValueLocation>& locations, const std::vector<Ref<Type>>& types);
1795317960
std::map<uint32_t, int32_t> GetDefaultRegisterStackAdjustments(
@@ -17992,15 +17999,18 @@ namespace BinaryNinja {
1799217999
virtual std::optional<Variable> GetReturnedIndirectReturnValuePointer() override;
1799318000

1799418001
virtual bool IsArgumentTypeRegisterCompatible(Type* type) override;
17995-
virtual bool AreNonRegisterArgumentsIndirect() override;
18002+
virtual bool IsNonRegisterArgumentIndirect(Type* type) override;
1799618003
virtual bool AreStackArgumentsNaturallyAligned() override;
18004+
virtual bool AreStackArgumentsPushedLeftToRight() override;
1799718005

1799818006
virtual CallLayout GetCallLayout(const ReturnValue& returnValue, const std::vector<FunctionParameter>& params,
1799918007
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt) override;
1800018008
virtual ValueLocation GetReturnValueLocation(const ReturnValue& returnValue) override;
1800118009
virtual std::vector<ValueLocation> GetParameterLocations(const std::optional<ValueLocation>& returnValue,
1800218010
const std::vector<FunctionParameter>& params,
1800318011
const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt) override;
18012+
virtual std::vector<Variable> GetParameterOrderingForVariables(
18013+
const std::map<Variable, Ref<Type>>& params) override;
1800418014
virtual int64_t GetStackAdjustmentForLocations(const std::optional<ValueLocation>& returnValue,
1800518015
const std::vector<ValueLocation>& locations, const std::vector<Ref<Type>>& types) override;
1800618016
virtual std::map<uint32_t, int32_t> GetRegisterStackAdjustments(

0 commit comments

Comments
 (0)