この段階で行なうことは,ABCL/f コンパイラの保持しているシンボル情報を C++コンパイラのコンパイル結果に埋め込むことである. この節では,マルチスレッディング用ライブラリ関数は除いて議論し, マルチスレッディング用ライブラリ関数の扱いについては, 4.5.3節において議論する.
gcc/g++, gdb間においては,普通 ``stabs'' と呼ばれるフォーマットで シンボル情報が扱われている. C/C++ コンパイラは,各シンボルがどのようなコンパイル結果に対応しているか, アセンブリコードの中にライン情報などのシンボル情報を保存する. 我々は,未拡張のgcc/g++を想定しているため, 当然C++プログラムとしてのシンボル情報がコンパイル結果に埋め込まれる. 一方我々の目標は もとのABCL/f プログラムに関するシンボル情報を埋め込むことである.
仮に,ABCL/f プログラムの持つシンボル情報と全く同じシンボル情報を持つ C++プログラムを生成することができれば,そのC++プログラムを コンパイルすることで,目的の結果を得ることができる. しかしながら,より簡易な形でABCL/f ソースからC++プログラム への変換を行なうABCL/f コンパイラの実装方式や,加えて, 式順序の違いや,C++における改行情報の入り方, ランタイムとして扱うべき行の扱いなどの問題から, 実際にはそのようなC++プログラムを生成することは困難である.
例えば,
1 (defun foo (n x) 2 (if (= n 0) 3 (foo x) 4 (zoo x)))なる式が
1 int foo (int n, int x) 2 { 3 if (n == 0) 4 result = foo(x); 5 else 6 result = zoo(x); 7 8 if (poll_remote_message()) 9 schedule_remote_message(); 10 }という形に変換されていたとする.この8,9行目では, 他のPEから来たメッセージのポーリングを行い, メッセージをあれば実行するとする. この場合,8,9行目に対応する ABCL/f 上の式を静的に決定することはできない. 仮に,8行目に対してABCL/f ソース上で例えば4行目に割り振ったと仮定すると, n=0でfooが実行された場合でも,3行目の次に4行目が実行されてしまう.
本来,8,9行目はランタイムであり,8行目の実行は本来表に見えない方が良い( 9行目の実行については, 4.5.3節 で議論する). しかし,C/C++ では,8行目に対して行ではないかの如く指定する事は想定されて おらず, 何らかな静的な行番号を割り当てる必要がある. このため,ABCL/f ソースと全く同じシンボル情報を与える事は出来ない.
今回我々のとったアプローチでは,C++プログラム中にABCL/f プログラム 上での位置を示すための情報を埋め込むと同時に, C++プログラム中でABCL/f ランタイムに相当する場所についても, その位置を示すダミー情報を付けて埋め込む事にした. この結果,コンパイル出力(アセンブリ)上のシンボル情報から, 各命令列が 対応する ABCL/f プログラム上での位置,もしくはランタイムであるか を知ることができる.
加えて, stabs format の場合,ライン情報は各行のスタートを示す 情報が付加されているが, ランタイムとして位置情報を指定している箇所に付いて これを削除することで, gdb はそのランタイムの実行を 先に実行されたABCL/f ソース行の一部の様に認識する事になる (但し,call 命令付近のライン情報については, gdb が step,next 実行の際に復帰時のブレイクポイントとして用いているものが あるので,取り扱いに注意する事). つまり,上述のようなランタイム部に対しては, その実行を gdb に対して隠す事が出来る.
我々の方法は,gcc/g++といったコンパイラ内部に手を入れるのではなく, 適切なABCL/f のライン情報をコンパイル結果に埋め込んでいる.