2

MIPS 64 的 gcc 使用复杂的方法来定位和调用编译单元中不存在的函数。这个代码模型的名称是什么(以及它在哪里记录)?我搜索但没有发现它即将发布。它涉及$28/$gp$25/$t9作为某种参数传递给被调用函数。

而且,这个翻译中是否存在错误(在代码生成或文本输出中)?

以下代码序列:

extern int g(int);

int f(int x)
{
    return g(x) + 2;
}

生成此输出:

        daddiu  $sp,$sp,-16
        sd      $28,0($sp)
        lui     $28,%hi(%neg(%gp_rel(f(int))))
        daddu   $28,$28,$25                             <--- sourcing $25/$t9 
        daddiu  $28,$28,%lo(%neg(%gp_rel(f(int))))
        ld      $25,%call16(_Z1gi)($28)
        sd      $31,8($sp)
        nop                       <--- where is the function call??

        ld      $31,8($sp)
        ld      $28,0($sp)
        addiu   $2,$2,2
        j       $31
        daddiu  $sp,$sp,16

在我上面的第二个 <-- 标记处,我希望看到一个间接函数调用,但所有的只有一个nop(这可能是用于调用指令的延迟槽,否则无法解释)。

(在我的第一个标记处,它的来源是 25 美元,因此它必须是提供给的某种参数ff似乎也设置了 25 美元g。)


https://godbolt.org/z/11n9nxs63

添加-msym32到上述命令行选项(告诉它假设所有符号都有一个 32 位地址),代码使用直接函数调用 via jal

4

1 回答 1

0

部分答案是“是否存在错误”部分,而不是 MIPS64 ABI 中代码模型的名称。

事实证明 [compiler-explorer] 标记毕竟是相关的:它隐藏了一个

1:   jalr   $25

nop(确实在分支延迟槽中)之前,这是.reloc 1f,R_MIPS_JALR,g上一行中 a 的目标。 取消选中“隐藏未使用的标签”;我猜过滤错误地假设标签不会与指令在同一行,而 MIPS 并非如此。

所以是的,确实,这是从 GOT 加载一个指针$25并跳过它。

显然,$25作为函数自己的地址作为 ABI/调用约定的一部分,以启用与位置无关的代码(显然 Linux MIPS 总是需要,尽管我认为 MIPS 直到最近的 MIPS 修订版才能非常有效地做到这一点ADDIUPC。)

于 2022-01-12T01:36:08.590 回答