2016-05-27 3 views
2

以下は、hello world MIPSアセンブリ・プログラムのデバッグ・セッションです。 プログラムはGCCを使用してアセンブルされ、gdb-multiarchを使用してデバッグされます。 コードはQEMU上で実行され、GDBはbreak mainを実行すると、私はGDBが7行目(jal hello)に破ることを期待8080GDBのブレーク・スキップ・ラインでラベルが表示されない

上のポートをデバッグQEMUsに接続しているが、それはライン9

(gdb) file proj.out 
Reading symbols from proj.out...done. 
(gdb) target remote 127.0.0.1:8080 
Remote debugging using 127.0.0.1:8080 
0x00400290 in _ftext() 
(gdb) break main 
Breakpoint 1 at 0x400460: file /import/src/main.s, line 9. 
(gdb) list 
1  
2  .text 
3  .globl main 
4  .extern hello 
5  
6  main: 
7   jal hello 
8  
9   li $a0, 0 
10  li $v0, 4001 
にブレークポイントを作成します

私はプログラムに追加した任意のラベルに対してこれを再現することができました。ラベルのない行で壊れただけでは発生しません。しかし、break mainの代わりにbreak main.s:6を使用した場合にも発生します。

私はGDBが私が気づいていない何らかの種類の慣例に固執すると思っています。

プログラムのバージョン:

GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1 
mips-linux-gnu-gcc (Debian 4.3.5-4) 4.3.5 
qemu-mips version 2.0.0 (Debian 2.0.0+dfsg-2ubuntu1.24) 
operating system: ubuntu:14.04.4 docker container 

コンパイルコマンド:

mips-linux-gnu-gcc -g -static -mips32r5 -O0 -o 

答えて

4

MIPSアーキテクチャは、 "分岐遅延スロット" を持っています。

簡略化して考えてみましょう。命令ユニットと命令実行ユニットをフェッチする2つの別々のユニットがあります。

フェッチユニットは、実行ユニットの「1つ先に」実行されます。これにより、ユニットのオーバーラップが可能になります。すなわち、実行ユニットはフェッチと並行して動作することができる。前のサイクルでフェッチされたinstを実行します。

サイクル0では、最初の命令がフェッチされます。サイクル1では、第1の命令が実行され、第2の命令がフェッチされる。サイクル2では2nd instが実行され、3番目の命令がフェッチされます。これは、次のようになります。

cycle  fetch  exec 
0   1   n/a 
1   2   1 
2   3   2 
3   4   3 

我々はどのような種類(すなわちjal)の分岐命令を打つまでは正常に動作します。あなたの例では、7 jal hello9 li $a0,0があります。あなたのCコードは表示されませんでしたが、私はhelloは一つの引数を取り、あなたの実際の呼び出しはそうhello(0)

た、シーケンスはli $a0,0最もアーチ上jal helloだろうと思われます。

命令フェッチが "先行"で実行されるため、先読みされた命令の後にjalが破棄され、無駄になります。

したがって、mipsには分岐遅延スロットがあります。 の後にブランチは、で、の遅延スロットです。ブランチの前に登場したかのように、は常にです。

だから、論理的に、あなたのプログラムは次のようになります。実際の実行順序はL1、L3、L2

ある

L1:  li  $a0,0    # first arg to hello 
L2:  jal  hello    # call to hello 
L3:  nop       # branch delay slot 

コンパイラはこれを最適化し、分岐遅延に便利な命令を入れることができましたスロット:

L1:  jal  hello    # call to hello 
L2:  li  $a0,0    # first arg to hello 

実行順序はL2、L1です。ブランチ[takenまたはではなく]の場合、分岐遅延スロットの命令は、最初に実行された場合と同様に、常にが最初に実行されることを覚えておいてください。

したがって、gdb となりました。ブレークポイントを正しい場所に置いてください:mainの最初の命令です。しかし、最初の命令がブランチであったため、break命令を置く正しい場所はブランチの分岐遅延スロットです。

はあなたの例では、jalは7行目であり、それはライン9


だったため、分岐遅延スロットはUPDATE:

残念ながら、ブレークポイントが誤った位置に設定されています命令に関係なく:jal helloli $a0, 1に置き換えることができ、何も変更されません。

