Date Tags CUDA

本文记录了探索NVIDIA CUDA SASS语法对应的二进制位的过程。

1. CUDA二进制文件

1.1 SASS

NVCC编译过程解读CUDA汇编PTX(二) SASS nvdisasm工具提过CUDA的汇编SASS,使用cuobjdump工具反编译出的SASS格式如下:

                                                 /* 0x083fc400e3e007f6 */
/*0008*/  MOV R1, c[0x0][0x20];                  /* 0x4c98078000870001 */
/*0010*/  S2R R2, SR_TID.X;                      /* 0xf0c8000002170002 */
/*0018*/  ISCADD R4.CC, R2.reuse, c[0x0][0x150], 0x2;  /* 0x4c18810005470204 */

第二列为反编译出的human-friendly code,包含了opcode(指令)、modifer(修饰符)、oprand(操作数)。

第三列即为实际二进制中的内容。需要注意的是,在反编译出的SASS文件中,第三列是以大端模式显示,但实际文件存储中是小端模式。

1.2 ELF格式

cu文件部分最后被编译为cubin文件,是一种ELF格式的可执行文件。

ELF文件格式

左边是ELF的链接视图,可以理解为是目标代码文件的内容布局。右边是ELF的执行视图,可以理解为可执行文件的内容布局。注意目标代码文件的内容是由section组成的,而可执行文件的内容是由segment组成的。

我们目前只需要关注linking view下文件结构即可。

1.3 example

使用readelf -a ./vector_add.sm_50.cubin获得的部分内容如下(可以使用-w 宽模式来显示输出):

ELF 头:
  Magic7f 45 4c 46 02 01 01 33 07 00 00 00 00 00 00 00 
  类别:                              ELF64
  数据:                              2 补码,小端序 (little endian)
  版本:                              1 (current)
  OS/ABI:                            <未知:33>
  ABI 版本:                          7
  类型:                              EXEC (可执行文件)
  系统架构:                          NVIDIA CUDA architecture
  版本:                              0x5a
  入口点地址:              0x0
  程序头起点:              1696 (bytes into file)
  Start of section headers:          1184 (bytes into file)
  标志:             0x320532
  本头的大小:       64 (字节)
  程序头大小:       56 (字节)
  Number of program headers:         3
  节头大小:         64 (字节)
  节头数量:         8
  字符串表索引节头: 1

节头:
  [号] 名称              类型             地址              偏移量
       大小              全体大小          旗标   链接   信息   对齐
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .shstrtab         STRTAB           0000000000000000  00000040
       00000000000000b2  0000000000000000           0     0     1
  [ 2] .strtab           STRTAB           0000000000000000  000000f2
       00000000000000cf  0000000000000000           0     0     1
  [ 3] .symtab           SYMTAB           0000000000000000  000001c8
       0000000000000060  0000000000000018           2     2     8
  [ 4] .nv.info          LOPROC+0         0000000000000000  00000228
       0000000000000024  0000000000000000           3     0     4
  [ 5] .nv.info._Z9vecto LOPROC+0         0000000000000000  0000024c
       000000000000005c  0000000000000000           3     7     4
readelf:警告:[ 6]: Unexpected value (7) in info field.
  [ 6] .nv.constant0._Z9 PROGBITS         0000000000000000  000002a8
       000000000000015c  0000000000000000   A       0     7     4
readelf:警告:[ 7]: Unexpected value (83886083) in info field.
  [ 7] .text._Z9vectorAd PROGBITS         0000000000000000  00000420
       0000000000000080  0000000000000000  AX       3   83886083     32

关于ELF文件格式不再赘述,资料很多。我们关心的是节头列表中[7]text._Z9vectorAdd的偏移量00000420,这实际上表明了kernel函数在cubin文件中的位置。使用sublime等编辑器打开cubin文件,下面即为cubin文件0x420字节处的内容:

f607 e0e3 00c4 3f08 0100 8700 8007 984c

可以发现恰好是0x083fc400e3e007f6 0x4c98078000870001的小端模式

2. 探索指令对应的二进制位

一个比较经典的方法是将cubin文件的二进制位按位翻转,翻转一个二进制位后,再次使用cuobjdump反编译出sass,看修改的对应代码行是否改变。

/*0008*/ MOV R1, c[0x0][0x20]; /* 0x4c98078000870001 */为例,将对应的cubin文件行二进制翻转一位,解析成新的SASS文件,如果新的文件中不再是MOV指令,则说明翻转的这一位属于MOV的控制位。通过循环翻转每一位,可以得出MOV指令到底由哪几位决定。

Zhang的论文便使用了这种方法,并将代码开源到了github:

https://github.com/PAA-NCIC/DeepPerf/tree/master/Solver

同理,modifer和oprand也可以按照这种方法得出。具体可以参看Reference中的论文。

3. CC 7.0+

Jia的论文中探索了Volta和Turing架构的变化。一条指令编码由原来的64-bit,变为128bit,原来的架构是三条指令编码配一条控制编码。

我修改了Zhang论文开源的代码,对CC 7.0+做了适配,更新中:

https://github.com/FindHao/nv_bin_explorer

需要注意的是,opcode的编码受modifer和oprand的影响,因此不能只跑opcoder,还需要解析出modifer和oprand才能真正搞清楚opcode的编码模式。

Reference中的论文都需要仔细研读。

Reference

Zhang X, Tan G, Xue S, et al. Understanding the gpu microarchitecture to achieve bare-metal performance tuning[J]. ACM SIGPLAN Notices, 2017, 52(8): 31-43.

Jia Z, Maggioni M, Smith J, et al. Dissecting the NVidia Turing T4 GPU via Microbenchmarking[J]. arXiv preprint arXiv:1903.07486, 2019.

Jia Z, Maggioni M, Staiger B, et al. Dissecting the nvidia volta gpu architecture via microbenchmarking[J]. arXiv preprint arXiv:1804.06826, 2018.

Ari B. Hayes etc.Decoding CUDA binary, CGO 2019

ELF格式探析之三:sections

Linux ELF文件格式分析

readelf elf文件格式分析

计算机那些事(4)——ELF文件结构

详解大端模式和小端模式


文章版权归 FindHao 所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明作者 FindHao 和本文原始地址:
https://www.findhao.net/academic/2559.html

Comments

comments powered by Disqus