Assembler 64 bit mutiple definition error - c

I am trying to learn Assembly, and using it with 64 bit. I want to compile an inline Assembler in C, but I get an error every time.
#include <stdio.h>
int main() {
__asm__ ( "mov %rdx, 10;"
"mov %rcx, 20;"
"add %rdx, rcx;"
);
__asm__ ( "mov %rdx, 10;"
"mov %rcx, 20;"
"sub %rcx, %rdx;"
);
__asm__ ( "mov %rdx, 10;"
"mov %rcx, 20;"
"sub %rcx, %rdx;"
);
__asm__ ( "mov %rdx, 10;"
"mov %rcx, 20;"
"imul %rdx, %rcx;"
);
return 0 ;
}
If I try to compile, I get the following error:
gcc -o onetest onetest.o onetest.c
/tmp/ccXkj6UQ.o: In function `main':
onetest.c:(.text+0x0): multiple definition of `main'
onetest.o:onetest.c:(.text+0x0): first defined here
/tmp/ccXkj6UQ.o: In function `main':
one.c:(.text+0x18): undefined reference to `rcx'
collect2: error: ld returned 1 exit status
At the beginning I had a few problems with registers, but now this too!

This is not a problem with assembler, but a linker.
gcc -o onetest onetest.o onetest.c
Tries to compile & link onetest.o and onetest.c together, where I assume onetest.o is derived from onetest.c. You are compiling that thing twice. Try
gcc -o onetest onetest.c
Edit:
If you want to actually have your asm interact with your C code then you are best off with extended asm. Example:
int64_t result = 10; // one of the arguments
asm (
"add %1, %0"
: "+r" (result) // input-output variable
: "g" (20) // second argument
: "cc"
);
printf("result = %lld\n", result);
Please keep in mind that in AT&T x86 syntax add, %a, %b works as %b += %a.
For the extended asm constrains: "+r" instructs your compiler to provide result in a register of it's choosing (available as %0 in the asm) for input and output. "g" instructs your compiler to provide 20 in any form it finds suitable for input only (available as %1 in asm). "cc" signals your compiler that the conditions flags register EFLAGS in x86 will be altered by your asm (a side effect of add).

Related

GCC doesn't push registers around my inline asm function call even though I have clobbers

