OpenVMS Alpha
オペレーティング・システム
64 ビット・アドレッシングおよび
VLM 機能説明書


前へ 次へ 目次 索引


パブリック・インタフェースのデータ構造では埋め込みポインタを避ける

新規インタフェースの新しい構造で埋め込みポインタが必要な場合,(クォドワード・アラインされている) 64 ビット・ポインタ用の構造の中で記憶域を用意します。呼び出されたルーチンは,場合によって構造からポインタを読み込む必要がありますが,単純に 64 ビット全体を読み込みます。

ポインタが 32 ビット符号拡張アドレスの制約を受けている場合 (たとえば,ポインタが 32 ビット・ルーチンに渡される場合),ルーチンの入り口で,64 ビット・ポインタについて符号拡張チェックが実行されます。符号拡張チェックが失敗すると,エラー状態 SS$_ARG_GTR_32_BITS が呼び出し側に返されます。または 64 ビット・アドレス空間に常駐しているデータが検出されると,これが 32 ビット・アドレス空間にコピーされます。

新しい構造は,64 ビットの呼び出し側も 32 ビットの呼び出し側も,余分なコードを使用しないで済むように定義する必要があります。構造では,64 ビットの呼び出し側を対象とするクォドワード・フィールドと,32 ビットの呼び出し側を対象とする 2 つのロングワード・フィールドが互いに重なり合って提供されます。先頭のロングワードは 32 ビット・ポインタ・フィールドで,次のロングワードはMBSE (must be sign-extension) フィールドです。32 ビットの呼び出し側の大半では,MBSE フィールドは 0 になります。これは,ポインタが 32 ビット・プロセス空間アドレスとなるためです。ここで重要なのは,ポインタを 64 ビット値として定義し,32 ビットの呼び出し側に対してクォドワード全体を入力する必要があることを明確にすることです。

次の例では,64 ビットと 32 ビットの両方の呼び出し側が,関数 routine を呼び出すときに,block 構造にポインタを渡し,同じ関数プロトタイプを使用します(data は別のモジュールで定義され,その構造は不定であるものとします)。


#pragma required_pointer_size save 
#pragma required_pointer_size 32 
 
typedef struct block { 
    int blk_l_size; 
    int blk_l_flags; 
    union  { 
#pragma required_pointer_size 64 
        struct data *blk_pq_pointer; 
#pragma required_pointer_size 32 
        struct  { 
            struct data *blk_ps_pointer; 
            int blk_l_mbse; 
            } blk_r_long_struct; 
        } blk_r_pointer_union; 
    } BLOCK; 
 
#define blk_pq_pointer     blk_r_pointer_union.blk_pq_pointer 
#define blk_r_long_struct  blk_r_pointer_union.blk_r_long_struct 
#define blk_ps_pointer     blk_r_long_struct.blk_ps_pointer 
#define blk_l_mbse         blk_r_long_struct.blk_l_mbse 
 
/* Routine accepts 64-bit pointer to the "block" structure */ 
#pragma required_pointer_size 64 
int routine(struct block*); 
 
#pragma required_pointer_size restore 

入力引数を指定する既存の 32 ビット・ルーチンの場合,これがポインタを埋め込む構造のときは,別の方法で既存の 32 ビット・インタフェースを保持できます。実行時に,32 ビット形式のデータ構造と区別できる,64 ビット形式のデータ構造を開発できます。32 ビット形式の構造だけを受け取る既存のコードは,64 ビット形式の構造が指定されると,自動的に異常終了します。

新しい 64 ビット構造についての構造定義には,32 ビット形式の構造を含む必要があります。32 ビット形式の構造を含むことによって,呼び出されたルーチンは入力引数を,64 ビット形式の構造へのポインタとして宣言し,いずれの場合でも明確に処理することができます。

言語に対して,型のチェックを行う 2 種類の関数プロトタイプを用意しなければなりません。省略時の設定時の関数プロトタイプは,引数を 32 ビット形式の構造へのポインタとして指定します。64 ビット形式の関数プロトタイプは,マニュアルに説明されているように,シンボルを定義することによって選択できます。

64 ビット対 32 ビット・ディスクリプタは,これがどのように行われるかを示す例です。

例: 次の例では,シンボルFOODEF64の状態が,正しい関数プロトタイプと共に,64 ビット形式の構造を選択します。シンボルFOODEF64が未定義の場合,古い 32 ビット構造が定義され,古い 32 ビット関数プロトタイプが使用されます。

関数foo_printを実現するソース・モジュールはシンボルFOODEF64を定義し,32 ビットおよび 64 ビットの呼び出し側からの呼び出しを処理することができます。64 ビットの呼び出し側はフィールドfoo64$l_mbm1を -1 に設定します。foo_printはフィールド foo64$l_mbm1 が -1 であるかどうかをテストすることによって,呼び出し側が 64 ビット形式の構造を使用しているか,または 32 ビット形式の構造を使用しているかを判断します。


#pragma required_pointer_size save 
#pragma required_pointer_size 32 
 
typedef struct foo { 
    short int     foo$w_flags; 
    short int     foo$w_type; 
    struct data * foo$ps_pointer; 
    } FOO; 
 
#ifndef FOODEF64 
 
/* Routine accepts 32-bit pointer to "foo" structure */ 
int foo_print(struct foo * foo_ptr); 
 
#endif 
 
#ifdef FOODEF64 
 
typedef struct foo64 { 
    union  { 
        struct  { 
            short int     foo64$w_flags; 
            short int     foo64$w_type; 
            int           foo64$l_mbmo; 
#pragma required_pointer_size 64 
            struct data * foo64$pq_pointer; 
#pragma required_pointer_size 32 
            } foo64$r_foo64_struct; 
        FOO foo64$r_foo32; 
        } foo64$r_foo_union; 
    } FOO64; 
 
#define foo64$w_flags    foo64$r_foo_union.foo64$r_foo64_struct.foo64$w_flags 
#define foo64$w_type     foo64$r_foo_union.foo64$r_foo64_struct.foo64$w_type 
#define foo64$l_mbmo     foo64$r_foo_union.foo64$r_foo64_struct.foo64$l_mbmo 
#define foo64$pq_pointer foo64$r_foo_union.foo64$r_foo64_struct.foo64$pq_point 
er#define foo64$r_foo32    foo64$r_foo_union.foo64$r_foo32 
 
/* Routine accepts 64-bit pointer to "foo64" structure */ 
#pragma required_pointer_size 64 
int foo_print(struct foo64 * foo64_ptr); 
 
#endif 
 
#pragma required_pointer_size restore 

上の例で,構造fooおよびfoo64が同じソース・モジュールの中で交換して使用される場合,シンボル FOODEF64 を削除できます。この場合,ルーチン foo_print は次のように定義されます。


int foo_print (void * foo_ptr); 

FOODEF64 シンボルを削除することによって,32 ビットの呼び出し側と 64 ビットの呼び出し側が同じ関数プロトタイプを使用できます。ただし C ソースのコンパイルの際に,厳密な型のチェックが行われることはありません。

8.2 Alpha/VAX ガイドライン

アドレス,サイズ,および長さの引数だけが,クォドワードとして値で渡されなければならない

値で渡される引数は,VAX 上ではロングワードに制限されています。VAX API との互換性を実現するには,クォドワード引数を値渡しではなく参照渡しする必要があります。しかし,アドレス,サイズ,および長さは,アーキテクチャが原因で,理論的には OpenVMS VAX 上でロングワード,かつ OpenVMS Alpha 上ではクォドワードになる引数の例です。

API が OpenVMS VAX 上で利用できない場合であっても,すべての API 上での一貫性を実現するため,このガイドラインに従ってください。

ページ・サイズに依存する単位の使用を避ける

長さやオフセットなどの引数は,バイトなど,ページ・サイズに依存しない単位で指定します。

ページレットは不便な単位です。これは VAX との互換性を目的として開発され,OpenVMS Alpha 上で,OpenVMS VAX 互換インタフェースの中で使用されています。ページレットはそのサイズが VAX ページに等しく,ページ・サイズに依存しない単位とは考えられません。これは Alpha 上の CPU 固有ページとしばしば混乱されるためです。

例: EXPREG_64 内の Length_64 引数は,クォドワード・バイト・カウントとして,値で渡されます。

参照渡しされるすべてのデータをすべて自然にアラインする

呼び出されるルーチンは,コンパイラに対して引数がアラインされていることを指定し,これによってコンパイラは,より効率的なロードおよび保存のシーケンスを実行できます。データがそのままアラインされていない場合,性能は低下します。

参照渡しのデータが自然にアラインされていないために呼び出されたルーチンが正しく実行できない場合,ルーチンは明示的にチェックを実行し,アラインされていない場合はエラーを返す必要があります。たとえば,ロック付きロード,条件付き保存がルーチンの内部でデータについて実行される場合,データがアラインされていないと,ロック付きロード,条件付き保存は正しく処理されません。

8.3 32 ビット API から 64 ビット API への拡張

API の拡張を,32 ビット設計の改善や新規機能の追加とは区別して考えると,必要な作業を容易に行うことができます。新しい 64 ビット API の中でのルーチンの呼び出しは,簡単なプログラミング作業に過ぎません。

64 ビット・ルーチンは,64 ビット形式の構造に加えて 32 ビット形式の構造を受け取る

API への呼び出しを簡単に修正できるように,インタフェースは,64 ビット形式に加えて,32 ビット形式の構造も受け取ることができなければなりません。

例: 32 ビット API が情報をディスクリプタで渡していた場合,新規インタフェースは同じ情報をディスクリプタで渡さなければなりません。

64 ビット・ルーチンは 32 ビット・ルーチンと同じ機能を提供する

新しい 64 ビット API が古い API の機能スーパセットではない場合でも,現在 32 ビット API を呼び出しているアプリケーションは,古い 32 ビット API への古い呼び出しの一部を保持することなく,完全にアップグレードして 64 ビット API を呼び出すことができなければなりません。

例: SYS$EXPREG_64 は P0,P1,および P2 プロセス空間で動作します。SYS$EXPREG_64 は $EXPREG の機能スーパセットであるため,呼び出し側はすべての呼び出しを SYS$EXPREG に置換できます。

接尾辞 "_64" を適切に使用する

システム・サービスの場合,この接尾辞は 64 ビット・アドレスを参照渡しで受け取るサービスで使用されます。拡張したサービスの場合,これによって 64 ビット機能のバージョンと,対応する 32 ビット機能のバージョンが区別されます。一方,新規ルーチンの場合は,この接尾辞によって,64 ビット長アドレス・セルが読み込み/書き込みされることが明確に示されます。埋め込み 64 ビット・アドレスを含む構造が渡されるとき,この構造が 64 ビット構造として自己識別しない場合にも,この接尾辞が使用されます。ルーチンが受け取るのは 64 ビット・ディスクリプタであるという理由で,ルーチン名に "_64" を含める必要はありません。なお,任意の値を参照渡しで渡すときには,接尾辞が必要ないことに注意してください。接尾辞が必要なのは,64 ビット・アドレスを参照渡しで渡すときです。

この規則は,ほかのルーチンに対しても同じように推奨されます。

例:

SYS$EXPREG_64 (region_id_64, length_64, acmode, return_va_64, return_length_64)
SYS$CMKRNL_64 (routine_64, quad_arglst_64)

8.4 32 ビット・ルーチンおよび 64 ビット・ルーチンの例

64 ビット・アドレッシングのサポートを目的として拡張された 32 ビット・ルーチン・インタフェースの例を次に示します。この例では,ガイドラインで記述された各種の問題を処理しています。

古いシステム・サービス SYS$CRETVA の C 関数宣言は,次の形式で行われます。


#pragma required_pointer_size save 
#pragma required_pointer_size 32 
int sys$cretva ( 
        struct _va_range * inadr, 
        struct _va_range * retadr, 
        unsigned int       acmode); 
#pragma required_pointer_size restore 

新しいシステム・サービス SYS$CREATE_VA の C 関数宣言は,次の形式で行われます。


#pragma required_pointer_size save 
#pragma required_pointer_size 64 
int sys$cretva_64 ( 
        struct _generic_64 * region_id_64, 
        void *               start_va_64, 
        unsigned __int64     length_64, 
        unsigned int         acmode, 
        void **              return_va_64, 
        unsigned __int64 *   return_length_64); 
#pragma required_pointer_size restore 

SYS$CRETVA_64 の新規ルーチン・インタフェースは,_va_range構造の中で埋め込みポインタを訂正し,64 ビットのregion_id_64引数を参照で渡し,64 ビットのlength_64引数を値で渡します。


第 9 章
64 ビット・アドレッシングをサポートする OpenVMS Alpha ツールおよびユーティリティ

本章では,64 ビット仮想アドレッシングをサポートするように強化された次の OpenVMS Alpha ツールについて,簡単に説明します。

9.1 OpenVMS デバッガ

OpenVMS Alpha システムのデバッガは,64 ビット・アドレッシングのサポートによって実現される拡張メモリにアクセスすることができます。完全な 64 ビット・アドレス空間の中で,データを検査したり操作することができます。

新しい [Quad] オプションを使用することによって,変数をクォドワードとして扱うことができます。このオプションは,[Monitor] プルダウン・メニューおよび [Examine] ダイアログ・ボックスの,[Typecast] メニューにあります。

デバッガの省略時の設定の型はロングワードです。これは,32 ビット・アプリケーションをデバッグするのに適しています。64 ビット・アドレス空間を使用するアプリケーションをデバッグするには,省略時の設定の型をクォドワードに変更することをおすすめします。この操作を行うには,SET TYPE QUADWORD コマンドを使用します。

16 進アドレスは,Alpha 上では 16 桁の数値であることに注意してください。この例を次に示します。


DBG> EVALUATE/ADDRESS/HEX %hex 000004A0
00000000000004A0
DBG>

デバッガは 32 ビット・ポインタおよび 64 ビット・ポインタをサポートします。

OpenVMS デバッガの使用についての詳細は,『OpenVMS デバッガ説明書』を参照してください。

9.2 OpenVMS Alpha システム・コード・デバッガ

OpenVMS Alpha システム・コード・デバッガは 64 ビット・アドレスを受け取り,64 ビット・アドレス全体を使用して情報を検索します。

9.3 Delta/XDelta

XDELTA は,OpenVMS Alpha 上で常に 64 ビット・アドレッシングをサポートしています。クォドワード表示モードは,情報をすべてクォドワードで表示します。また,64 ビット・アドレス表示モードは,すべてのアドレスを 64 ビットの長さとして受け取り,表示します。

XDELTA は,PFN データベースの内容を表示するコマンド文字列をあらかじめ定義しています。OpenVMS Alpha Version 7.0 における PFN データベース・レイアウトの変更に伴い,表示用のコマンド文字列およびその形式が合わせて変更されました。

Delta/Xdelta についての詳細は,『OpenVMS Delta/XDelta Debugger Manual』を参照してください。

9.4 OpenVMS ランタイム・ライブラリの LIB$ および CVT$ 機能

OpenVMS RTL ライブラリの LIB$ 機能および CVT$ 機能の,64 ビット・アドレッシング・サポートについての詳細は,『OpenVMS RTL Library (LIB$) Manual』を参照してください。

9.5 ウォッチポイント・ユーティリティ

ウォッチポイント・ユーティリティは,64 ビット・アドレスにウォッチポイントを設定することにより,共用システム空間内の特定の位置に加えられた修正の履歴を保持するデバッグ・ツールです。これは S0,S1,または S2 空間の,任意のシステム・アドレスをウォッチします。

ウォッチポイント・ユーティリティに対する $QIO インタフェースは,64 ビット・アドレスをサポートします。WATCHPOINT コマンド・インタプリタ (WP) は,DCL 構文の標準規則に従うコマンドから,WATCHPOINT ドライバ (WPDRIVER) に対して,$QIO 要求を発行します。

コマンドは WATCHPOINT> プロンプトに対して入力し,ウォッチポイントからの情報の設定,削除,および取得を行います。WATCHPOINT コマンド・インタプリタ (WP) を起動する前に,または WATCHPOINT ドライバをロードする前に,まず,SYSGEN MAXBUF ダイナミック・パラメータを 64000 に設定しなければなりません。この操作は次の手順で行います。


$ RUN SYS$SYSTEM:SYSGEN 
SYSGEN> SET MAXBUF 64000 
SYSGEN> WRITE ACTIVE 
SYSGEN> EXIT 

WP を起動する前に,SYSMAN で WPDRIVER をインストールしなければなりません。次の手順で行います。


$ RUN SYS$SYSTEM:SYSMAN 
SYSMAN> IO CONNECT WPA0/DRIVER=SYS$WPDRIVER/NOADAPTER 
SYSMAN> EXIT 

次のコマンドで WP を起動します。


$ RUN SYS$SYSTEM:WP 

WATCHPOINT> プロンプトに対してコマンドを入力し,ウォッチポイントからの情報の設定,削除,および取得を行います。

ターミナルの表示幅を 132 桁に設定すると,ウォッチポイント・ユーティリティへの出力および WP ヘルプ画面を最適に表示することができます。この設定は次の手順で行います。


$ SET TERM/WIDTH=132 

9.6 SDA

OpenVMS Alpha Version 7.0 の場合,SDA は,ユーザが式の中で 64 ビット・アドレスおよび 64 ビット値を指定することを認めています。また,適切な場所で完全な 64 ビット値も表示します。

SDA の 64 ビット・アドレッシング・サポートの使用についての詳細は,『OpenVMS Alpha System Dump Analyzer Utility Manual』を参照してください。


前へ 次へ 目次 索引