Does anyone know how to access the stack pointer in GCC? I need it for a fast context switch.
Regards,
Peter
Does anyone know how to access the stack pointer in GCC? I need it for a fast context switch.
Regards,
Peter
Use assembler?
Leon
You could take the address of your first argument or an auto variable or something and do some pointer arithmetic to find your stack frame.
You might be able to do it with gcc’s [explicit register variables feature too.
A little inline assembler is probably better/easier than either of these, though.
It’s also possible to implement coroutines / context switches using longjmp() on some architectures.](Explicit Reg Vars (Using the GNU Compiler Collection (GCC)))
I tested a context switching routine without any assembler code by manipulating the SP register directly as a variable.
I used this method in various ports of my project, it is very efficient.
It is described here:
oh right, I’d forgotten about that post of yours. Very clever use of the asm() statement, IMHO.
gdisirio:
void DoSwitch(Thread *otp, Thread *ntp) {
register struct intctx *sp asm(“sp”);
otp->p_ctx.r13 = sp;
sp = ntp->p_ctx.r13;
asm (“” : : “r” (sp) : “r4”, “r5”, “r6”, “r7”, “r8”, “r9”, “r10”, “r11”, “lr”);
}
This assumes that registers are saved in the prologue.
The compiler is free to do it after sp has been changed.
And it could save some of the registers in r0-r3 & ip.
If you compile with optimization it might completely remove the asm because there are no outputs. You should add volatile.
I really think this stuff should be written in asm.
If you put all registers in the context structure, it can be written in two instructions in non-thumb code:
stmia r0,{r4,r5,r6,r7,r8,r9,r10,r11,sp,lr}
ldmia r1,{r4,r5,r6,r7,r8,r9,r10,r11,sp,pc}
I also think “asm” should become “asm volatile” but it works anyway, I tested it with GCC 3.x, 4.1.x, 4.2.x and 4.3.0 in any optimization level, the code, of course, is highly GCC-specific.
GCC does not seem to delay the register saving after the prologue. Anyway it could be enforced by adding another “asm volatile” before accessing “sp”.
As example:
void DoSwitch(Thread *otp, Thread *ntp) {
register struct intctx *sp asm("sp");
asm volatile ("" : : : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "lr");
otp->p_ctx.r13 = sp;
sp = ntp->p_ctx.r13;
asm volatile ("" : : "r" (sp));
}
The function generates exactly 4 ARM instructions (5 if you use interworking): stmia, str sp, ldr sp, ldmia (, bx).
It also works for AVR and MSP430 by just changing the register names.
I really think this stuff should be written in asm.
I usually do, it is just a curiosity.
Giovanni