使用C ++代码中的链接符号作为共享库(DLL)中的固定常量(NOT重定位)

时间:2017-03-07 00:39:29

标签: gcc dll mingw-w64 relocation

很抱歉,如果标题不是很清楚。我正在使用MinGW和GCC 6.3.0在Windows上构建一个x86 32位DLL(到目前为止)。我会向您详细说明为什么我需要通过代码访问其部分中的hacky偏移,所以请不要问它是否有用(因为我不想打扰的)。

所以,如果我可以使用以下测试用例,那我很好。这是我的问题:

在C ++文件中,我想直接将链接器符号作为绝对数字值,重新定位。请记住,我正在构建一个32位DLL,需要 .reloc 部分进行重定位,但在这种情况下我不想重定位,实际上重定位会将其完全搞砸。

以下是一个示例:如果您不知道它们是什么,请检索__imp__MessageBoxW@16相对于__IAT_start__偏移量,{ {1}}是在运行时指向实际函数的重定位指针,__imp__MessageBoxW@16是默认脚本文件中的链接器符号。在这里定义:

__IAT_start__
到目前为止,没问题。因为GAS不允许我减去"两个外部定义的符号(两个符号都在链接器中定义),我必须在链接描述文件中定义符号,所以在链接描述文件的 end 我有这个:

.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))
}

然后在C ++中我使用这个小内联asm来检索这个相对差异,一旦链接就应该是一个固定值

test_symbol = ABSOLUTE("__imp__MessageBoxW@16" - __IAT_start__);

现在asm("movl $test_symbol, %0":"=r"(var)); 应该包含固定号码吗?错!

因为var是"未定义"关于汇编程序的符号,它使它重新定位。或者我不知道为什么,但我尝试了这么多东西来迫使它成为一个"绝对常数值符号"而不是一个"重新定位的符号"无济于事。即使用test_symbol等其他内容编辑链接描述文件,也根本不起作用。

仅当DLL没有重新定位时,其值才是正确的

你看,GNU LD或汇编程序在 .reloc 部分为那个movl指令添加一个条目,这是错误的!

有没有办法强制它将外部/未定义的符号视为固定的CONSTANT并对其应用不重定位?基本上,从 .reloc 部分省略它。

我对此感到疯狂,请告诉我,我忽略了一些简单的事情,我搜索了小时

换句话说,有没有办法在内联asm / C ++ 中使用链接器符号而不用将其重新定位?没有进入.reloc部分或任何内容,基本上与$ 1234之类的常量相同。因此,如果DLL被加载到另一个基地址,该常量每次都是相同的

更新:我忘记了这个问题,但决定提出更新,因为似乎很可能没有人会发表评论。对于与我同舟共济的其他人,我认为这是COFF对象格式本身的限制。换句话说,外部符号是隐式重新定位的,并且它似乎没有办法对付它。

我没有"修复"它是我想要的方式,但我是以一种非常黑客的方式做到的。如果有人有兴趣,这里是我的丑陋" hack":

首先,我提出了一个特殊的"习惯"内联汇编中的指令,我从C ++引用这个外部符号。这个"定制"指令持有占位符指令,该指令捕获符号(具有虚拟常量的正常x86 asm指令,例如1234)以及识别它的方法。然后让GCC生成汇编文件(.S文件),然后用一个简单的脚本解析程序集,当我发现" custom"指令我为链接器插入一个标签(使其成为.global),同时将一个指令添加到一个自定义的"即时"生成的链接器脚本,最后从我的主链接器脚本中包含。

这将数据放在生成的DLL中的临时区域中,并且对我需要的自定义指令有绝对偏移量,但没有重定位。

接下来,我解析二进制DLL本身,特别是我添加了所有这些hack的临时部分。我从那里获取偏移量,将它们转换为文件偏移量,并直接修改DLL的.text部分,其中这些偏移量指向(记住那些占位符指令?它用链接器中的相应值替换它们的立即常量1234&# 39; s非重新定位的常数)。然后我从DLL中删除临时部分,并完成了。 当然,所有这些都是由帮助程序和脚本

自动完成的

这是一个疯狂的黑客攻击,但是它起作用了,而且它已经完全自动化了。如果我的假设是正确的,COFF不支持非重新定位的外部符号,那么它真的唯一的方式使用C ++中的链接器常量而不重新定位它们,这将是一场灾难。

0 个答案:

没有答案