内容


z/OS XL C/C++ 编译器对内联汇编的支持

在低级编程中使用高级编程语言的两种方法

Comments

自 z/OS XL C V1R9 起,Metal C 提供了 C 语言的扩展用以支持将高级汇编语言(High-Level Assembler, HLASM)指令直接嵌入 C 语言程序中。

自 z/OS XL C/C++ V2.1.1 起,也可以将 HLASM 指令嵌入到 C 或 C++ 程序中。Metal C(下文中简称为 METAL)支持用户通过系统提供的汇编宏来用直接调用 MVS™ 的系统服务。而内联汇编(Inline assembly, 下文中简称为 ASM)支持将硬件指令直接嵌入到 C 和 C++ 程序中,同时支持全部语言环境和运行时库。

本文着重阐述了 ASM 和 Metal C 的特性,通过代码示例比较了两者之间的差异。此外, 还讲解了如何结合 ASM 来使用 ASMLIB 编译器选项和数据定义名(DDname)去搜索源代码中包含的汇编宏。

ASM 特性

  • XL C 和 XL C++ 编译器都支持 ASM
  • 生成目标代码更容易
  • 支持编译器支持的所有链接方式, 包括 XPLINK 和 NONXPLINK
  • 支持所有的优化等级, 包括 OPT(2), OPT(3), IPA, 以及 HOT
  • 支持所有的寻址模式,包括 ILP32 和 LP64
  • 可为用户生成调试文件
  • 包含全部的语言环境(Language Environment)运行时库

METAL特性

  • 仅 XL C 编译器支持 METAL
  • 用于系统编程开发
  • 使用MVS链接规范
  • 支持所有的优化等级, 包括 OPT(2), OPT(3), IPA, 以及 HOT
  • 支持所有的寻址模式,包括 ILP32 和 LP64
  • 不依赖于语言环境
  • 用户可以指定函数调用时保存现场(prolog)和恢复现场(epilog)的代码

ASM 和 METAL 比较

表 1 总结了 ASM 和 METAL 之间的主要区别。

表 1. ASM 和 METAL 比较
特性ASMMETAL
支持的编译器XL C 和 XL C++XL C
编译器控制选项MVS: ASM
USS: -qasm
MVS: METAL
USS: -qmetal -S
最早支持的编译器版本z/OS V2R1M1 z/OS V1R9
支持的硬件架构所有架构 ARCH(5) 及以上
HLASM 要求V2R1 HLASM 附加 APAR P121235

V2R2 HLASM
V1R9 HLASM
XL C/C++ 编译器输出目标文件 HLASM 源代码
需调用 HLASM 编译源代码
支持的链接方式XL C/C++ 支持的全部链接方式 仅限 MVS 操作系统支持的链接方式
支持的运行时库z/OS XL C/C++ 运行时库 z/OS METAL C 运行时库
支持语言环境
METAL C 生成的代码不依赖于语言环境
用户可指定函数调用时保存现场(prolog)和恢复现场(epilog)的代码
编译器生成的汇编代码可修改
支持存取寄存器(AR)模式
支持 AMODE 切换

处理方式区别

下面我们通过实例来对比用 ASM 和 METAL 编译源代码生成应用程序的区别。假设编译一个如下所示的 C 语言程序 example.c,执行应用程序的返回代码是55。

example.c

int main (void) {
   int a=10, b=45 ;
   __asm (" AR %0,%1 " :"+r"(a) :"r"(b));
   return a;
}

例1. 在 z/OS UNIX 系统服务(UNIX System Services)下使用 ASM 生成应用程序

基本步骤和命令为:

  1. 编译:xlc –c –qasm example.c
  2. 链接:xlc example.o
  3. 运行:a.out

:可将上述步骤1和步骤2合并为一个步骤,即:

  1. 编译并链接: xlc –qasm example.c
  2. 运行:a.out

例2. 在 z/OS UNIX 系统服务下使用 METAL 生成应用程序

  1. 编译:xlc -qmetal -S example.c
  2. 汇编:as example.s
  3. 链接:ld –e main example.o
  4. 运行: a.out

例3. 在 z/OS 批处理(batch)环境下使用 ASM 生成应用程序

当使用 ASM 选项生成应用程序时,用户可以使用下述方法:

  • 使用标准的编目过程(cataloged procedures)来分步生成应用程序。 例如:
    • 使用 EDCC 编译,并用 CEEWL 链接程序 (参见清单 1 )
  • 使用合并的编目过程来生成应用程序。例如:
    • 使用 EDCCB 来编译和链接程序 (参见清单 2)
    • 使用 EDCCBG 来编译,绑定,以及运行程序(参见清单 3)
