mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-19 02:16:40 +00:00
svc: sanitize booleans in autogenerated abi stubs
This commit is contained in:
parent
4b9e7c7d27
commit
b3bd443636
5 changed files with 71 additions and 15 deletions
|
@ -189,6 +189,11 @@ namespace ams::svc::codegen::impl {
|
||||||
__asm__ __volatile__("mov x%c[dst], x%c[src]" :: [dst]"i"(Dst), [src]"i"(Src) : "memory");
|
__asm__ __volatile__("mov x%c[dst], x%c[src]" :: [dst]"i"(Dst), [src]"i"(Src) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<size_t Reg>
|
||||||
|
static ALWAYS_INLINE void ConvertToBoolean() {
|
||||||
|
__asm__ __volatile__("and x%c[reg], x%c[reg], #1" :: [reg]"i"(Reg) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
template<size_t Reg, size_t Offset, size_t Size>
|
template<size_t Reg, size_t Offset, size_t Size>
|
||||||
static ALWAYS_INLINE void LoadFromStack() {
|
static ALWAYS_INLINE void LoadFromStack() {
|
||||||
if constexpr (Size == 4) {
|
if constexpr (Size == 4) {
|
||||||
|
|
|
@ -317,6 +317,38 @@ namespace ams::svc::codegen::impl {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Conversion, size_t ParameterIndex = 0>
|
||||||
|
static constexpr void SanitizeInputBooleans(MetaCodeGenerator &mcg) {
|
||||||
|
/* Get the input layout. */
|
||||||
|
constexpr auto InputLayout = Conversion::LayoutForSvc.GetInputLayout();
|
||||||
|
|
||||||
|
/* Check if we're done. */
|
||||||
|
if constexpr (ParameterIndex < InputLayout.GetNumParameters()) {
|
||||||
|
/* Get the relevant parameter. */
|
||||||
|
constexpr auto Param = InputLayout.GetParameter(ParameterIndex);
|
||||||
|
|
||||||
|
/* Handle the case where the parameter is a boolean. */
|
||||||
|
if constexpr (Param.IsBoolean()) {
|
||||||
|
/* Boolean parameters should have one location. */
|
||||||
|
static_assert(Param.GetNumLocations() == 1);
|
||||||
|
|
||||||
|
/* Get the location. */
|
||||||
|
constexpr auto Loc = Param.GetLocation(0);
|
||||||
|
|
||||||
|
/* TODO: Support boolean parameters passed-by-stack. */
|
||||||
|
static_assert(Loc.GetStorage() == Storage::Register);
|
||||||
|
|
||||||
|
/* Convert the input to boolean. */
|
||||||
|
mcg.template ConvertToBoolean<Loc.GetIndex()>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the next parameter. */
|
||||||
|
if constexpr (ParameterIndex + 1 < InputLayout.GetNumParameters()) {
|
||||||
|
SanitizeInputBooleans<Conversion, ParameterIndex + 1>(mcg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename... T>
|
template<typename... T>
|
||||||
struct TypeIndexFilter {
|
struct TypeIndexFilter {
|
||||||
|
|
||||||
|
@ -436,6 +468,9 @@ namespace ams::svc::codegen::impl {
|
||||||
mcg.template AllocateStackSpace<UsedStackSpace>();
|
mcg.template AllocateStackSpace<UsedStackSpace>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sanitize all input booleans. */
|
||||||
|
SanitizeInputBooleans<Conversion>(mcg);
|
||||||
|
|
||||||
/* Generate code for before operations. */
|
/* Generate code for before operations. */
|
||||||
if constexpr (Conversion::NumBeforeOperations > 0) {
|
if constexpr (Conversion::NumBeforeOperations > 0) {
|
||||||
allocator = GenerateBeforeOperations<Conversion, InitialAllocator>(mcg, typename Conversion::BeforeOperations{});
|
allocator = GenerateBeforeOperations<Conversion, InitialAllocator>(mcg, typename Conversion::BeforeOperations{});
|
||||||
|
|
|
@ -36,21 +36,21 @@ namespace ams::svc::codegen::impl {
|
||||||
: abi(a), num_parameters(0), parameters()
|
: abi(a), num_parameters(0), parameters()
|
||||||
{ /* ... */ }
|
{ /* ... */ }
|
||||||
|
|
||||||
constexpr void AddSingle(Parameter::Identifier id, ArgumentType type, size_t ts, size_t ps, bool p, Storage s, size_t idx) {
|
constexpr void AddSingle(Parameter::Identifier id, ArgumentType type, size_t ts, size_t ps, bool p, bool b, Storage s, size_t idx) {
|
||||||
for (size_t i = 0; i < this->num_parameters; i++) {
|
for (size_t i = 0; i < this->num_parameters; i++) {
|
||||||
if (this->parameters[i].Is(id)) {
|
if (this->parameters[i].Is(id)) {
|
||||||
this->parameters[i].AddLocation(Location(s, idx));
|
this->parameters[i].AddLocation(Location(s, idx));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->parameters[this->num_parameters++] = Parameter(id, type, ts, ps, p, Location(s, idx));
|
this->parameters[this->num_parameters++] = Parameter(id, type, ts, ps, p, b, Location(s, idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr size_t Add(Parameter::Identifier id, ArgumentType type, size_t ts, size_t ps, bool p, Storage s, size_t i) {
|
constexpr size_t Add(Parameter::Identifier id, ArgumentType type, size_t ts, size_t ps, bool p, bool b, Storage s, size_t i) {
|
||||||
size_t required_registers = 0;
|
size_t required_registers = 0;
|
||||||
|
|
||||||
while (required_registers * this->abi.register_size < ps) {
|
while (required_registers * this->abi.register_size < ps) {
|
||||||
this->AddSingle(id, type, ts, ps, p, s, i++);
|
this->AddSingle(id, type, ts, ps, p, b, s, i++);
|
||||||
required_registers++;
|
required_registers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +115,7 @@ namespace ams::svc::codegen::impl {
|
||||||
|
|
||||||
constexpr size_t ArgumentTypeSize = AbiType::template Size<ArgType>;
|
constexpr size_t ArgumentTypeSize = AbiType::template Size<ArgType>;
|
||||||
constexpr bool PassedByPointer = IsPassedByPointer<AbiType, ArgType>;
|
constexpr bool PassedByPointer = IsPassedByPointer<AbiType, ArgType>;
|
||||||
|
constexpr bool IsBoolean = std::same_as<ArgType, bool>;
|
||||||
constexpr size_t ArgumentPassSize = PassedByPointer ? AbiType::PointerSize : ArgumentTypeSize;
|
constexpr size_t ArgumentPassSize = PassedByPointer ? AbiType::PointerSize : ArgumentTypeSize;
|
||||||
|
|
||||||
/* TODO: Is there ever a case where this is not the correct alignment? */
|
/* TODO: Is there ever a case where this is not the correct alignment? */
|
||||||
|
@ -135,19 +136,19 @@ namespace ams::svc::codegen::impl {
|
||||||
const size_t registers_available = AbiType::RegisterCount - NGRN;
|
const size_t registers_available = AbiType::RegisterCount - NGRN;
|
||||||
if constexpr (!PassedByPointer && IsIntegralOrUserPointer<ArgType> && ArgumentTypeSize > AbiType::RegisterSize) {
|
if constexpr (!PassedByPointer && IsIntegralOrUserPointer<ArgType> && ArgumentTypeSize > AbiType::RegisterSize) {
|
||||||
if (registers_available >= 2) {
|
if (registers_available >= 2) {
|
||||||
this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, Storage::Register, NGRN);
|
this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, IsBoolean, Storage::Register, NGRN);
|
||||||
NGRN += 2;
|
NGRN += 2;
|
||||||
} else {
|
} else {
|
||||||
/* Argument went on stack, so stop allocating arguments in registers. */
|
/* Argument went on stack, so stop allocating arguments in registers. */
|
||||||
NGRN = AbiType::RegisterCount;
|
NGRN = AbiType::RegisterCount;
|
||||||
|
|
||||||
NSAA += (NSAA & 1);
|
NSAA += (NSAA & 1);
|
||||||
this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, Storage::Stack, NSAA);
|
this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, IsBoolean, Storage::Stack, NSAA);
|
||||||
NSAA += 2;
|
NSAA += 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ArgumentPassSize <= AbiType::RegisterSize * registers_available) {
|
if (ArgumentPassSize <= AbiType::RegisterSize * registers_available) {
|
||||||
NGRN += this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, Storage::Register, NGRN);
|
NGRN += this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, IsBoolean, Storage::Register, NGRN);
|
||||||
} else {
|
} else {
|
||||||
/* Argument went on stack, so stop allocating arguments in registers. */
|
/* Argument went on stack, so stop allocating arguments in registers. */
|
||||||
NGRN = AbiType::RegisterCount;
|
NGRN = AbiType::RegisterCount;
|
||||||
|
@ -155,7 +156,7 @@ namespace ams::svc::codegen::impl {
|
||||||
/* TODO: Stack pointer alignment is only ensured for aapcs64. */
|
/* TODO: Stack pointer alignment is only ensured for aapcs64. */
|
||||||
/* What should we do here? */
|
/* What should we do here? */
|
||||||
|
|
||||||
NSAA += this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, Storage::Stack, NSAA);
|
NSAA += this->input.Add(id, Type, ArgumentTypeSize, ArgumentPassSize, PassedByPointer, IsBoolean, Storage::Stack, NSAA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,7 +177,7 @@ namespace ams::svc::codegen::impl {
|
||||||
/* TODO: It's unclear how to handle the non-integral and too-large case. */
|
/* TODO: It's unclear how to handle the non-integral and too-large case. */
|
||||||
if constexpr (!std::is_same<ReturnType, void>::value) {
|
if constexpr (!std::is_same<ReturnType, void>::value) {
|
||||||
constexpr size_t ReturnTypeSize = AbiType::template Size<ReturnType>;
|
constexpr size_t ReturnTypeSize = AbiType::template Size<ReturnType>;
|
||||||
layout.output.Add(Parameter::Identifier("ReturnType"), ArgumentType::Invalid, ReturnTypeSize, ReturnTypeSize, false, Storage::Register, 0);
|
layout.output.Add(Parameter::Identifier("ReturnType"), ArgumentType::Invalid, ReturnTypeSize, ReturnTypeSize, false, false /* TODO */, Storage::Register, 0);
|
||||||
static_assert(IsIntegral<ReturnType> || ReturnTypeSize <= AbiType::RegisterSize);
|
static_assert(IsIntegral<ReturnType> || ReturnTypeSize <= AbiType::RegisterSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +271,7 @@ namespace ams::svc::codegen::impl {
|
||||||
const auto location = param.GetLocation(i);
|
const auto location = param.GetLocation(i);
|
||||||
if (location.GetStorage() == Storage::Register) {
|
if (location.GetStorage() == Storage::Register) {
|
||||||
reg_allocator.Allocate(location.GetIndex());
|
reg_allocator.Allocate(location.GetIndex());
|
||||||
dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), param.GetTypeSize(), param.GetPassedSize(), param.IsPassedByPointer(), Storage::Register, location.GetIndex());
|
dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), param.GetTypeSize(), param.GetPassedSize(), param.IsPassedByPointer(), param.IsBoolean(), Storage::Register, location.GetIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,7 +282,7 @@ namespace ams::svc::codegen::impl {
|
||||||
const auto location = param.GetLocation(i);
|
const auto location = param.GetLocation(i);
|
||||||
if (location.GetStorage() == Storage::Stack) {
|
if (location.GetStorage() == Storage::Stack) {
|
||||||
const size_t free_reg = reg_allocator.AllocateFirstFree();
|
const size_t free_reg = reg_allocator.AllocateFirstFree();
|
||||||
dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), param.GetTypeSize(), param.GetPassedSize(), param.IsPassedByPointer(), Storage::Register, free_reg);
|
dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), param.GetTypeSize(), param.GetPassedSize(), param.IsPassedByPointer(), param.IsBoolean(), Storage::Register, free_reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,7 +292,7 @@ namespace ams::svc::codegen::impl {
|
||||||
const size_t type_size = param.GetTypeSize();
|
const size_t type_size = param.GetTypeSize();
|
||||||
for (size_t sz = 0; sz < type_size; sz += AbiType::RegisterSize) {
|
for (size_t sz = 0; sz < type_size; sz += AbiType::RegisterSize) {
|
||||||
const size_t free_reg = reg_allocator.AllocateFirstFree();
|
const size_t free_reg = reg_allocator.AllocateFirstFree();
|
||||||
dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), type_size, type_size, false, Storage::Register, free_reg);
|
dst_layout.AddSingle(param.GetIdentifier(), param.GetArgumentType(), type_size, type_size, false, param.IsBoolean(), Storage::Register, free_reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace ams::svc::codegen::impl {
|
||||||
AllocateStackSpace,
|
AllocateStackSpace,
|
||||||
FreeStackSpace,
|
FreeStackSpace,
|
||||||
MoveRegister,
|
MoveRegister,
|
||||||
|
ConvertToBoolean,
|
||||||
LoadFromStack,
|
LoadFromStack,
|
||||||
LoadPairFromStack,
|
LoadPairFromStack,
|
||||||
StoreToStack,
|
StoreToStack,
|
||||||
|
@ -47,6 +48,7 @@ namespace ams::svc::codegen::impl {
|
||||||
META_CODE_OPERATION_KIND_ENUM_CASE(AllocateStackSpace);
|
META_CODE_OPERATION_KIND_ENUM_CASE(AllocateStackSpace);
|
||||||
META_CODE_OPERATION_KIND_ENUM_CASE(FreeStackSpace);
|
META_CODE_OPERATION_KIND_ENUM_CASE(FreeStackSpace);
|
||||||
META_CODE_OPERATION_KIND_ENUM_CASE(MoveRegister);
|
META_CODE_OPERATION_KIND_ENUM_CASE(MoveRegister);
|
||||||
|
META_CODE_OPERATION_KIND_ENUM_CASE(ConvertToBoolean);
|
||||||
META_CODE_OPERATION_KIND_ENUM_CASE(LoadFromStack);
|
META_CODE_OPERATION_KIND_ENUM_CASE(LoadFromStack);
|
||||||
META_CODE_OPERATION_KIND_ENUM_CASE(LoadPairFromStack);
|
META_CODE_OPERATION_KIND_ENUM_CASE(LoadPairFromStack);
|
||||||
META_CODE_OPERATION_KIND_ENUM_CASE(StoreToStack);
|
META_CODE_OPERATION_KIND_ENUM_CASE(StoreToStack);
|
||||||
|
@ -117,6 +119,7 @@ namespace ams::svc::codegen::impl {
|
||||||
META_CODE_OPERATION_KIND_GENERATE_CODE(AllocateStackSpace)
|
META_CODE_OPERATION_KIND_GENERATE_CODE(AllocateStackSpace)
|
||||||
META_CODE_OPERATION_KIND_GENERATE_CODE(FreeStackSpace)
|
META_CODE_OPERATION_KIND_GENERATE_CODE(FreeStackSpace)
|
||||||
META_CODE_OPERATION_KIND_GENERATE_CODE(MoveRegister)
|
META_CODE_OPERATION_KIND_GENERATE_CODE(MoveRegister)
|
||||||
|
META_CODE_OPERATION_KIND_GENERATE_CODE(ConvertToBoolean)
|
||||||
META_CODE_OPERATION_KIND_GENERATE_CODE(LoadFromStack)
|
META_CODE_OPERATION_KIND_GENERATE_CODE(LoadFromStack)
|
||||||
META_CODE_OPERATION_KIND_GENERATE_CODE(LoadPairFromStack)
|
META_CODE_OPERATION_KIND_GENERATE_CODE(LoadPairFromStack)
|
||||||
META_CODE_OPERATION_KIND_GENERATE_CODE(StoreToStack)
|
META_CODE_OPERATION_KIND_GENERATE_CODE(StoreToStack)
|
||||||
|
@ -185,6 +188,12 @@ namespace ams::svc::codegen::impl {
|
||||||
this->meta_code.AddOperation(op);
|
this->meta_code.AddOperation(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<size_t Reg>
|
||||||
|
constexpr void ConvertToBoolean() {
|
||||||
|
constexpr auto op = MetaCode::MakeOperation<OperationKind::ConvertToBoolean, Reg>();
|
||||||
|
this->meta_code.AddOperation(op);
|
||||||
|
}
|
||||||
|
|
||||||
template<size_t Reg, size_t Offset, size_t Size = 0>
|
template<size_t Reg, size_t Offset, size_t Size = 0>
|
||||||
constexpr void LoadFromStack() {
|
constexpr void LoadFromStack() {
|
||||||
constexpr auto op = MetaCode::MakeOperation<OperationKind::LoadFromStack, Reg, Offset, Size>();
|
constexpr auto op = MetaCode::MakeOperation<OperationKind::LoadFromStack, Reg, Offset, Size>();
|
||||||
|
|
|
@ -105,15 +105,16 @@ namespace ams::svc::codegen::impl {
|
||||||
size_t type_size;
|
size_t type_size;
|
||||||
size_t passed_size;
|
size_t passed_size;
|
||||||
bool passed_by_pointer;
|
bool passed_by_pointer;
|
||||||
|
bool is_boolean;
|
||||||
size_t num_locations;
|
size_t num_locations;
|
||||||
Location locations[MaxLocations];
|
Location locations[MaxLocations];
|
||||||
public:
|
public:
|
||||||
constexpr explicit Parameter()
|
constexpr explicit Parameter()
|
||||||
: identifier(), type(ArgumentType::Invalid), type_size(0), passed_size(0), passed_by_pointer(0), num_locations(0), locations()
|
: identifier(), type(ArgumentType::Invalid), type_size(0), passed_size(0), passed_by_pointer(0), is_boolean(0), num_locations(0), locations()
|
||||||
{ /* ... */ }
|
{ /* ... */ }
|
||||||
|
|
||||||
constexpr explicit Parameter(Identifier id, ArgumentType t, size_t ts, size_t ps, bool p, Location l)
|
constexpr explicit Parameter(Identifier id, ArgumentType t, size_t ts, size_t ps, bool p, bool b, Location l)
|
||||||
: identifier(id), type(t), type_size(ts), passed_size(ps), passed_by_pointer(p), num_locations(1), locations()
|
: identifier(id), type(t), type_size(ts), passed_size(ps), passed_by_pointer(p), is_boolean(b), num_locations(1), locations()
|
||||||
{
|
{
|
||||||
this->locations[0] = l;
|
this->locations[0] = l;
|
||||||
}
|
}
|
||||||
|
@ -142,6 +143,10 @@ namespace ams::svc::codegen::impl {
|
||||||
return this->passed_by_pointer;
|
return this->passed_by_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool IsBoolean() const {
|
||||||
|
return this->is_boolean;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr size_t GetNumLocations() const {
|
constexpr size_t GetNumLocations() const {
|
||||||
return this->num_locations;
|
return this->num_locations;
|
||||||
}
|
}
|
||||||
|
@ -169,6 +174,7 @@ namespace ams::svc::codegen::impl {
|
||||||
this->type_size == rhs.type_size &&
|
this->type_size == rhs.type_size &&
|
||||||
this->passed_size == rhs.passed_size &&
|
this->passed_size == rhs.passed_size &&
|
||||||
this->passed_by_pointer == rhs.passed_by_pointer &&
|
this->passed_by_pointer == rhs.passed_by_pointer &&
|
||||||
|
this->is_boolean == rhs.is_boolean &&
|
||||||
this->num_locations == rhs.num_locations))
|
this->num_locations == rhs.num_locations))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue