Skip to content

Commit 3d10f49

Browse files
committed
Implement return value location handling for x86 ELF ABI
1 parent 90ef728 commit 3d10f49

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
@@ -3843,6 +3843,43 @@ class X86BaseCallingConvention: public CallingConvention
38433843
};
38443844

38453845

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

38683905

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

3876-
virtual vector<uint32_t> GetIntegerArgumentRegisters() override
3941+
vector<uint32_t> GetIntegerArgumentRegisters() override
38773942
{
38783943
return vector<uint32_t>{ XED_REG_EAX, XED_REG_EDX, XED_REG_ECX };
38793944
}
3945+
3946+
bool IsReturnTypeRegisterCompatible(Type* type) override
3947+
{
3948+
if (!type)
3949+
return false;
3950+
if (type->IsFloat())
3951+
return true;
3952+
if (type->IsStructure() || type->IsArray())
3953+
return false;
3954+
if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4
3955+
|| type->GetWidth() == 8)
3956+
return true;
3957+
return false;
3958+
}
3959+
3960+
bool IsArgumentTypeRegisterCompatible(Type* type) override
3961+
{
3962+
if (!type)
3963+
return false;
3964+
if (type->IsFloat())
3965+
return true;
3966+
return type->GetWidth() <= 12;
3967+
}
38803968
};
38813969

38823970

@@ -3899,6 +3987,82 @@ class X86FastcallCallingConvention: public X86BaseCallingConvention
38993987
};
39003988

39013989

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

39254089

4090+
class X86GCCThiscallCallingConvention: public X86BaseCallingConvention
4091+
{
4092+
public:
4093+
X86GCCThiscallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "gcc-thiscall")
4094+
{
4095+
}
4096+
4097+
vector<uint32_t> GetIntegerArgumentRegisters() override
4098+
{
4099+
return vector<uint32_t>{ XED_REG_ECX };
4100+
}
4101+
4102+
vector<uint32_t> GetRequiredArgumentRegisters() override
4103+
{
4104+
return vector<uint32_t>{ XED_REG_ECX };
4105+
}
4106+
4107+
bool IsStackAdjustedOnReturn() override
4108+
{
4109+
return true;
4110+
}
4111+
4112+
bool IsReturnTypeRegisterCompatible(Type* type) override
4113+
{
4114+
if (!type)
4115+
return false;
4116+
if (type->IsFloat())
4117+
return true;
4118+
if (type->IsStructure() || type->IsArray())
4119+
return false;
4120+
if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4
4121+
|| type->GetWidth() == 8)
4122+
return true;
4123+
return false;
4124+
}
4125+
4126+
Variable GetIndirectReturnValueLocation() override
4127+
{
4128+
return Variable::Register(XED_REG_ECX);
4129+
}
4130+
};
4131+
4132+
4133+
class X86ClangThiscallCallingConvention: public X86BaseCallingConvention
4134+
{
4135+
public:
4136+
X86ClangThiscallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "clang-thiscall")
4137+
{
4138+
}
4139+
4140+
vector<uint32_t> GetIntegerArgumentRegisters() override
4141+
{
4142+
return vector<uint32_t>{ XED_REG_ECX };
4143+
}
4144+
4145+
vector<uint32_t> GetRequiredArgumentRegisters() override
4146+
{
4147+
return vector<uint32_t>{ XED_REG_ECX };
4148+
}
4149+
4150+
bool IsStackAdjustedOnReturn() override
4151+
{
4152+
return true;
4153+
}
4154+
4155+
bool IsReturnTypeRegisterCompatible(Type* type) override
4156+
{
4157+
if (!type)
4158+
return false;
4159+
if (type->IsFloat())
4160+
return true;
4161+
if (type->IsStructure() || type->IsArray())
4162+
return false;
4163+
if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4
4164+
|| type->GetWidth() == 8)
4165+
return true;
4166+
return false;
4167+
}
4168+
4169+
Variable GetIndirectReturnValueLocation() override
4170+
{
4171+
return Variable::StackOffset(4);
4172+
}
4173+
};
4174+
4175+
39264176
class X86LinuxSystemCallConvention: public CallingConvention
39274177
{
39284178
public:
@@ -5284,15 +5534,27 @@ extern "C"
52845534
x86->RegisterCallingConvention(conv);
52855535
x86->SetDefaultCallingConvention(conv);
52865536
x86->SetCdeclCallingConvention(conv);
5537+
conv = new X86SystemVCallingConvention(x86);
5538+
x86->RegisterCallingConvention(conv);
52875539
conv = new X86StdcallCallingConvention(x86);
52885540
x86->RegisterCallingConvention(conv);
52895541
x86->SetStdcallCallingConvention(conv);
5542+
conv = new X86SystemVStdcallCallingConvention(x86);
5543+
x86->RegisterCallingConvention(conv);
52905544
conv = new X86RegParmCallingConvention(x86);
52915545
x86->RegisterCallingConvention(conv);
52925546
conv = new X86FastcallCallingConvention(x86);
52935547
x86->RegisterCallingConvention(conv);
5548+
conv = new X86GCCFastcallCallingConvention(x86);
5549+
x86->RegisterCallingConvention(conv);
5550+
conv = new X86ClangFastcallCallingConvention(x86);
5551+
x86->RegisterCallingConvention(conv);
52945552
conv = new X86ThiscallCallingConvention(x86);
52955553
x86->RegisterCallingConvention(conv);
5554+
conv = new X86GCCThiscallCallingConvention(x86);
5555+
x86->RegisterCallingConvention(conv);
5556+
conv = new X86ClangThiscallCallingConvention(x86);
5557+
x86->RegisterCallingConvention(conv);
52965558
conv = new X86LinuxSystemCallConvention(x86);
52975559
x86->RegisterCallingConvention(conv);
52985560
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)