Skip to main content
Arduino

Return to Revisions

4 of 4
Commonmark migration

Accessing a C++ static variable from gcc inline asm

For some reason I want to mix a bit of assembly with C++ (not C).
To allow the code to be compilable using the standard Arduino IDE, I don't want to use direct assembly source.
I don't want to use a wrapper C file either.

My problem is as follows:

I have a class with a single instance (implementing some kind of driver) that looks like this:

class cDriver {
public:
 char ISR_param;
 // ...
};
cDriver Driver;

If I want to access the ISR_param of this single instance from within an ISR, I can do something like:

ISR (TIMER2_COMPA_Vect) {
 do_something_with (Driver.ISR_param);
}

This works like a charm: the address of Driver.ISR_param beign a constant, the compiler simply generates an lds r24, &Driver.ISR_param instruction to load the proper byte as a parameter for do_something_with.

Now when I try to replicate the same mechanism with inline assembler, things get a lot more complicated.

The address of Driver.ISR_param is only known to the C++ compiler as an mangled label, and I can't find a way to pass it to the inline assembler to generate the equivalent lds r24, <&Driver.ISR_param>.

trying to remane the variable

The renaming of variables for assembly like so:

char global_var asm("my_var");

and an attempt to use it like so:

asm ("lds r24, my_var\n");

will compile, but produce a linker error (my_var is undefined).

Looking at the object symbol table, the only label for global_var is a C++-like mangled name.
However hard I tried this renaming trick, I could not bring the compiler to generate a my_var label.

trying to use asm constraints

A constraint like

asm (lds r24, %0\n" : : "I"(&global_var));

will simply not compile. I scoured the possible parameter types and could not find a way to let the assembler know about this bloody address.

a terribly awkward workaround

The only way I found to make the compiler generate this dreaded lds r24,... instruction is to perform an actual function call.

So you can do something like:

__attribute__((always_inline)) give_me_my_friggin_variable(char data)
{
 asm volatile ("cmp %0,%0\n"::"r"(data));
} 
ISR (TIMER2_COMPA_Vect, ISR_NAKED) {
 <some prologue to save SREG and all needed registers>
 //...
 give_me_my_friggin_variable(Driver.ISR_param);
 // continue assembly code with r24 properly initialized
}

That will generate:

 lds r24, <the proper address> // added by the compiler...
 cmp r24,r24 // ...because of the register constraint here

Well, that sort of works, but at the cost of generating a totally useless instruction.

so my question is...

Is there a simpler way to let the assembler know about addresses of C++ static variables?

lang-cpp

AltStyle によって変換されたページ (->オリジナル) /