I'm trying to use GCC's extended ASM like Microsoft's assembler. Under Microsoft's MASM, we can do the following, where __FUNC is a C variable:
mov eax, __FUNC
According to Extended Asm - Assembler Instructions with C Expression Operands, § 6.44.3.1 Input Operands:
Operands are separated by commas. Each operand has this format:
[ [asmSymbolicName] ] constraint (cexpression)
asmSymbolicName
Specifies a symbolic name for the operand. Reference the name in the assembler template by enclosing it in square brackets (i.e. ‘%[Value]’). The scope of the name is the asm statement that contains the definition. Any valid C variable name is acceptable, including names already defined in the surrounding code...
When I try and use it in code:
unsigned int func = 1;
...
__asm__ __volatile__ (
"movl %[__FUNC], %%eax"
...
:
: __FUNC "" (func)
);
It results in:
cpu.cpp:148:5: error: expected string-literal before ‘__FUNC’
: __FUNC "" (func)
^
cpu.cpp:148:5: error: expected ‘(’ before ‘__FUNC’
cpu.cpp:148:17: error: ‘__FUNC’ was not declared in this scope
...
The best I can tell, I am using __FUNC according to the manual and its description of asmSymbolicName. But obviously I am not since there's an error.
What am I doing wrong?
I also tried the following because the manual told me I could use variable names in surrounding code, but it did not work either:
"movl %[func], %%eax"
...
:
: func "" (func)
And:
"movl %[func], %%eax"
...
:
: func (func)
...
This is correct:
Operands are separated by commas. Each operand has this format:
[ [asmSymbolicName] ] constraint (cexpression)
However [asmSymbolicName] means asmSymbolicName is literally surrounded by square brackets [ and ] (The outside brackets say that it is an optional parameter). You might have been going for this:
uint32_t func = 1;
uint32_t result;
__asm__ __volatile__ (
"movl %[func], %[result]"
: [result]"=a"(result)
: [func]"g"(func)
);
This takes an input parameter of func makes it available as a symbolic name called func within the assembler template. Output parameter is eax (writable) with a symbolic name of result and eax will be stored in the C variable result when finished. I chose "g" since any immediate value, memory address, or register would be appropriate for the source in movl . You could pass an immediate value rather than a "C" variable with:
: [func]"g"(42)
Related
Trying to multiply 400 by 2 with inline assembly, using the fact imul implicity multiplies by eax. However, i'm getting "undefined reference" compile errors to $1 and $2
int c;
int a = 400;
int b = 2;
__asm__(
".intel_syntax;"
"mov eax, $1;"
"mov ebx, $2;"
"imul %0, ebx;"
".att_syntax;"
: "=r"(c)
: "r" (a), "r" (b)
: "eax");
std::cout << c << std::endl;
Do not use fixed registers in inline asm, especially if you have not listed them as clobbers and have not made sure inputs or outputs don't overlap them. (This part is basically a duplicate of segmentation fault(core dumped) error while using inline assembly)
Do not switch syntax in inline assembly as the compiler will substitute wrong syntax. Use -masm=intel if you want intel syntax.
To reference arguments in an asm template string use % not $ prefix. There's nothing special about $1; it gets treated as a symbol name just like if you'd used my_extern_int_var. When linking, the linker doesn't find a definition for a $1 symbol.
Do not mov stuff around unnecessarily. Also remember that just because something seems to work in a certain environment, that doesn't guarantee it's correct and will work everywhere every time. Doubly so for inline asm. You have to be careful. Anyway, a fixed version could look like:
__asm__(
"imul %0, %1"
: "=r"(c)
: "r" (a), "0" (b)
: );
Has to be compiled using -masm=intel. Notice b has been put into the same register as c.
using the fact imul implicity multiplies by eax
That's not true for the normal 2-operand form of imul. It works the same as other instructions, doing dst *= src so you can use any register, and not waste uops writing the high half anywhere if you don't even want it.
I try to do a simple example to insert, into a C code, a piece of Sparc assembly 32 bits; this little code performs an incrementation on the variable "sum".
The code is :
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
int n;
int sum;
int main ()
{
n = 100;
sum = 0;
struct timeval tv1, tv2;
long long diff;
gettimeofday (&tv1, NULL);
asm volatile ("set sum, %g1\n\t" \
"set n, %g3\n" \
"loop:\n\t" \
"add %g1, 1, %g2\n\t" \
"sub %g3, 1, %g4\n\t" \
"bne loop\n\t" \
"nop\n\t" \
: "=r" (sum)
: "r" (n)
);
gettimeofday (&tv2, NULL);
diff = (tv2.tv_sec - tv1.tv_sec) * 1000000L + (tv2.tv_usec - tv1.tv_usec);
printf ("Elapsed time = %d usec\n", diff);
printf ("Sum = %d\n", sum);
return 0;
}
Unfortunately, compilation with gcc4.1.2 produces the following errors :
loop_dev_for-assembly_code.c: In function #main#:
loop_dev_for-assembly_code.c:18: error: invalid 'asm': invalid operand output code
loop_dev_for-assembly_code.c:18: error: invalid 'asm': operand number out of range
loop_dev_for-assembly_code.c:18: error: invalid 'asm': invalid operand output code
loop_dev_for-assembly_code.c:18: error: invalid 'asm': operand number out of range
loop_dev_for-assembly_code.c:18: error: invalid 'asm': operand number out of range
loop_dev_for-assembly_code.c:18: error: invalid 'asm': operand number out of range
It seems the line 18 corresponds to "asm volatile ("set sum, %g1\n\t" \ ...".
But I don't know how to circumvent these errors. It may come from the variable sum which is set to %g1 register.
About the links between variable belonging to C code and variable localted in Assembly code part. I have also seen, for inputs and outputs parameters, the syntax "=g" (output paramter ??), "g" (input parameter) : I think that it corresponds to different registers between the 2 syntax.
if someone could give to me some clues to understand this link and debug my little code which does a simple loop to increment variable sum.
Thanks for your help, regards.
As somebody else said, there are many errors and misconceptions in your inline assembly code. Here are just a few things. First, in extended asm syntax, you must escape all the '%' symbols with another '%', so for example you need to put '%%g1' instead of '%g1' and do this for all the registers you access. Second, you can't use 'set' for either of the variables n or sum, since they are both stack variables, not globals. You have already declared these variables as positional parameters in your asm statement, so sum is parameter %0 and n is %1. Your add instruction puts the result in %g2, which is never initialized or used anywhere.
I think the entire sequence could be rendered much more simply like this (not tested):
asm volatile ("clr %%g1\n" \
"loop:\n\t" \
"add %%g1, 1, %%g1\n\t" \
"subcc %1, 1, %1\n\t" \
"bne loop\n\t" \
"nop\n\t" \
"mov %%g1, %0\n" \
: "=r" (sum)
: "r" (n)
: "g1" );
I have tried to mix SSE2 intrinsics and inline assembler in gcc. But if I specify a variable as xmm0/register as input then in some cases I get a compiler error. Example:
#include <emmintrin.h>
int main() {
__m128i test = _mm_setzero_si128();
asm ("pxor %%xmm0, %%xmm0" : : "xmm0" (test) : );
}
When compiled with gcc version 4.6.1 I get:
>gcc asm_xmm.c
asm_xmm.c: In function ‘main’:
asm_xmm.c:10:3: error: matching constraint references invalid operand number
asm_xmm.c:7:5: error: matching constraint references invalid operand number
The strange thing is that in same cases where I have other input variables/registers then it suddenly works with xmm0 as input but not xmm1, etc. And in another case I was able to specify xmm0-xmm4 but not above. A little confused/frustrated about this :S
Thanks :)
You should let the compiler do the register assignment. Here's an example of pshufb (for gcc too old to have tmmintrin for SSSE3):
static inline __m128i __attribute__((always_inline))
_mm_shuffle_epi8(__m128i xmm, __m128i xmm_shuf)
{
__asm__("pshufb %1, %0" : "+x" (xmm) : "xm" (xmm_shuf));
return xmm;
}
Note the "x" qualifier on the arguments and simply %0 in the assembly itself, where the compiler will substitute in the register it selected.
Be careful to use the right modifiers. "+x" means xmm is both an input and an output parameter. If you are sloppy with these modifiers (eg using "=x" meaning output only when you needed "+x") you will run into cases where it sometimes works and sometimes doesn't.
I want to move the value of the variable "userstack" inside the ESP register and then do an absolute jump to the memory address contained in the variable "location".
This is what I've got:
// These are the two variables that contains memory addresses
uint32_t location = current_running->LOCATION;
uint32_t userstack = current_running->user_stack;
// And then something like this
__asm__ volatile ("movl userstack, %esp");
__asm__ volatile ("ljmp $0x0000, location");
However when I try to compile I get the errors:
"Error: suffix or operands invalid for ljmp" and "undefined reference to `userstack'".
Any help would be very much appreciated.
Take a look at the manual.
I think you'd need something like this:
asm volatile ("movl %0, %esp" : "g" (userstack));
asm volatile ("ljmp $0x0000, %0" : "g" (location));
Basically GCC needs know what and where userstack and location may be (registers, memory operands, floating, restricted subset of registers, etc.) and that is specified by "g", in this case meaning a general operand.
Was wondering how to inline a usage of fbstp on a 32 bit I86 architecture. I tried something like
int main( )
{
double foo = 100.0;
long bar = 0;
asm( "pushl %1; fbstp %0"
: "=m"(bar)
: "r"(foo)
);
...
But bar is unchanged. I have tried reading everything I can find on this but most example simply do things like add two integers together. I can’t find any that talk about pushing operands onto the stack and what I should be doing when an instruction like fbstp writes 80 bits of data back to memory ( i.e. what C type to use ) and how to specify it in the asm syntax.
Also on x86-64 there seems to be a pushq and no pushl but fbstp still exists whereas fbstq does not. Is there some other magic for 64 bit.
There's an example here: http://bap.ece.cmu.edu/download/bap-0.1/VEX/test/test-i386.c
which seems to suggest doing something like this:
unsigned short bcd[5];
double a;
asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st");