@@ -3971,6 +3971,170 @@ 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+ std::optional<int64_t > varStorage;
4092+ std::optional<uint64_t > varSize;
4093+ for (auto & component: it->components )
4094+ {
4095+ if (component.variable .type != StackVariableSourceType)
4096+ continue ;
4097+ if (!varStorage.has_value () || component.variable .storage > varStorage.value ())
4098+ {
4099+ varStorage = component.variable .storage ;
4100+ if (!it->indirect )
4101+ varSize = component.size ;
4102+ }
4103+ }
4104+
4105+ if (!varStorage.has_value () || varStorage.value () < stackOffset)
4106+ continue ;
4107+ if (it->indirect )
4108+ varSize = 4 ;
4109+
4110+ size_t width = 4 ;
4111+ if (varSize.has_value ())
4112+ width = varSize.value ();
4113+ else if (i < params.size () && params[i].type .GetValue ())
4114+ width = params[i].type ->GetWidth ();
4115+
4116+ if (width < 4 )
4117+ width = 4 ;
4118+ else if ((width % 4 ) != 0 )
4119+ width += 4 - (width % 4 );
4120+
4121+ stackOffset = varStorage.value () + width;
4122+ }
4123+
4124+ result.returnValue = Variable::StackOffset (stackOffset);
4125+ }
4126+ else
4127+ {
4128+ result.returnValue = returnValue.location .GetValue ();
4129+ }
4130+ }
4131+
4132+ result.registerStackAdjustments = GetRegisterStackAdjustments (view, result.returnValue , result.parameters );
4133+ return result;
4134+ }
4135+ };
4136+
4137+
39744138class X64BaseCallingConvention : public CallingConvention
39754139{
39764140public:
@@ -4145,6 +4309,111 @@ class X64LinuxSystemCallConvention: public CallingConvention
41454309};
41464310
41474311
4312+ class X64GoStackCallingConvention : public CallingConvention
4313+ {
4314+ public:
4315+ X64GoStackCallingConvention (Architecture* arch): CallingConvention(arch, " go-stack" )
4316+ {
4317+ }
4318+
4319+ bool IsEligibleForHeuristics () override
4320+ {
4321+ // This convention cannot be detected by heuristics at this time and will cause issues
4322+ // with non-Go code.
4323+ return false ;
4324+ }
4325+
4326+ uint32_t GetIntegerReturnValueRegister () override
4327+ {
4328+ return BN_INVALID_REGISTER ;
4329+ }
4330+
4331+ vector<uint32_t > GetCallerSavedRegisters () override
4332+ {
4333+ return vector<uint32_t > { XED_REG_RAX , XED_REG_RCX , XED_REG_RDX , XED_REG_RBX , XED_REG_RBP ,
4334+ XED_REG_R8 , XED_REG_R9 , XED_REG_R10 , XED_REG_R11 , XED_REG_R12 , XED_REG_R13 , XED_REG_R14 ,
4335+ XED_REG_R15 };
4336+ }
4337+
4338+ RegisterValue GetIncomingFlagValue (uint32_t flag, Function*) override
4339+ {
4340+ RegisterValue result;
4341+ if (flag == IL_FLAG_D )
4342+ {
4343+ result.state = ConstantValue;
4344+ result.value = 0 ;
4345+ }
4346+ return result;
4347+ }
4348+
4349+ ValueLocation GetReturnValueLocation (BinaryView*, const ReturnValue&) override
4350+ {
4351+ // It is not possible for this API to determine the return value location on the stack at
4352+ // this point, return an invalid location and fall back to GetCallLayout.
4353+ return ValueLocation ();
4354+ }
4355+
4356+ CallLayout GetCallLayout (BinaryView* view, const ReturnValue& returnValue, const vector<FunctionParameter>& params,
4357+ const std::optional<set<uint32_t >>& permittedRegs) override
4358+ {
4359+ CallLayout result;
4360+ result.parameters = GetParameterLocations (view, result.returnValue , params, permittedRegs);
4361+
4362+ if (returnValue.type .GetValue () && returnValue.type ->GetClass () != VoidTypeClass)
4363+ {
4364+ if (returnValue.defaultLocation )
4365+ {
4366+ int64_t stackOffset = 8 ;
4367+ size_t i = 0 ;
4368+ for (auto it = result.parameters .begin (); it != result.parameters .end (); ++i, ++it)
4369+ {
4370+ std::optional<int64_t > varStorage;
4371+ std::optional<uint64_t > varSize;
4372+ for (auto & component: it->components )
4373+ {
4374+ if (component.variable .type != StackVariableSourceType)
4375+ continue ;
4376+ if (!varStorage.has_value () || component.variable .storage > varStorage.value ())
4377+ {
4378+ varStorage = component.variable .storage ;
4379+ if (!it->indirect )
4380+ varSize = component.size ;
4381+ }
4382+ }
4383+
4384+ if (!varStorage.has_value () || varStorage.value () < stackOffset)
4385+ continue ;
4386+ if (it->indirect )
4387+ varSize = 8 ;
4388+
4389+ size_t width = 8 ;
4390+ if (varSize.has_value ())
4391+ width = varSize.value ();
4392+ else if (i < params.size () && params[i].type .GetValue ())
4393+ width = params[i].type ->GetWidth ();
4394+
4395+ if (width < 8 )
4396+ width = 8 ;
4397+ else if ((width % 8 ) != 0 )
4398+ width += 8 - (width % 8 );
4399+
4400+ stackOffset = varStorage.value () + width;
4401+ }
4402+
4403+ result.returnValue = Variable::StackOffset (stackOffset);
4404+ }
4405+ else
4406+ {
4407+ result.returnValue = returnValue.location .GetValue ();
4408+ }
4409+ }
4410+
4411+ result.registerStackAdjustments = GetRegisterStackAdjustments (view, result.returnValue , result.parameters );
4412+ return result;
4413+ }
4414+ };
4415+
4416+
41484417class x86MachoRelocationHandler : public RelocationHandler
41494418{
41504419public:
@@ -5052,6 +5321,12 @@ extern "C"
50525321 x86->RegisterCallingConvention (conv);
50535322 conv = new X86LinuxSystemCallConvention (x86);
50545323 x86->RegisterCallingConvention (conv);
5324+ conv = new X86PascalCallingConvention (x86);
5325+ x86->RegisterCallingConvention (conv);
5326+ conv = new X86PascalRegisterCallingConvention (x86);
5327+ x86->RegisterCallingConvention (conv);
5328+ conv = new X86GoStackCallingConvention (x86);
5329+ x86->RegisterCallingConvention (conv);
50555330
50565331 x86->RegisterRelocationHandler (" Mach-O" , new x86MachoRelocationHandler ());
50575332 x86->RegisterRelocationHandler (" KCView" , new x86MachoRelocationHandler ());
@@ -5069,6 +5344,8 @@ extern "C"
50695344 x64->RegisterCallingConvention (conv);
50705345 conv = new X64LinuxSystemCallConvention (x64);
50715346 x64->RegisterCallingConvention (conv);
5347+ conv = new X64GoStackCallingConvention (x64);
5348+ x64->RegisterCallingConvention (conv);
50725349
50735350 x64->RegisterRelocationHandler (" Mach-O" , new x64MachoRelocationHandler ());
50745351 x64->RegisterRelocationHandler (" KCView" , new x64MachoRelocationHandler ());
0 commit comments