2013-02-23 6 views
5

J'ai vu le post sur la même erreur, mais je suis encore obtenir l'erreur:asm en C « trop de références de mémoire pour` mov ' »

too many memory references for `mov' 
junk `hCPUIDmov buffer' after expression 

... voici le code (compilateur MinGW/C :: B):


    #include iostream 

    using namespace std; 

    union aregister 
    { 
     int theint; 
     unsigned bits[32]; 
    }; 

    union tonibbles 
    { 
     int integer; 
     short parts[2]; 
    }; 

    void GetSerial() 
    { 
     int part1,part2,part3; 
     aregister issupported; 
     int buffer; 

     __asm(
      "mov %eax, 01h" 
      "CPUID" 
      "mov buffer, edx" 
     );//do the cpuid, move the edx (feature set register) to "buffer" 


     issupported.theint = buffer; 
     if(issupported.bits[18])//it is supported 
     { 
      __asm(
       "mov part1, eax" 
       "mov %eax, 03h" 
       "CPUID" 
      );//move the first part into "part1" and call cpuid with the next subfunction to get 
      //the next 64 bits 

      __asm(
       "mov part2, edx" 
       "mov part3, ecx" 
      );//now we have all the 96 bits of the serial number 


      tonibbles serial[3];//to split it up into two nibbles 

      serial[0].integer = part1;//first part 
      serial[1].integer = part2;//second 
      serial[2].integer = part3;//third 
     } 
    } 

+2

Vous ne devriez pas utiliser ''% pour tous vos accès registre? –

+4

Je pense que vous avez oublié quelques signes% avant d'enregistrer les noms. – fuz

+0

Quelles sont ces 3 lignes à la fin de la question me disant que mon article est principalement du code? –

Répondre

8

Votre code d'assembly est not correctly formatted pour gcc.

Tout d'abord, gcc utilise AT & T syntaxe (EDIT: by default, thanks nrz), donc il a besoin d'un % ajouté pour enregistrer chaque référence et un $ pour opérandes immédiats. L'opérande de destination est toujours sur le côté droit. Deuxièmement, vous devrez passer un séparateur de ligne (par exemple \n\t) pour une nouvelle ligne. Puisque gcc passe directement votre chaîne à l'assembleur, elle nécessite une syntaxe particulière.

Vous devriez généralement essayer de minimiser votre assembleur car cela pourrait causer des problèmes à l'optimiseur. Le moyen le plus simple de minimiser l'assembleur requis serait probablement de décomposer l'instruction cpuid en fonction et de la réutiliser.

void cpuid(int32_t *peax, int32_t *pebx, int32_t *pecx, int32_t *pedx) 
{ 
    __asm(
     "CPUID" 
      /* All outputs (eax, ebx, ecx, edx) */ 
     : "=a"(*peax), "=b"(*pebx), "=c"(*pecx), "=d"(*pedx) 
      /* All inputs (eax) */ 
     : "a"(*peax)           
    ); 
} 

Ensuite, il suffit d'appeler en utilisant;

int a=1, b, c, d; 

cpuid(&a, &b, &c, &d); 

Une autre façon peut-être plus élégant est à do it using macros.

+0

Ce code manque également de contraintes de registre, donc autant que je sache, c'est complètement dangereux/faux. Vous devez indiquer à gcc quels registres vous utiliserez/clobber et où vont les entrées/sorties. –

+0

@R .. Ouais, mon mauvais, j'ai pris un mauvais exemple de la page. Remplacé par quelques liens vers des informations et un exemple plus pertinent. –

4
  1. En raison de la façon dont fonctionne C,

    __asm(
        "mov %eax, 01h" 
        "CPUID" 
        "mov buffer, edx" 
    ); 
    

    est équivalent à

    __asm("mov %eax, 01h" "CPUID" "mov buffer, edx"); 
    

    qui équivaut à

    __asm("mov %eax, 01hCPUIDmov buffer, edx"); 
    

    qui n'est pas ce que vous voulez.

  2. AT & La syntaxe T (par défaut du GAS) place le registre de destination à la fin.

  3. AT & La syntaxe T exige que les préfixes soient immédiatement préfixés par $.

  4. Vous ne pouvez pas référencer des variables locales comme cela; vous devez les passer en tant qu'opérandes.

Wikipedia's article donne un exemple de travail qui retourne eax.

L'extrait suivant pourrait couvrir votre cas d'utilisation (je ne suis pas intimement familier avec l'assembleur en ligne de GCC ou CPUID):

int eax, ebx, ecx, edx; 
eax = 1; 
__asm("cpuid" 
    : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx)); 
buffer = edx