8

Borland Turbo C++ をインライン アセンブラー コードで使用しているため、おそらく Turbo Assembler (TASM) スタイルのアセンブリ コードです。私は次のことをしたい:

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
SomeLabel:
    // ...
}

そのため、SomeLabel のアドレスが EAX に配置されます。これは機能せず、コンパイラは次のように文句を言います: 未定義のシンボル 'SomeLabel'。

Microsoft Assembler (MASM) では、ドル記号 ($) が現在の場所のカウンターとして機能します。これは、私の目的に役立ちます。しかし、これも Borlands Assember では機能しないようです (式の構文エラー)。

更新: もう少し具体的に言うと、実行時ではなく、コンパイル/リンク中に定数として eax に移動するアドレスをコンパイラが生成する必要があるため、「mov eax, 0x00401234」のようにコンパイルされます。

誰でもこれを機能させる方法を提案できますか?

更新: Pax の質問 (コメントを参照) に応答するには、実行時に Windows ローダーによってベース アドレスが変更された場合でも、DLL/EXE PE イメージは Windows ローダーによって再配置され、ラベル アドレスは実行時に次のようにパッチされます。ローダーは再ベースのアドレスを使用するため、ラベル アドレスにコンパイル/リンク時の値を使用しても問題ありません。

よろしくお願いします。

4

12 に答える 12

4

前回、いくつかのアセンブリ コードを Borland 互換にしようとしたときに、ラベルを前方参照できないという制限に遭遇しました。それがあなたがここで実行しているものかどうかはわかりません。

于 2008-10-16T23:55:39.457 に答える
4

ボーランドについて私が見つけることができるすべては、これがうまくいくはずであることを示唆しています. 他のサイト (ここここ) での同様の質問は、Borland がラベルの前方参照を処理できることを示唆していますが、ラベルは asm ブロックの外側にあると主張しています。ただし、ラベルは既に asm ブロックの外にあったため...

たとえば、jmp 命令内でこのラベルを使用することをコンパイラが許可するかどうかに興味があります。それをいじってみると (確かに、完全に異なるコンパイラで)、コンパイラがオペランドの型について不平を言う厄介な傾向があることがわかりました。

構文はかなり異なります。インライン asm を長い間試したのはこれが初めてですが、gcc で動作するように十分に変更したと思います。おそらく、違いはありますが、これはあなたに役立つかもしれません:

#include <stdio.h>
int main()
{
    void *too = &&SomeLabel;
    unsigned int out;
    asm
    (
      "movl %0, %%eax;"
      :"=a"(out)
      :"r"(&&SomeLabel)
    );
SomeLabel:
    printf("Result: %p %x\n", too, out);

    return 0;
}

これにより、次が生成されます。

...
        movl    $.L2, %eax
...
.L2:

&& 演算子は非標準の拡張機能です。gcc 以外では機能しないと思います。うまくいけば、これはいくつかの新しいアイデアをかき立てたかもしれません...頑張ってください!

編集: Microsoft 固有のものとしてリストされていますが、ラベルにジャンプする別の例を次に示します。

于 2009-01-28T12:49:01.847 に答える
1

試してみることがさらにいくつかあります(暗闇の中でのショット):

  • 次の組み立て手順を使用すると役立つかどうかを確認してください。

    mov eax, offset SomeLabel
    
  • ほとんどのコンパイラは、生成したコードのアセンブリリストを生成できます(Codegear / Embarcaderoは、Turbo C ++を無料の非プロフェッショナルコンパイラとして位置付けているため、Turbo C ++が生成できるかどうかはわかりません)。

    同じ関数内にいくつかのインラインアセンブリを使用して、(たとえばターゲットとして)ラベルを使用するCコードでリストを作成してみてくださいgoto。ただし、アセンブリからラベルにアクセスしようとしないでください。これは、エラーのないコンパイラとアセンブリリストを取得できるようにするためです。何かのようなもの:

    int foo()
    {
        int x = 3;
        printf( "x =%d\n", x);
        goto SomeLabel;
                               //
        __asm {
            mov eax, 0x01
        }
                               //
    SomeLabel:
        printf( "x =%d\n", x);
                               //
        return x;
    }
    

    アセンブリリストを見て、生成されたアセンブリがインラインアセンブリで複製できるようにラベル名を装飾しているかどうかを確認します。

于 2009-02-03T19:22:16.100 に答える
1

あなたが遭遇している問題は、__asmブロック内のラベルとC++コード内のラベルが2つの完全に異なるものであるということだと思います。インラインアセンブリからそのようにC++ラベルを参照できるとは思いませんが、TurboC++を使用してからかなりの時間が経過していると言わざるを得ません。

