Error in my first assembly program (GCC Inline Assembly) - gcc

After a lot of internet research I implemented a small assembler routine in my C++ program to get the CPU's L1 cache size using cpuid.
int CPUID_getL1CacheSize() {
int l1CacheSize = -1;
asm ( "mov $5, %%eax\n\t" // EAX=80000005h: L1 Cache and TLB Identifiers
"cpuid\n\t"
"mov %%eax, %0" // eax into l1CacheSize
: "=r"(l1CacheSize) // output
: // no input
: "%eax" // clobbered register
);
return l1CacheSize;
}
It works perfectly on Windows 7 64 bit with MinGW (GCC, G++). Next I tried this on my Mac computer using GCC 4.0 and there must be an error somewhere because my program shows strange strings in the ComboBoxes and some signals cannot be connected (Qt GUI).
This is my first assembler program, I hope someone can give me a hint, Thanks!

I think that CPUID actually clobbers EAX, EBX, ECX, EDX, so it's probably just a register trashing problem. The following code appears to work OK with gcc 4.0.1 and 4.2.1 on Mac OS X:
#include <stdio.h>
int CPUID_getL1CacheSize()
{
int l1CacheSize = -1;
asm ( "mov $5, %%eax\n\t" // EAX=80000005h: L1 Cache and TLB Identifiers
"cpuid\n\t"
"mov %%eax, %0" // eax into l1CacheSize
: "=r"(l1CacheSize) // output
: // no input
: "%eax", "%ebx", "%ecx", "%edx" // clobbered registers
);
return l1CacheSize;
}
int main(void)
{
printf("CPUID_getL1CacheSize = %d\n", CPUID_getL1CacheSize());
return 0;
}
Note that you need to compile with -fno-pic as EBX is reserved when PIC is enabled. (Either that or you need to take steps to save and restore EBX).
$ gcc-4.0 -Wall -fno-pic cpuid2.c -o cpuid2
$ ./cpuid2
CPUID_getL1CacheSize = 64
$ gcc-4.2 -Wall -fno-pic cpuid2.c -o cpuid2
$ ./cpuid2
CPUID_getL1CacheSize = 64
$

I finally resolved the problem. I got a compiler error while playing around: "error: PIC register '%ebx' clobbered in 'asm'" and after some internet research I modified my code to:
int CPUID_getL1CacheSize() {
int l1CacheSize = -1;
asm volatile ( "mov $5, %%eax\n\t"
"pushl %%ebx; cpuid; popl %%ebx\n\t"
"mov %%eax, %0"
: "=r"(l1CacheSize)
:
: "%eax"
);
return l1CacheSize;
}
Thanks Paul, The compiler option -fno-pic is a nice solution too.
Greetings

Related

gcc inline assembly: how to use intel syntax temporarily with constraint 'm' under 'gcc -masm=att' [duplicate]

