Skip to content

Commit 20c6392

Browse files
committed
Implement return value location handling for x86 ELF ABI
1 parent 75c242c commit 20c6392

3 files changed

Lines changed: 269 additions & 3 deletions

File tree

arch/x86/arch_x86.cpp

Lines changed: 263 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3847,6 +3847,43 @@ class X86BaseCallingConvention: public CallingConvention
38473847
};
38483848

38493849

3850+
class X86SystemVCallingConvention: public X86BaseCallingConvention
3851+
{
3852+
public:
3853+
X86SystemVCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "sysv")
3854+
{
3855+
}
3856+
3857+
bool IsReturnTypeRegisterCompatible(Type* type) override
3858+
{
3859+
if (!type)
3860+
return false;
3861+
if (type->IsFloat())
3862+
return true;
3863+
if (type->IsStructure() || type->IsArray())
3864+
return false;
3865+
if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4
3866+
|| type->GetWidth() == 8)
3867+
return true;
3868+
return false;
3869+
}
3870+
3871+
int64_t GetStackAdjustmentForLocations(const std::optional<ValueLocation>& returnValue,
3872+
const vector<ValueLocation>&, const vector<Ref<Type>>&) override
3873+
{
3874+
if (!returnValue.has_value())
3875+
return 0;
3876+
for (auto& component: returnValue->components)
3877+
{
3878+
// Indirect return values have the pointer popped off the stack by the called function
3879+
if (component.indirect)
3880+
return 4;
3881+
}
3882+
return 0;
3883+
}
3884+
};
3885+
3886+
38503887
class X86CdeclCallingConvention: public X86BaseCallingConvention
38513888
{
38523889
public:
@@ -3870,17 +3907,68 @@ class X86StdcallCallingConvention: public X86BaseCallingConvention
38703907
};
38713908

38723909

3910+
class X86SystemVStdcallCallingConvention: public X86BaseCallingConvention
3911+
{
3912+
public:
3913+
X86SystemVStdcallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "sysv-stdcall")
3914+
{
3915+
}
3916+
3917+
bool IsStackAdjustedOnReturn() override
3918+
{
3919+
return true;
3920+
}
3921+
3922+
bool IsReturnTypeRegisterCompatible(Type* type) override
3923+
{
3924+
if (!type)
3925+
return false;
3926+
if (type->IsFloat())
3927+
return true;
3928+
if (type->IsStructure() || type->IsArray())
3929+
return false;
3930+
if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4
3931+
|| type->GetWidth() == 8)
3932+
return true;
3933+
return false;
3934+
}
3935+
};
3936+
3937+
38733938
class X86RegParmCallingConvention: public X86BaseCallingConvention
38743939
{
38753940
public:
38763941
X86RegParmCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "regparm")
38773942
{
38783943
}
38793944

3880-
virtual vector<uint32_t> GetIntegerArgumentRegisters() override
3945+
vector<uint32_t> GetIntegerArgumentRegisters() override
38813946
{
38823947
return vector<uint32_t>{ XED_REG_EAX, XED_REG_EDX, XED_REG_ECX };
38833948
}
3949+
3950+
bool IsReturnTypeRegisterCompatible(Type* type) override
3951+
{
3952+
if (!type)
3953+
return false;
3954+
if (type->IsFloat())
3955+
return true;
3956+
if (type->IsStructure() || type->IsArray())
3957+
return false;
3958+
if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4
3959+
|| type->GetWidth() == 8)
3960+
return true;
3961+
return false;
3962+
}
3963+
3964+
bool IsArgumentTypeRegisterCompatible(Type* type) override
3965+
{
3966+
if (!type)
3967+
return false;
3968+
if (type->IsFloat())
3969+
return true;
3970+
return type->GetWidth() <= 12;
3971+
}
38843972
};
38853973

38863974

@@ -3903,6 +3991,82 @@ class X86FastcallCallingConvention: public X86BaseCallingConvention
39033991
};
39043992

39053993

