• ベストアンサー

マシン語(MS-DOS)の実行過程がわかりません

LSI C-86 Ver 3.30 試食版を利用して、「hello, world」を表示するプログラムをコンパイルしました。 出来上がったhello.exeがどのように実行されるのか知りたくて、SYMDEBコマンドでステップ実行してみることにしました。 その前にバイナリエディタでhello.exeを開くと、ヘッダは512バイトあり、200hからは最初のマシン語命令「B8 8B 02」が確認できました。 アセンブリ言語では「MOV AX,028Bh」となり、AXレジスタに028Bhがセットされるはずです。 しかし、実際にエミュレータ上で「SYMDEB hello.exe」実行してみると、次のような結果になりました。 -------------------- Microsoft (R) Symbolic Debug Utility Version 4.00 Copyright (C) Microsoft Corp 1984, 1985. All rights reserved. Processor is [8086] -r AX=4B01 BX=0000 CX=2CC1 DX=0000 SP=09C4 BP=0000 SI=0000 DI=0000 DS=117A ES=117A SS=146E CS=118A IP=0000 NV UP EI PL NZ NA PO NC 118A:0000 B81514 MOV AX,1415 -u 118A:0003 8ED0 MOV SS,AX 118A:0005 BC540F MOV SP,0F54 118A:0008 368C1E5800 MOV SS:[0058],DS 118A:000D B430 MOV AH,30 ;'0' 118A:000F CD21 INT 21 118A:0011 36A34500 MOV SS:[0045],AX 118A:0015 8A1E8000 MOV BL,[0080] 118A:0019 32FF XOR BH,BH -------------------- 最初のマシン語命令が、「MOV AX,1415」と書き換わっています。以降の命令はバイナリエディタで見た通りのようです。 なぜ最初の命令が書き換わってしまうのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • dell_OK
  • ベストアンサー率13% (740/5643)
回答No.3

試してみました。 環境が違うためか私の方では「MOV AX,0F9B」になってしまいました。 アドレス的なものかと思ってこんな引き算をしてみました。 AXレジスタセット値 - 開始アドレス 1415 - 118A = 28B 質問者さま 0F9B - 0D10 = 28B 私 と同じ値だったので、アドレスに対して相対的に「28B」を示している値なのかなと思えます。 質問者さまが想定している「MOV AX,028Bh」の値です。 回答No.2さまが言われているように、「リロケーションのためにアドレスを示す語が書き換わる」と言うことではないでしょうか。

saturn120660
質問者

お礼

わざわざ実際にEXEファイルまで作成していただいて、大変ありがとうございます。 CSレジスタとの差分には全く気づきませんでした。 これが最も重要なヒントになりそうです。 皆さんがおっしゃる通り、やはりリロケーションのロジックの一部のようです。DSレジスタとCSレジスタの間で値を調整しているのかもしれません。 この考えを基に、さらに調べを進められそうです。 大変ありがとうございました。

その他の回答 (2)

  • notnot
  • ベストアンサー率47% (4847/10260)
回答No.2

詳細な知識が無くて細かいところまで説明できませんが、EXEファイルはリロケータブルオブジェクトなので、メモリーへのロード時にリロケーションのためにアドレスを示す語が書き換わる可能性があります。 該当のデータはSSにセットされる値(物理アドレス)なので、リロケーション対象なのでしょう。EXEヘッダのどの部分がそれを示していて、028Bがどういうロジックで1415に変化するのか、等は私の知識では説明できません。 ググルとEXEファイルのヘッダ構造の説明ページもあるようなのでそのレベルまで突っ込んで理解したければ解読してみて下さい。 ただ、軽くググった感じだとネット上には細かいところまで解説した日本語ページは無さそうな気がします。

saturn120660
質問者

お礼

ご回答ありがとうございます。 プログラムの実行時にEXEファイルのヘッダ情報がどのように使われるかは、「MS-DOSエンサイクロペディア」という本で調べました。 プログラム部分の実行に先立って、ヘッダに定義されている初期セグメントレジスタ値がMS-DOSによってリロケーションされると書いてあるのですが、プログラムのコード自体が書き換わるとは書いていなかったので、理解できなかったのです。 わざわざ調べていただいてありがとうございました。

  • SPROCKETER
  • ベストアンサー率26% (2022/7547)
回答No.1

8086命令でプログラムを書いているのは良いのですが、DS,ES,CS,SSのセグメント定義をきちんとしていないのではないですか。ちゃんと初期化して置きましょう。 86系命令はPC286C(PC98互換機)を使っていた頃にゲームプログラムを書いていましたが、セグメント初期化を忘れると、とんでもないアドレスから実行を始める事がありますから、注意が必要です。 初期化をきちんとやって置かないと、おかしな挙動をする事があります。

