2016-08-26 12 views
0

私は現在、カスタムasmのようなプログラミング言語 のコンパイラを作成していますが、データラベルの適切なPC相対アドレッシングの方法については本当に混乱しています。アセンブリ言語のコンパイラでのPC相対アドレッシング

main LDA RA hello 
     IPT #32 
     HLT 

hello .STR "Hello, world!" 

上記の擬似コードは、コンパイル後、次のヘクスで結果:

31 80 F0 20 F0 0C 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 00 

3180F020F00CLDAIPTHLT命令です。

コードに見られるように、LDA命令は、ラベルhelloを引数として使用します。コンパイル時に値が02になります。これは "Incremented PC + 0x02"を意味します(LDAコールに対する相対的な "Hello、world!"行のコードを参照してください) 問題は次のとおりです。 .STRは命令ではなく、コンパイラに実行可能ファイルの末尾に(0で終了する)文字列を追加する必要があるため、helloラベル宣言後に他の命令があった場合、そのオフセットは間違っています。

しかし、私は正しいオフセットを計算する方法を見つけることができません。コンパイラが時間を遡って実行できるようにすること以外は、2回コンパイルする必要がありますか?まず、データラベルの場合は実際の手順?

+1

'hello'の宣言に対するオフセットは、' .STR'変数の後の命令によっては変更されません。 – kdopen

答えて

2

はい、ほとんどのアセンブラは(少なくとも)2回通過します。正確には、これらのような前方参照があるからです。マクロ機能を追加すると、より多くのパスを追加できます。

オペレーションコードだけでなく、アセンブリリストも見てください。あなたは実際のオフセットが "2"であると言いますから、私はメモリがワードアドレスであると仮定しています。

0000 3180 main LDA RA hello 
0001 F020   IPT #32 
0002 F00C   HLT 

0003 4865 hello .STR "Hello, world!" 

最初の2つの列は、PCとオペコードです。

最初のパスでは、すべてのアドレッシングが相対的であると仮定すると、アセンブラはオペコードの固定部分を出力します( LDA RA部分をカバーする)と、2番目のパスでhelloのアドレスで命令にパッチを当てる必要があることを示すマーカーが付いています。

この時点で、最終的な機械語のサイズは知っていますが、完全な値ではありません。

次に、各命令のアドレスを計算し、そのシンボルテーブルを構築します。

2番目のパスでは、上記の情報を知り、相対オフセットなどを計算して各命令をパッチします。出力(PC値を含む)全体を再生成することもよくあります。

場合によっては、2番目のパスで何かが検出され、それが継続しないようにします。たとえば、256ワード(-127〜+128)のオブジェクトしか参照できない場合がありますが、ラベルhelloは128ワード以上離れていることが判明しています。つまり、2ワード命令(絶対アドレス付き)を使用する必要があり、最初のパスで学習したすべての内容が変更されるはずです。

これは、しばしば「修正」エラーと呼ばれます。リンクフェーズでも同じことが起こる可能性があります。

シングルパスアセンブラは、「使用前に定義する」と主張する場合にのみ可能です。この場合、コードはhelloを未定義のシンボルとして報告します。

"プログラムセクション"も参照する必要があります。 .STRは実行可能な命令ではありませんが、です。アセンブラは、文字列のバイナリ表現をイメージのCODEセクションに配置します(DATA)。

+0

PC相対オフセットは、マシンのエンコーディングで2倍にスケールされますが、そのメモリはワードでしかアドレス指定できません。また、実行可能ファイルのコードセクションには、文字列のような読み取り専用データを置くのが普通です。 (例えば、Unixプラットフォーム用の '.section .rodata')。 –

+0

でも、8ビットまたは24ビットの命令がないことを意味します。 – kdopen

+0

PC相対アドレス指定モードでアドレス指定したいものは、最大1バイトのパディングが必要です。それは、-128 .. + 127Bのほうがかなり小さい範囲になるからです。あなたは通常、コードとデータをちょっと分けたいと思っているからです。 –

関連する問題