1
0
Fork 0
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:
Michael Scire 2021-04-06 23:07:58 -07:00 committed by SciresM
parent 4b9e7c7d27
commit b3bd443636
5 changed files with 71 additions and 15 deletions

View file

@ -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) {

View file

@ -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{});

View file

@ -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:

View file

@ -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>();

View file

@ -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;