【実務・中級編】BASED変数とADDR/POINTERビルトイン関数の連携 – PL/Iの基本構文とデータ制御実践ガイド

おい、ちょっといいか。今、夜間バッチのログを見て冷や汗をかいたところだ。
SYSTEM COMPLETION CODE=0C4」――出たな、恐るべきS0C4アベンドだ。

メインフレームの保守現場において、この「S0C4(保護例外)」ほどエンジニアを絶望させるエラーコードもない。特に、CICSのオンライン領域や、何百万件も回る大型VSAMバッチの真夜中の実行中にこれが起きたときの胃が痛くなる感覚は、長年この世界にいる我々なら痛いほど分かるはずだ。

原因の多くは決まっている。「ポインタの迷子」、そして今日焦点を当てる「境界アライメント(Alignment)の無視」だ。

PL/Iは、C言語の `malloc` のような泥臭いメモリ管理を、`BASED`変数と `ADDR`、`POINTER` といった洗練されたビルトイン関数でスマートに隠蔽してくれる。しかし、この「スマートさ」ゆえに、ハードウェア(System/390やz/Architecture)の物理的な制約を忘れがちになるのだ。

今日は、レガシーシステムのブラックボックスを暴き、S0C4を華麗に回避するためのPL/Iメモリ直接操作の極意を伝授しよう。心して聞いてくれ。

1. なぜS0C4は起きるのか? ― 境界アライメントの罠

PL/Iの `BASED` 変数というのは、それ自体にはメモリ上の実体を伴わない。いわば「型の鋳型(テンプレート)」だ。`POINTER` 変数に格納されたメモリアドレスをこの鋳型にあてがうことで、任意のメモリ領域を構造体として読み書きできる。ここまでは基本だな。

問題は、「ハードウェアがデータを読み込むときのルール」だ。

IBMメインフレームのCPUアーキテクチャでは、データ型によって「偶数境界」「4バイト境界」「8バイト境界」といったメモリ上の配置ルール(アライメント)が厳格に定められている。

  • FIXED BINARY(31)(フルワード): 4の倍数のアドレス(4バイト境界)に配置されるべき。
  • FIXED BINARY(63)(ダブルワード): 8の倍数のアドレス(8バイト境界)に配置されるべき。

もし、奇数アドレスや境界を外れた位置にあるフルワード変数を、アライメント違反を許容しない命令(あるいは厳密なコンパイラ最適化コード)でアクセスしようとすると、CPUは容赦なく例外割り込みを発生させる。これが、君たちが夜中に叩き起こされるS0C4の正体のひとつだ。

特に、VSAMの不安全なレコード領域や、外部から受け取ったアンフォーマットのワークエリア(エリア変数)を `BASED` 変数で無理やりマッピングするときに、この地雷をよく踏み抜くことになる。

2. 実践:安全なポインタ操作とアライメントの制御

百聞は一見に如かずだ。実際のバッチプログラムを想定したコードを見てみよう。
以下のコードは、VSAMから読み込んだワーク領域に対し、`BASED` 変数を用いて安全にフィールドアクセスを行い、アライメント違反を防ぐためのテクニックを盛り込んだものだ。

1

  • モジュール名: S0C4SOLV
  • 概要: BASED変数とPOINTERを用いたVSAMレコードの安全なマッピング


S0C4SOLV: PROC OPTIONS(MAIN);

DCL 1 W_VSAM_RECORD BASED(P_REC),
3 R_KEY FIXED BIN(31), / フルワード (4バイト境界必須) /
3 R_CODE CHARACTER(2), / 文字列データ /
3 R_AMT FIXED DEC(15,2);/ パック十進数 /

DCL P_REC POINTER; レコード用ポインタ
DCL P_WORK_AREA POINTER; ワーキングストレージ
DCL MY_AREA CHARACTER(100) BASED(P_WORK_AREA);

DCL VSAM_EOF BIT(1) INIT(‘0’B);

/ BUILTIN関数の明示的な宣言(PL/Iの基本マナー) /
DCL (ADDR, NULL, LENGTH) BUILTIN;

DISPLAY(‘ S0C4SOLV START ‘);

/ 1. ワーキングストレージの確保(実際はGETMAINや動的割当て) /
/ ここでは説明のため疑似的にメモリを割り当てる想定 /
P_WORK_AREA = ALLOCATE_MEMORY(); / 独自の割当てルーチン想定 /

IF P_WORK_AREA = NULL THEN DO;
DISPLAY(‘MEMORY ALLOCATION FAILED.’);
SIGNAL ERROR;
END;

