Date: Wed, 31 May 2023 08:20:13 +0100
A month or two ago I suggested that we should have a standard library
function to get the value of the stack pointer, and also the frame pointer.
Another useful function for analysing and manipulating the stack would be
as follows:
void set_stack_pointer_and_invoke( char *custom_stack, void
(*funcptr)(void) );
You would use this function to invoke another function with your own custom
stack, for example:
char *const mystack = new char[4096u];
set_stack_pointer_and_invoke( mystack + 4088u, SomeLibraryFunction );
Since the stack grows negatively on x86_64, I add 4088 to it to give it the
highest address for a 64-Bit value. Alternatively the function could take a
third parameter to indicate the size of the stack and let the compiler
decide how to calculate it. Here's one way of determining it:
bool stack_grows_positively_Detail(int *const p)
{
return static_cast<uintptr_t>(p) < static_cast<uintptr_t>(&p);
}
bool stack_grows_positively(void)
{
int i;
return stack_grows_positively_Detail(&i);
}
This would serve two purposes:
(1) If you have a recursive function that will re-enter thousands of times,
then you can temporarily allocate a stack in the gigabytes.
(2) If the stack isn't executable, and you need to execute the stack. Or,
if the stack _is_executable, and you want to prevent execution of the stack
(for added security when calling 3rd party library functions).
The x86_64 assembler for changing and later restoring the stack pointer is
as follows:
set_stack_pointer_and_invoke:
push r15 ; callee-saved
mov r15,rsp ; save the original stack pointer
mov rsp,rdi ; set the stack pointer
call rsi ; invoke the function pointer
mov rsp,r15 ; restore the original stack pointer
pop r15 ; restore the original value of r15
ret
I have this working for x86_64 up on GodBolt with support for exception
handling:
https://godbolt.org/z/M9544Meqq
function to get the value of the stack pointer, and also the frame pointer.
Another useful function for analysing and manipulating the stack would be
as follows:
void set_stack_pointer_and_invoke( char *custom_stack, void
(*funcptr)(void) );
You would use this function to invoke another function with your own custom
stack, for example:
char *const mystack = new char[4096u];
set_stack_pointer_and_invoke( mystack + 4088u, SomeLibraryFunction );
Since the stack grows negatively on x86_64, I add 4088 to it to give it the
highest address for a 64-Bit value. Alternatively the function could take a
third parameter to indicate the size of the stack and let the compiler
decide how to calculate it. Here's one way of determining it:
bool stack_grows_positively_Detail(int *const p)
{
return static_cast<uintptr_t>(p) < static_cast<uintptr_t>(&p);
}
bool stack_grows_positively(void)
{
int i;
return stack_grows_positively_Detail(&i);
}
This would serve two purposes:
(1) If you have a recursive function that will re-enter thousands of times,
then you can temporarily allocate a stack in the gigabytes.
(2) If the stack isn't executable, and you need to execute the stack. Or,
if the stack _is_executable, and you want to prevent execution of the stack
(for added security when calling 3rd party library functions).
The x86_64 assembler for changing and later restoring the stack pointer is
as follows:
set_stack_pointer_and_invoke:
push r15 ; callee-saved
mov r15,rsp ; save the original stack pointer
mov rsp,rdi ; set the stack pointer
call rsi ; invoke the function pointer
mov rsp,r15 ; restore the original stack pointer
pop r15 ; restore the original value of r15
ret
I have this working for x86_64 up on GodBolt with support for exception
handling:
https://godbolt.org/z/M9544Meqq
Received on 2023-05-31 07:20:16