如何在LLVM IR中获取程序的映像基址
我正在尝试创建输出相对虚拟地址的LLVM IR。但是,在编译和链接之后,我看到它根据可执行文件的首选映像基址而不是相对地址输出地址 例如,如果我使用如下代码:如何在LLVM IR中获取程序的映像基址,llvm,llvm-ir,Llvm,Llvm Ir,我正在尝试创建输出相对虚拟地址的LLVM IR。但是,在编译和链接之后,我看到它根据可执行文件的首选映像基址而不是相对地址输出地址 例如,如果我使用如下代码: @.myconstant = private constant [12 x i8] c"My constant\00" @.myglobal = global {i8*} {i8* bitcast([12 x i8]* @.myconstant to i8*)} 在匹配可执行文件部分,我看到一个十六进制值,如: 44 30 40 00
@.myconstant = private constant [12 x i8] c"My constant\00"
@.myglobal = global {i8*} {i8* bitcast([12 x i8]* @.myconstant to i8*)}
在匹配可执行文件部分,我看到一个十六进制值,如:
44 30 40 00
或者简单地说是0x403044,它比我的整个可执行文件的大小要大得多,即使在节对齐之后也是如此
如果我手动减去0x400000,如下所示:
@.myconstant = private constant [12 x i8] c"My constant\00"
@.myglobal = global {i8*} {i8* inttoptr (i32 sub(i32 ptrtoint([12 x i8]* @.myconstant to i32), i32 u0x400000) to i8*)}
我在可执行文件中得到了正确的地址。但此解决方案不可维护,因为映像基址不能保证为0x400000
同时,我必须使用一个指向全局的指针,因为我不知道该全局将在相关部分中的何处结束(因为这取决于同一部分中的其他全局),或者将为该部分分配什么相对内存地址(因为这取决于与前面部分的对齐)
所以我的问题是,我如何获取作为常量的基址,或者获取相对于程序加载地址的地址
更新:显然,lld的开发人员已经遇到了这个问题,并在AT&T汇编语言中添加了一个扩展来解释这个问题:
.regular_global:
.long .L.myconstant # Outputs 0x403044
.rva_global:
.long .L.myconstant@imgrel # Outputs 0x3044
所以我的问题变成了:我如何通过IR生成这个组件?好吧,我找到了解决方案。我需要定义一个名为
@\uuu ImageBase
的外部全局变量,如下所示:
@__ImageBase = external global i8
然后,我执行相对于该全局地址的指针减法,如下所示:
@.myconstant = private constant [12 x i8] c"My constant\00"
@.myglobal = global {i8*} {i8* inttoptr (i32 sub(i32 ptrtoint([12 x i8]* @.myconstant to i32), i32 ptrtoint(i8* @__ImageBase to i32)) to i8*)}
最后,我需要调用带有Windows目标三元组的llc
,因为它是唯一支持图像相对重定位的平台。例如,我可以在命令行中设置-mtriple=i386-pc-win32
出于某种原因,在源文件中设置目标三元组如下:
target triple = "i386-pc-win32"
这是不够的。如果不添加上面的命令行,则LLVM会抱怨未定义的常量\uuuuuu ImageBase
使用目标三元组x86\u 64-pc-win32
并将指针算术从使用i32
替换为使用i64
,64位也可以实现同样的效果