ASM

2013-02-23 32 views
5

ASM

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

...ここにコード(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

次のスニペットは、あなたのユースケースを(私はGCCのインラインアセンブリまたはCPUIDと複雑に慣れていないよ)をカバーでしょうか? –

+4

あなたはレジスタ名の前にいくつかの%記号を忘れてしまったと思います。 – fuz

+0

質問の最後に私の投稿が主にコードであることを伝える3行は何ですか? –

答えて

8

gccのアセンブリコードはnot correctly formattedです。

まず、GCCは& T構文(EDIT:by default, thanks nrz)での使用ので、%は即値オペランドため$をそれぞれ参照を登録するために添加し、必要です。宛先オペランドは常にの右側にあります。

第2に、新しい行に改行記号(たとえば、\n\t)を渡す必要があります。 gccは文字列をアセンブラに直接渡すので、特定の構文が必要です。

通常、オプティマイザに問題が発生する可能性があるため、アセンブラを最小限に抑えるようにしてください。必要なアセンブラを最小限に抑える最も簡単な方法は、おそらくcpuid命令を関数に分解して再利用することでしょう。

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)           
    ); 
} 

次に、単にを使用して呼び出します。

int a=1, b, c, d; 

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

do it using macrosに別の方法があります。そのためCがどのように動作するかの

+0

このコードにはレジスタの制約もありません。私が知っている限り、完全に安全でない/偽のものです。あなたは/ clobberを使うレジスタと、入出力がどこに行くのかをgccに伝えなければなりません。 –

+0

@R ..ええ、私の悪い、私はページから悪い例を選んだ。それを情報へのリンクと関連性の高い例に置き換えました。 –

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

    は、あなたが望むものではありません

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

    と同等です

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

    に相当します。

  2. & T構文(GASのデフォルト)は、宛先レジスタを最後に置きます。

  3. & T構文では、直前に$を付ける必要があります。

  4. このようなローカル変数は参照できません。それらをオペランドとして渡す必要があります。

Wikipedia's articleは、eaxを返す動作例を示します。あなたのレジスタがアクセスするすべてのために ``%を使用してはいけません

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