Gcc 使用C++;在共享库(DLL)中作为固定常量(未重新定位)编码

Gcc 使用C++;在共享库(DLL)中作为固定常量(未重新定位)编码,gcc,dll,mingw-w64,relocation,Gcc,Dll,Mingw W64,Relocation,对不起,如果标题不是很清楚。我正在使用MinGW和GCC 6.3.0在Windows上构建一个x86 32位DLL(到目前为止)。我将不告诉您为什么我需要代码中可访问的部分的hacky offset,所以请不要问它是否有用(因为我不想费心解释) 所以,如果我能让下面的测试用例工作,我就很好了。我的问题是: < >在C++文件中,我想直接访问链接符作为绝对数值>值,不重定位。请记住,我正在构建一个32位DLL,它需要一个.reloc节来进行重新定位,但在这种情况下,我不希望重新定位,事实上重新定位

对不起,如果标题不是很清楚。我正在使用MinGW和GCC 6.3.0在Windows上构建一个x86 32位DLL(到目前为止)。我将不告诉您为什么我需要代码中可访问的部分的hacky offset,所以请不要问它是否有用(因为我不想费心解释)

所以,如果我能让下面的测试用例工作,我就很好了。我的问题是:

< >在C++文件中,我想直接访问链接符作为绝对<强>数值>值,<强>不<强>重定位。请记住,我正在构建一个32位DLL,它需要一个.reloc节来进行重新定位,但在这种情况下,我不希望重新定位,事实上重新定位会把它完全搞砸

下面是一个示例:检索say
\uu imp的偏移量__MessageBoxW@16
相对于
\uu IAT\u start\uuu
,如果您不知道它们是什么,
\uu imp__MessageBoxW@16
是运行时指向实际函数的重新定位指针,
是默认脚本文件中的链接器符号。这里是它的定义:

.idata BLOCK(__section_alignment__) :
{
    /* This cannot currently be handled with grouped sections.
    See pe.em:sort_sections.  */
    KEEP (SORT(*)(.idata$2))
    KEEP (SORT(*)(.idata$3))
    /* These zeroes mark the end of the import list.  */
    LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
    KEEP (SORT(*)(.idata$4))
    __IAT_start__ = .;
    KEEP (SORT(*)(.idata$5))
    __IAT_end__ = .;
    KEEP (SORT(*)(.idata$6))
    KEEP (SORT(*)(.idata$7))
}
到目前为止,没有问题。由于GAS不允许我“减去”两个外部定义的符号(两个符号都在链接器中定义),我必须在链接器脚本中定义符号,因此在链接器脚本的末尾,我有以下内容:

test_symbol = ABSOLUTE("__imp__MessageBoxW@16" - __IAT_start__);
P> >在C++中,我使用这个小的内联ASM检索这个相对差值,它被认为是一个固定值,一旦链接:

asm("movl $test_symbol, %0":"=r"(var));
现在
var
应该包含那个固定的数字,对吗?错了

因为就汇编程序而言,
test\u symbol
是一个“未定义”的符号,所以它使它重新定位。或者我不知道为什么,但是我尝试了很多东西来强迫它成为一个“绝对常量值符号”,而不是一个“重新定位的符号”,但都无济于事。即使使用
LD\u功能(“SANE\u EXPR”)
等工具编辑链接器脚本,也根本不起作用

仅当DLL未重新定位时,其值才正确

您可以看到,GNU LD或汇编程序在.reloc部分中为该movl指令添加了一个条目,这是错误的

是否有办法强制它将外部/未定义的符号视为固定常量,并对其应用无重新定位?基本上,从.reloc部分中省略它

我快发疯了,请告诉我有件事我很容易忽略,我找了好几个小时

换句话说,有没有一种方法可以从内联asm/C++中使用链接器符号,而无需重新定位?没有.reloc部分的条目或任何内容,基本上与$1234之类的常量相同。因此,如果一个DLL被加载到另一个基址,那么这个常量每次都是相同的

更新:我忘记了这个问题,但决定进行更新,因为这似乎不可能,因为甚至没有人发表评论。对于与我处于同一条船上的其他人,我认为这是COFF对象格式本身的一个限制。换句话说,外部符号被隐式地重新定位,似乎没有办法解决这个问题

我并没有按照我想要的方式“修复”它,但我用了一种非常粗糙的方式。如果有人感兴趣,下面是我丑陋的“黑客”:

首先,我在内嵌程序集中添加了一个特殊的“自定义”指令,在这里引用C++的外部符号。此“自定义”指令包含一条占位符指令,用于获取符号(带有伪常量的普通x86 asm指令,例如1234)以及标识符号的方法。然后让GCC生成程序集文件(.S文件),然后我用一个简单的脚本解析程序集,当我找到“自定义”指令时,我为链接器插入一个标签(make it.global),同时将一个指令添加到一个自定义的“动态”生成的链接器脚本中,该脚本从我的主链接器脚本中包含在最后

这会将数据放置在生成的DLL中的临时部分中,与我需要的自定义指令具有绝对偏移量,但不会重新定位

接下来,我解析二进制DLL本身,特别是我用所有这些技巧添加的临时部分。我从那里获取偏移量,将其转换为文件偏移量,并直接修改这些偏移量所指向的DLL的.text部分(还记得那些占位符说明吗?它将用链接器未重新定位的常量中的相应值替换它们的立即数常量1234)。然后我从DLL中剥离临时部分,就完成了。当然,所有这些都是由助手程序和脚本自动完成的

这是一个疯狂的黑客,但它的工作和它的全自动,现在我把它。如果我的假设是正确的,COFF不支持非重新定位的外部符号,那么它确实是<强> >唯一的方式使用< C++的链接器常数,而不被重新定位,这将是一个灾难。< /P>