前へ | 次へ | 目次 | 索引 |
ここでは 64 ビット・アドレスの操作,64 ビット値の下位 32 ビットの符合拡張のチェック,および 64 ビット形式のディスクリプタをチェックする MACRO-32 マクロについて説明します。
これらのマクロはディレクトリ ALPHA$LIBRARY:STARLET.MLB (たいていは SYS$LIBRARY:STARLET.MLB と同じ)にあり,アプリケーション・コードとシステム・コードの両方で使用できます。ページ・マクロも 64 ビット・アドレス用に強化されています。このサポートは新しいパラメータ QUAD=NO/YES によって提供されます。
この付録で説明されているマクロに対して特定の引数を使用することで,レジスタ・セットを指定できることに注意してください。レジスタ・セットを表すには,レジスタをカンマで区切ってリストし,これを不等号で囲みます。次に例を示します。
<R1,R2,R3> |
レジスタ・セット内のレジスタが 1 つだけの場合は,これを囲む不等号を省略します。
B.1 64 ビット・アドレスを操作するマクロ
この節では,64 ビット・アドレスの操作を目的として設計されている次のマクロについて説明します。
呼び出しシーケンスを初期化します。
$SETUP_CALL64 arg_count, inline=true または false
arg_count
呼び出し内の引数の個数。inline
TRUE が設定されている場合,JSB ルーチンを作成せずインライン展開を実行します。引数が 6 個以下の場合,省略時の設定は INLINE=FALSE です。
このマクロは,64 ビット CALL の状態を初期化します。$PUSH_ARG64 および $CALL64 を使用する前に,これを使用しなければなりません。引数の個数が 6 個以下の場合,コードは常にインラインです。
省略時の設定では,引数の個数が 6 個を越える場合,JSB ルーチンが作成され,このルーチンを起動して実際の呼び出しを実行します。しかし,INLINE=TRUE でインライン・オプションが指定されると,コードはインラインで生成されます。このオプションは,オプションの対象となるコードのスタックの深さが固定の場合に限って有効です。RUNTIMSTK または VARSIZSTK メッセージが表示されない場合,スタックの深さが固定であると仮定できます。それ以外の場合,スタック・アライメントが少なくともクォドワードでないと,呼び出されたルーチン,および呼び出されたルーチンが呼び出すものの中で,アライメント異常が発生する可能性があります。省略時の設定の動作 (INLINE=FALSE) ではこの問題は発生しません。
引数の個数が 6 個を越える場合,$SETUP_CALL64 と対応する $CALL64 との間で,AP または SP への参照は行われません。これは,$CALL64 が別の JSB ルーチンにある場合があるからです。また,一時的なレジスタ (R16 以上) は $SETUP_CALL64 以降,有効ではありません。ただし,R16 〜 R21 がすでに設定されている引数レジスタと関係する場合を除いて,これらを範囲の中で使用することはできます。このような場合,上位の一時レジスタを代わりに使用します。
注意
$SETUP_CALL64,$PUSH_ARG64,および $CALL64 マクロは,インライン・シーケンスの中で使用することを目的としています。つまり,$SETUP_CALL64/$PUSH_ARG64/$CALL64 シーケンスの中央に分岐したり,$PUSH_ARG64 マクロの回りで分岐することはできず,シーケンスを出て $CALL64 を避けることもできません。
呼び出しの引数プッシュに相当する機能を実行します。
$PUSH_ARG64 引数
引数
プッシュされる引数。
このマクロは,64 ビット呼び出しの 64 ビット引数をプッシュします。なお,$PUSH_ARG64 を使用する前にマクロ $SETUP_CALL64 を使用しなければなりません。引数はアラインされたクォドワードとして読み込まれます。つまり,$PUSH_ARG64 4(R0) という指定は,4(R0) でクォドワードを読み込み,クォドワードをプッシュします。インデックス操作はクォドワード・モードで行われます。
メモリのロングワード値をクォドワード値としてプッシュする場合,まずこれを,ロングワード命令でレジスタに移動し,レジスタ上で $PUSH_ARG64 を使用します。同様に,アラインされていないクォドワード値をプッシュするには,まずこれを一時レジスタに移動し $PUSH_ARG64 を使用します。
呼び出しの引数の個数が 6 個を越える場合,このマクロは引数内の SP 参照または AP 参照をチェックします。呼び出しの引数の個数が 6 個を越える場合,SP 参照は認められず,また,AP 参照はインライン・オプションが使用されている場合に限って認められます。
マクロは,現在の $CALL64 に対してすでに設定されている,引数レジスタへの参照についてもチェックします。このような参照が検出されると,引数レジスタが $PUSH_ARG64 内でのソースとして使用される前に,これを上書きすることがないよう,注意を促す警告メッセージが表示されます。
引数の個数が 6 個以下の場合にも,AP 参照について同じチェックが行われます。これは認められますが,コンパイラではその使用前に上書きすることを禁止できません。このため,このような参照が検出されると,情報メッセージが表示されます。
オペランドが,R16 〜 R21 のいずれかの文字列をその名前に含むシンボルを,レジスタ参照以外で使用する場合,このマクロは,間違ったエラーを報告することがあります。たとえば,R21 が設定された後で$PUSH_ARG64 SAVED_R21を起動すると,このマクロは,(必要でないのに)引数レジスタの上書きに関する情報メッセージを表示します。
$PUSH_ARG64 は条件付きコードの中で使用できないことにも注意してください。$PUSH_ARG64 は,引数の個数などを追跡するシンボルを更新します。$SETUP_CALL64/$CALL64 シーケンスの中央で,$PUSH_ARG64 の回りに分岐するコードを作成しようとしても,正しく動作しません。
ターゲット・ルーチンを起動します。
$CALL64 call_target
call_target
起動するルーチン。
このマクロは,$SETUP_CALL64 で引数の個数を指定し,$PUSH_ARG64 でクォドワード引数をプッシュしたものとして,指定されたルーチンを呼び出します。このマクロは,プッシュの回数がセットアップ呼び出しの中で指定された回数に一致するかチェックします。call_target オペランドが AP ベースまたは SP ベースであってはなりません。
ここで説明するマクロは,特定の値を含んでいるかチェックし,そのチェックの結果に基づきプログラム・フローを決めます。
64 ビット値の下位 32 ビットの符号拡張をチェックし,チェックの結果に基づいて,プログラム・フローを指示します。
$IS_32BITS quad_arg, leq_32bits, gtr_32bits, temp_reg=22
quad_arg
レジスタまたはアラインされたクォドワード・メモリ位置のいずれかにある 64 ビット値。leq_32bits
quad_arg が 32 ビット符号拡張値の場合の分岐先のラベル。gtr_32bits
quad_arg が 32 ビットを越える場合の分岐先のラベル。temp_reg=22
ソース値の下位ロングワードを保持する一時レジスタとして使用するレジスタ。省略時の設定の値は R22 です。
$IS_32BITS は 64 ビット値の下位 32 ビットの符号拡張をチェックし,チェックの結果に基づいて,プログラム・フローを指示します。
#1 |
---|
$is_32bits R9, 10$ |
この例では,省略時の設定の一時レジスタ R22 を使用して,R9 の64 ビット値の下位 32 ビットの符号拡張をチェックします。分岐の種類およびチェックの結果によって,プログラムは分岐,またはインラインを継続します。
#2 |
---|
$is_32bits 4(R8), 20$, 30$, R28 |
この例では,一時レジスタ R28 を使用して,4(R8) の64 ビット値の下位 32 ビットの符号拡張をチェックし,その結果によって,20$ または 30$ に分岐します。
指定されたディスクリプタをチェックし,これが 64 ビット形式のディスクリプタかどうかを判断し,チェックの結果に基づいてプログラム・フローを指示します。
$IS_DESC desc_addr, target, size=long or quad
desc_addr
チェックするディスクリプタのアドレス。target
ディスクリプタが 64 ビット形式の場合の分岐先のラベル。size=long
ディスクリプタを示しているアドレスのサイズ。"long" (省略時の設定) および "quad" が有効。
$IS_DESC64 は,64 ビット・ディスクリプタと 32 ビット・ディスクリプタを区別するフィールドをチェックします。これが 64 ビット形式の場合,指定されたターゲットに分岐が行われます。SIZE=QUAD が指定されていない限り,チェックするアドレスはロングワードとして読み込まれます。
#1 |
---|
$is_desc64 r9, 10$ |
この例では,R9 によって示されるディスクリプタがチェックされ,これが 64 ビット形式の場合は 10$ への分岐が行われます。
#2 |
---|
$is_desc64 8(r0), 20$, size=quad |
この例では,8(R0) のクォドワードが読み込まれ,これが示すディスクリプタがチェックされます。これが 64 ビット形式の場合は 20$ への分岐が行われます。
このサンプル・プログラムは,64 ビット・リージョンの作成および削除のシステム・サービスを紹介します。SYS$CREATE_REGION_64 を使用してリージョンを作成し,SYS$EXPREG_64 を使用してそのリージョンの中で仮想アドレスを割り当てます。仮想アドレス空間およびリージョンは,SYS$DELETE_REGION_64 を呼び出すことによって削除されます。
/* ***************************************************************************** * * Copytight (c) Digital Equipment Corporation, 1995 All Rights Reserved. * Unpublished rights reserved under the copyright laws of the United States. * * The software contained on this media is proprietary to and embodies the * confidential technology of Digital Equipment Corporation. Possession, use, * duplication or dissemination of the software and media is authorized only * pursuant to a valid written license from Digital Equipment Corporation. * * RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure by the U.S. * Government is subject to restrictions as set forth in Subparagraph * (c)(1)(ii) of DFARS 252.227-7013, or in FAR 52.227-19, as applicable. * ***************************************************************************** /* This program creates a region in P2 space using the region creation service and then creates VAs within that region. The intent is to demonstrate the use of the region services and how to allocate virtual addresses within a region. The program also makes use of 64-bit descriptors and uses them to format return values into messages with the aid of SYS$GETMSG. To build and run this program type: $ CC/POINTER_SIZE=32/STANDARD=RELAXED/DEFINE=(__NEW_STARLET=1) - REGIONS.C $ LINK REGIONS.OBJ $ RUN REGIONS.EXE */ #include <descrip.h> /* Descriptor Definitions */ #include <far_pointers.h> /* Long Pointer Definitions */ #include <gen64def.h> /* Generic 64-bit Data Type Definition */ #include <iledef.h> /* Item List Entry Definitions */ #include <ints.h> /* Various Integer Typedefs */ #include <iosbdef.h> /* I/O Status Block Definition */ #include <psldef.h> /* PSL$ Constants */ #include <ssdef.h> /* SS$_ Message Codes */ #include <starlet.h> /* System Service Prototypes */ #include <stdio.h> /* printf */ #include <stdlib.h> /* malloc, free */ #include <string.h> /* memset */ #include <syidef.h> /* $GETSYI Item Code Definitions */ #include <vadef.h> /* VA Creation Flags and Constants */ /* Module-wide constants and macros. */ #define BUFFER_SIZE 132 #define HW_NAME_LENGTH 32 #define PAGELET_SIZE 512 #define REGION_SIZE 128 #define good_status(code) ((code) & 1) /* Module-wide Variables */ int page_size; $DESCRIPTOR64 (msgdsc, ""); /* Function Prototypes */ int get_page_size (void); static void print_message (int code, char *string); main (int argc, char **argv) { int i, status; uint64 length_64, master_length_64, return_length_64; GENERIC_64 region_id_64; VOID_PQ master_va_64, return_va_64; /* Get system page size, using SYS$GETSYI. */ status = get_page_size (); if (!good_status (status)) return (status); /* Get a buffer for the message descriptor. */ msgdsc.dsc64$pq_pointer = malloc (BUFFER_SIZE); printf ("Message Buffer Address = %016LX\n\n", msgdsc.dsc64$pq_pointer); /* Create a region in P2 space. */ length_64 = REGION_SIZE*page_size; status = sys$create_region_64 ( length_64, /* Size of Region to Create */ VA$C_REGION_UCREATE_UOWN, /* Protection on Region */ 0, /* Allocate in Region to Higher VAs */ ®ion_id_64, /* Region ID */ &master_va_64, /* Starting VA in Region Created */ &master_length_64); /* Size of Region Created */ if (!good_status (status)) { print_message (status, "SYS$CREATE_REGION_64"); return (status); } printf ("\nSYS$CREATE_REGION_64 Created this Region: %016LX - %016LX\n", master_va_64, (uint64) master_va_64 + master_length_64 - 1); /* Create virtual address space within the region. */ for (i = 0; i < 3; ++i) { status = sys$expreg_64 ( ®ion_id_64, /* Region to Create VAs In */ page_size, /* Number of Bytes to Create */ PSL$C_USER, /* Access Mode */ 0, /* Creation Flags */ &return_va_64, /* Starting VA in Range Created */ &return_length_64); /* Number of Bytes Created */ if (!good_status (status)) { print_message (status, "SYS$EXPREG_64"); return status; } printf ("Filling %016LX - %16LX with %0ds.\n", return_va_64, (uint64) return_va_64 + return_length_64 - 1, i); memset (return_va_64, i, page_size); } /* Return the virtual addresses created within the region, as well as the region itself. */ printf ("\nReturning Master Region: %016LX - %016LX\n", master_va_64, (uint64) master_va_64 + master_length_64 - 1); status = sys$delete_region_64 ( ®ion_id_64, /* Region to Delete */ PSL$C_USER, /* Access Mode */ &return_va_64, /* VA Deleted */ &return_length_64); /* Length Deleted */ if (good_status (status)) printf ("SYS$DELETE_REGION_64 Deleted VAs Between: %016LX - %016LX\n", return_va_64, (uint64) return_va_64 + return_length_64 - 1); else { print_message (status, "SYS$DELTE_REGION_64"); return (status); } /* Return message buffer. */ free (msgdsc.dsc64$pq_pointer); } /* This routine obtains the system page size using SYS$GETSYI. The return value is recorded in the module-wide location, page_size. */ int get_page_size () { int status; IOSB iosb; ILE3 item_list [2]; /* Fill in SYI item list to retrieve the system page size. */ item_list[0].ile3$w_length = sizeof (int); item_list[0].ile3$w_code = SYI$_PAGE_SIZE; item_list[0].ile3$ps_bufaddr = &page_size; item_list[0].ile3$ps_retlen_addr = 0; item_list[1].ile3$w_length = 0; item_list[1].ile3$w_code = 0; /* Get the system page size. */ status = sys$getsyiw ( 0, /* EFN */ 0, /* CSI address */ 0, /* Node name */ &item_list, /* Item list */ &iosb, /* I/O status block */ 0, /* AST address */ 0); /* AST parameter */ if (!good_status (status)) { print_message (status, "SYS$GETJPIW"); return (status); } if (!good_status (iosb.iosb$w_status)) { print_message (iosb.iosb$w_status, "SYS$GETJPIW IOSB"); return (iosb.iosb$w_status); } return SS$_NORMAL; } /* This routine takes the message code passed to the routine and then uses SYS$GETMSG to obtain the associated message text. That message is then printed to stdio along with a user-supplied text string. */ #pragma inline (print_message) static void print_message (int code, char *string) { msgdsc.dsc64$q_length = BUFFER_SIZE; sys$getmsg ( code, /* Message Code */ (unsigned short *) &msgdsc.dsc64$q_length, /* Returned Length */ &msgdsc, /* Message Descriptor */ 15, /* Message Flags */ 0); /* Optional Parameter */ *(msgdsc.dsc64$pq_pointer+msgdsc.dsc64$q_length) = '\0'; printf ("Call to %s returned: %s\n", string, msgdsc.dsc64$pq_pointer); } |
前へ | 次へ | 目次 | 索引 |