Impossible constraint in 'asm': __asm__ __volatile__ - c

I trying since a few days to write a very simple inline assembler code, but nothing worked. I have as IDE NetBeans and as compiler MinGW.
My latest code is:
uint16 readle_uint16(const uint8 * buffer, int offset) {
unsigned char x, y, z;
unsigned int PORTB;
__asm__ __volatile__("\n"
"addl r29,%0\n"
"addl r30,%1\n"
"addl r31,%2\n"
"lpm\n"
"out %3,r0\n"
: "=I" (PORTB)
: "r" (x), "r" (y), "r" (z)
);
return value;
}
But I get everytime the same message "error: impossible constraint in 'asm'".
I tried to write all in a single line or to use different asm introductions. I have no idea what I can do otherwise.

Notice that gcc's inline assembly syntax is
asm [volatile] ( AssemblerTemplate
: OutputOperands
[ : InputOperands
[ : Clobbers ] ])
After the assembler instructions first come the output operands, then the inputs.
As #DavidWohlferd said, I is for "constant greater than −1, less than 64 "constants ("immediates").
While the out instruction in fact requires a constant value from that range, PORTB is not that constant value. (You can see that for yourself if you look into the corresponding avr/ioXXXX.h file for your controller, where you may find something like #define PORTB _SFR_IO8(0x05).)
Also, not all IO registers may be accessible via out/in; especially the bigger controllers have more than 64 IO registers, but only the first 64 can be accessed as such. However, all IO registers can be accessed at their memory-mapped address through lds/sts. So, depending on which register on which controller you want to access you may not be able to use out for that register at all, but you can always use sts instead. If you want your code to be portable you'll have to take that into account, like suggested here for example.
If you know that PORTB is one of the first 64 IO registers on your controller, you can use
"I" (_SFR_IO_ADDR( PORTB )) with out, else use
"m" ( PORTB ) with sts.
So this:
__asm__ __volatile__("\n"
"addl r29,%0\n"
"addl r30,%1\n"
"addl r31,%2\n"
"lpm\n"
"out %3,r0\n"
: /* No output operands here */
: "r" (x), "r" (y), "r" (z), "I" (_SFR_IO_ADDR( PORTB ))
);
should get you rid of that "impossible constraint" error. Although the code still does not make any sense, mostly because you're using "random", uninitialized data as input. You clobber registers r29-r31 without declaring them, and I'm totally not sure what your intention is with all the code before the lpm.

As EOF says, the I constraint is used for parameters that are constant (see the AVR section at https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html). By putting this parameter after the first colon (and by using an =), you are saying this is an output. Outputting to a constant makes no sense.
Also:
You list x, y, and z as inputs to the asm (by putting them after the second colon), but they never get assigned a value. An input that has never been assigned a value makes no sense.
You are (apparently) modifying registers 29-31, but you don't tell the compiler that you are doing so?
There's more, but I just can't follow what you think this code is supposed to do. You might want to take some time to look thru the gcc docs for asm to understand how this works.

Related

How do I access a local variable using ARM assembly language?

I use the following piece of assembly code to enter the critical section in ARM Cortex-M4.
The question is, how can I access the local variable primeMask?
volatile uint8_t primaskValue;
asm(
"MRS R0, PRIMASK \n"
"CPSID i \n"
"STRB R0,%[output] \n"
:[output] "=r" (primaskValue)
);
The %[output] string in the asm code is replaced by the register used to hold the value specified by the constraint [output] "=r" (primaskValue) which will be a register used as the value of primaskValue afterwards. So within the block of the asm code, that register is the location of primaskValue.
If you instead used the constraint string "+r", that would be input and output (so the register would be initialized with the prior value of primaskValue as well as being used as the output value)
Since primaskValue had been declared as volatile this doesn't make a lot of sense -- it is not at all clear what (if anything) volatile means on a local variable.

Mixing C and assembly and its impact on registers

Consider the following C and (ARM) assembly snippet, which is to be compiled with GCC:
__asm__ __volatile__ (
"vldmia.64 %[data_addr]!, {d0-d1}\n\t"
"vmov.f32 q12, #0.0\n\t"
: [data_addr] "+r" (data_addr)
: : "q0", "q12");
for(int n=0; n<10; ++n){
__asm__ __volatile__ (
"vadd.f32 q12, q12, q0\n\t"
"vldmia.64 %[data_addr]!, {d0-d1}\n\t"
: [data_addr] "+r" (data_addr),
:: "q0", "q12");
}
In this example, I am initialising some SIMD registers outside the loop and then having C handle the loop logic, with those initialised registers being used inside the loop.
This works in some test code, but I'm concerned of the risk of the compiler clobbering the registers between snippets. Is there any way of ensuring this doesn't happen? Can I infer any assurances about the type of registers that are going to be used in a snippet (in this case, that no SIMD registers will be clobbered)?
In general, there's not a way to do this in gcc; clobbers only guarantee that registers will be preserved around the asm call. If you need to ensure that the registers are saved between two asm sections, you will need to store them to memory in the first, and reload in the second.
Edit: After much fiddling around I've come to the conclusion this is much harder to solve in general using the strategy described below than I initially thought.
The problem is that, particularly when all the registers are used, there is nothing to stop the first register stash from overwriting another. Whether there is some trick to play with using direct memory writes that can be optimised away I don't know, but initial tests would suggest the compiler might still choose to clobber not-yet-stashed registers
For the time being and until I have more information, I'm unmarking this answer as correct and this answer should treated as probably wrong in the general case. My conclusion is this that such local protection of registers needs better support in the compiler to be useful
This absolutely is possible to do reliably. Drawing on the comments by #PeterCordes as well as the docs and a couple of useful bug reports (gcc 41538 and 37188) I came up with the following solution.
The point that makes it valid is the use of temporary variables to make sure the registers are maintained (logically, if the loop clobbers them, then they will be reloaded). In practice, the temporary variables are optimised away which is clear from inspection of the resultant asm.
// d0 and d1 map to the first and second values of q0, so we use
// q0 to reduce the number of tmp variables we pass around (instead
// of using one for each of d0 and d1).
register float32x4_t data __asm__ ("q0");
register float32x4_t output __asm__ ("q12");
float32x4_t tmp_data;
float32x4_t tmp_output;
__asm__ __volatile__ (
"vldmia.64 %[data_addr]!, {d0-d1}\n\t"
"vmov.f32 %q[output], #0.0\n\t"
: [data_addr] "+r" (data_addr),
[output] "=&w" (output),
"=&w" (data) // we still need to constrain data (q0) as written to.
::);
// Stash the register values
tmp_data = data;
tmp_output = output;
for(int n=0; n<10; ++n){
// Make sure the registers are loaded correctly
output = tmp_output;
data = tmp_data;
__asm__ __volatile__ (
"vadd.f32 %[output], %[output], q0\n\t"
"vldmia.64 %[data_addr]!, {d0-d1}\n\t"
: [data_addr] "+r" (data_addr),
[output] "+w" (output),
"+w" (data) // again, data (q0) was written to in the vldmia op.
::);
// Remember to stash the registers again before continuing
tmp_data = data;
tmp_output = output;
}
It's necessary to instruct the compiler that q0 is written to in the last line of each asm output constraint block, so it doesn't think it can reorder the stashing and reloading of the data register resulting in the asm block getting invalid values.

How does this sfrw(x,x_) macro work (msp430)?

I just ran into an interesting phenomenon with msp430f5529 (TI launchpad). After trying different approaches I was able to find a solution, but I don't understand what is going on here.
This code is part of a timer interrupt service routine (ISR). The special function register (SFR) TA0IV is supposed to hold the value of the interrupt number that triggered the ISR.
1 unsigned int index;
2
3 index = TA0IV; // Gives wrong value: 19874
4 index = *((volatile unsigned int *) TA0IV_); // Correct value: 4
TA0IV is defined with macros here:
5 #define sfrw_(x,x_) volatile __MSPGCC_PERIPHERAL__ unsigned int x __asm__("__" #x)
6 #define sfrw(x,x_) extern sfrw_(x,x_)
7 #define TA0IV_ 0x036E /* Timer0_A5 Interrupt Vector Word */
8 sfrw(TA0IV, TA0IV_);
What does this part of the first macro on line 5 do?
asm("__" #x)
Why is there no "x_" on the right hand side in the macro on line 5?
Last and most important question: Why does the usual typecasting on line 4 work as expected, but the one on line 3 doesn't?
BTW I use gcc-4.7.0.
Edit: More info
9 #define __MSPGCC_PERIPHERAL__ __attribute__((__d16__))
1) The # is a preprocessor "stringify" operator. You can see the impact of this using the -E compiler switch. Google "c stringify" for details.
2) Couldn't say. It isn't required that all parameters get used, and apparently whoever wrote this decided they didn't need it.
3) I'll take a shot at this one, but since I don't have all the source code or the hardware and can't experiment, I probably won't get it quite right. Maybe close enough for what you need though.
The first thing to understand is what the asm bit is doing. Normally (ok, sometimes) when you declare a variable (foo), the compiler assigns its own 'internal' name to the variable (ie _foo). However, when interfacing with asm modules (or other languages), sometimes you need to be able to specify the exact name to use, not allowing the compiler to mangle it in any fashion. That's what this asm is doing (see Asm Labels). So when you brush aside all the #define nonsense, what you've got is:
extern volatile __MSPGCC_PERIPHERAL__ unsigned int TA0IV __asm__("__TA0IV");
Since the definition you have posted is "extern," presumably somewhere (not shown), there's a symbol named __TA0IV that's getting defined. And since accessing it isn't working right, it appears that it is getting MIS-defined.
With the caveat that I HAVEN'T TRIED THIS, I would find this to be somewhat more readable:
#define TA0IV_ 0x036E
inline int ReadInterruptNumber()
{
int retval;
asm volatile("movl (%c1), %0": "=rm" (retval) : "i" (TA0IV_));
return retval;
}
FWIW.