/ ————————————————————- /
/ 【重要】アライメント調整のテクニック /
/ 奇数アドレスから始まるエリアにフルワード変数をマッピングすると /
/ S0C4や性能劣化(スリップ)の原因になる。 /
/ ————————————————————- /

/ アドレスの下位2ビットを確認し、4バイト境界にアライメントを調整 /
P_REC = ADJUST_TO_BOUNDARY(P_WORK_AREA, 4);

/ 2. VSAMレコードを模したデータをエリアに展開して処理 /
R_KEY = 12345;
R_CODE = ‘AB’;
R_AMT = 987654321.10;

/ 正常系の処理フロー /
CALL PROCESS_RECORD(P_REC);

DISPLAY(‘ S0C4SOLV END NORMAL ‘);
RETURN;

/ 境界調整を行う内部サブルーチン(概念モデル) /
ADJUST_TO_BOUNDARY: PROC(P_IN, ALIGN_BYTE) RETURNS(POINTER);
DCL P_IN POINTER;
DCL ALIGN_BYTE FIXED BIN(31);
DCL ADDR_VAL FIXED BIN(31) BASED(ADDR(P_IN));
DCL P_OUT POINTER;

/ 実務では非推奨のポインタ演算だが、概念としてアドレスを調整 /
/ ※実際にはPL/IのAUTOMATIC変数のデフォルト境界や /
/ ALIGNED属性を正しく活用するのが王道である。 /

RETURN(P_IN);
END ADJUST_TO_BOUNDARY;

PROCESS_RECORD: PROC(P_TARGET);
DCL P_TARGET POINTER;
DCL 1 LOCAL_REC BASED(P_TARGET),
3 L_KEY FIXED BIN(31),
3 L_REST CHARACTER(10);

DISPLAY(‘PROCESSING KEY: ‘ || L_KEY);
END PROCESS_RECORD;

END S0C4SOLV;

3. コンパイラオプションと `ALIGNED` 属性の魔力

さて、ここで先輩として一つ重要な事実を教えておこう。
PL/Iのコンパイラ(Enterprise PL/Iなど)は、デフォルトで構造体のメンバに対して適切な境界調整(`ALIGNED` 属性)を行うようになっている。

もし、メモリを節約しようとして `UNALIGNED`(非整列)属性を軽はずみに指定していないか?

1
/ 危険な例:UNALIGNEDを指定するとアライメント違反の温床に /
DCL 1 DANGEROUS_REC UNALIGNED,
3 D_BYTE CHAR(1),
3 D_FULLWORD FIXED BIN(31); / 奇数アドレスから始まってしまう! /

`UNALIGNED` が指定された構造体の中にある `FIXED BIN(31)` が奇数アドレスに位置してしまった場合、コンパイラはそれを安全に処理するために、裏でわざわざ余分なバイトをシム(隙間)として埋めたり、低速な命令に置き換えたりする。最悪の場合、ポインタ経由で直接叩いた瞬間に冒頭のS0C4が炸裂するのだ。

現場で使えるデバッグと回避の鉄則

1. `ALIGNED` を基本とせよ
特に理由がない限り、構造体の定義には `UNALIGNED` を安易に使わないこと。PL/Iコンパイラに正しい境界配置を任せるのが、最も確実なS0C4予防策だ。
2. `ADDR` と `POINTER` の型キャストに頼りすぎるな
ポインタを無理やり整数(FIXED BIN(31))にキャストして足し算・引き算を行うレガシーコードが見受けられるが、これはアーキテクチャの変更(31ビットアドレッシングから64ビットAMODE 64への移行など)の際に確実に足をすくわれる。
3. ONユニット(ERROR / STORAGE)でトラップを仕掛けろ
万が一のアベンド時に備え、バッチのジョブステップでは `ON ERROR` や `ON STORAGE` を適切に記述し、障害発生瞬間のポインタ値やダンプを採取できるようにしておくこと。現場の運用者への礼儀だ。

おわりに

レガシーシステムのメンテナンスは、先人たちが残した「暗黙のルール」との戦いだ。
しかし、PL/Iという言語の仕様、そして背後にあるメインフレームのハードウェア挙動を正しく理解していれば、S0C4は決して「原因不明の怪物」などではない。すべてはロジカルに説明がつき、防ぐことができるエラーなのだ。

次に夜間バッチでS0C4に遭遇したときは、慌ててIPLを頼る前に、まずはそのポインタが指すアドレスの「境界」を確認してみたまえ。
君なら、冷静に原因を突き止められるはずだ。さあ、仕事に戻ろうか。

タイトルとURLをコピーしました