RISCv 给函数传递参数的时候,必须用 PC rel 的方式吗 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
amiwrong123
V2EX    程序员

RISCv 给函数传递参数的时候,必须用 PC rel 的方式吗

  •  
  •   amiwrong123 179 天前 1211 次点击
    这是一个创建于 179 天前的主题,其中的信息可能已经有所发展或是发生改变。

    所谓的 pc rel 的方式,比如说哈,我要传递第一个参数,是通过 auipc+addi 的方式来设置 a0.

    我现在编译程序的时候,会遇到一个 trancated PCRELHI20 的链接错误。下面是一个,我的问题场景的简化场景:

    extern int array[];// 这个数组的地址很高,在 0xFFFF_F000;这个符号来自于另一个 c 文件 //下面的函数,都是基于 0x0 的地址开始进行分配 int test(int a) { return a*gType; } int main() { test((int)array); //这里放置第一个参数的时候,就会报错 } 

    就是说,为了给 test 函数传递 array 这个实参,汇编指令使用了 auipc+addi 的方式,而且当前 pc 和 array 这个符号的地址太远了,导致了会报错。

     __asm__ volatile ( "lui a0, %%hi(array)\n\t" "addi a0, a0, %%lo(array)\n\t" : : "r"(array) ); 

    我尝试写了一个内嵌汇编,来模拟放置 a0 (也就是第一个参数),这里我用的是 lui+addi ,而不是 auipc+addi 的方式。但还是报一样的错。

    我真的不理解了,这个问题到底怎么解

    9 条回复    2025-04-17 13:40:07 +08:00
    cheese
        1
    cheese  
       179 天前
    试试马斯克的 grok3 ?我帮你尝试问了下,输出的回答“看起来”非常正确,但是 v2 不能贴 ai 回答,你试试
    XimCN
        2
    XimCN  
       178 天前 via iPhone   2
    这和 pc relative 或直接加载无关,单纯是地址太高超出了 risc-v 两条指令的立即数部分拼接能寻址的地址范围(总共 4GB )。要么把这个数组的地址放在一个低地址变量里做一次指针 load ,要么多加几条指令,把地址高位拼接出来并 shift 到高位,再用现在的方案把低位拼进去,组成一个完整的高地址
    amiwrong123
        3
    amiwrong123  
    OP
       178 天前
    @XimCN #2
    要么把这个数组的地址放在一个低地址变量里做一次指针 load
    ------
    extern int array[];

    uintptr_t ptr_to_array = (uintptr_t)array; // 变量本身位于低地址
    test((int)ptr_to_array);

    请教下,你是这个意思吗?再多定义一个指针变量,这个指针变量 离当前 PC 不会有那么远,所以就不会有问题。

    我刚才实测了一下,同样会出问题的地方,加了指针变量后,就不会编译报错了,哈哈。
    amiwrong123
        4
    amiwrong123  
    OP
       178 天前
    @XimCN #2
    单纯是地址太高超出了 risc-v 两条指令的立即数部分拼接能寻址的地址范围(总共 4GB )
    ----
    我理解是这样的吧,auipc+addi ,只能定位 当前 pc 前后 2GB 的空间。因为 auipc 的高位是符号位。

    但我这个例子里,当前 PC 离 array 的距离,大于了 2GB ,所以超过了呗?
    amiwrong123
        5
    amiwrong123  
    OP
       178 天前
    @XimCN #2
    要么多加几条指令,把地址高位拼接出来并 shift 到高位
    -----
    我想了一下,是不是 用 li + 左移 组合,多用几次,应该就 可以拼接出来了吧
    XmCN
        6
    XimCN  
       178 天前
    > 我理解是这样的吧,auipc+addi ,只能定位 当前 pc 前后 2GB 的空间。因为 auipc 的高位是符号位。
    > 但我这个例子里,当前 PC 离 array 的距离,大于了 2GB ,所以超过了呗?

    > 我想了一下,是不是 用 li + 左移 组合,多用几次,应该就 可以拼接出来了吧
    对,auipc+addi/lui+addi 一次可以拼接 32 bit 数据,用两组这样的组合可以拼出 64 bit 完整地址
    Shaaaadow
        7
    Shaaaadow  
       178 天前
    这不是传参的问题,是拿全局变量地址的问题。

    可以了解一下 PIC 这个概念,也可以试试像 `-mcmodel=medany` 或者 `-fno-pic` 这样的配置
    XimCN
        8
    XimCN  
       178 天前 via iPhone
    如果要用编译选项解决,mcmodel=any 不够,需要 mcmodel=large
    amiwrong123
        9
    amiwrong123  
    OP
       177 天前
    @Shaaaadow #7 #7

    很奇怪, 我在编译每个 o 文件时,加了这种`-fno-pic 选项,还是不行。甚至感觉编译出来的反汇编都是一样的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5454 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 08:34 PVG 16:34 LAX 01:34 JFK 04:34
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86