1

I'm working on Xeno Kovah's example in slide 18 of Intermediate Assembly. He's using Visual Studios with Intel Assembly, inline. I've tried adapting that to GCC as follows. I'm compiling with -masm=intel -fPIC

#include <stdio.h>
int main(){
  unsigned int maxBasicCPUID;
  char vendorString[13];
  char * vendorStringPtr = (char *)vendorString; //Move the address into its own register
  //because it makes the asm syntax easier
  //First we will check whether we can even use CPUID
  //Such a check is actually more complicated than it seems (OMITED FROM SLIDES)

  __asm (
    "mov edi, vendorStringPtr;" //Get the base address of the char[] into a register
    "mov eax, 0;" //We're going to do CPUID with input of 0
    "cpuid;" //As stated, the instruction doesn't have any operands
    //Get back the results which are now stored in eax, ebx, ecx, edx
    //and will have values as specified by the manual
    "mov maxBasicCPUID, eax;"
    "mov [edi], ebx;" //We order which register we put into which address
    "mov [edi+4], edx;" //so that they all end up forming a human readable string
    "mov [edi+8], ecx;"
  );
  vendorString[12] = 0;
  printf("maxBasicCPUID = %#x, vendorString = %s\n", maxBasicCPUID, vendorString);
  return 0xb45eba11;
}

I'm not sure what I'm doing wrong, but I'm getting the following error

/usr/bin/ld: /tmp/ccSapgOG.o: relocation R_X86_64_32S against undefined symbol `vendorStringPtr' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
  • With GCC you'll want to use [extended inline assembly](https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html) templates to pass arrays and variables to the assembly – Michael Petch Mar 04 '18 at 04:03
  • 1
    You're using 32-bit registers for pointers, but still compiling for x86-64. But more importantly, MSVC-style inline asm is completely different from GNU C style. [What is the difference between `__asm` and `__asm__`?](https://stackoverflow.com/questions/3323445/what-is-the-difference-between-asm-and-asm) – Peter Cordes Mar 04 '18 at 19:20

1 Answers1

4

In gcc, you can't reference local variables directly by name within the assembly code.

Also, you need to tell the compiler about all the registers you use (clobber).

But, on the plus side, you can get the compiler to do a lot more of the work for you, as you can see in the following rewrite of your code:

   uint32_t *str = (uint32_t *)vendorString;
   __asm("cpuid"
       : "=a"(maxBasicCPUID), "=b"(str[0]), "=d"(str[1]), "=c"(str[2])
       : "a"(0));

The first line of parameters tells the compiler where to store the results, and the second line tells the compiler what values to load before executing the inline assembly.

For all the details, see https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html. (Thanks to @MichaelPetch for the link.)

prl
  • 11,716
  • 2
  • 13
  • 31