This question already has answers here:
How to set gcc or clang to use Intel syntax permanently for inline asm() statements?
(2 answers)
Can I use Intel syntax of x86 assembly with GCC?
(2 answers)
Closed last year.
I'd like to use intel syntax gcc inline assembly, leaving gcc's default -masm=att dialect untouched.
The following code works fine:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a = 123;
int b = 0;
printf("before: a = %d\n", a);
printf("before: b = %d\n", b);
__asm__ __volatile__ (
".intel_syntax noprefix\n\t"
"mov eax, %[a]\n\t"
"mov %[b], eax\n\t"
".att_syntax prefix\n\t"
: [b]"+r"(b)
: [a]"r"(a)
: "eax"
);
printf("after: a = %d\n", a);
printf("after: b = %d\n", b);
return 0;
}
// before: a = 123
// before: b = 0
// after: a = 123
// after: b = 123
But if i change Output Operands Constraint from register('r') to memory('m'), error occurs:
Error: junk `(%rbp)' after expression
In the generated assembly file, I find this:
#APP
.intel_syntax noprefix
mov eax, -16(%rbp)
mov -12(%rbp), eax
.att_syntax prefix
#NO_APP
It looks like gcc renders Assembler Template using AT&T Effective-Address dialect.
I searched the web, Extended Asm shows something like "Multiple assembler dialects in asm templates" and "x86 Operand Modifiers", but I still didn't solve the problem.
Is there a way to tell gcc, (maybe some instructions around __asm__, telling gcc to do operand-substitution with Intel-syntax addressing modes temporarily, like -masm=intel do in the whole file), render the Assembler Template using Intel Effective-Address dialect temporarily in __asm__ () block, not the whole file, like this:
#APP
.intel_syntax noprefix
mov eax, [%rbp - 16]
mov [%rbp - 12], eax
.att_syntax prefix
#NO_APP

Unexpected GCC inline ASM behaviour (clobbered variable overwritten)

On my computer, the compiled executable omits executing "mov %2, %%ax" at the top of the loop
when "add %1, %%ax" uncommented.
Anyone to doublecheck or comment ?
#include <stdio.h>
int main() {
short unsigned result, low ,high;
low = 0;
high = 1;
__asm__ (
"movl $10, %%ecx \n\t"
"loop: mov %2, %%ax \n\t"
// "add %1, %%ax \n\t" // uncomment and result = 10
"mov %%ax, %0 \n\t"
"subl $1, %%ecx \n\t"
"jnz loop"
: "=r" (result)
: "r" (low) , "r" (high)
: "%ecx" ,"%eax" );
printf("%d\n", result);
return 0;
}
Follows the assembly generated
movl $1, %esi
xorl %edx, %edx
/APP
movl $10 ,%ecx
loop: mov %si, %ax
mov %dx, %bx
add %bx, %ax
mov %ax, %dx
subl $1, %ecx
jnz loop
/NO_APP
Thanks to Jester the solution :
: "=&r" (result) // early clober modifier
GCC inline assembly is advanced programming, with a lot of pitfalls. Make sure you actually need it, and can't replace it with standalone assembly module, or C code using intrinsics. or vector support.
If you insist on inline assembly, you should be prepared to at least look at the generated assembly code and try to figure out any mistakes from there. Obviously the compiler does not omit anything that you write into the asm block, it just substitutes the arguments. If you look at the generated code, you might see something like this:
add %dx, %ax
mov %ax, %dx
Apparently the compiler picked dx for both argument 0 and 1. It is allowed to do that, because by default it assumes that the input arguments are consumed before any outputs are written. To signal that this is not the case, you must use an early clobber modifier for your output operand, so it would look like "=&r".
PS: Even when inline assembly seems to work, it may have hidden problems that will bite you another day, when the compiler happens to make other choices. You should really avoid it.

How can I compile assembly language with gcc and codeblock?

I am now trying to compile the following codes with gcc and codeblock:
#include <stdio.h>
int main()
{
char alphabet = 'X';
printf ("Type letter = ");
asm{ //line 8
mov ah, 02
mov dl, [alphabet] // line 9
int 21h
}
printf ("\n");
return (0);
}
The error messages I have got are as follows:
error: expected '(' before '{' token line 8
error: 'mov' was not declared in this scope line9
I am compiling for x86 computer, and was wondering how I could compile the above codes successfully. Thanks!
Unfortunately gcc doesn't support simple syntax like this:
asm {
mov ah, 02
mov dl, [alphabet]
int 21h
}
You can find more information on the gcc-inline-assembler with the link DCoder commented: click me
Explaining everything would be too much for an answer, so I simply write the code for gcc, which should do the job for you:
__asm__(
"movb $2, %%ah;"
"movb %0, %%dl;"
"int $0x21;"
:
: "r"(alphabet)
: "%ah", "%dl"
);
Note, that you can also use the keyword asm instead of __asm__.

GCC inline assembly error: Error: junk `(%esp)' after expression

