0

文字列の文字数をカウントするアセンブリ コードを作成しようとしましたが、エラーが発生しました。

コード、gcc と intel_syntax を使用

#include <stdio.h>

int main(){
char *s = "aqr  b qabxx xryc pqr";
int x;

asm volatile (
    ".intel_syntax noprefix;"
    "mov eax, %1;"
    "xor ebx,ebx;"
    "loop:"
        "mov al,[eax];"
        "or al, al;"
        "jz print;"
        "inc ebx;"
        "jmp loop"
    "print:"
    "mov %0, ebx;"
    ".att_syntax prefix;"
    : "=r" (x)
    : "r" (s)
    : "eax", "ebx"
);

    printf("Length of string: %d\n", x);
    return 0;

}

そして、私はエラーが発生しました:

Error: invalid use of register

最後に、正規表現 pattern([pq][^a]+a) を検索し、開始位置と長さを出力するプログラムを作成したいと思います。私は C で書きましたが、アセンブリで動作させる必要があります: 私の C コード:

#include <stdio.h>
#include <string.h>

int main(){
  char *s = "aqr  b qabxx xryc pqr";
  int y,i;
  int x=-1,length=0, pos = 0;

    int len = strlen(s);
    for(i=0; i<len;i++){
        if((s[i] == 'p' || s[i] == 'q') && length<=0){
            pos = i;
            length++;
            continue;
        } else if((s[i] != 'a')) && pos>0){
            length++;
        } else if((s[i] == 'a') && pos>0){
            length++;
            if(y < length) {
                y=length;
                length = 0;
                x = pos;
                pos = 0;    
            }
            else 
                length = 0;
                pos = 0;
        }
    }  

    printf("position: %d, length: %d", x, y);
    return 0;

}
4

1 に答える 1

1

jmp loopとの後のセミコロンを省略しましたprint:


また、あなたの asm は正しく動作しません。へのポインターをseax に移動しますが、それを で上書きしますmov al,[eax]。そのため、ループを通過する次のパスでは、eax はもう文字列を指していません。

そして、それを修正するときは、ループを通過するたびに次の文字を指すように eax を変更する必要があるという事実を考慮する必要があります。そうしないmov al,[eax]と、同じ文字を読み続けます。


まだ回答を受け入れていないので (左側のチェックマークをクリックして)、もう一度編集する時間があります。

普段は「人の宿題をする」ことはないのですが、ここ数日です。おそらく課題の期日は過ぎています。そのため、OP の教育と将来の SO ユーザーの両方のためのいくつかの解決策を次に示します。

1)割り当ての(やや奇妙な)制限に従う:

asm volatile (
    ".intel_syntax noprefix;"
    "mov eax, %1;"
    "xor ebx,ebx;"
    "cmp byte ptr[eax], 0;"
    "jz print;"
    "loop:"
        "inc ebx;"
        "inc eax;"
        "cmp byte ptr[eax], 0;"
        "jnz loop;"
    "print:"
    "mov %0, ebx;"
    ".att_syntax prefix;"
    : "=r" (x)
    : "r" (s)
    : "eax", "ebx"
);

2) 割り当て規則のいくつかに違反して、コードを少し改善する:

asm (
    "\n.intel_syntax noprefix\n\t"
    "mov eax, %1\n\t"
    "xor %0,%0\n\t"
    "cmp byte ptr[eax], 0\n\t"
    "jz print\n"
    "loop:\n\t"
        "inc %0\n\t"
        "inc eax\n\t"
        "cmp byte ptr[eax], 0\n\t"
        "jnz loop\n"
    "print:\n"
    ".att_syntax prefix"
    : "=r" (x)
    : "r" (s)
    : "eax", "cc", "memory"
);

これにより、使用するレジスタが 1 つ少なくなり (no ebx)、(不要な)volatile修飾子が省略されます。また、「cc」クロバーを追加して、コードがフラグを変更することを示し、「メモリ」クロバーを使用して、「保留中」の書き込みがsasm を実行する前にメモリにフラッシュされるようにします。また、フォーマット (\n\t) を使用するため、ビルドからの出力-Sは読み取り可能です。

3) さらに少ないレジスタを使用し ( no eax)、 NULL でないことを確認しs(-1 を返す)、記号名を使用し-masm=intel、より読みやすいコードになると仮定する高度なバージョン:

__asm__ (
    "test %[string], %[string]\n\t"
    "jz print\n"
    "loop:\n\t"
        "inc %[length]\n\t"
        "cmp byte ptr[%[string] + %[length]], 0\n\t"
        "jnz loop\n"
    "print:"
    : [length] "=r" (x)
    : [string] "r" (s), "[length]" (-1)
    : "cc", "memory"
);

(恣意的でよく考えられていない) 代入制約を取り除くことで、これを 7 行に減らすことができます (NULL をチェックしない場合は 5 行、ラベルをカウントしない場合は 3 行 [実際には命令ではない])。 .

これをさらに改善する方法はあります (%=重複シンボルの問題を回避するためにラベルを使用する、ローカル ラベル ( .L) を使用する、 と の両方で機能するように記述する など) が、あえて言えば、これら 3 つのいずれかが優れています。元の質問のコードより。-masm=intel-masm=att


くばさん、あなたが答えを受け入れる前に、あなたがここで何を求めているのかわかりません。それでも、Peter のバージョンを含める機会を与えてくれます。

4) ポインタの増分:

__asm__ (
    "cmp byte ptr[%[string]], 0\n\t"
    "jz .Lprint%=\n"
    ".Loop%=:\n\t"
    "inc %[length]\n\t"
    "cmp byte ptr[%[length]], 0\n\t"
    "jnz .Loop%=\n"
    ".Lprint%=:\n\t"    
    "sub %[length], %[string]"
    : [length] "=&r" (x)
    : [string] "r" (s), "[length]" (s)
    : "cc", "memory"
);

これは #3 の「NULL ポインター」チェックを行いませんが、Peter が推奨していた「ポインターのインクリメント」を行います。また、( を使用して) 潜在的な重複シンボルを回避%=し、「ローカル」ラベル ( で始まるもの.L) を使用して、余分なシンボルがオブジェクト ファイルに書き込まれるのを回避します。

「パフォーマンス」の観点からは、これはわずかに優れている可能性があります (時間は計測していません)。ただし、「学校のプロジェクト」の観点からは、#3 の明快さがより良い選択であるように思われます。「何らかの奇妙な理由で、標準のc関数を使用する代わりにasmでこれを書かなければならなかった場合、現実の世界で何を書くか」という観点から、おそらく使用法を調べますが、これがパフォーマンスに重要でない限り、将来のメンテナンスを容易にするために、#3 を使用したくなるでしょう。

于 2016-11-15T19:33:25.620 に答える