Hipcc compile procedure

AMDGPU驱动(准确地说是ROCm软件栈,特别是HIP runtime和HSA runtime)解析hipcc编译的可执行文件的过程,是一个从ELF段读取到用户态Runtime解析,最后通过内核驱动加载的多层协作过程。

简单来说,hipcc将GPU代码(HSACO)打成由特定格式包裹的”Fat Binary”,并嵌入到Host程序的ELF文件中。程序运行时,通过自动生成的构造函数将这段数据的指针注册给HIP Runtime,Runtime再根据当前GPU型号提取对应的代码并加载。

以下是详细的解析流程:

1. 编译阶段:Fat Binary 的生成与嵌入

在理解解析之前,必须先知道文件结构是怎么来的。hipcc(实际调用clang)的编译流程如下:

  • 设备侧编译: 源代码被编译为AMD GPU的机器码,即HSA Code Object (HSACO)。如果你指定了多个架构(如 –offload-arch=gfx90a –offload-arch=gfx942),会生成多个HSACO文件。

  • 打包 (Bundling): 使用 clang-offload-bundler 工具,将这些不同架构的HSACO文件打包成一个 Clang Offload Bundle。这是一个包含Magic Number(通常是CCOB)和目录索引的二进制格式。

  • 嵌入 (Embedding): 这个Bundle被作为数据段嵌入到最终的Host ELF可执行文件中。
    Section Name: .hip_fatbin
    Symbol: __hip_fatbin (这是一个全局符号,指向该段的起始地址

2. 启动阶段:自动注册 (Self-Registration)

当你运行可执行文件时,操作系统加载器(Loader)将ELF文件映射到内存。此时GPU驱动并未介入,而是依靠编译器插入的Host侧构造函数来触发解析:

  • 构造函数: 编译器在每个编译单元中插入了一个全局构造函数(类似于 attribute((constructor)))。

  • 注册调用: 这个构造函数会执行 __hipRegisterFatBinary(&__hip_fatbin)。

    • __hip_fatbin 就是指向内存中 .hip_fatbin 段的指针。
    • 该函数是 libamdhip64.so (HIP Runtime) 提供的API

3. HIP Runtime 解析逻辑

当 __hipRegisterFatBinary 被调用时,HIP Runtime (用户态驱动) 开始工作。它并不会立即把所有代码加载到GPU,而是建立索引:

  • 识别 Bundle 格式: Runtime 检查传入指针的头部,识别 Clang Offload Bundle 格式(检查魔数 CCOB 或旧版的 __CLANG_OFFLOAD_BUNDLE__)。
  • 解析目录 (Index Parsing): Runtime 解析Bundle的头部信息,读取其中包含的所有 Bundle Entry ID。
    • Entry ID 格式通常为:hip-amdgcn-amd-amdhsa–gfx90a (指明了语言-架构-厂商-OS-具体GPU型号)。
    • 匹配设备: Runtime 此时会查询系统中的GPU设备信息(通过 rocminfo 或 HSA 接口获取当前显卡的 GFX ID,例如 gfx90a)。
    • 提取代码 (Extraction):
    • Runtime 遍历 Bundle 目录,寻找与当前系统GPU架构最匹配的 Entry。
    • 一旦找到,计算出该 HSACO 在内存中的偏移量和大小,将其“解包”(逻辑上提取,实际是指向该内存片段.

4. 加载到 GPU (HSA Runtime & KMD)

拿到提取出来的 HSACO (ELF格式的GPU二进制) 后,HIP Runtime 将其交给更底层的 HSA Runtime (ROCr) 进行加载:

  • 创建可执行对象: 调用 hsa_executable_create 创建一个空的GPU可执行容器。
  • 加载代码对象: 调用 hsa_executable_load_code_object。
    • HSA Runtime 解析 HSACO 的 ELF 格式,处理其中的 .text (指令)、.data (全局变量) 等段。
    • 它会解析 Kernel Descriptor,这是AMD GPU特有的元数据,包含寄存器使用量(SGPR/VGPR)、LDS大小等信息。

5. 内核态交互 (KMD)

HSA Runtime 通过 ioctl 系统调用与内核驱动 amdgpu (KFD部分) 通信。
驱动负责分配显存,将代码段和数据段DMA到GPU显存中,并设置页表。

总结流程图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[ELF Executable File]
|
+-- Section: .hip_fatbin (包含了所有架构的GPU代码)
|
[程序启动 (Host CPU)]
|
+-- Constructor Function (__hip_fatbin_ctor)
|
v
+-- Call __hipRegisterFatBinary(&__hip_fatbin)
|
[HIP Runtime (User Space)] <--- 此时开始解析
|
+-- 1. 识别 Clang Offload Bundle (Magic: CCOB)
+-- 2. 遍历 Bundle Entry IDs
+-- 3. 匹配当前 GPU (例如: 找到 gfx90a)
+-- 4. 提取对应的 HSACO 二进制数据
|
v
[HSA Runtime (ROCr)]
|
+-- 解析 HSACO ELF (Kernel Descriptors, Symbols)
+-- hsa_executable_load_code_object
|
v
[AMDGPU Kernel Driver (KFD)]
|
+-- 分配显存,将代码上传至 VRAM
+-- 准备好 Kernel Handle 供后续 hipLaunchKernel 使用
Author

Jing Zhou

Posted on

2026-06-12

Updated on

2026-10-24

Licensed under

Comments