You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需内联汇编:如何用LLVM的BuildMI生成指向0x40010的CALL指令?

问题描述

我尝试调用地址0x40010,但LLVM似乎在通过自身计算修正该地址。请问能否在不使用内联汇编的情况下禁用这一行为?

我当前用于实现该需求的代码如下,但其无法生成预期的call 0x40010指令:

uintptr_t imm = 0x40010;
const GlobalValue* GV = M->getNamedValue(MF->getName());
const MachineInstrBuilder& MIB = BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(X86::CALL64pcrel32));
MIB.addGlobalAddress(GV, imm, MCSymbolRefExpr::VK_None);

生成的MIR结果为:

CALL64pcrel32 @test + 262160, implicit $esp, implicit $ssp

当我使用以下代码时:

const MachineInstrBuilder& MIB = BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(X86::CALL64pcrel32));
MIB.addImm(imm);

生成的结果为:

CALL64pcrel32 262160, implicit $esp, implicit $ssp

但编译时会报错:Assertion failed: Target.getSymA() && "Relocation must reference a symbol!"


解决方案

问题根源

X86架构的CALL64pcrel32指令依赖PC相对重定位机制,LLVM对该指令的操作数有严格要求:必须关联一个符号(而非直接传入立即数),这就是直接使用addImm触发断言失败的原因。而你第一次尝试的addGlobalAddress用法,LLVM会将传入的偏移量视为目标全局符号的相对偏移,而非绝对地址,因此生成了@test + 262160的结果。

实现方式

要生成指向绝对地址0x40010的调用,你需要创建一个绑定到该地址的符号,再让LLVM生成指向该符号的调用指令,具体代码如下:

  1. 创建并绑定绝对地址的临时符号:
// 获取当前模块的MC上下文
MCContext &Ctx = M->getContext();
// 创建临时符号用于标记目标地址
MCSymbol *TargetAddrSym = Ctx.createTempSymbol();
// 通知汇编器将该符号绑定到绝对地址0x40010
M->getContext().getStreamer()->emitAbsoluteSymbol(TargetAddrSym, 0x40010);
  1. 构建CALL指令并引用该符号:
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(X86::CALL64pcrel32))
    .addSym(TargetAddrSym);

这样LLVM会生成指向该绝对符号的PC相对调用,最终汇编器会将其解析为预期的call 0x40010指令。


内容的提问来源于stack exchange,提问作者Kashikoi Clev-san

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 05:33:21