Borland x86インラインアセンブラ。ラベルのアドレスを取得しますか?
質問
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」のようにコンパイルします。
誰でもこれを機能させる方法を提案できますか?
UPDATE:Paxの質問(コメントを参照)に応答するために、Windowsローダーによって実行時にベースアドレスが変更された場合、WindowsローダーによってDLL / EXE PEイメージが引き続き再配置され、ラベルアドレスにパッチが適用されますローダーがランタイムを再ベースアドレスを使用するため、ラベルアドレスにコンパイル/リンク時間の値を使用することは問題になりません。
事前に感謝します。
解決
前回、ボーランド互換のアセンブリコードを作成しようとしましたが、ラベルを前方参照できないという制限に遭遇しました。ここで何が起こっているのかわかりません。
他のヒント
ボーランドに関するすべての情報は、これが機能することを示唆しています。他のサイトでの同様の質問(こちらおよびこちら)は、ボーランドがラベルの前方参照を処理できることを示唆していますが、 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:
&amp;&amp; operatorは非標準の拡張機能であり、gcc以外のどこでも機能するとは思わないでしょう。うまくいけば、これがいくつかの新しいアイデアを呼び起こしたかもしれません...幸運を祈ります!
編集:Microsoft固有のものとしてリストされていますが、こちらはラベルにジャンプする別のインスタンス。
3つの提案:
1)アセンブリのSomeLabelの前に「_」を付けて、&quot; mov eax、_SomeLabel &quot ;.通常、コンパイラはCをアセンブリに変換するときに追加します。
または
2)アセンブリセクションにラベルを配置します。これにより、コンパイラが「_」を追加できなくなります。
または
3)アセンブリをコメントアウトし、コンパイルし、リストファイル(* .lst)を調べて、ラベル名がどうなるかを確認します。
Turbo C ++環境には、TASMのオプションを設定する方法がありますか?
その場合、「最大パス(/ m)」のオプションを変更するかどうかを確認します。 2つ以上のヘルプになります(デフォルトでは1パスになります)。
また、問題を引き起こす可能性のある長いラベル名を使用している場合-少なくとも1つのIDEのデフォルトが12に設定されていました。「最大シンボル長(/ mv)オプション」を変更します。
この情報は、BorlandのRAD Studio IDEに基づいています。
さらにいくつかのこと(暗闇でのショット)を試してください:
-
次のアセンブリ命令の使用が役立つかどうかを確認します。
mov eax, offset SomeLabel
-
ほとんどのコンパイラーは、生成するコードのアセンブリー・リストを作成できます(Codegear / Embarcaderoが無料の非プロフェッショナル・コンパイラーとして位置付けているため、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; }
アセンブリのリストを見て、生成されたアセンブリがインラインアセンブリで複製できるようにラベル名を修飾しているかどうかを確認します。
思い出すと、インラインアセンブリで外部(C ++)ラベルを使用することはできませんが、アセンブリ命令自体で参照できるasmブロックにTASMスタイルのラベルを付けることができます。フラグとポストアセンブラの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;
}
コンパイラー/アセンブラーについて具体的には知りませんが、次の場所を呼び出してスタックをレジスターにポップするのがかなりのトリックです。呼び出しは必ず返信先アドレスをプッシュするようにしてください。
あなたが直面している問題は、 __ asm
ブロック内のラベルとC ++コードのラベルがまったく異なる2つのものだと思います。インラインアセンブリからこの方法でC ++ラベルを参照できるとは思いませんが、Turbo C ++を使用してから非常に長い時間がかかったと言わざるを得ません。
mov
の代わりに lea
命令を試しましたか?
C / ++コンパイラでインラインアセンブラを使用したことがないので推測するだけです...
void foo::bar( void )
{
__asm
{
mov eax, SomeLabel
// ...
}
// ...
__asm
{
SomeLabel:
// ...
}
// ...
}
TASMの正確な構文はわかりません。
これはIvanの提案の変形ですが、試してみてください:
void foo::bar( void )
{
__asm
{
mov eax, offset SomeLabel
// ...
}
// ...
__asm SomeLabel:
// ...
}
可能な方法は次のとおりです。
// 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 ++では動作します。ほぼ確実にコンパイラと最適化の設定に依存しています。
オプションの1つは、個別の「裸」を使用することです。 (プロローグなし)ラベルではなくSomeLabelプロシージャ