2

私はCがかなり得意で、アセンブリはあまり得意ではありませんが、興味から、gccを使用してC内で作業したいと思っていました。問題は、私のプログラムがばかげた数値を出すかクラッシュするかです。

unsigned sadd32(unsigned a, unsigned b)
{
    unsigned c = 0;

    __asm__("movl %%eax, %0" : "=a"(a));
    __asm__("addl %%eax, %0" : "=b"(b));
    __asm__("movl %edx, 0xffffffff");
    __asm__("cmovc %eax, %edx");

    __asm__("movl %0, %%eax" : "=c"(c));


    return c;
}

誰にとっても明らかな場合、私は何かばかげたことをしたと確信しています?? ;)

4

3 に答える 3

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

unsigned sadd32(unsigned a, unsigned b)
{
    unsigned c = 0;
   __asm__ ("movl %2, %%eax\n\t"
                    "addl %1, %%eax\n\t"
                    "movl %%eax, %0\n\t"
                    :"=r"(c)
                    :"r"(a),"r"(b)
                    :"%eax"
             );
    return c;
}

int main()
{
    unsigned int a=3,b=5;
    printf("The sum of %u and %u is %u\n",a,b,sadd32(a,b));
    return 0;
}

参照: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html

私が見たところ、あなたのコードにはいくつかの欠陥があります::

unsigned sadd32(unsigned a, unsigned b)
{
    unsigned c = 0;

    __asm__("movl %%eax, %0" : "=a"(a));
    __asm__("addl %%eax, %0" : "=b"(b));
    __asm__("movl %edx, 0xffffffff"); /* this here, you are specifying a manual location, may not be accessible or valid */
    __asm__("cmovc %eax, %edx"); /* resulting in its error */

    __asm__("movl %0, %%eax" : "=c"(c));


    return c;
}

また、「=$」の概念を理解していないと思います。私が見たところ、そこに変数名を書いているだけですが、それはどのように機能するかではありません。サイトからの制約制約 (既知のとおり) は次のとおりです。

  1. "m" : メモリ オペランドは、マシンが一般的にサポートするあらゆる種類のアドレスで許可されます。
  2. "o" : メモリ オペランドが許可されますが、アドレスがオフセット可能である場合に限ります。つまり、アドレスに小さなオフセットを追加すると、有効なアドレスが得られます。
  3. "V" : オフセットできないメモリ オペランド。言い換えれば、m’ constraint but not theo'constraint に適合するものなら何でも。
  4. "i" : 即値整数オペランド (定数値を持つオペランド) が許可されます。これには、アセンブリ時にのみ値がわかる記号定数が含まれます。
  5. "n" : 既知の数値を持つ即値整数オペランドが許可されます。多くのシステムは、1 ワード幅未満のオペランドのアセンブリ時定数をサポートできません。これらのオペランドの制約には、「i」ではなく「n」を使用する必要があります。
  6. "g" : 汎用レジスタではないレジスタを除き、任意のレジスタ、メモリ、または即値整数オペランドが許可されます。

その他の例やその他の制約については、サイトを参照してください。これが役に立ったことを願っています!:)

于 2013-04-19T14:50:41.350 に答える
2

編集: Michael がこれは飽和 addであるとコメントしたため、コードを修正しました。

gcc インライン アセンブリの使用方法に関する主なポイント:

  1. インライン アセンブリを 1 つのasm(...)ブロックに配置します。
  2. 拡張アセンブリで入力、出力、および破壊されたレジスタを定義します。
  3. 最適なレジスターの使用法として、使用するレジスターの決定は gcc に任せてください。どの汎用レジスターもコードで同様に機能する場合です。
  4. インライン アセンブリ ブロックの先頭に値を設定するために使用する必要はありませんmov。入力を定義するだけです。
  5. GCC-Inline-Assembly-HOWTO 、特にExtended Asmの部分を注意深く確認してください。

コードは次のとおりです。

#include <stdio.h>

unsigned my_sadd(unsigned a, unsigned b)
{
    asm(
            "addl %2, %0;"
            "cmovcl %3, %0;"
            /* outputs */
            : "=r"(a)
            /* inputs */
            : "0"(a), "r"(b), "r" (0xffffffff)
        );
    return a;
}

int main(void)
{
    unsigned a;
    unsigned b;
    unsigned c;

    a = 123456;
    b = 314159;

    c = my_sadd(a, b);
    printf("%u + %u = %u\n", a, b, c);

    a = 0x80000000;
    b = 0xF0000000;
    c = my_sadd(a, b);

    printf("%u + %u = %u\n", a, b, c);
    return 0;
}
于 2013-04-19T14:49:58.970 に答える