3994+
class X86GCCFastcallCallingConvention: public X86BaseCallingConvention
3995+
{
3996+
public:
3997+
X86GCCFastcallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "gcc-fastcall")
3998+
{
3999+
}
4000+
4001+
vector<uint32_t> GetIntegerArgumentRegisters() override
4002+
{
4003+
return vector<uint32_t>{ XED_REG_ECX, XED_REG_EDX };
4004+
}
4005+
4006+
bool IsStackAdjustedOnReturn() override
4007+
{
4008+
return true;
4009+
}
4010+
4011+
bool IsReturnTypeRegisterCompatible(Type* type) override
4012+
{
4013+
if (!type)
4014+
return false;
4015+
if (type->IsFloat())
4016+
return true;
4017+
if (type->IsStructure() || type->IsArray())
4018+
return false;
4019+
if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4
4020+
|| type->GetWidth() == 8)
4021+
return true;
4022+
return false;
4023+
}
4024+
4025+
Variable GetIndirectReturnValueLocation() override
4026+
{
4027+
return Variable::Register(XED_REG_ECX);
4028+
}
4029+
};
4030+
4031+
4032+
class X86ClangFastcallCallingConvention: public X86BaseCallingConvention
4033+
{
4034+
public:
4035+
X86ClangFastcallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "clang-fastcall")
4036+
{
4037+
}
4038+
4039+
vector<uint32_t> GetIntegerArgumentRegisters() override
4040+
{
4041+
return vector<uint32_t>{ XED_REG_ECX, XED_REG_EDX };
4042+
}
4043+
4044+
bool IsStackAdjustedOnReturn() override
4045+
{
4046+
return true;
4047+
}
4048+
4049+
bool IsReturnTypeRegisterCompatible(Type* type) override
4050+
{
4051+
if (!type)
4052+
return false;
4053+
if (type->IsFloat())
4054+
return true;
4055+
if (type->IsStructure() || type->IsArray())
4056+
return false;
4057+
if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4
4058+
|| type->GetWidth() == 8)
4059+
return true;
4060+
return false;
4061+
}
4062+
4063+
Variable GetIndirectReturnValueLocation() override
4064+
{
4065+
return Variable::StackOffset(4);
4066+
}
4067+
};
4068+
4069+
39064070
class X86ThiscallCallingConvention: public X86BaseCallingConvention
39074071
{
39084072
public:
@@ -3927,6 +4091,92 @@ class X86ThiscallCallingConvention: public X86BaseCallingConvention
39274091
};
39284092

39294093

