summaryrefslogtreecommitdiff
path: root/arch/x86/arch_x86.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/arch_x86.cpp')
-rw-r--r--arch/x86/arch_x86.cpp277
1 files changed, 277 insertions, 0 deletions
diff --git a/arch/x86/arch_x86.cpp b/arch/x86/arch_x86.cpp
index 83a476bf..98454dd9 100644
--- a/arch/x86/arch_x86.cpp
+++ b/arch/x86/arch_x86.cpp
@@ -3971,6 +3971,170 @@ public:
};
+class X86PascalCallingConvention : public X86BaseCallingConvention
+{
+public:
+ X86PascalCallingConvention(Architecture* arch) : X86BaseCallingConvention(arch, "pascal") {}
+
+ bool IsNonRegisterArgumentIndirect(BinaryView*, Type* type) override
+ {
+ return type && !type->IsFloat() && type->GetWidth() > 4;
+ }
+
+ bool IsStackAdjustedOnReturn() override
+ {
+ return true;
+ }
+
+ bool AreStackArgumentsPushedLeftToRight() override
+ {
+ return true;
+ }
+
+ Variable GetIndirectReturnValueLocation() override
+ {
+ // Return value pointer is always at the top of the stack (effectively the last parameter
+ // in a left-to-right convention)
+ return Variable::StackOffset(4);
+ }
+
+ std::optional<Variable> GetReturnedIndirectReturnValuePointer() override
+ {
+ return std::nullopt;
+ }
+};
+
+
+class X86PascalRegisterCallingConvention : public X86BaseCallingConvention
+{
+public:
+ X86PascalRegisterCallingConvention(Architecture* arch) : X86BaseCallingConvention(arch, "register") {}
+
+ vector<uint32_t> GetIntegerArgumentRegisters() override
+ {
+ return { XED_REG_EAX, XED_REG_EDX, XED_REG_ECX };
+ }
+
+ bool IsNonRegisterArgumentIndirect(BinaryView*, Type* type) override
+ {
+ return type && !type->IsFloat() && type->GetWidth() > 4;
+ }
+
+ bool AreStackArgumentsPushedLeftToRight() override
+ {
+ return true;
+ }
+
+ std::optional<Variable> GetReturnedIndirectReturnValuePointer() override
+ {
+ return std::nullopt;
+ }
+};
+
+
+class X86GoStackCallingConvention: public CallingConvention
+{
+public:
+ X86GoStackCallingConvention(Architecture* arch): CallingConvention(arch, "go-stack")
+ {
+ }
+
+ bool IsEligibleForHeuristics() override
+ {
+ // This convention cannot be detected by heuristics at this time and will cause issues
+ // with non-Go code.
+ return false;
+ }
+
+ uint32_t GetIntegerReturnValueRegister() override
+ {
+ return BN_INVALID_REGISTER;
+ }
+
+ vector<uint32_t> GetCallerSavedRegisters() override
+ {
+ return vector<uint32_t> { XED_REG_EAX, XED_REG_ECX, XED_REG_EDX, XED_REG_EBX, XED_REG_EBP };
+ }
+
+ RegisterValue GetIncomingFlagValue(uint32_t flag, Function*) override
+ {
+ RegisterValue result;
+ if (flag == IL_FLAG_D)
+ {
+ result.state = ConstantValue;
+ result.value = 0;
+ }
+ return result;
+ }
+
+ ValueLocation GetReturnValueLocation(BinaryView*, const ReturnValue&) override
+ {
+ // It is not possible for this API to determine the return value location on the stack at
+ // this point, return an invalid location and fall back to GetCallLayout.
+ return ValueLocation();
+ }
+
+ CallLayout GetCallLayout(BinaryView* view, const ReturnValue& returnValue, const vector<FunctionParameter>& params,
+ const std::optional<set<uint32_t>>& permittedRegs) override
+ {
+ CallLayout result;
+ result.parameters = GetParameterLocations(view, result.returnValue, params, permittedRegs);
+
+ if (returnValue.type.GetValue() && returnValue.type->GetClass() != VoidTypeClass)
+ {
+ if (returnValue.defaultLocation)
+ {
+ int64_t stackOffset = 4;
+ size_t i = 0;
+ for (auto it = result.parameters.begin(); it != result.parameters.end(); ++i, ++it)
+ {
+ std::optional<int64_t> varStorage;
+ std::optional<uint64_t> varSize;
+ for (auto& component: it->components)
+ {
+ if (component.variable.type != StackVariableSourceType)
+ continue;
+ if (!varStorage.has_value() || component.variable.storage > varStorage.value())
+ {
+ varStorage = component.variable.storage;
+ if (!it->indirect)
+ varSize = component.size;
+ }
+ }
+
+ if (!varStorage.has_value() || varStorage.value() < stackOffset)
+ continue;
+ if (it->indirect)
+ varSize = 4;
+
+ size_t width = 4;
+ if (varSize.has_value())
+ width = varSize.value();
+ else if (i < params.size() && params[i].type.GetValue())
+ width = params[i].type->GetWidth();
+
+ if (width < 4)
+ width = 4;
+ else if ((width % 4) != 0)
+ width += 4 - (width % 4);
+
+ stackOffset = varStorage.value() + width;
+ }
+
+ result.returnValue = Variable::StackOffset(stackOffset);
+ }
+ else
+ {
+ result.returnValue = returnValue.location.GetValue();
+ }
+ }
+
+ result.registerStackAdjustments = GetRegisterStackAdjustments(view, result.returnValue, result.parameters);
+ return result;
+ }
+};
+
+
class X64BaseCallingConvention: public CallingConvention
{
public:
@@ -4145,6 +4309,111 @@ public:
};
+class X64GoStackCallingConvention: public CallingConvention
+{
+public:
+ X64GoStackCallingConvention(Architecture* arch): CallingConvention(arch, "go-stack")
+ {
+ }
+
+ bool IsEligibleForHeuristics() override
+ {
+ // This convention cannot be detected by heuristics at this time and will cause issues
+ // with non-Go code.
+ return false;
+ }
+
+ uint32_t GetIntegerReturnValueRegister() override
+ {
+ return BN_INVALID_REGISTER;
+ }
+
+ vector<uint32_t> GetCallerSavedRegisters() override
+ {
+ return vector<uint32_t> { XED_REG_RAX, XED_REG_RCX, XED_REG_RDX, XED_REG_RBX, XED_REG_RBP,
+ XED_REG_R8, XED_REG_R9, XED_REG_R10, XED_REG_R11, XED_REG_R12, XED_REG_R13, XED_REG_R14,
+ XED_REG_R15 };
+ }
+
+ RegisterValue GetIncomingFlagValue(uint32_t flag, Function*) override
+ {
+ RegisterValue result;
+ if (flag == IL_FLAG_D)
+ {
+ result.state = ConstantValue;
+ result.value = 0;
+ }
+ return result;
+ }
+
+ ValueLocation GetReturnValueLocation(BinaryView*, const ReturnValue&) override
+ {
+ // It is not possible for this API to determine the return value location on the stack at
+ // this point, return an invalid location and fall back to GetCallLayout.
+ return ValueLocation();
+ }
+
+ CallLayout GetCallLayout(BinaryView* view, const ReturnValue& returnValue, const vector<FunctionParameter>& params,
+ const std::optional<set<uint32_t>>& permittedRegs) override
+ {
+ CallLayout result;
+ result.parameters = GetParameterLocations(view, result.returnValue, params, permittedRegs);
+
+ if (returnValue.type.GetValue() && returnValue.type->GetClass() != VoidTypeClass)
+ {
+ if (returnValue.defaultLocation)
+ {
+ int64_t stackOffset = 8;
+ size_t i = 0;
+ for (auto it = result.parameters.begin(); it != result.parameters.end(); ++i, ++it)
+ {
+ std::optional<int64_t> varStorage;
+ std::optional<uint64_t> varSize;
+ for (auto& component: it->components)
+ {
+ if (component.variable.type != StackVariableSourceType)
+ continue;
+ if (!varStorage.has_value() || component.variable.storage > varStorage.value())
+ {
+ varStorage = component.variable.storage;
+ if (!it->indirect)
+ varSize = component.size;
+ }
+ }
+
+ if (!varStorage.has_value() || varStorage.value() < stackOffset)
+ continue;
+ if (it->indirect)
+ varSize = 8;
+
+ size_t width = 8;
+ if (varSize.has_value())
+ width = varSize.value();
+ else if (i < params.size() && params[i].type.GetValue())
+ width = params[i].type->GetWidth();
+
+ if (width < 8)
+ width = 8;
+ else if ((width % 8) != 0)
+ width += 8 - (width % 8);
+
+ stackOffset = varStorage.value() + width;
+ }
+
+ result.returnValue = Variable::StackOffset(stackOffset);
+ }
+ else
+ {
+ result.returnValue = returnValue.location.GetValue();
+ }
+ }
+
+ result.registerStackAdjustments = GetRegisterStackAdjustments(view, result.returnValue, result.parameters);
+ return result;
+ }
+};
+
+
class x86MachoRelocationHandler: public RelocationHandler
{
public:
@@ -5052,6 +5321,12 @@ extern "C"
x86->RegisterCallingConvention(conv);
conv = new X86LinuxSystemCallConvention(x86);
x86->RegisterCallingConvention(conv);
+ conv = new X86PascalCallingConvention(x86);
+ x86->RegisterCallingConvention(conv);
+ conv = new X86PascalRegisterCallingConvention(x86);
+ x86->RegisterCallingConvention(conv);
+ conv = new X86GoStackCallingConvention(x86);
+ x86->RegisterCallingConvention(conv);
x86->RegisterRelocationHandler("Mach-O", new x86MachoRelocationHandler());
x86->RegisterRelocationHandler("KCView", new x86MachoRelocationHandler());
@@ -5069,6 +5344,8 @@ extern "C"
x64->RegisterCallingConvention(conv);
conv = new X64LinuxSystemCallConvention(x64);
x64->RegisterCallingConvention(conv);
+ conv = new X64GoStackCallingConvention(x64);
+ x64->RegisterCallingConvention(conv);
x64->RegisterRelocationHandler("Mach-O", new x64MachoRelocationHandler());
x64->RegisterRelocationHandler("KCView", new x64MachoRelocationHandler());