ごめんなさい。 liは、それが擬似命令であり、実際の命令を1-2個生成できるので、手がかりになったはずです。たとえば、li $a0,0x01020304は、次のように生成されます。lui $a0,0x0102 ori $a0,$a0,0x0304

ただし、分岐遅延スロットには注意が必要です。 qemuについてはわかりませんが、marsspimのようないくつかのmipsシミュレータでは、スロットの有効/無効を設定することができます。スロットのデフォルト値はです。オフの場合、スロットは無視できます。それ以外の場合は、各ブランチの後にnopを追加してください。

コードは "手作業で"書かれており、Cまたは他の言語からコンパイルされていません。

もう一度、申し訳ありません。私は「GCCで組み立てられた」代わりに「GCCでコンパイルされた」を見た。


問題の一部は、gdbが高水準言語ソースデバッガです。それがその主要な方向です。行番号の概念は、HLL(例えば、C)行番号に向けられている。だから、いくつかの助けを借りずにasm行番号に/からのマッピングが難しいかもしれません。ソースが.sであっても、それはcc -c -s -o foo.s foo.c ; cc -o foo foo.sから来る可能性があります。

gdbは、プログラムが-gでコンパイルされています。これは、特定のasmディレクティブを追加してデバッグ情報を定義します。それはどのようなものかを確認するには、Cプログラム[あるいはただの.cファイルについて]と[クロス]を取る使用して、それをコンパイルし-g [または-gdwarf-2]と-s。出力ファイル.sを見てください。

あなたは正確に何あなたは行番号があるべきだと思うgdbを伝えるための場所で同様のディレクティブを追加する必要があるかもしれません。これは、もちろん、手動で行うことができます。しかし、私は与えられた.sをとり、必要なものを追加するために "メタプログラミング"スクリプトを通してそれを供給することが知られていました。私はデバッグASMへgdbを使用し、精密な制御を必要とする、私はより良い配向されているいくつかの異なるGDBコマンドを使用してきた時はいつでもそう、これの出力は、gcc --YMMV


に供給されているものですが、アセンブラをデバッグする。

stepiの代わりstep。これは、gdb がソース行であると考える代わりに、単一のasm命令で処理します。

disassemble mainの代わりlist main。これは、ソースリストの代わりに実際の指示を出します。またはx/i <address>。良い例はx/i $pcです。

<address>は、ラベルやラベルを使用した簡単な式にすることができます。今

、ビギー:break *<address>代わりbreak <function>またはbreak <line_number>の、私はアドレスフォームを使用します。

したがって、disassemble mainが最初の命令がアドレス0x00001000にあることを示した場合、break *0x1000を実行します。

しかし、それは面倒です。アドレス形式はシンボルを許可します。したがって、あなたはbreak *mainを行うことができます。また、アドレス式も使用できます。break *main+0x4。私は別のアプローチ


:-)「これら は、あなたが探しているドロイドですが、」シミュレーションのため marsまたは spimの使用を検討することだと思います。これらはGUIベースであり、使用するのがはるかに簡単です(そしてアセンブラが組み込まれています)。あなただけのMIPSアセンブラを習得しようとすると、単純なものをやっている場合は

は、彼らがでスタートするためのより良い選択かもしれません。私が見てきた質問のほとんどは、実際のハードウェア(通常はlinuxの下で起動)でデバッグを行います。

qemuを使用すると、それほど多くは見られませんでした。したがって、OS要件がない場合は、mars/spimを試してみる価値があります。私は両方を使いました。私は好きです。mars

あなたのプロジェクトがどれほど大きくなっているかによって、それはまだ一部の答えになるかもしれません(特定の関数を特定してデバッグする)。あなたの豊富な答えをhttp://courses.missouristate.edu/KenVollmar/MARS/

+0

ありがとう:

あなたはそれを試してみることにしたい場合は、ここに火星へのリンクです。 残念ながら、ブレークポイントは命令に関係なく間違った位置に設定されています。 'jal hello'を' li $ a0、1'に置き換えることができ、何も変更されません。 コードは "手作業で"書かれており、Cまたは他の言語からコンパイルされていません。 –

+0

'break * main'へのヒントが鍵でした。 'dissassemble main'はかなり役に立ちます。どうもありがとう。 –

関連する問題