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

Intel XED解码同一条指令时得到不同函数调用地址的问题

问题场景

测试用C代码如下:

#include <stdio.h>

void greet(void){
    printf("Hello!\n");
}

int main (){
    greet();
    return 0;
}

使用gcc将上述代码编译为名为hello的64位ELF可执行文件,开展两组XED解码实验:

  • 第一组解码整个.text段,执行命令:
    ./xed -i hello
    
    其中对greet函数的调用指令解码结果为:
    XDIS 1168: CALL    BASE    E8DCFFFFFF     call 0x1149 <greet>
    
    结果符合预期,0x1149确实是greet函数的入口地址。
  • 第二组仅单独解码上述call指令的十六进制编码E8DCFFFFFF,执行命令:
    ./xed -d E8DCFFFFFF
    
    得到输出:
    ICLASS:     CALL_NEAR
    CATEGORY:   CALL
    EXTENSION:  BASE
    IFORM:      CALL_NEAR_RELBRz
    ISA_SET:    I86
    ATTRIBUTES: FIXED_BASE0 MPX_PREFIX_ABLE SCALABLE STACKPUSH0 
    SHORT:      call 0xffffffe1
    

预期解码结果为call 0x1149,实际输出为call 0xffffffe1。

原因说明
  • x86_64架构下,操作码0xE8对应相对近调用指令,属于位置相关指令:它的操作数不是目标地址的绝对值,而是以「当前call指令的下一条指令地址」为基准的32位有符号相对偏移,跳转目标的计算规则为:
    目标绝对地址 = call指令起始地址 + 指令长度(固定5字节) + 32位有符号相对偏移
  • 整文件反汇编时,XED可以从ELF的段信息中拿到.text段的加载基址,明确知道这条call指令的起始地址是0x1168,因此能算出正确目标:
    • 指令编码E8DCFFFFFF中,首字节E8是操作码,后续4字节DC FF FF FF是小端序存储的32位有符号偏移,按补码解析为十进制值-36
    • call指令的下一条指令地址为0x1168 + 5 = 0x116D
    • 代入公式计算目标地址:0x116D + (-36) = 0x1149,和greet函数入口地址完全匹配。
  • 单独解码十六进制串时,XED没有任何文件格式提供的地址上下文,不知道这条指令实际会被加载到哪个内存地址运行,只能默认将指令起始地址设为0来计算:
    • 默认下一条指令地址为0 + 5 = 5
    • 代入公式计算目标地址:5 + (-36) = -31,将这个有符号值转为32位无符号表示就是0xffffffe1,和单独解码的输出完全一致。

本质是单独解码指令字节流时,缺失了指令的实际加载地址这一必要上下文,自然无法算出正确的绝对跳转目标,只能给出基于0基址的计算结果。


内容的提问来源于stack exchange,提问作者Farzam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 10:06:36