lea代わりに指示を試しましたmovか?

于 2009-01-27T09:44:01.783 に答える
1

Turbo C++ 環境には TASM のオプションを設定する方法がありますか (Borland IDE のいくつかはそうでした)?

その場合は、「最大パス (/m)」のオプションを 2 つ以上に変更すると役立つかどうかを確認してください (デフォルトで 1 パスになる場合があります)。

また、問題を引き起こす可能性のある長いラベル名を使用している場合、少なくとも 1 つの IDE でデフォルトが 12 に設定されていました。「最大シンボル長 (/mv) オプション」を変更します。

この情報は、Borland の RAD Studio IDE に基づいています。

于 2009-02-03T09:14:11.460 に答える
1

3 つの提案:

1) アセンブリ内の SomeLabel の前に「_」を配置して、「mov eax, _SomeLabel」になるようにします。通常、コンパイラは C をアセンブリに変換するときに 1 つ追加します。

または

2) 組み立てセクションにラベルを入れます。これにより、コンパイラは「_」を追加できなくなります。

または

3) アセンブリをコメント アウトし、コンパイルして、リスト ファイル (*.lst) を調べて、ラベル名がどうなるかを確認します。

于 2008-10-16T16:34:18.380 に答える
0

私が覚えていることから、インラインアセンブリで外部(C ++)ラベルを使用することはできませんが、アセンブリ命令自体で参照できるTASMスタイルのラベルをasmブロックに含めることはできます。分岐を処理するには、フラグとアセンブラ後のswitchステートメントを使用すると思います。例えば:

int result=0;

__asm__ {
    mov result, 1
}

switch (result){
    case 1:  printf("You wanted case 1 to happen in your assembler\n"); break;
    case 0:  printf("Nothing changed with the result variable.. defaulting to:\n");
    default: printf("Default case!\n"); break;
}
于 2008-10-16T16:37:38.013 に答える
0

可能な方法は次のとおりです。

// get_address
// gets the address of the instruction following the call
// to this function, for example
//     int addr = get_address (); // effectively returns the address of 'label'
//   label:
int get_address ()
{
    int address;
    asm
    {
        mov eax,[esp+8]
        mov address,eax
    }
    return address;
}
// get_label_address
// a bit like get_address but returns the address of the instruction pointed
// to by the jmp instruction after the call to this function, for example:
//     int addr;
//     asm
//     {
//       call get_label_address // gets the address of 'label'
//       jmp label
//       mov addr,eax
//     }
//     <some code>
//   label:
// note that the function should only be called from within an asm block.
int get_label_address()
{
    int address = 0;
    asm
    {
        mov esi,[esp+12]
        mov al,[esi]
        cmp al,0ebh
        jne not_short
        movsx eax,byte ptr [esi+1]
        lea eax,[eax+esi-1]
        mov address,eax
        add esi,2
        mov [esp+12],esi
        jmp done
    not_short:
        cmp al,0e9h
        jne not_long
        mov eax,dword ptr [esi+1]
        lea eax,[eax+esi+2]
        mov address,eax
        add esi,5
        mov [esp+12],esi
        jmp done
    not_long:
        // handle other jmp forms or generate an error
    done:
    }
    return address;
}
int main(int argc, char* argv[])
{
    int addr1,addr2;
    asm
    {
        call get_label_address
        jmp Label1
        mov addr1,eax
    }

    addr2 = get_address ();
Label1:
    return 0;
}

少しハックですが、私が持っている Turbo C++ のバージョンで動作します。ほぼ確実に、コンパイラと最適化の設定に依存しています。

于 2009-01-27T15:03:25.100 に答える
0

これは Ivan の提案の変形ですが、これを試してみてください。

void foo::bar( void )
{
    __asm
    {
      mov eax, offset SomeLabel
      // ...
    }
    // ...
    __asm SomeLabel:
    // ...
}
于 2010-11-13T12:42:28.103 に答える
0

具体的にあなたのコンパイラ/アセンブラについては知りませんが、私がかなり使ったトリックは、次の場所を呼び出してから、スタックをレジスタにポップすることです。発信する呼び出しがリターン アドレスのみをプッシュすることを確認してください。

于 2008-10-16T17:56:26.810 に答える
0

C/++コンパイラでインラインアセンブラを使用したことがないので、推測です...

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
    __asm
    {
      SomeLabel:
      // ...
    }
    // ...
}

TASM の正確な構文がわかりません。

于 2009-01-28T10:22:05.277 に答える
0

オプションの 1 つは、ラベルの代わりに別の「ネイキッド」(プロローグのない) プロシージャ SomeLabel を使用することです。

于 2013-10-10T05:14:38.587 に答える