-2

C++ (Dev-CPP) で Assembly を使用しようとしていますが、本来の文字列が出力されません。いくつかの調査の後、AT&T 構文を使用していることを発見しました。私のコードは、アセンブリ メッセージが表示されるだけの文字列を出力しません。これは私のコードです:

#include <iostream>

using namespace std;

int main()
{
    asm(".section .data");
    asm("hello: .string\"Hello, World!$\"\n");
    asm(".section .text");
    asm("movl $0x09, %ah \n");
    asm("mov hello, %dx\n");
    asm("int 0x21");

    system("PAUSE"); 
    return 0; 
}

助けてください。

4

2 に答える 2

2

理論的には、DJGPP (DOS 用の gcc ポート) でコンパイルされたプログラムのみが、DOS または Windows (XP 以下、通常は Vista/7/8 ではない) で実行する場合に、DOS エクステンダーを介して DOS サービス機能を合法的に使用できます。また、gcc は 16 ビットの x86 コードを生成しません。

さらに、インラインアセンブリを実際に学ぶ必要があります(グーグルで調べてください)。

コードが次のようになる場合のコンパイル可能なバージョン:

#include <iostream>
#include <cstdlib>

using namespace std;

int main()
{
    asm(".section .data");
    asm("hello: .string\"Hello, World!$\"\n");
    asm(".section .text");
    asm("movb $0x09, %ah\n"); // movl->movb
    asm("movl $hello, %edx\n"); // mov->movl,hello->$hello,dx->edx
    asm("int $0x21"); // 0x21->$0x21

    system("PAUSE"); 
    return 0; 
}

ただし、次の理由から、インライン アセンブリとして適切である可能性は低いです。

  • あなたのコードはレジスタを破棄し、どれが破棄されたかをコンパイラに通知しないため、プログラムの状態が破損し、クラッシュやハングにつながる可能性があります。
  • 個々の asm ステートメントに命令を記述します。その間に、コンパイラはあらゆる種類のコードを挿入し、インライン アセンブリを中断できます。それを防ぐために、関連する命令を単一のブロックに入れたいと本当に思っています。

このようなものが良いでしょう:

asm volatile (
  ".section .data\n"
  "hello: .string \"Hello, World!$\"\n"
  ".section .text\n"
  "movb $0x09, %ah\n"
  "movl $hello, %edx\n"
  "int $0x21\n"
);

残念ながら、これは DJGPP でも機能しません。この問題は、DJGPP と DPMI ホスト (CWSDPMI) によって行われるメモリ セグメンテーション セットアップ (おそらく仮想メモリ) と関係があります。何が間違っているのか正確にはわかりませんが、上記のコードはそのままでは機能しません。

そのため、プログラムをコンパイルする OS を特定し、その OS に適したインライン アセンブリ コードを記述してください。つまり、正しいレジスタとシステム コール メカニズムを使用してください。

DOS int 21h 関数は、ネイティブの Windows および Linux アプリでは機能しません。限目。間違ったチュートリアルを持っています。

于 2012-09-02T02:13:41.747 に答える
0

Alexeyの答え(セグメンテーションの問題を克服する方法)を拡張するために、これはコンパイルされます(そしておそらくDOSで実行されます):

asm volatile(
    "call 0f\n"
    ".byte 'H','e','l','l','o','W','o','r','l','d','!',0\n"
    "0: pop %0\n"
    "push %ds\n"
    "push %cs\n"
    "pop %ds\n"
    "int $0x21\n"
    "pop %ds\n" : "d"(0), "a"(9) : : "memory", "cc");

アイデアは、コード内で文字列をインライン化することですが、それを飛び越えます。その呼び出しのリターンアドレスは、文字列の開始アドレスです。次に、データセグメントを一時的にコードセグメントと同一にし、DOS INTを呼び出して、その後適切なデータセグメントを復元します。

于 2012-09-18T13:11:49.100 に答える