I have a function (C) that modifies "ecx" (or any other registers)
int proc(int n) {
int ret;
asm volatile ("movl %1, %%ecx\n\t" // mov (n) to ecx
"addl $10, %%ecx\n\t" // add (10) to ecx (n)
"movl %%ecx, %0" /* ret = n + 10 */
: "=r" (ret) : "r" (n) : "ecx");
return ret;
}
now i want to call this function in another function which that function moves a value in "ecx" before calling "proc" function
int main_proc(int n) {
asm volatile ("movl $55, %%ecx" ::: "ecx"); /// mov (55) to ecx
int ret;
asm volatile ("call proc" : "=r" (ret) : "r" (n) : "ecx"); // ecx is modified in proc function and the value of ecx is not 55 anymore even with "ecx" clobber
asm volatile ("addl %%ecx, %0" : "=r" (ret));
return ret;
}
in this function, (55) is moved into "ecx" register and then "proc" function is called (which modifies "ecx"). in this situation, "proc" function Must push "ecx" first and pop it at the end but it's not going to happen !!!!
this is the assembly source with (-O3) optimiaztion level
proc:
movl %edi, %ecx
addl $10, %ecx
movl %ecx, %eax
ret
main_proc:
movl $55, %ecx
call proc
addl %ecx, %eax
ret
why GCC is not going to use (push) and (pop) for "ecx" register ?? i used "ecx" clobber too !!!!!
You are using inline asm completely wrong. Your input/output constraints need to fully describe the inputs / outputs of each asm statement. To get data between asm statements, you have to hold it in C variables between them.
Also, call isn't safe inside inline asm in general, and specifically in x86-64 code for the System V ABI it steps on the red-zone where gcc might have been keeping things. There's no way to declare a clobber on that. You could use sub $128, %rsp first to skip past the red zone, or you could make calls from pure C like a normal person so the compiler knows about it. (Remember that call pushes a return address.) Your inline asm doesn't even make sense; your proc takes an arg but you didn't do anything in the caller to pass one.
The compiler-generated code in proc could have also destroyed any other call-clobbered registers, so you at least need to declare clobbers on those registers. Or hand-write the whole function in asm so you know what to put in clobbers.
why GCC is not going to use (push) and (pop) for "ecx" register ?? i used "ecx" clobber too !!!!!
An ecx clobber tells GCC that this asm statement destroys whatever GCC had in ECX previously. Using an ECX clobber in two separate inline-asm statements doesn't declare any kind of data dependency between them.
It's not equivalent to declaring a register-asm local variable like
register int foo asm("ecx"); that you use as a "+r" (foo) operand to the first and last asm statement. (Or more simply that you use with a "+c" constraint to make an ordinary variable pick ECX).
From GCC's point of view, your source means only what the constraints + clobbers tell it.
int main_proc(int n) {
asm volatile ("movl $55, %%ecx" ::: "ecx");
// ^^ black box that destroys ECX and produces no outputs
int ret;
asm volatile ("call proc" : "=r" (ret) : "r" (n) : "ecx");
// ^^ black box that can take `n` in any register, and can produce `ret` in any reg. And destroys ECX.
asm volatile ("addl %%ecx, %0" : "=r" (ret));
// ^^ black box with no inputs that can produce a new value for `ret` in any register
return ret;
}
I suspect you wanted the last asm statement to be "+r"(ret) to read/write the C variable ret instead of telling GCC that it was output-only. Because your asm uses it as an input as well as output as the destination of an add.
It might be interesting to add comments like # %%0 = %0 %%1 = %1 inside your 2nd asm statement to see which registers the "=r" and "r" constraints picked. On the Godbolt compiler explorer:
# gcc9.2 -O3
main_proc:
movl $55, %ecx
call proc # %0 = %edi %1 = %edi
addl %ecx, %eax # "=r" happened to pick EAX,
# which happens to still hold the return value from proc
ret
That accident of picking EAX as the add destinatino might not happen after this function inlines into something else. or GCC happens to put some compiler-generated instructions between asm statements. (asm volatile is barrier to compile-time reordering but not not a strog one. It only definitely stops optimizing away entirely).
Remember that inline asm templates are purely text substitution; asking the compiler to fill in an operand into a comment is no different from anywhere else in the template string. (Godbolt strips comment lines by default so sometimes it's handy to tack them onto other instructions, or onto a nop).
As you can see, this is 64-bit code (n arrives in EDI as per the x86-64 SysV calling convention, like how you built your code), so push %ecx wouldn't be encodeable. push %rcx would be.
Of course if GCC actually wanted to keep a value around past an asm statement with an "ecx" clobber, it would have just used mov %ecx, %edx or whatever other call-clobbered register that wasn't in the clobber list.

How to use a variable declared in C within inline assembly

I am trying to figure out how to use the variable ret within the inline assembly code below, but I keep getting this error: undefined reference to 'ret.
char getkey(void){
int ret;
asm(
"movq $0, %RAX\n\t"
"INT $0X16\n\t"
"movq %RAX, ret"
);
return ret;
}
What you're trying to do won't work. PC BIOS interrupts, like int 16h, are only available when the system is running in real mode (i.e, at startup before the MMU is enabled); they cannot be used in Linux executables.
That being said, in general, you can specify an output register using gcc assembler constraints. For example:
asm(
"movq $0, %RAX\n"
"int $0x16\n"
: "=a" (ret)
);
Note that there's no mov instruction at the end of this code! The "=A" constraint tells the compiler that the result will be left in the A register; it'll figure out what to do from there. (There are ways to eliminate the first mov as well, if you're clever about it.)

Crash on kfree call (inside a kernel module)

I have this code
int64_t ret;
char *fmt = "\n\n\n%s\n\n\n";
char *s;
s = kmalloc(13, GFP_KERNEL);
memcpy(s, "Hello world!\0", 13);
__asm__ __volatile__ (
"movq %2, %%rdi;"
"movq %1, %%rsi;"
"movq $2, %%rax;"
"call printk;"
"movq %%rax, %0;"
: "=r" (ret)
: "r" (s), "r" (fmt)
:
);
__asm__ __volatile__ (
"movq %0, %%rdi;"
"movq $1, %%rax;"
"call kfree;"
:
: "r" (s)
:
);
return ret;
which crashes on the kfree call. It must be something silly, but I can't find out what it is. What is the problem?
EDIT: "Crashes" == The kernel module triggers an Oops.
EDIT: It seems to work just fine if I use m instead of r. But why?
You should look at the generated assembly code (use -S option to gcc) to see exactly what is happening.
I am guessing that the problem is that you didn't specify the correct clobbers for the printk block. Remember that certain registers may be freely used by a called function. The compiler doesn't process the contents of the inline asm block, so it doesn't know it has a call inside. It expects that registers not specified as output or clobber will come out unchanged from the asm block. Thus, I assume the compiler caches the variable s in a register that is destroyed by the printk or your use of rax, rdi and rsi which you also don't tell the compiler. Note that there are specific register constraints, so you could use those instead of moving the arguments around in assembly.
Also note that rax (actually al) is only used for varargs and stdargs functions, and even then it should just contain the number of arguments passed via sse vector (xmm) registers, not the total number. See the x86-64 ABI docs for more information.
Finally, if you really want to write asm code, you should consider writing standalone asm module instead of C if possible. You could save yourself some headache. See this question for an example.

Assembly compilation error (gcc4.2.4=win, gcc4.3.3=fail)

We recently upgraded the code to gcc4.3.3 from gcc4.2.4.
void testAndSet( volatile int* s, int* val )
{
__asm__ __volatile__ ( "btsl $0, %0\n "
"jc bitSet\n "
"movl $0, %1\n "
"jmp returnVector\n"
"bitSet:\n "
"movl $1, %1\n"
"returnVector: " : "=m"(*s), "=m"(*val) );
}
Our code now fails with the following errors,
lock.cxx: Assembler messages:
lock.cxx:59: Error: symbol `bitSet' is already defined
lock.cxx:61: Error: symbol `returnVector' is already defined
lock.cxx:59: Error: symbol `bitSet' is already defined
lock.cxx:61: Error: symbol `returnVector' is already defined
Those symbols weren't found anywhere else. (Renaming them causes the same error with the new name).
What's up with this? why do I get the errors twice?
Probably the optimizer has changed and is now inlining your testAndSet() function into 2 places. Because you are using global names for your labels, this does not work. You should use local names instead. E.g:
__asm__ __volatile__ ( "btsl $0, %0\n "
"jc 0f\n "
"movl $0, %1\n "
"jmp 1f\n"
"0:\n "
"movl $1, %1\n"
"1: " : "=m"(*s), "=m"(*val) );
Local labels are just numbers; to disambiguate cases where there are many labels called "0" you need to use "jmp 0f" for forward jumps and "jmp 0b" for backward jumps.
This is unrelated to your error, but you could improve your code and avoid branches simply using the setCC instruction:
__asm__ __volatile__ ( "btsl $0, %0\n "
"mov $0, %1\n"
"setc %1\n" : "=m"(*s), "=m"(*val) );
The setCC instruction (where CC is one of the condition code flags, analogous to the jCC instruction) sets a byte to 0 or 1 depending on whether or not the given condition was satisfied. Since the destination is a 4-byte value, you need to either preload it with 0 or use the MOVZX instruction to make the upper 3 bytes 0.
Also you may use local label names by adding %= after each local label:
"loop%=:" "\n\t"

Is there a way to insert assembly code into C?

I remember back in the day with the old borland DOS compiler you could do something like this:
asm {
mov ax,ex
etc etc...
}
Is there a semi-platform independent way to do this now? I have a need to make a BIOS call, so if there was a way to do this without asm code, that would be equally useful to me.
Using GCC
__asm__("movl %edx, %eax\n\t"
"addl $2, %eax\n\t");
Using VC++
__asm {
mov eax, edx
add eax, 2
}
In GCC, there's more to it than that. In the instruction, you have to tell the compiler what changed, so that its optimizer doesn't screw up. I'm no expert, but sometimes it looks something like this:
asm ("lock; xaddl %0,%2" : "=r" (result) : "0" (1), "m" (*atom) : "memory");
It's a good idea to write some sample code in C, then ask GCC to produce an assembly listing, then modify that code.
A good start would be reading this article which talk about inline assembly in C/C++:
http://www.codeproject.com/KB/cpp/edujini_inline_asm.aspx
Example from the article:
#include <stdio.h>
int main() {
/* Add 10 and 20 and store result into register %eax */
__asm__ ( "movl $10, %eax;"
"movl $20, %ebx;"
"addl %ebx, %eax;"
);
/* Subtract 20 from 10 and store result into register %eax */
__asm__ ( "movl $10, %eax;"
"movl $20, %ebx;"
"subl %ebx, %eax;"
);
/* Multiply 10 and 20 and store result into register %eax */
__asm__ ( "movl $10, %eax;"
"movl $20, %ebx;"
"imull %ebx, %eax;"
);
return 0 ;
}
For Microsoft compilers, inline assembly is supported only for x86. For other targets you have to define the whole function in a separate assembly source file, pass it to an assembler and link the resulting object module.
You're highly unlikely to be able to call into the BIOS under a protected-mode operating system and should use whatever facilities are available on that system. Even if you're in kernel mode it's probably unsafe - the BIOS may not be correctly synchronized with respect to OS state if you do so.
use of asm or __asm__ function ( in compilers have difference )
also you can write fortran codes with fortran function
asm("syscall");
fortran("Print *,"J");

Resources