I have to write inline assembly code that executes a custom instruction that I integrated into my hardware.
Depending on what hardware is to find on the actual chip, the instruction behaves differently. My assembly looks as follows:
asm volatile (
" instr_generic %1, %2, %0 \n\t"
: "=r" (c)
: "r" (a), "r" (b)
: "%g0"
);
This instr_generic could now execute either an addition or subtraction for example, depending on what is on the hardware.
Now, instead of instr_generic I wanna write cust_add or cust_sub and this should then be replaced with instr_generic. In other words, it should look like this here
#define cust_add instr_generic
...
asm volatile (
" cust_add %1, %2, %0 \n\t"
: "=r" (c)
: "r" (a), "r" (b)
: "%g0"
);
But I guess I can't use the pre-processor in this context to replace inline assemly is that right? Is there another way to do that easily?
...
#define cust(arg) \
asm volatile (
" " #arg " %1, %2, %0 \n\t" \
: "=r" (c) \
: "r" (a), "r" (b) \
: "%g0" \
)
...
cust(cust_add);
I would either do an if-then-else with the different solutions based on runtime detection of the processor, or to squeeze a little speed, use a function pointer to functions containing the different solution, if detected a then funptr = a_solution, else if detected b then funptr = b_solution, etc. Do that one time then use funptr for the duration of the program.
As already mentioned the custom instruction needs to be compiled at compile time not runtime. if you want to change the instruction runtime that is a third option to do self-modifying code to insert the proper instruction at runtime.
Can't you just use string concatenation? Or is there some reason you can't do it that way?
#define cust_add "instr_generic"
...
asm volatile (
cust_add " %1, %2, %0 \n\t"
: "=r" (c)
: "r" (a), "r" (b)
: "%g0"
);
Related
Extended asm gives the following description regarding the "+" modifier:
Operands using the ‘+’ constraint modifier count as two operands (that
is, both as input and output) towards the total maximum of 30 operands
per asm statement.
So I assume that it is not necessary to mention output operand with the "+" modifier in the input section again, but it is not specified how to determine their index. I wrote the following example Godbolt :
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
void asm_add(uint64_t o1, uint64_t o2, uint64_t o3){
__asm__ volatile (
"addq %2, %3\n\
addq %2, %4":
"+r" (o2), "+r" (o3):
"r" (o1):
"cc"
);
printf("o2 = %" PRIu64 "\n", o2);
printf("o3 = %" PRIu64 "\n", o3);
}
int main(void){
asm_add(20, 30, 40);
}
Which printed
o2 = 50
o3 = 60
Is the template using +
__asm__ volatile (
"addq %2, %3\n\
addq %2, %4":
"+r" (o2), "+r" (o3):
"r" (o1):
"cc"
);
exactly the same as
__asm__ volatile (
"addq %2, %3\n\
addq %2, %4":
"+r" (o2), "+r" (o3):
"r" (o1), "0" (o2), "1" (o3):
"cc"
);
where all inputs are specified explicitly? So in the first example the "implicit" inputs are appended.
By using "+r" (o2), you are saying that this parameter needs to contain o2 on entry to the asm block, and will contain an updated value on exit.
In other words, %0 describes both input and output. The fact that you can (apparently?) reference indices greater than the number of parameters is an undocumented quirk. Don't depend upon it.
You might also consider using symbolic names, which (I find) are easier to read, especially as the number of asm lines goes up. Names are particularly useful when you are first creating the asm and there's the potential for adding/removing parameters. Having to renumber everything is painful and error prone:
__asm__ volatile (
"addq %[o1], %[o2]\n\
addq %[o1], %[o3]":
[o2] "+r" (o2), [o3] "+r" (o3):
[o1] "r" (o1):
"cc"
);
Lastly, consider not using inline asm for anything beyond educational purposes. And even then, inline asm is the hardest possible way to learn asm.
So I have this inline assembly code along with my C code, and I want to use intel syntax for this particular call to asm(), however I need to switch back to ATT syntax or else it will give a long list of errors.
asm(".intel_syntax prefix");
asm volatile (
"add %0, $1 \n\t"
: "=r" (dst)
: "r" (src));
asm(".att_syntax prefix");
Now it gives the following error
/tmp/ccDNa2Wk.s: Assembler messages:
/tmp/ccDNa2Wk.s:180: Error: no such instruction: `movl -16(%ebp),%eax'
/tmp/ccDNa2Wk.s:187: Error: no such instruction: `movl %eax,-12(%ebp)'
I dont understand how to fix the error, i have no call to movl in any part of my code.
Since you haven't yet accepted an answer (<hint><hint>), let me add a third thought:
1) Instead of having 3 asm statements, do it in 1:
asm(".intel_syntax prefix\n\t"
"add %0, 1 \n\t"
".att_syntax prefix"
: "=r" (dst)
: "r" (src));
2) Change your compile options to include -masm=intel and omit the 2 syntax statements.
3) It is possible to support both intel and att at the same time. This way your code works whatever value is passed for -masm:
asm("{addl $1, %0 | add %0, 1}"
: "=r" (dst)
: "r" (src));
I should also mention that your asm may not work as expected. Since you are updating the contents of dst (instead of overwriting it), you probably want to use "+r" instead of "=r". And you do realize that this code doesn't actually use src, right?
Oh, and your original asm is NOT intel format (the $1 is the give-away).
I would try to do the following tests:
In some C code not containing inline assembler insert the line
asm(".att_syntax prefix");
in multiple different locations. Then compile the C code to object files and disassemble these object files (compiling to assembler won't work for this test).
Then compare the disassembly of the original code with the disassembly of the code containing the ".att_syntax" lines.
If the line ".att_syntax prefix" indeed is the correct line for switching back to AT&T mode the disassemblies must be equal AND compiling must work without any errors.
In the next step take your code and compile to assembler instead of object code ("-S" option of GCC). Then you can look at the assembler code.
My idea is the following one:
If you use data exchange in inline assembler ("=r" and "r" for example) GCC needs to insert code that is doing the data exchange:
asm(".intel_syntax prefix");
// GCC inserts code moving "src" to "%0" here
asm volatile (
"add %0, $1 \n\t"
: "=r" (dst)
: "r" (src));
// GCC inserts code moving "%0" to "dst" here
asm(".att_syntax prefix");
This code inserted by GCC is of course in AT&T syntax.
If you want to use Intel syntax in inline assembly you have to use the ".att_syntax" and ".intel_syntax" instructions in the same inline assembly block, just like this:
// GCC inserts code moving "src" to "%0" here
asm volatile (
".intel_syntax prefix \n\t"
"add %0, $1 \n\t"
".att_syntax prefix \n\t"
: "=r" (dst)
: "r" (src));
// GCC inserts code moving "%0" to "dst" here
This question already has answers here:
When to use earlyclobber constraint in extended GCC inline assembly?
(2 answers)
Closed 4 months ago.
Following this manual I wanted to create simplest inline AVR assembly snippet possible: copy values of two variables to two other variables.
uint8_t a, b, c, d;
a = 42;
b = 11;
asm(
"mov %0, %2\n\t"
"mov %1, %3\n\t"
: "=r" (c), "=r" (d)
: "r" (a), "r" (b)
);
I would expect it to be equivalent to:
uint8_t a, b, c, d;
a = 42;
b = 11;
c = a;
d = b;
However, after running both values of c and d are equal to 42. If I change the asm snipptet to:
asm(
"mov %0, %3\n\t"
"mov %1, %2\n\t"
: "=r" (c), "=r" (d)
: "r" (a), "r" (b)
);
c is equal to 11 and d is equal to 42 as expected. Similarly, changing both source operands to %2 yields two 42 and setting both of them to %3 yields two 11.
Why the first version does not work as intended?
I would expect it to be equivalent to:
uint8_t a, b, c, d;
a = 42;
b = 11;
c = a;
d = b;
No, it's not1. The reason is that in the C code, one assignment follows after the other, whereas in inline asm, the compiler treats the "code" as if it happens at once. The compiler does not analyze the code in the asm string template in any way, it's just a string on which it performs replacements of %-operands. In
asm ("mov %0, %3" "\n\t"
"mov %1, %2"
: "=r" (c), "=r" (d)
: "r" (a), "r" (b));
the lifetime of a and b ends at the asm, and the lifetime of c and d begins. Therefore, it's totally fine for the compiler to use the same register for, say c and a. This means the output of the 1st move overrides the input of the 2nd move. This is the classic early-clobber situation, and you'll have to tell this fact to the compiler by means of early-clobber modifier &:
asm ("mov %0, %3" "\n\t"
"mov %1, %2"
: "=&r" (c), "=r" (d)
: "r" (a), "r" (b));
However, the code that's generated is sub-optimal because it's actually fine if the compiler uses the same register for c and b, and the same register for d and a. This means you don't need any explicit asm code at all, and everything can be described by means of the constraints:
asm (""
: "=r" (c), "=r" (d)
: "1" (a), "0" (b));
1Apart from that, your asm code tries to implement c = b and d = a, not c = a and d = b.
I want to translate this function:
iowrite32(mem1, value1);
into assembly code.
mem1 is defined as:
int * mem1;
in order to use ioremap.
I've written this code:
asm volatile(
"mov %[whr],%[wht]"
: [whr] "=r" (mem1)
: [wht] "r" (value)
);
Then I've realized I don't want to move value to mem1, but to the ADDRESS stored in mem1.
How do I write it in assembly?
You might want to take a look at the m constraint
asm volatile(
"mov %[wht], %[whr];"
: [whr] "=m" (*mem1)
: [wht] "r" (value)
);
Using inline assembler I could specify an add operation with
two inputs and one result as follows:
int a = 5;
int b = 5;
int res;
asm volatile (
" add %1, %2, %0 \n\t"
: "=r" (res)
: "r" (a), "r" (b)
: "%g0"
);
On a 32-bit architecture, this produces me an instruction word that could look like
this: 0x91050101
Now I am wondering, rather then explicitly specifying the assembler code for the addition,
I would like to specify the instruction word right away and put it into the executable. That should look something like this here
asm volatile (%x91, %x05, %x01, %x01);
Anyone an idea where I can find more information how this could be done and how the syntax has to look like to do that (the above is only a wild guess).
Many thanks!
asm volatile (
" .byte 0x91, 0x5, 0x1, 0x1 \n"
);
should do it.
You find the documentation at http://sourceware.org/binutils/docs/as/
Microsoft supports the _emit pseudo instruction
http://msdn.microsoft.com/en-us/library/1b80826t.aspx
I'm not sure what g++ supports