I've programmed a task scheduler for STM32 (ARM) MCU which enables multitasking. I can create concurrent tasks, each having an own allocated stack, as this is the most straightforward way to do it. These stacks are allocated on the heap. Since these stacks are static in size, which is a very inefficient way to use memory space, I'm planning to add dynamic stack reallocation.
My question is: If I reallocate a task's stack on another memory address and copy all stack contents and update the task (ie. stack pointer), can the task continue running without any problem, if I'm not using in the task's code any absolute address of the stack? Is the C compiler using relative addressing only in the stack even if I'm taking an address of a variable in the scope?
Example:
void A() {
int i = 0;
int* iPtr = &i;
}
In the case above the value of iPtr
will be a static address, or relative like currAddress-4
? (If I'm not passing it to another function, just using it inside the scope.)
So is there any way the compiler uses relative address with offset in this scope, or just uses the direct address of the variable?
If there is relative address handling then I can reallocate the stack freely on another memory space, if not then I can't, which would be a problem.
I didn't really find any good documentation about this, so that also would be appreciated!
If not this is the right approach, then how stack reallocation for tasks used to be implemented?
CodePudding user response:
Sorry to say it, but pointers are always absolute. You can confirm this by looking at the assembly of a small program that takes a pointer to a local variable and passes it to another function:
void set(int *p) {
*p = 42;
}
void bar(void) {
int l;
set(&l);
}
compiles to
set:
movs r3, #42
str r3, [r0] // store to absolute address in r0
bx lr
bar:
push {lr}
sub sp, sp, #12
add r0, sp, #4 // form absolute pointer to stack location [sp 4]
bl set
add sp, sp, #12
ldr pc, [sp], #4
https://godbolt.org/z/7EWoK3eda
This really couldn't work any other way: the function set
has to compile to code that will do the right thing whether it is passed a pointer to the stack, or static memory, or heap. Also, an sp-relative pointer wouldn't even make sense when passed to a function with a different stack frame and hence a different value for sp.
So if you try to relocate the stack out from under a C program, it is almost certain to break.
Normally, the way you avoid wasting a ton of memory on stack is with virtual memory: you allocate a large block of virtual address space for the task's stack. Then you map physical memory into only a small part of it. As the stack grows and touches previously unused pages, the MMU signals a page fault, which your OS handles by allocating and mapping another page of physical memory. Because the mapping of virtual to physical pages is arbitrary, the stack remains at a fixed virtual address whereas the physical memory underneath need not be contiguous. It could even be copied and remapped while the task is suspended.