saturn120660
質問者

補足

ご回答ありがとうございます。 説明が不親切で申し訳ありません、プログラムはアセンブリ言語で書いたわけではなく、C言語(LSI-C)で書きました。 【ソースコード】 #include <stdio.h> main() { printf("hello, world\n"); } 目的は、8086CPUがどのようにマシン語命令を実行していくか知りたかったためです。 レジスタの初期化がされているかどうかというよりも、一番最初に実行される命令が、 MOV AX,028B(EXEファイルをバイナリエディタで確認) ↓ MOV AX,1415(EXEファイルをSYMDEBで読み込んだ後に確認) のように、実行時に勝手に書き換わってしまっている理由がわからず質問をさせていただきました。

関連するQ&A

  • アセンブラ(二度目)

    先ほど質問させていただいたのですが、NASMでobjファイルを出力して、 ALINKをつかってexeファイルを出力したのですが、その際結果を確認するのに邪魔なものが一緒に出力されました。 ソースはこれです。 segment code ..start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, stacktop mov dx, hello mov ah, 0x09 int 0x21 mov ax, 0x4c00 int 0x21 segment data hello: db 'Hello World',13,10,'$' segment stack stack resb 64 stacktop:

  • MS-DOS or バッチ 一括実行

    フォルダー内に a.wav,b.wav,c.wav… と入っていて これらすべてを実行ファイル(Lame.exe) に渡す場合 lame.exe a.wav lame.exe b.wav を一括でする方法はありませんか?

  • 他の実行ファイルを実行するプログラム

    他の実行ファイルを実行するプログラムを作りたいです。 わかりにくいと思うので例を書いて説明します。 まずhello.cというプログラムがあったとします。 中身は -hello.c----------------- #include <stdio.h> main(){ printf("Hello!\n"); } -------------------------- これをコンパイルしてできた実行ファイルを他のプログラムから呼び出す?実行したいんです。 説明が下手ですいません(>_<) たとえば新しくexe.cというプログラムを作ります。 このexeを実行するとhello.exeが呼び出されて 結果的にhello.cの中身が実行されるような exe.cを作りたいです。 初歩的な質問ですいません。 どなたかアドバイスいただけないでしょうか(>_<)

  • VisualStudioでC#が実行できない

    VisualStudio Express2012でC#のコンソールアプリケーションを作成してみたのですが 下記のような簡単なコードでも実行に失敗します。 VIsualStudioのコンソールには以下のようなエラーが表示されるのですが 何か原因がわかる方いらっしゃいますでしょうか。 【コード】 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication3 { class Program { static void Main(string[] args) { Console.WriteLine("abc"); } } } 【エラー内容】 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities\11.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Drawing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities.Sync\11.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.Sync.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\11.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'c:\users\mishina\documents\visual studio 2012\Projects\ConsoleApplication3\ConsoleApplication3\bin\Debug\ConsoleApplication3.vshost.exe' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Data.DataSetExtensions\v4.0_4.0.0.0__b77a5c561934e089\System.Data.DataSetExtensions.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\Microsoft.Net\assembly\GAC_32\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll' が読み込まれました 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll' が読み込まれました スレッド 'vshost.NotifyLoad' (0x1350) はコード 0 (0x0) で終了しました。 スレッド 'vshost.LoadReference' (0x58c) はコード 0 (0x0) で終了しました。 'ConsoleApplication3.vshost.exe' (マネージ (v4.0.30319)): 'c:\users\mishina\documents\visual studio 2012\Projects\ConsoleApplication3\ConsoleApplication3\bin\Debug\ConsoleApplication3.exe が読み込まれました。シンボルが読み込まれました。 スレッド 'vshost.RunParkingWindow' (0x2698) はコード 0 (0x0) で終了しました。 スレッド '<名前がありません>' (0x26a0) はコード 0 (0x0) で終了しました。 プログラム '[7700] ConsoleApplication3.vshost.exe: マネージ (v4.0.30319)' はコード 0 (0x0) で終了しました。

  • WSHプログラミングで、Shell実行プロセスが終了しない内に、次の処理が実行されちゃいます・・・

    WSH(WindowsScriptingHost)でプログラミングを行っております。 以下のように、「A.exe」実行後、「B.exe」を実行するようにスクリプトを記述しています。 ところが、実際に実行してみると、「A.exe」が終了しない内に、「B.exe」が実行されてしまっている様なのです。 しかし、プログラム処理上、「A.exe」が実行終了してからでないと、「B.exe」を実行するのはまずいのです。 WSHで、「A.exe」が実行終了するまで、「B.exe」を実行させないようなスクリプトの記述方法を教えて下さい。 Set Shell = CreateObject("WScript.Shell") Shell.Run "cmd.exe /c D:\A.exe" Shell.Run "cmd.exe /c D:\B.exe"

  • 複数バイト命令実行のタイミング

    1バイト単位でメモリの各アドレスにデータが保存されているコンピューターにおいて、複数のバイトで表される命令がどのように実行されるのか教えて下さい。 メモリには一つのアドレスごとに8ビット(1バイト)のデータが入っており、CPUはプログラムカウンタで示されたメモリ上のアドレスにあるデータや命令を一つずつ順番に読み込んで、それをデコーダーが解釈し各回路への指令に変換することでプログラムを実行していくということは理解しています。 しかし現在の32ビットコンピューターなどにおいてアセンブリの命令、例えば「MOV A,B」(Bレジスタの内容をAレジスタにコピーする)といった命令は、「B90001」などの3バイトのマシン語で表されるとすると、メモリ上では アドレス  内容 0000  0xB9 0001  0x00 0002  0x01 のように3つの連続するアドレスにまたがってデータが存在し、CPUが「MOV A,B」を読み込み、それを順次デコーダーに送るまでには「MOV」、「A」、「B」の3クロックを要すると思います。 その際、デコーダーが命令を解釈し各回路に指令の信号を送るタイミングというのは、最後の「B」のデータを読み込んだ時点になるのでしょうか?もしそうならば、3クロック目に最後の「B」のデータがデコーダーに到着するまでの間、「MOV」と「A」のデータというのはCPUにメモリから読み込まれた後はどのように扱われるのでしょうか? 少し質問が分かりにくく恐縮ですが、情報工学を独学で勉強しており、プログラムが実際の回路でどのように実行されるのか理解したいと思っています。 どうぞご回答よろしくお願い致します。

  • ワクチンの実行

    http://www.microsoft.com/downloads/details.aspx?FamilyId=2B2409F1-A844-483A-B019-16C0442D86F6&displaylang=ja 上記のページに行き 対策ツール「SNS_ABM.exe」をダウンロード、その次の段階で 『ファイルを実行させるアプリケーションを選んで下さい。』 とのことなのですが・・・初心者の私ではどのアプリケーションを 選べばいいのか判らずに先に進めません。

  • バイナリエディタについて。

    同容量のファイルを比較しようと思いますが、バイナリエディタの機能で AとBとCがあったとき、AとBでは値がN違いAとCでは値がM違う のような検索ができるバイナリエディタを探しています。 上記のような機能、又は似たような機能を持つバイナリエディタをご存知の方よろしくお願いします。

  • Windowsでコマンドを短縮入力したい

    入力を省略す補助ツールを作りたいのです。 いつもファイル一式を作ったり修正したりするのに、 C:\>[生成実行.exe] [生成コマンド] [命令A] C:\>[生成実行.exe] [生成コマンド] [命令B] C:\>[生成実行.exe] [生成コマンド] [命令C] C:\>[生成実行.exe] [生成コマンド] [命令D] と打っています。 よくやる操作なので、できるだけ最短入力できるよう効率化したいです。 「入力省略.bat」を作り、「ファイル名を指定して実行」から「[入力省略.bat] [案件名]」と入力すると C:\> [命令A] C:\> [命令B] C:\> [命令C] C:\> [命令D] と略せるといいのですが…。 入力された値を必ずあるアプリケーションに渡すあたりの、何かヒントを頂けると嬉しいです。

  • プログラムがうまく実行できません。

    下にソースを載せたのですが、このプログラムがうまく実行できません。 OSはWin XPでコンパイラはボーランドのフリーコンパイラを利用しています。 #include<stdio.h> #include<math.h> int main() { double a,b,c,d,e,p; a=-1.43; b=1.43; c=-4.29; d=1.72; e=2.43; fot (p=0; p<1; p=p+0.0001){ printf("(%1.5f*pow(p,2)+%1.5f)/(%1.5%f*pow(p,2)+%1.5f*p+%1.5f,\n",a,b,c,d,e); } return 0; } (変えたい内容) pの値が0<p<1の範囲で、0.0001から0.0001ずつ増して行き、0.9999まで繰り返し処理して、1回ずつの値を出力したいのですが、うまくいきません。

専門家に質問してみよう