mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +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");
|
||||
}
|
||||
|
||||
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>
|
||||
static ALWAYS_INLINE void LoadFromStack() {
|
||||
if constexpr (Size == 4) {
|
||||
|
|
|
@ -317,6 +317,38 @@ namespace ams::svc::codegen::impl {
|
|||
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>
|
||||
struct TypeIndexFilter {
|
||||
|
||||
|
@ -436,6 +468,9 @@ namespace ams::svc::codegen::impl {
|
|||
mcg.template AllocateStackSpace<UsedStackSpace>();
|
||||
}
|
||||
|
||||
/* Sanitize all input booleans. */
|
||||
SanitizeInputBooleans<Conversion>(mcg);
|
||||
|
||||
/* Generate code for before operations. */
|
||||
if constexpr (Conversion::NumBeforeOperations > 0) {
|
||||
allocator = GenerateBeforeOperations<Conversion, InitialAllocator>(mcg, typename Conversion::BeforeOperations{});
|
||||
|
|
|
@ -36,21 +36,21 @@ namespace ams::svc::codegen::impl {
|
|||
: 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++) {
|
||||
if (this->parameters[i].Is(id)) {
|
||||
this->parameters[i].AddLocation(Location(s, idx));
|
||||
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;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
|
@ -115,6 +115,7 @@ namespace ams::svc::codegen::impl {
|
|||
|
||||
constexpr size_t ArgumentTypeSize = AbiType::template Size<ArgType>;
|
||||
constexpr bool PassedByPointer = IsPassedByPointer<AbiType, ArgType>;
|
||||
constexpr bool IsBoolean = std::same_as<ArgType, bool>;
|
||||
constexpr size_t ArgumentPassSize = PassedByPointer ? AbiType::PointerSize : ArgumentTypeSize;
|
||||
|
||||
/* 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;
|
||||
if constexpr (!PassedByPointer && IsIntegralOrUserPointer<ArgType> && ArgumentTypeSize > AbiType::RegisterSize) {
|
||||
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;
|
||||
} else {
|
||||
/* Argument went on stack, so stop allocating arguments in registers. */
|
||||
NGRN = AbiType::RegisterCount;
|
||||
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
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 {
|
||||
/* Argument went on stack, so stop allocating arguments in registers. */
|
||||
NGRN = AbiType::RegisterCount;
|
||||
|
@ -155,7 +156,7 @@ namespace ams::svc::codegen::impl {
|
|||
/* TODO: Stack pointer alignment is only ensured for aapcs64. */
|
||||
/* 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. */
|
||||
if constexpr (!std::is_same<ReturnType, void>::value) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -270,7 +271,7 @@ namespace ams::svc::codegen::impl {
|
|||
const auto location = param.GetLocation(i);
|
||||
if (location.GetStorage() == Storage::Register) {
|
||||
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);
|
||||
if (location.GetStorage() == Storage::Stack) {
|
||||
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();
|
||||
for (size_t sz = 0; sz < type_size; sz += AbiType::RegisterSize) {
|
||||
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:
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace ams::svc::codegen::impl {
|
|||
AllocateStackSpace,
|
||||
FreeStackSpace,
|
||||
MoveRegister,
|
||||
ConvertToBoolean,
|
||||
LoadFromStack,
|
||||
LoadPairFromStack,
|
||||
StoreToStack,
|
||||
|
@ -47,6 +48,7 @@ namespace ams::svc::codegen::impl {
|
|||
META_CODE_OPERATION_KIND_ENUM_CASE(AllocateStackSpace);
|
||||
META_CODE_OPERATION_KIND_ENUM_CASE(FreeStackSpace);
|
||||
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(LoadPairFromStack);
|
||||
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(FreeStackSpace)
|
||||
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(LoadPairFromStack)
|
||||
META_CODE_OPERATION_KIND_GENERATE_CODE(StoreToStack)
|
||||
|
@ -185,6 +188,12 @@ namespace ams::svc::codegen::impl {
|
|||
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>
|
||||
constexpr void LoadFromStack() {
|
||||
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 passed_size;
|
||||
bool passed_by_pointer;
|
||||
bool is_boolean;
|
||||
size_t num_locations;
|
||||
Location locations[MaxLocations];
|
||||
public:
|
||||
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)
|
||||
: identifier(id), type(t), type_size(ts), passed_size(ps), passed_by_pointer(p), num_locations(1), locations()
|
||||
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), is_boolean(b), num_locations(1), locations()
|
||||
{
|
||||
this->locations[0] = l;
|
||||
}
|
||||
|
@ -142,6 +143,10 @@ namespace ams::svc::codegen::impl {
|
|||
return this->passed_by_pointer;
|
||||
}
|
||||
|
||||
constexpr bool IsBoolean() const {
|
||||
return this->is_boolean;
|
||||
}
|
||||
|
||||
constexpr size_t GetNumLocations() const {
|
||||
return this->num_locations;
|
||||
}
|
||||
|
@ -169,6 +174,7 @@ namespace ams::svc::codegen::impl {
|
|||
this->type_size == rhs.type_size &&
|
||||
this->passed_size == rhs.passed_size &&
|
||||
this->passed_by_pointer == rhs.passed_by_pointer &&
|
||||
this->is_boolean == rhs.is_boolean &&
|
||||
this->num_locations == rhs.num_locations))
|
||||
{
|
||||
return false;
|
||||
|
|
Loading…
Reference in a new issue