I'm trying to read in the address from my c-pointer to a register using inline thumb assembly.
here's a reproducible:
static uint32_t volatile * volatile CurrentTaskStackPtr;
CurrentTaskStackPtr = (uint32_t *) 0x20000001;
__asm volatile("LDR R8, =%0" : : "i"(CurrentTaskStackPtr) );
Also, I'm trying to avoid changing the state of any 'context' registers, and that's why I use an immediate read.
I keep getting this error:
warning: 'asm' operand 0 probably does not match constraints
187 | __asm volatile("LDR R8, =%0" : : "i"(CurrentTaskStackPtr) );
I have tried using different constraint characters, but I'm not familiar enough with assembly to make any progress, any help would be appreciated.
Thanks.
"i"(CurrentTaskStackPtr)is asking for the value of a C variable as an immediate. That can only work if the C variable is a compile-time constant, likeuint32_t *const CurrentTaskStackPtr = .... But your variable isvolatile(separately from pointing tovolatile), so even with optimization enabled, you've forbidden the compiler from doing constant-propagation through the assignment to make"i"(0x20000001).If you want the address, take the address,
"i"(&CurrentTaskStackPtr).Or better, ask the compiler to have the address in R8 for you, instead of putting an
ldrpseudo-instruction into your asm template, unless you need to control how it materializes the address or something.See also https://stackoverflow.com/tags/inline-assembly/info and ARM inline asm: exit system call with value read from memory for an example of how this compiles.
The GCC manual (https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html) is explicit that the only guaranteed behaviour of an register asm local variable is picking the specified register for inline
asmstatements; it's not guaranteed to use that register at any other time.See also How can I indicate that the memory *pointed* to by an inline ASM argument may be used? for more about why the
"memory"clobber is necessary. Probably best to use that instead of dummy input/output operands; you don't want the compiler trying to optimize around a context-switch anyway.You might have a better time writing a context-switch function as
__attribute__((naked)), so you don't have to worry about when the compiler accesses local vars relative to the stack pointer. Changing the stack pointer inside anasmstatement is not officially supported. (https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#index-asm-clobbers - the clobber list shouldn't contain the stack pointer.)Except in a
nakedfunction, where you're writing the entire function's asm in a Basic Asm statement, and it can't inline into any callers since it's like__attribute__((noinline,noipa)), or like writing it in a separate.sfile and just defining a prototype.