I'm trying to do a simple inline asm command in C and compile it with gcc. I want to push the variable num to the stack:
asm (
"push %0"
: //output
: "r"(num) //input
: //clobber
);
The above is generating the error:
Error: expression too complex -- `push r3'
I'm following this tutorial and I found nothing about the push command.
I also tried:
asm ( "push %num" ); //Assembler Error: expression too complex -- `push %num'
and:
asm ( "push %[num]" ); //gcc error: undefined named operand 'num'
But none worked.
edit:
I'm using this compiler: arm-linux-gnueabihf-gcc
In ARM assembly, the push instruction is a shorthand for stmdb. It can push multiple registers at once. Thus, you have to use braces around the operand as it indicates a set of registers:
asm("push {%0}" : : "r"(num) : );
Related
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)
I'm trying to compile seabios in a more debug-able state, and so I want to cancel function inlining.
To do so, I have added -fon-inline to the compilation flag, but then I get compilation error:
error: can't find a register in class 'GENERAL_REGS' while reloading 'asm'
Which is complaning on the following code:
asm volatile(
"calll __call16big_from32"
: "+a" (callregs), "+m" (*callregs)
:
: "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
I've looked this error up and found this means that compiler has ran out of registers so it can't compile that asm statement.
The thing is, the exact same code compile just fine without -fon-inline, why is that?
Why doesn't compile?
The first argument to the asm may not share a register with the address of the second because the first is modified. If the function is inlined callregs may be a constant or an offset from the stack pointer, and therefore a separate register is not required.
How to fix the program so it compiles
Given the presence of volatile and "memory", and no reference to it the second argument may be removed.
asm volatile(
"call __call16big_from32"
: "+a" (callregs)
:
: "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
#include "stdio.h"
void fseek(void *, int, int);
main () {
FILE* f = fopen("myfile", "rb");
asm("push 2");
asm("push 0");
asm("push f");
asm("call fseek");
asm("add esp, 12");
}
gcc -masm=intel call.c
call.c:(.text+0x2c): undefined reference to `f'
call.c:(.text+0x31): undefined reference to `fseek'
I have been trying to use AT/T syntax but got the same result.
Well you can not write like this, since there is no grantee that symbol f would exist in the generated assembly -- it's merely a symbol in C.
The solution is to use GCC's extended asm syntax. For example, push f could be rewrited into this:
asm volatile ("pushl %0"
: /* no output operands */
: "m" (f)
: /* no clobbered operands */);
As for the function call fseek, I believed your code shall be alright (at least in my experience and on my laptop it works just now). What's your platform info? Do you have glibc or similar things providing the standard libraries of C?
Also Please notice you're using a weird declaration of fseek since it shall at least have a return value according to the C specification.
Just for your information, you may try this style of an indirect call:
asm volatile ("call *%0"
: /* no output operands */
: "r"(fseek)
: /* no clobbered operands */);
I have this part of code that was compiling using ARMASM :
/* Software Interrupt */
/* we must save lr in case it is called from SVC mode */
#define ngARMSwi( code) __asm { SWI code,{},{},{lr} }
example of use :
ngARMSwi( 0x23);
I try to convert this to compile using gcc (code sourcery GCC-4.6.2 eabi). I found this link http://www.ethernut.de/en/documents/arm-inline-asm.html but I cannot find a way to compile this line correctly.
my best try is
#define ngARMSwi( code) __asm__ ("SWI " (code) : : :"lr" )
but I get compile error :
error: expected ':' or ')' before '(' token
Any help is appreciated!
You probably want
#define ngARMSwi(code) __asm__("SWI %0" : : "I"(code) : "lr")
Note that code is an input to the instruction, so it goes in the third section. Its place in the instuction is marked by the %0 in the string. The I is a constraint on code, indicating that it must be an 8-bit constant.
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.