读取RIP的MSVC汇编代码移植到GCC的正确实现咨询
你的实现存在以下错误
- 致命错误:内联汇编中添加了
ret指令,执行到这条指令时会直接终止当前父函数(也就是调用_get_addr的GetImageAddress)的执行,不会走后续的代码逻辑,运行直接出错。 - 符号重定义风险:你使用的
_lb是全局符号,如果多个编译单元引入该函数,会出现符号冲突报错。 - 寄存器使用未声明:你直接修改了
rax寄存器,但没有在GCC内联汇编的破坏列表中声明,可能会覆盖编译器在寄存器中存储的其他变量值,导致未定义行为。
关于内联修饰的合理性
你原本的理解有一点偏差:原MSVC实现的_get_addr返回的不是调用者的地址,而是自身函数内部_lb标签的地址,本质是获取当前模块内的一个有效代码段地址,用来向下检索镜像基址。
这种场景下always_inline修饰是合理的:
- 内联后汇编代码会嵌入到调用者位置,返回的地址是调用者函数内部的地址,依然属于当前模块的代码段,完全满足后续检索基址的逻辑。
- 还避免了额外的函数调用开销,对EDK2这种底层场景更友好。
正确的GCC移植实现
static __inline__ __attribute__((always_inline)) PVOID _get_addr(void) { PVOID pointer; __asm__ volatile ( "call 1f\n" "1: pop %[ptr]\n" : [ptr] "=r"(pointer) ); return pointer; }
如果明确要对齐原MSVC实现使用rax寄存器存储返回值,可以写成:
static __inline__ __attribute__((always_inline)) PVOID _get_addr(void) { PVOID pointer; __asm__ volatile ( "call 1f\n" "1: pop %%rax\n" : "=a"(pointer) ); return pointer; }
注意添加volatile修饰避免GCC优化掉这段汇编代码
功能验证说明
该实现和原MSVC版本功能完全等价:call指令会将下一条指令(也就是局部标签1的位置)的地址压入栈,pop指令将该地址赋值给输出变量,返回的值是当前代码段的一个有效地址,完全满足后续检索当前EFI镜像基址的需求。
内容的提问来源于stack exchange,提问作者l00k
相关产品推荐
相关产品推荐

