Simple assembly example : set inputs and get output - right syntax - gcc

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" );

Related

Inline assembly multiplication "undefined reference" on inputs

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.

unit32_t size error in Code composer

I am working on C++ based project where i am getting one error for below statement:
Code:
typedef char pb_static_assertion_UINT32_T_WRONG_SIZE3507__COUNTER__ [ ( sizeof ( uint32_t ) == 4 ) ? 1 : - 1 ] ; // The line at which i am getting error
Error:
"C:\Users\tkumar\Documents\LDRA\LDRAunit_C_CPP_9.7.1\trial\inszt_algctivationgateway.cpp", line 4330: error #95: the size of an array must be greater than zero"
Reference:
uint32_t is defined using:
typedef unsigned long uint32_t;
I have doubt for unsigned long size, anybody here to explain to tell me the reason behind this error ?
1) Code-Composer compiler outputs object in formats called COFF or EABI. When COFF was selected, unsigned long was 40-bits on for some of the microprocessors at least. When EABI was selected, it was 32-bits.
2) For some of the TI microprocessors, such as the C2000 series, the smallest addressable word was 16 bits, and sizeof would then output 2 instead of 4 for a 32-bit type.
3) One or the other of these is probably causing your sizeof statement to be returning something other than 4, causing ?: to select -1. So the array size is less than 0.
4) Don't think you really want an array after a typedef.

Assembler templates, asmSymbolicName and "error: expected string-literal"

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)

can't find a register in class 'CREG' while reloading 'asm' - memcpy inline asm

I am trying to make an earlier verion Linux got compiled, you can download the source code from git://github.com/azru0512/linux-0.12.git. While compiling ''kernel/blk_drv/ramdisk.c'', I got error message below,
ramdisk.c:36:10: error: can't find a register in class 'CREG' while reloading 'asm'
ramdisk.c:40:10: error: can't find a register in class 'CREG' while reloading 'asm'
ramdisk.c:36:10: error: 'asm' operand has impossible constraints
ramdisk.c:40:10: error: 'asm' operand has impossible constraints
What in ramdisk.c are,
if (CURRENT-> cmd == WRITE) {
(void) memcpy(addr,
CURRENT->buffer,
len);
} else if (CURRENT->cmd == READ) {
(void) memcpy(CURRENT->buffer,
addr,
len);
} else
panic("unknown ramdisk-command");
And the memcpy is,
extern inline void * memcpy(void * dest,const void * src, int n)
{
__asm__("cld\n\t"
"rep\n\t"
"movsb"
::"c" (n),"S" (src),"D" (dest)
:"cx","si","di");
return dest;
}
I guess it's memcpy (include/string.h) inline asm problem, so I remove the clobber list from it but without luck. Could you help me to find out what's going wrong? Thanks!
GCC's syntax for this has changed / evolved a bit.
You must now specify each of the special target registers as an output operand:
...("...instructions..."
: "=c"(n), "=S"(src), "=D"(dest)
and then additionally as the same registers as source operands:
: "0"(n), "1"(src), "2"(dest)
and finally you need to clobber "memory" (I can't remember offhand if this affects condition codes, if so you would also need "cc"):
: "memory")
Next, because this instruction should not be moved or deleted, you need to use either volatile or __volatile__ (I'm not entirely sure why but without this the instructions were deleted, in my test-case).
Last, it's no longer a good idea to attempt to override memcpy because gcc "knows" how to implement the function. You can override gcc's knowledge with -fno-builtin.
This compiles (for me anyway, with a somewhat old gcc on an x86-64 machine):
extern inline void * memcpy(void * dest,const void * src, int n)
{
__asm__ volatile("cld\n\t"
"rep\n\tmovsb\n\t"
: "=c" (n), "=S" (src), "=D" (dest)
: "0" (n), "1" (src), "2" (dest)
: "memory", "cc");
return dest;
}
This exact problem & its reasons are discussed on GCC's bugzilla :
Bug 43998 - inline assembler: can't set clobbering for input register
gcc wont allow input & output registers as clobbers.
If you corrupt input register, do a dummy output to same register :
unsigned int operation;
unsigned int dummy;
asm ("cpuid" : "=a" (dummy) : "0" ( operation) :);

gcc inline assembler shift left problem

I'm having trouble compiling the code below. It may also have logical errors, please help. thanks,
#include <iostream>
using namespace std;
int main()
{
int shifted_value;
int value = 2;
__asm__("shll %%eax,%1;" : "=a" (shifted_value): "a" (value));
cout<<shifted_value<<endl;
return 0 ;
}
The error is:
Error: suffix or operands invalid for `shl'
It should look like
__asm__(("shll %%cl, %%eax;"
: "=a" (shifted_value)
: "a" (shifted_value), "c" (value)
);
Credit for correct code goes to the other answer for pointing out that the operands were in the incorrect order.
You dont need to specify eax as clobbered because eax is an output register.
it can work with shll also, shll being the GNU at&t mnemonic for "shift left longword". However, the invalid operand error is due to the operand needing to come first! I found this out when I googled up these sources: http://meplayer.googlecode.com/svn-history/r23/trunk/meplayer/src/filters/transform/mpcvideodec/ffmpeg/libavcodec/cabac.h. I also used the excellent http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s6
Here is one way that works, taking into account Jesus Ramos's observation that shifted_value needs to be initialized:
jcomeau#intrepid:/tmp$ cat test.cpp; make test; ./test
#include <iostream>
using namespace std;
int main()
{
int shifted_value = 1;
char value = 2;
__asm__("shll %%cl, %%eax;"
: "=a" (shifted_value)
: "a" (shifted_value), "c" (value)
);
cout<<shifted_value<<endl;
return 0 ;
}
g++ test.cpp -o test
4

Resources