Workload 切片组装问题定位案例分享
发表于 2025/06/10
0
Workload 单线程组装工具(xtrace2elfies)基于开源binutils实现,通过trace采集工具,从原业务获得真实的指令流与寄存器状态(trace),然后基于trace的信息,加入必要的修正代码(补偿),重新组装为可执行的二进制切片
本文介绍组装工具在适配一款新应用时,对一个设计缺陷问题的定位
问题现象
在工具的组装使用过程中,我们遇到了一个段错误问题
段错误(Segmentation fault)一般由错误的内存访问导致,对于工具源码,猜测可能由空指针引用、踩内存等引起
我们通过GDB查看源码报错位置,通过bt命令发现,源码从InstFlowAnalysisLoop0调用到AssembleMemOps函数报错,报错在xtrace2elfies.cpp第328行
打开源码,查看相应位置的逻辑,发现报错在一行赋值语句,很容易猜测到,段错误的原因是curOffset过大引起的数组越界访问
理解一下这个函数的功能,函数主要执行的逻辑是,对一条访存指令所涉及的多个地址和数据,将访存数据填入buf中,并按照前后地址范围差值,对空闲区域补0,同时记录offset标识buf中数据的范围
以一条ldp(load pair)指令为例,假设这条指令从0x1230地址取出64位数据0x1,放在寄存器x0中,从0x1238地址取出64位数据0x2,放在寄存器x1中,我们将这条指令涉及的这些数据存入buf
易知,该用例中,offset最大不会超过mems[1].addr – mems[0].addr = 0x8
那么难道是一条访存跨度较大的指令引入的问题吗,我们在arm指令手册中选择一条NEON指令继续分析
ld4(Load single 4-element structure to one lane of four registers),ld4是一条NEON指令,它从一块连续地址中取出4个128位的数,存放到四个NEON寄存器的一个通道中
ld4 { v0.16b, v1.16b, v2.16b, v3.16b }, [sp]
- LD 64-bit M[0x1000] -> 0x1
- LD 64-bit M[0x1008] -> 0x2
- LD 64-bit M[0x1010] -> 0x3
- LD 64-bit M[0x1018] -> 0x4
- LD 64-bit M[0x1020] -> 0x5
- LD 64-bit M[0x1028] -> 0x6
- LD 64-bit M[0x1030] -> 0x7
- LD 64-bit M[0x1038] -> 0x8
该指令在采集工具采集时,会被拆分记录为N个ld/st指令,每条指令最大操作64bit数据,这是由qemu微指令最大访存单元为ld/st_i64决定的。因此该用例会记录为8个ld指令,offset最大不会超过mems[7].addr – mems[0].addr = 0x38,实际使用的buf范围是0x40(ld4指令访存连续,不会填入多余的0,因此此处的buf范围即是最终范围),可以容纳8 * 64bit = 64Bytes的数据
查看上层调用位置,发现buf数组的最大数据容纳是1024Bytes,因此即使是最大的NEON指令,也不会超过buf范围
我们继续怀疑下一个点,由于该应用是SVE应用,我们怀疑产生问题的指令可能会是一条SVE指令,SVE访存指令特点如下:
寄存器可变长度:
例如SVE 512的场景下,8通道访存涉及的连续地址范围为512bit * 8 = 512Bytes,而SVE理论最高上限是2048bit,即使我们提高
MAX_DATA_PER_INST,也无法满足未来的所有场景
地址离散性:
地址离散性使得SVE/SME访存指令所涉及的地址范围理论上无限扩大,在前文的函数设计中,offset(mems[i].addr – baseAddr)也会无限放大,即使是SVE 128也有超出MAX_DATA_PER_INST的可能
为了验证猜想,我们通过添加打印,结合GDB命令,查看这条引发数组越界访存指令的实际指令码,定位到此时的指令码为0x850640a0,通过反汇编工具得到指令为一条ld1w指令
Ld1w(Gather load unsigned words to vector),是一条sve指令,用于从内存加载多个32位无符号整数到向量寄存器中,已知当前Trace的sve_len为256,可知这条ld1w指令为8通道访存,通过gdb验证信息一致,且通道8与通道1的地址偏移较大,远远超过1024 bytes
在buf填充过程中,由于地址离散,相邻地址的差值较大,因此buf中将会填充许多的0
以上两张图是相邻ld i64访存的地址差值,以及地址不可达的最终位置(0x73e0)
解决方案:
该问题定位为数据结构设计不满足SVE/SME指令场景,因此我们需要在工具中添加地址连续性检测,当检测到离散访存时,切换为多buf模式进行记录,避免buf越界