RISC-V汇编插入符号地址字面量遇阻:C与汇编联调矩阵乘法问题
问题与解决方案
问题背景
现有C矩阵乘法程序,声明了外部指针类型的矩阵变量:
extern float* MATR_A; extern float* MATR_B; extern float* MATR_C; extern int N; //矩阵维度大小 int mmult() { for(int i=0; i<N; i++) { for(int j=0; j<N; j++) { MATR_C[i*N + j] = 0; for(int k=0; k<N; k++) { MATR_C[i*N + j] += MATR_A[i*N + k] * MATR_B[k*N + j]; } } } }
配套的汇编文件直接将MATR_A标签指向矩阵数据,导致C代码把矩阵第一个元素的值当作地址使用,引发错误:
.globl _start .globl MATR_A .globl MATR_B .globl MATR_C .globl N .section .text _start: j mmult halt: nop j halt .section .data MATR_A: .float 1.0 .float 2.0 .float 3.0 .float 4.0 MATR_B: .float 4.0 .float 3.0 .float 2.0 .float 1.0 MATR_C: .word 0 #预留空间 .word 0 .word 0 .word 0 N: .word 2
从反汇编片段可见,代码错误地将MATR_A的第一个元素值加载到寄存器当作地址:
0001009c <mmult>: 1009c: 86c1a883 lw x17,-1940(x3) # 1119c <N> 100a0: 09105463 blez x17,10128 <mmult+0x8c> 100a4: 000117b7 lui x15,0x11 100a8: 1307a303 lw x6,304(x15) # 11130 <MATR_A> ; 此处读取的是MATR_A指向的float值,而非矩阵地址 ...
仅用汇编的解决方案
核心思路是:让MATR_A、MATR_B、MATR_C这些符号对应存储矩阵地址的指针变量,而非矩阵数据本身。修改汇编代码如下:
.globl _start .globl MATR_A .globl MATR_B .globl MATR_C .globl N .section .text _start: j mmult halt: nop j halt .section .data ; 定义实际的矩阵数据,用内部标签(下划线前缀避免外部可见) _MATR_A: .float 1.0 .float 2.0 .float 3.0 .float 4.0 _MATR_B: .float 4.0 .float 3.0 .float 2.0 .float 1.0 _MATR_C: .word 0 #预留空间 .word 0 .word 0 .word 0 ; 定义C中引用的指针变量,存储对应矩阵的地址 MATR_A: .word _MATR_A MATR_B: .word _MATR_B MATR_C: .word _MATR_C N: .word 2
修改后,C代码读取MATR_A时,得到的是_MATR_A的地址(即矩阵数据的起始地址),而非矩阵第一个元素的值,完全符合float*类型的要求。
链接器方案(无需额外脚本)
如果不想修改汇编中的标签命名逻辑,也可以通过编译时的符号别名完成映射:
保持C代码不变,在编译命令中添加链接选项,将矩阵数据标签的地址赋值给C中引用的指针符号:
riscv64-unknown-elf-gcc -nostdlib -nostartfiles -march=rv32if -mabi=ilp32 -O3 -Wl,--defsym=MATR_A=_MATR_A -Wl,--defsym=MATR_B=_MATR_B -Wl,--defsym=MATR_C=_MATR_C mmult.S mmult.c -o mmult.elf
前提是汇编中把原矩阵数据标签改为_MATR_A、_MATR_B、_MATR_C,本质和第一种方案逻辑一致,只是通过链接器完成符号地址的映射。
内容的提问来源于stack exchange,提问作者user2687408
相关产品推荐
相关产品推荐

