'Error in simple g++ inline assembler

I'm trying to write a "hello world" program to test inline assembler in g++. (still leaning AT&T syntax)

The code is:

#include <stdlib.h>
#include <stdio.h>

# include <iostream> 

using namespace std;

int main() {
    int c,d;

    __asm__ __volatile__ (
        "mov %eax,1;    \n\t"
        "cpuid;         \n\t"
        "mov %edx, $d;  \n\t"
        "mov %ecx, $c;  \n\t"
    );

    cout << c << " " << d << "\n";

    return 0;
}

I'm getting the following error:

inline1.cpp: Assembler messages:
inline1.cpp:18: Error: unsupported instruction `mov'
inline1.cpp:19: Error: unsupported instruction `mov'

Can you help me to get it done?

Tks



Solution 1:[1]

Your assembly code is not valid. Please carefully read on Extended Asm. Here's another good overview. Here is a CPUID example code from here:

static inline void cpuid(int code, uint32_t* a, uint32_t* d)
{
    asm volatile ( "cpuid" : "=a"(*a), "=d"(*d) : "0"(code) : "ebx", "ecx" );
}

Note the format:

  • first : followed by output operands: : "=a"(*a), "=d"(*d); "=a" is eax and "=b is ebx
  • second : followed by input operands: : "0"(code); "0" means that code should occupy the same location as output operand 0 (eax in this case)
  • third : followed by clobbered registers list: : "ebx", "ecx"

Solution 2:[2]

I kept @AMA answer as accepted one because it was complete enough. But I've put some thought on it and I concluded that it is not 100% correct.

The code I was trying to implement in GCC is the one below (Microsoft Visual Studio version).

int c,d;
_asm
{
  mov eax, 1;
  cpuid;
  mov d, edx;
  mov c, ecx;
}

When cpuid executes with eax set to 1, feature information is returned in ecx and edx.

The suggested code returns the values from eax ("=a") and edx (="d"). This can be easily seen at gdb:

(gdb) disassemble cpuid
Dump of assembler code for function cpuid(int, uint32_t*, uint32_t*):
  0x0000000000000a2a <+0>:  push   %rbp
  0x0000000000000a2b <+1>:  mov    %rsp,%rbp
  0x0000000000000a2e <+4>:  push   %rbx
  0x0000000000000a2f <+5>:  mov    %edi,-0xc(%rbp)
  0x0000000000000a32 <+8>:  mov    %rsi,-0x18(%rbp)
  0x0000000000000a36 <+12>: mov    %rdx,-0x20(%rbp)
  0x0000000000000a3a <+16>: mov    -0xc(%rbp),%eax
  0x0000000000000a3d <+19>: cpuid   
  0x0000000000000a3f <+21>: mov    -0x18(%rbp),%rcx
  0x0000000000000a43 <+25>: mov    %eax,(%rcx)        <== HERE
  0x0000000000000a45 <+27>: mov    -0x20(%rbp),%rax
  0x0000000000000a49 <+31>: mov    %edx,(%rax)        <== HERE
  0x0000000000000a4b <+33>: nop
  0x0000000000000a4c <+34>: pop    %rbx
  0x0000000000000a4d <+35>: pop    %rbp
  0x0000000000000a4e <+36>: retq   
End of assembler dump.

The code that generates something closer to what I want is (EDITED based on feedbacks on the comments):

static inline void cpuid2(uint32_t* d, uint32_t* c)
{
   int a = 1;
   asm volatile ( "cpuid" : "=d"(*d), "=c"(*c), "+a"(a) :: "ebx" );
}

The result is:

(gdb) disassemble cpuid2
Dump of assembler code for function cpuid2(uint32_t*, uint32_t*):
   0x00000000000009b0 <+0>:   push   %rbp
   0x00000000000009b1 <+1>:   mov    %rsp,%rbp
   0x00000000000009b4 <+4>:   push   %rbx
   0x00000000000009b5 <+5>:   mov    %rdi,-0x20(%rbp)
   0x00000000000009b9 <+9>:   mov    %rsi,-0x28(%rbp)
   0x00000000000009bd <+13>:  movl   $0x1,-0xc(%rbp)
   0x00000000000009c4 <+20>:  mov    -0xc(%rbp),%eax
   0x00000000000009c7 <+23>:  cpuid  
   0x00000000000009c9 <+25>:  mov    %edx,%esi
   0x00000000000009cb <+27>:  mov    -0x20(%rbp),%rdx
   0x00000000000009cf <+31>:  mov    %esi,(%rdx)
   0x00000000000009d1 <+33>:  mov    -0x28(%rbp),%rdx
   0x00000000000009d5 <+37>:  mov    %ecx,(%rdx)
   0x00000000000009d7 <+39>:  mov    %eax,-0xc(%rbp)
   0x00000000000009da <+42>:  nop
   0x00000000000009db <+43>:  pop    %rbx
   0x00000000000009dc <+44>:  pop    %rbp
   0x00000000000009dd <+45>:  retq   
End of assembler dump.

Just to be clear... I know that there are better ways of doing it. But the purpose here is purely educational. Just want to understand how it works ;-)

-- edited (removed personal opinion) ---

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2