# REP30: Handling of `Microsoft_x86_64`'s register parameter stack area
###### tags: `microsoft` `abi` `stack` `registers` `rep` `design`
**Status**: `🟢 READY`
## What is this?
`Microsoft_x86_64` reserves 4 stack slots to store the register arguments ([docs](https://learn.microsoft.com/en-us/cpp/build/stack-usage?view=msvc-170#stack-allocation)).
We need to treat them correctly.
## Why is this important?
Right now, we're emitting out-of-bound accesses on the stack, which is incorrect.
## Example
[Godbolt](https://godbolt.org/z/55YWvoMPf).
```c
long long use_reserved_space(long long arg) {
int a = 1;
return arg;
}
void asd() {
use_reserved_space(1);
}
```
Output:
```x86asm
use_reserved_space PROC
$LN3:
mov QWORD PTR [rsp+8], rcx
sub rsp, 24
mov DWORD PTR a$[rsp], 1
mov rax, QWORD PTR arg$[rsp]
add rsp, 24
ret 0
use_reserved_space ENDP
```
Note how `rcx` (`arg`) is moved on the stack *below* the return address.
Current output:
```c
#include "types-and-globals.h"
#include "helpers.h"
_ABI(Microsoft_x86_64)
uint64_t use_reserved_space(uint32_t argument_0) {
struct _PACKED struct_1 {
uint32_t offset_0;
uint8_t padding_at_4[20];
} _stack;
// NOTE: out-of-bound write
*((generic64_t *) ((pointer_or_number64_t) &(&_stack)[1] + 8)) = argument_0;
_stack.offset_0 = 1;
// NOTE: out-of-bound read
return *((generic64_t *) ((pointer_or_number64_t) &(&_stack)[1] + 8));
}
```
> **NOTE**: MIPS also, technically, requires the same thing, but I wasn't able to force a compiler (either gcc or clang) to use this space. They allocate it, but never store anything there.
## Design
The current situation is:
1. `DetectABI` builds an initial `RawFunctionDefinition`, ignoring the stack.
2. `DetectStackSize` adds to such definition a `StackArgumentsType` `struct` with the size of stack arguments.
Such `struct` includes the "register parameter stack area".
This is not entirely incorrect, since one could consider that area as unused stack arguments.
3. `DataLayoutAnalysis` populates the `struct` above, creating fields for the "register parameter stack area" as well.
4. `ConvertFunctionsToCABI` upgrades the `RawFunctionDefinition` to a `CABIFunctionDefinition` with ABI `Microsoft_x86_64`.
This is the problematic part.
Our desired output would be:
```c
#include "types-and-globals.h"
#include "helpers.h"
_ABI(Microsoft_x86_64)
uint64_t use_reserved_space(uint32_t argument_0) {
struct _PACKED struct_1 {
uint32_t offset_0;
uint8_t padding_at_4[20];
} _stack;
struct _PACKED struct_2 {
uint64_t offset_0;
uint8_t padding_at_8[24];
} _stack2;
_stack2.offset_0 = argument_0;
_stack.offset_0 = 1;
return _stack2.offset_0;
}
```
We need to:
* Extend [`model::Function`](https://docs.rev.ng/references/model/#Function) to have a `StackFrameType2` field (TODO: find a better name) that represents this area.
* Extend `ConvertFunctionsToCABI` for `Microsoft_x86_64` so that does the following:
* Move the last 4 stack slots of `RawFunctionDefintion::StackArgumentsType` to `model::Function::StackFrameType2` and consequently shrink `StackArgumentsType`.
* Process the stack arguments ignoring the second part that has been moved.
If any of these is not viable, we can simply bail out the conversion and stick with the `RawFunctionDefinition`.
For instance, if, for some reason, we have field crossing he boundary where we want to split, we can just bail out.
* Extend `SegregateStackAccesses` to emit a second variable for the `StackFrameType2`.
Also, we need to extend the rest of the decompilation pipeline to emit it as well.
This is pretty similar to what we are already doing with `_stack`, it shouldn't be problematic.
In the future, optionally, we need to:
* Extend `DataLayoutAnalysis` to report somehow how much of a `Function::StackFrameType` is read before being written to in at least one path.
This will enable us to reduce false positives.