清单 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 应用程序的作业控制语言代码
//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 应用程序的作业控制语言代码
//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;
}
/>

例4. 在 z/OS 批处理环境下使用 METAL 生成应用程序 batch

当使用 METAL 选项编译程序时,不支持使用合并的编目过程来编译和绑定程序。这是因为编译器的输出是 HLASM 源代码,需要在链接之前用 HLASM 汇编器对该源代码做汇编处理。

清单 4. 使用编目过程 EDCC 和 ASMAC 编译和汇编 METAL 应用程序的的作业控制语言代码
//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

如表 3 所示,ASM 和 METAL 在关键字,预定义宏,以及编译指示(pragma)方面都有区别。

表 3. ASM 和 METAL 的其他区别
区别ASMMETAL
关键字 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)

ASMLIB

可以通过以下三种途径来指示编译器定位包含在 ASM 语句中的宏:

  1. ASMLIB 编译器选项
  2. ASMLIB DDname 语句
  3. 同时使用以上两种方式,编译器选项具有更高优先级

编译器选项

通过编译器选项指示编译器宏库的搜索路径。可以指定以下宏库:分区数据集(Partitioned Data Set,PDS), 扩展分区数据集(Partitioned Data Set Extended,PDSE), UNIX 系统服务目录,或者以上三种宏库的组合。

  • NOASMLIB
    • NOASMLIB 为默认选项,不为 ASMLIB DD 分配任何宏库
    • 不接受子选项
    • 清除所有之前由 ASMLIB 选项所指定的宏库
    • 不会解除分配已经分配的 ASMLIB DDname
  • ASMLIB(lib1,lib2,..)
    • 子选项仅接受完全限定的分区数据集名,扩展分区数据集名,和 UNIX 系统服务目录
    • 所有数据集名必须以 // 为起始。例如, ASMLIB( //'SYS1.MACLIB')
  • 多个 ASMLIB 选项
    • 当指定多个 ASMLIB 选项时,宏库按照被指定的顺序并置(concatenation)

示例

表 4 举例说明了如何通过 ASMLIB 编译器选项搜索用户定义的宏和系统宏。

表 4. ASMLIB 选项用法示例
应用场景指定的编译器选项及结果
分区数据集,或扩展分区数据集MVS: CPARM='ASMLIB(//''''SYS1.MACLIB'''')'
USS: -qasmlib="//'SYS1.MACLIB'"
结果:搜索 'SYS1.MACLIB'数据集
UNIX系统服务目录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'
NOASMLIBMVS: CPARM='ASMLIB(/hlq/mymacrolib), NOASMLIB, ASMLIB(//''''HLQ.MYMACLIB'''')'
USS: -qasmlib=/hlq/mymacrolib -qnoasmlib -qasmlib="//'HLQ.MYMACLIB'"
结果:仅搜索'HLQ.MYMACLIB'

DDname

  • 支持多个包含数据集和 USS 目录的的 DD 语句(参见清单 5)
  • 当在作业控制语言代码中同时指定 ASMLIB 编译器选项和 ASMLIB DD 语句时,宏库被并置为一个搜索列表。 编译器选项优先级高于 DDname(参见清单 6)。
清单 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

结果:编译器按以下顺序搜索:

  1. 数据集 SYS1.MACLIB
  2. 数据集 HLQ.MYMACLIB
  3. 目录 /hlq/mymacrolib
清单 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

结果:编译器按以下顺序搜索:

  1. 数据集 HLQ.MYMLIB2
  2. 目录 /hlq/mymacrolib2
  3. 数据集 SYS1.MACLIB
  4. 数据集 HLQ.MYMACLIB
  5. 目录 /hlq/mymacrolib

:HLQ.MYMLIB1 和 /hlq/mymacrolib1 被 NOASMLIB 清除。

结论

z/OS XL C/C++ 编译器针对不同的用途提供不同的内联汇编支持方式。 METAL C 用于系统编程开发。ASM 允许用户利用标准语音环境中的汇编宏库和硬件指令。

致谢

感谢 Rajan Bhakta, Visda Vokhshoori 以及 Milos Lalovic 为本文提供的帮助和技术指导。感谢卢昉将本文翻译为中文。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Rational
ArticleID=1047327
ArticleTitle=z/OS XL C/C++ 编译器对内联汇编的支持
publish-date=07052017