4094+
class X86GCCThiscallCallingConvention: public X86BaseCallingConvention
4095+
{
4096+
public:
4097+
X86GCCThiscallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "gcc-thiscall")
4098+
{
4099+
}
4100+
4101+
vector<uint32_t> GetIntegerArgumentRegisters() override
4102+
{
4103+
return vector<uint32_t>{ XED_REG_ECX };
4104+
}
4105+
4106+
vector<uint32_t> GetRequiredArgumentRegisters() override
4107+
{
4108+
return vector<uint32_t>{ XED_REG_ECX };
4109+
}
4110+
4111+
bool IsStackAdjustedOnReturn() override
4112+
{
4113+
return true;
4114+
}
4115+
4116+
bool IsReturnTypeRegisterCompatible(Type* type) override
4117+
{
4118+
if (!type)
4119+
return false;
4120+
if (type->IsFloat())
4121+
return true;
4122+
if (type->IsStructure() || type->IsArray())
4123+
return false;
4124+
if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4
4125+
|| type->GetWidth() == 8)
4126+
return true;
4127+
return false;
4128+
}
4129+
4130+
Variable GetIndirectReturnValueLocation() override
4131+
{
4132+
return Variable::Register(XED_REG_ECX);
4133+
}
4134+
};
4135+
4136+
4137+
class X86ClangThiscallCallingConvention: public X86BaseCallingConvention
4138+
{
4139+
public:
4140+
X86ClangThiscallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "clang-thiscall")
4141+
{
4142+
}
4143+
4144+
vector<uint32_t> GetIntegerArgumentRegisters() override
4145+
{
4146+
return vector<uint32_t>{ XED_REG_ECX };
4147+
}
4148+
4149+
vector<uint32_t> GetRequiredArgumentRegisters() override
4150+
{
4151+
return vector<uint32_t>{ XED_REG_ECX };
4152+
}
4153+
4154+
bool IsStackAdjustedOnReturn() override
4155+
{
4156+
return true;
4157+
}
4158+
4159+
bool IsReturnTypeRegisterCompatible(Type* type) override
4160+
{
4161+
if (!type)
4162+
return false;
4163+
if (type->IsFloat())
4164+
return true;
4165+
if (type->IsStructure() || type->IsArray())
4166+
return false;
4167+
if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4
4168+
|| type->GetWidth() == 8)
4169+
return true;
4170+
return false;
4171+
}
4172+
4173+
Variable GetIndirectReturnValueLocation() override
4174+
{
4175+
return Variable::StackOffset(4);
4176+
}
4177+
};
4178+
4179+
39304180
class X86LinuxSystemCallConvention: public CallingConvention
39314181
{
39324182
public:
@@ -5288,15 +5538,27 @@ extern "C"
52885538
x86->RegisterCallingConvention(conv);
52895539
x86->SetDefaultCallingConvention(conv);
52905540
x86->SetCdeclCallingConvention(conv);
5541+
conv = new X86SystemVCallingConvention(x86);
5542+
x86->RegisterCallingConvention(conv);
52915543
conv = new X86StdcallCallingConvention(x86);
52925544
x86->RegisterCallingConvention(conv);
52935545
x86->SetStdcallCallingConvention(conv);
5546+
conv = new X86SystemVStdcallCallingConvention(x86);
5547+
x86->RegisterCallingConvention(conv);
52945548
conv = new X86RegParmCallingConvention(x86);
52955549
x86->RegisterCallingConvention(conv);
52965550
conv = new X86FastcallCallingConvention(x86);
52975551
x86->RegisterCallingConvention(conv);
5552+
conv = new X86GCCFastcallCallingConvention(x86);
5553+
x86->RegisterCallingConvention(conv);
5554+
conv = new X86ClangFastcallCallingConvention(x86);
5555+
x86->RegisterCallingConvention(conv);
52985556
conv = new X86ThiscallCallingConvention(x86);
52995557
x86->RegisterCallingConvention(conv);
5558+
conv = new X86GCCThiscallCallingConvention(x86);
5559+
x86->RegisterCallingConvention(conv);
5560+
conv = new X86ClangThiscallCallingConvention(x86);
5561+
x86->RegisterCallingConvention(conv);
53005562
conv = new X86LinuxSystemCallConvention(x86);
53015563
x86->RegisterCallingConvention(conv);
53025564
conv = new X86PascalCallingConvention(x86);

docs/guide/types/attributes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ The following built-in calling conventions without dedicated keywords are availa
138138
|`apple-syscall`|aarch64|macOS and iOS system calls|
139139
|`go-stack`|x86, x86_64|Stack-based calling convention used by the Go compiler on 32-bit x86 or older compilers|
140140
|`register`|x86|Register-based calling convention with left-to-right parameter passing (used by default in Delphi)|
141+
|`gcc-fastcall`|x86|The `fastcall` calling convention as implemented in GCC on non-Windows platforms|
142+
|`clang-fastcall`|x86|The `fastcall` calling convention as implemented in Clang on non-Windows platforms|
143+
|`gcc-thiscall`|x86|The `thiscall` calling convention as implemented in GCC on non-Windows platforms|
144+
|`clang-thiscall`|x86|The `thiscall` calling convention as implemented in Clang on non-Windows platforms|
141145
142146
## System Call Functions for Type Libraries
143147

platform/linux/platform_linux.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class LinuxX86Platform: public Platform
1515
{
1616
Ref<CallingConvention> cc;
1717

18-
cc = arch->GetCallingConventionByName("cdecl");
18+
cc = arch->GetCallingConventionByName("sysv");
1919
if (cc)
2020
{
2121
RegisterDefaultCallingConvention(cc);
@@ -26,7 +26,7 @@ class LinuxX86Platform: public Platform
2626
if (cc)
2727
RegisterCallingConvention(cc);
2828

29-
cc = arch->GetCallingConventionByName("stdcall");
29+
cc = arch->GetCallingConventionByName("sysv-stdcall");
3030
if (cc)
3131
RegisterStdcallCallingConvention(cc);
3232

0 commit comments

Comments
 (0)