自 z/OS V1R9 XL C 开始,METAL C 提供了 C 语言扩展来允许直接将高级汇编器 (HLASM) 指令嵌入到 C 程序中。从 z/OS XL C/C++ V2.1.1 开始,您可以将 HLASM 指令嵌入到 C/C++ 程序中。METAL C(在本文中称为 METAL)允许用户直接通过系统提供的汇编宏来利用 MVS™ 系统服务。最新的内联汇编支持(在本文中称为 ASM)允许直接将硬件指令嵌入到标准的 C 和 C++ 程序中,提供全语言环境和运行时库支持。本文将重点介绍 ASM 和 METAL 的特征,以及它们之间的区别。还会介绍如何结合使用 ASMLIB 选项、数据定义名称 (DDname) 与 ASM,搜索源代码中包含的汇编器宏。
回页首
回页首
ASM 与 METAL 支持的主要区别如下所示:
表 1. ASM 与 METAL 比较
特征 | ASM | METAL |
---|---|---|
支持编译器 | C 和 C++ | C |
控制编译器选项 | MVS:ASMUSS:-qasm | MVS:METALUSS:-qmetal -S |
可用版本 | z/OS V2R1M1 | z/OS V1R9 |
硬件架构 | 所有架构级别 | 最低 ARCH(5) |
HLASM 编译器需求 | V2R1 HLASM 和 APAR P121235 或 V2R2 HLASM | V1R9 HLASM |
来自 C/C++ 编译器的输出 | 对象文件 | HLASM 源代码 |
用户需要调用 HLASM 来编译源代码 | 否 | 是 |
链接支持 | C 和 C++ 支持的所有链接 | 仅支持 MVS OS 链接 |
运行时库支持 | z/OS C/C++ 运行时库 | z/OS METAL C 运行时库 |
语言环境支持 | 是 | 否METAL C 生成与 LE 独立的代码 |
使用自定义的 prolog/epilog 支持 | 否 | 是 |
可修改编译器生成的汇编代码 | 否 | 是 |
AR 模式支持 | 否 | 是 |
AMODE 开关支持 | 否 | 是 |
以下示例使用了一个简单程序 (example.c) 来演示如何使用 ASM,并使用替代性的 METAL 选项来创建应用程序。执行该应用程序的返回代码为 55。
int main (void) { int a=10, b=45 ; __asm (" AR %0,%1 " :"+r"(a) :"r"(b)); return a; }
xlc –c –qasm example.c
xlc example.o
a.out
备注:可将第 1 和第 2 步组合到一步中:
xlc –qasm example.c
a.out
xlc -qmetal -S example.c
as example.s
ld –e main example.o
a.out
使用 ASM 选项编译应用程序时,可以为每一步使用标准编目过程,或者使用组合编目过程来构建应用程序。
清单 1. 使用编目过程 EDCC 和 CEEWL 来构建 ASM 应用程序的 JCL
//jobcard information… //PROC JCLLIB ORDER=(CBC.SCCNPRC, CEE.SCEEPROC) //*------------------------------------------------------------------- //* Compile step //*------------------------------------------------------------------- //COMP EXEC EDCC, // OUTFILE='HLQ.OBJECT(EXAMPLE),DISP=SHR', // CPARM='ASM' //STEPLIB DD DSN=CBC.SCCNCMP,DISP=SHR // DD DSN=CEE.SCEERUN,DISP=SHR // DD DSN=CEE.SCEERUN2,DISP=SHR // DD DSN=ASM.SASMMOD1,DISP=SHR //COMPILE.SYSIN DD DATA,DLM='/>' int main(void) { int a=10, b=45 ; __asm(" AR %0,%1 " :"+r"(a) :"r"(b)); return a; } /> //*------------------------------------------------------------------- //* Link step //*------------------------------------------------------------------- //LINK EXEC CEEWL, // PARM= AMODE=31,CASE=MIXED //SYSLMOD DD DSN=HLQ.LOAD(EXAMPLE),DISP=SHR //OBJECT DD DSN=HLQ.OBJECT,DISP=SHR //SYSLIN DD * INCLUDE OBJECT(EXAMPLE) /* //SYSPRINT DD SYSOUT=* //*------------------------------------------------------------------- //* Run step //*------------------------------------------------------------------- //GO EXEC PGM=EXAMPLE //STEPLIB DD DSN=HLQ.LOAD,DISP=SHR
清单 2. 使用编目过程 EDCCB 来构建 ASM 应用程序的 JCL
//jobcard information… //PROC JCLLIB ORDER=(CBC.SCCNPRC) //*------------------------------------------------------------------- //* Compile and bind step //*------------------------------------------------------------------- //COMP EXEC EDCCB, // OUTFILE='HLQ.LOAD(EXAMPLE),DISP=SHR', // CPARM='ASM' //STEPLIB DD DSN=CBC.SCCNCMP,DISP=SHR // DD DSN=CEE.SCEERUN,DISP=SHR // DD DSN=CEE.SCEERUN2,DISP=SHR // DD DSN=ASM.SASMMOD1,DISP=SHR //COMPILE.SYSIN DD DATA,DLM='/>' int main(void) { int a=10, b=45 ; __asm(" AR %0,%1 " :"+r"(a) :"r"(b)); return a; } /> //*------------------------------------------------------------------- //* Run step //*------------------------------------------------------------------- //GO EXEC PGM=EXAMPLE //STEPLIB DD DSN=HLQ.LOAD,DISP=SHR
清单 3. 使用编目过程 EDCCBG 来构建和运行 ASM 应用程序的 JCL
//jobcard information… //PROC JCLLIB ORDER=(CBC.SCCNPRC) //*------------------------------------------------------------------- //* Compile, bind and run //*------------------------------------------------------------------- //CBG EXEC EDCCBG, // CPARM='ASM' //STEPLIB DD DSN=CBC.SCCNCMP,DISP=SHR // DD DSN=CEE.SCEERUN,DISP=SHR // DD DSN=CEE.SCEERUN2,DISP=SHR // DD DSN=ASM.SASMMOD1,DISP=SHR //COMPILE.SYSIN DD DATA,DLM='/>' int main(void) { int a=10, b=45 ; __asm(" AR %0,%1 " :"+r"(a) :"r"(b)); return a; } />
使用 METAL 选项编译应用程序时,不能使用组合的标准编目过程来编译和绑定程序。这是因为编译器的输出是 HLASM 源代码,在执行链接步骤之前需要通过 HLASM 进行汇编。
清单 4. 使用编目过程 EDCC 和 ASMAC 来编译和汇编 METAL 应用程序的 JCL
//jobcard information... //PROC JCLLIB ORDER=(CBC.SCCNPRC) //*------------------------------------------------------- //* Compile step //*------------------------------------------------------- //COMP EXEC EDCC, // OUTFILE='HLQ.ASMSRC(EXAMPLE),DISP=SHR', // CPARM='METAL' //COMPILE.SYSIN DD DATA,DLM='/>' int main(void) { int a=10, b=45 ; __asm (" AR %0,%1 " :"+r"(a) :"r"(b)); return a; } /> //*------------------------------------------------------- //* Assembly step //*------------------------------------------------------- //ASMC EXEC ASMAC //SYSIN DD DSN=HLQ.ASMSRC(EXAMPLE),DISP=SHR //SYSLIN DD DSN=HLQ.OBJECT(EXAMPLE),DISP=SHR //*------------------------------------------------------- //* Link step //*------------------------------------------------------- //LINK EXEC PGM=IEWL, // PARM= AMODE=31,CASE=MIXED //SYSLMOD DD DSN=HLQ.LOAD(EXAMPLE),DISP=SHR //OBJECT DD DSN=HLQ.OBJECT,DISP=SHR //SYSLIN DD DATA,DLM='/>' INCLUDE OBJECT(EXAMPLE) ENTRY main /> //SYSPRINT DD SYSOUT=* //*------------------------------------------------------- //* Run step //*------------------------------------------------------- //GO EXEC PGM=EXAMPLE //STEPLIB DD DSN=HLQ.LOAD,DISP=SHR
在编译过程中,可以将一些编译器选项与 ASM 或 METAL 结合使用,增强内联汇编支持。表 2 显示了哪些选项可与 ASM 或 METAL 结合使用。
表 2. 可编译的编译器选项
编译器选项 | ASM | METAL |
---|---|---|
ARMODE | 否 | 是 |
ASMDATASIZE | 否 | 是 |
ASMLIB | 是 | 否 |
DSAUSER | 否 | 是 |
EPILOG | 否 | 是 |
GENASM | 否 | 是 |
KEYWORD(asm) | 是 | 否 – 在 V2R1M1 以前是 – V2R1M1 和更高版本 |
PROLOG | 否 | 是 |
RESERVED_REG | 否 | 是 |
SYSSTATE | 否 | 是 |
ASM 和 METAL 在关键字、预定义的宏和编译指示 (pragma) 支持上还有其他区别。表 3 重点介绍了这些区别。
表 3. 其他技术区别
ASM | METAL | |
---|---|---|
关键词 | asm, __asm, __asm__ | __asm, __asm__ 1 |
编译器预定义宏 | __IBM_ASM_SUPPORT = 1 | __IBM_METAL__ = 1__IBM_FAR_IS SUPPORTED__ = 1 |
#pragma insert_asm | 不支持 | 是否支持 |
_Pragma("insert_asm") | 不支持 | 是否支持 |
1 如果想要在嵌入的汇编语句中使用关键字或标志 ASM,可以执行以下操作来接受标志 ASM:
#define asm __asm
#define asm __asm__
KEYWORD(asm)
回页首
可通过 3 种方式告诉编译器,在何处找到包含在 ASM 语句中的宏:
此选项为编译器提供宏库的搜索路径。指定的宏库可以是 Partitioned Data Set (PDS)、Partitioned Data Set Extended (PDSE) 或 UNIX System Service (USS) 目录,或者所有 3 种库的组合。
NOASMLIB
NOASMLIB
是默认选项;它表示不给 ASMLIB DD
分配任何库 ASMLIB( //'SYS1.MACLIB')
。 表 4 展示了如何通过 ASMLIB 编译器选项搜索用户定义的宏和系统宏。
表 4. ASMLIB 选项用法示例
变体 | 选项规范 |
---|---|
PDS/PDSE | MVS:CPARM=' ASMLIB(//'SYS1.MACLIB')' USS:-qasmlib="//'SYS1.MACLIB'" 结果:搜索数据集 ‘SYS1.MACLIB’ |
USS 目录 | MVS:CPARM='ASMLIB(/hlq/mymacrolib)' USS:-qasmlib=/hlq/mymacrolib 结果:搜索目录 /hlq/mymacrolib |
多个选项和混合类型 | MVS:CPARM='ASMLIB(/hlq/mymacrolib) , ASMLIB(//'HLQ.MYMACLIB')' USS:-qasmlib=/hlq/mymacrolib –qasmlib= "//'HLQ.MYMACLIB'" 结果:搜索 /hlq/mymacrolib 和 ‘HLQ.MYMACLIB’ |
多个子选项和混合类型 | MVS:CPARM='ASMLIB(//'HLQ.MYMACLIB', /hlq/mymacrolib, //'SYS1.MACLIB')' USS:-qasmlib=“//’HLQ.MYMACLIB’”:/hlq/mymacrolib:’’//’SYS1.MACLIB’” 结果:搜索 ‘HLQ.MYMACLIB’、/hlq/mymacrolib 和 ‘SYS1.MACLIB’ |
NOASMLIB | MVS:CPARM='ASMLIB(/hlq/mymacrolib), NOASMLIB, ASMLIB(//'HLQ.MYMACLIB')' USS:-qasmlib=/hlq/mymacrolib -qnoasmlib -qasmlib=“//’HLQ.MYMACLIB’” 结果:仅搜索 ‘HLQ.MYMACLIB’ |
清单 5. ASMLIB DDname 示例
//ASMLIB DD DSN=SYS1.MACLIB,DISP=SHR // DD DSN=HLQ.MYMACLIB,DISP=SHR // DD PATH='/hlq/mymacrolib', // PATHOPTS=(ORDONLY,ONONBLOCK), // PATHMODE=(SIRUSR,SIXUSR), // FILEDATA=TEXT
结果:编译器使用以下搜索顺序:
清单 6. ASMLIB 编译器选项和 DDname 的示例
//COMP EXEC EDCC, // CPARM='ASM OPTFILE(DD:XOPTS)' //XOPTS DD DATA,DLM='/>' ASMLIB(//'HLQ.MYMLIB1',/hlq/mymacrolib1) NOASMLIB ASMLIB(//'HLQ.MYMLIB2',/hlq/mymacrolib2) /> //ASMLIB DD DSN=SYS1.MACLIB,DISP=SHR // DD DSN=HLQ.MYMACLIB,DISP=SHR // DD PATH='/hlq/mymacrolib', // PATHOPTS=(ORDONLY,ONONBLOCK), // PATHMODE=(SIRUSR,SIXUSR), // FILEDATA=TEXT
结果:编译器使用以下搜索顺序:
备注:HLQ.MYMLIB1 和 /hlq/mymacrolib1 被 NOASMLIB 清除。
回页首
z/OS XLC/C++ 编译器提供的不同的内联汇编支持是为不同用途而设计的。METAL C 用于系统编程开发。ASM 允许用户在标准语言环境中利用汇编宏程序库(assembler macro libraries)和硬件指令。
感谢 Rajan Bhakta、Visda Vokhshoori 和 Milos Lalovic 为本文提供的帮助和建议。