GCC inline assembly error: Error: junk `(%esp)' after expression
I'm studying gcc inline assembly. My environment is Win 7 32bit, mingw-gcc 4.6.1.
I have got a problem about the 'm' constraint. Here is my c function code:
static int asm_test(int a, int b)
{
int c = 0;
__asm__ __volatile__(".intel_syntax\n"
"mov eax, %1\n" //error
"mov edx, %2\n" //error
"add eax, edx\n"
"mov %0, eax\n" //error
".att_syntax"
:"=m"(c)\
:"m"(a),"m"(b)\
:"eax","edx"
);
return c;
}
For at&t code, it is like this:
static int asm_test(int a, int b)
{
int c = 0;
__asm__ __volatile__(
"movl %1, $eax\n" //error
"movl %2, $edx\n" //error
"addl $edx, $eax\n"
"movl $eax, %0\n" //error
:"=m"(c)\
:"m"(a),"m"(b)\
:"eax","edx"
);
return c;
}
For each of the three lines which operate input/output operands, gcc generate an error when compiling, read like this:
C:\Users\farta\AppData\Local\Temp\cc99HxYj.s:22: Error: junk `(%esp)' after expression
If i use 'r' for input/output constraint, the code will work. But I cannot understand why it works and what the error stands for. Can anyone tell me? As far as I know 'm' is just telling gcc not to allocate registers but directly access them in memory if inline asm code try to access input/output operands. Is this correct?
Thanks a lot.
The problem here is the GCC generates AT&T syntax construct for %0, %1 and %2. If you look at the generated assembly, it looks like:
.intel_syntax
mov eax, 8(%ebp)
mov edx, 12(%ebp)
add eax, edx
mov -4(%ebp), eax
which is not a valid Intel syntax.
Generally, you don't need to include in the inline assembly explicit load/store operation - just specify register constraint and the compiler will generate loads/stores by itself. This has the advantage that even if your variables (parameters, locals) do not reside in memory at all, but are in registers your code will still be correct - unlike in the case if you explicitly put memory load/stores there.
For your example, try the following code, look at the assembly (gcc -S) and notice how the compiler will perform moves from argument area (e.g. stack on x86) all by itself.
int asm_test(int a, int b)
{
__asm__ __volatile__ (
".intel_syntax\n"
"add %0, %1 \n"
".att_syntax \n"
:"+r"(a)
:"r"(b));
return a;
}

How to write multiline inline assembly code in GCC C++?

This does not look too friendly:
__asm("command 1"
"command 2"
"command 3");
Do I really have to put a doublequote around every line?
Also... since multiline string literals do not work in GCC, I could not cheat with that either.
I always find some examples on Internet that the guy manually insert a tab and new-line instead of \t and \n, however it doesn't work for me. Not very sure if your example even compile.. but this is how I do:
asm volatile( // note the backslash line-continuation
"xor %eax,%eax \n\t\
mov $0x7c802446, %ebx \n\t\
mov $1000, %ax \n\t\
push %eax \n\t\
call *%ebx \n\t\
add $4, %esp \n\t\
"
: "=a"(retval) // output in EAX: function return value
:
: "ecx", "edx", "ebx" // tell compiler about clobbers
// Also x87 and XMM regs should be listed.
);
Or put double quotes around each line, instead of using \ line-continuation. C string literals separately only by whitespace (including a newline) are concatenated into one long string literal. (Which is why you need the \n inside it, so it's separate lines when it's seen by the assembler).
This is less ugly and makes it possible to put C comments on each line.
asm volatile(
"xor %eax,%eax \n\t"
"mov $0x7c802446, %ebx \n\t"
"mov $1000, %ax \n\t"
"push %eax \n\t" // function arg
"call *%ebx \n\t"
"add $4, %esp \n\t" // rebalance the stack: necessary for asm statements
: "=a"(retval)
:
: "ecx", "edx", "ebx" // clobbers. Function calls themselves kill EAX,ECX,EDX
// function calls also clobber all x87 and all XMM registers, omitted here
);
C++ multiline string literals
Interesting how this question pointed me to the answer:
main.cpp
#include <cassert>
#include <cinttypes>
int main() {
uint64_t io = 0;
__asm__ (
R"(
incq %0
incq %0
)"
: "+m" (io)
:
:
);
assert(io == 2);
}
Compile and run:
g++ -o main -pedantic -std=c++11 -Wall -Wextra main.cpp
./main
See also: C++ multiline string literal
GCC also adds the same syntax as a C extension, you just have to use -std=gnu99 instead of -std=c99:
main.c
#include <assert.h>
#include <inttypes.h>
int main(void) {
uint64_t io = 0;
__asm__ (
R"(
incq %0
incq %0
)"
: "+m" (io)
:
:
);
assert(io == 2);
}
Compile and run:
gcc -o main -pedantic -std=gnu99 -Wall -Wextra main.c
./main
See also: How to split a string literal across multiple lines in C / Objective-C?
One downside of this method is that I don't see how to add C preprocessor macros in the assembly, since they are not expanded inside of strings, see also: Multi line inline assembly macro with strings
Tested on Ubuntu 16.04, GCC 6.4.0, binutils 2.26.1.
.incbin
This GNU GAS directive is another thing that should be in your radar if you are going to use large chunks of assembly: Embedding resources in executable using GCC
The assembly will be in a separate file, so it is not a direct answer, but it is still worth knowing about.

Resources