Errors using inline assembly in C

I'm trying my hand at assembly in order to use vector operations, which I've never really used before, and I'm admittedly having a bit of trouble grasping some of the syntax.
The relevant code is below.
unit16_t asdf[4];
asdf[0] = 1;
asdf[1] = 2;
asdf[2] = 3;
asdf[3] = 4;
uint16_t other = 3;
__asm__("movq %0, %%mm0"
:
: "m" (asdf));
__asm__("pcmpeqw %0, %%mm0"
:
: "r" (other));
__asm__("movq %%mm0, %0" : "=m" (asdf));
printf("%u %u %u %u\n", asdf[0], asdf[1], asdf[2], asdf[3]);
In this simple example, I'm trying to do a 16-bit compare of "3" to each element in the array. I would hope that the output would be "0 0 65535 0". But it won't even assemble.
The first assembly instruction gives me the following error:
error: memory input 0 is not directly addressable
The second instruction gives me a different error:
Error: suffix or operands invalid for `pcmpeqw'
Any help would be appreciated.
You can't use registers directly in gcc asm statements and expect them to match up with anything in other asm statements -- the optimizer moves things around. Instead, you need to declare variables of the appropriate type and use constraints to force those variables into the right kind of register for the instruction(s) you are using.
The relevant constraints for MMX/SSE are x for xmm registers and y for mmx registers. For your example, you can do:
#include <stdint.h>
#include <stdio.h>
typedef union xmmreg {
uint8_t b[16];
uint16_t w[8];
uint32_t d[4];
uint64_t q[2];
} xmmreg;
int main() {
xmmreg v1, v2;
v1.w[0] = 1;
v1.w[1] = 2;
v1.w[2] = 3;
v1.w[3] = 4;
v2.w[0] = v2.w[1] = v2.w[2] = v2.w[3] = 3;
asm("pcmpeqw %1,%0" : "+x"(v1) : "x"(v2));
printf("%u %u %u %u\n", v1.w[0], v1.w[1], v1.w[2], v1.w[3]);
}
Note that you need to explicitly replicate the 3 across all the relevant elements of the second vector.
From intel reference manual:
PCMPEQW mm, mm/m64 Compare packed words in mm/m64 and mm for equality.
PCMPEQW xmm1, xmm2/m128 Compare packed words in xmm2/m128 and xmm1 for equality.
Your pcmpeqw uses an "r" register which is wrong. Only "mm" and "m64" registers
valter
The code above failed when expanding the asm(), it never tried to even assemble anything. In this case, you are trying to use the zeroth argument (%0), but you didn't give any.
Check out the GCC Inline assembler HOWTO, or read the relevant chapter of your local GCC documentation.
He's right, the optimizer is changing register contents. Switching to intrinsics and using volatile to keep things a little more in place might help.

C preprocessor variable constant?

I'm writing a program where a constant is needed but the value for the constant will be determined during run time. I have an array of op codes from which I want to randomly select one and _emit it into the program's code. Here is an example:
unsigned char opcodes[] = {
0x60, // pushad
0x61, // popad
0x90 // nop
}
int random_byte = rand() % sizeof(opcodes);
__asm _emit opcodes[random_byte]; // optimal goal, but invalid
However, it seems _emit can only take a constant value. E.g, this is valid:
switch(random_byte) {
case 2:
__asm _emit 0x90
break;
}
But this becomes unwieldy if the opcodes array grows to any considerable length, and also essentially eliminates the worth of the array since it would have to be expressed in a less attractive manner.
Is there any way to neatly code this to facilitate the growth of the opcodes array? I've tried other approaches like:
#define OP_0 0x60
#define OP_1 0x61
#define OP_2 0x90
#define DO_EMIT(n) __asm _emit OP_##n
// ...
unsigned char abyte = opcodes[random_byte];
DO_EMIT(abyte)
In this case, the translation comes out as OP_abyte, so it would need a call like DO_EMIT(2), which forces me back to the switch statement and enumerating every element in the array.
It is also quite possible that I have an entirely invalid approach here. Helpful feedback is appreciated.
I'm not sure what compiler/assembler you are using, but you could do what you're after in GCC using a label. At the asm site, you'd write it as:
asm (
"target_opcode: \n"
".byte 0x90\n" ); /* Placeholder byte */
...and at the place where you want to modify that code, you'd use:
extern volatile unsigned char target_opcode[];
int random_byte = rand() % sizeof(opcodes);
target_opcode[0] = random_byte;
Perhaps you can translate this into your compiler's dialect of asm.
Note that all the usual caveats about self-modifying code apply: the code segment might not be writeable, and you may have to flush the I-cache before executing the modified code.
You won't be able to do any randomness in the C preprocessor AFAIK. The closest you could get is generating the random value outside. For instance:
cpp -DRND_VAL=$RANDOM ...
(possibly with a modulus to maintain the value within a range), at least in UNIX-based systems. Then, you can use the definition value, that will be essentially random.
How about
char operation[4]; // is it really only 1 byte all the time?
operation[0] = random_whatever();
operation[1] = 0xC3; // RET
void (*func)() = &operation[0];
func();
Note that in this example you'd need to add a RET instruction to the buffer, so that in the end you end up at the right instruction after calling func().
Using an _emit at runtime into your program code is kind of like compiling the program you're running while the program is running.
You should describe your end-goal rather than just your idea of using _emit at runtime- there might be abetter way to accomplish what you want. Maybe you can write your opcodes to a regular data array and somehow make that bit of memory executable. That might be a little tricky due to security considerations, but it can be done.

Resources