如何使用MinGW-gcc摆脱DLL .reloc部分?

时间:2016-05-02 17:55:00

标签: c gcc mingw portable-executable relocation

我正在用C手工构建vtables。从DLL导出时,它们会在其重定位表中生成大量条目。
示例$mdBottomSheet输出:

z-index

有没有办法摆脱它们,还是它们是Windows的唯一途径? 以上是我的发现:

  1. 在Visual Studio的md-bottom-sheet{ z-index: 81; } 中,有一个选项objdump(完全符合我的要求)
  2. this tuturial,但大多数似乎只适用于Linux下的Virtual Address: 00002000 Chunk size 24 (0x18) Number of fixups 8 reloc 0 offset 0 [2000] HIGHLOW reloc 1 offset 4 [2004] HIGHLOW reloc 2 offset 8 [2008] HIGHLOW reloc 3 offset c [200c] HIGHLOW reloc 4 offset 10 [2010] HIGHLOW reloc 5 offset 14 [2014] HIGHLOW reloc 6 offset 18 [2018] HIGHLOW reloc 7 offset 1c [201c] HIGHLOW
  3. 我可以在不使用link的情况下构建DLL,而是设置/FIXED
  4. 最后一个确实起作用(没有生成gcc部分),但我认为这是一个极端丑陋的黑客,因为它实际上不再是DLL了。

    澄清

    我觉得这个问题只是因为人们发现重新安置是一件好事而被低估了。 我承认,他们一般都很好,但我有一个非常具体的目标。我想展示如何在O(1)中实现与vtable的动态多态,如下所示:

    -shared

    由于“高级演员”仅涉及指针算术,因此这是O(1)(特别是,没有像Java那样进行线性搜索)。

    现在回到重新定位:无论成本有多低,它恰好是O(n),因为每个类中的每个方法都需要更新。叹息。

    TL;博士
    GCC的微软--image-base有挂件吗?如果没有,在PE中设置哪些标志以实现所需的行为?

2 个答案:

答案 0 :(得分:2)

好的,我自己找到了答案:

必须在DLL上使用strip -R .reloc,然后手动将IMAGE_FILE_RELOCS_STRIPPED(0x0001)添加到PE头中的Characteristics字段。那样做。

当然,这与自定义基地址(-Wl,--image-base=...)一起使用 - 否则Windows无法加载DLL。
生成的模块也可能是防病毒软件的误报(因此可以立即移动到容器中)。

答案 1 :(得分:1)

PIC并不意味着与位置无关的数据。您的代码与位置无关,但会产生运行时成本。在编译/链接时,数据部分可以用函数地址填充,这没有什么神奇之处,因为它们在运行时会有所不同 - 否则PIE开始时就不会有所说的运行时成本。编译器可能会使用某种不同类型的函数指针来指向PIC函数并在调用之前得到修复,但这会在每个函数指针取消引用时产生额外的成本。因此,编译器默认不这样做。

你可以让运行时链接器完成它的工作并在你的代码加载时修复你的vtable,或者你可以在运行时填充vtable,如果编译器不能优化这样的代码并给你rdata vtable返回。无论哪种方式,你都在做同样的事情而你却无法摆脱它。

而不是带有函数指针的vtable,你可以明确地发送thunk并希望交换机不会用编译器生成的vtable实现。然后C_foo(&c, ...) thunk调用将替换c->vtable->foo(...)调用。

typedef enum { C_type, D_type } type_t;


typedef struct {
  type_t type;
} C;

typedef struct {
  type_t type;
} D;

// Replaces the vtable
void C_foo_impl(int);
void D_foo_impl(int);
void C_foo(C * self, int i) {
  switch (self->type) {
  case C_type: return C_foo_impl(i);
  case D_type: return D_foo_impl(i);
  default: return;
  }
}

void C_init(C * self) {
  self->type = C_type;
}

void D_init(D * self) {
  C_init((C*)self);
  self->type = D_type;
}

void test(void) {
  C c;
  C_init(&c);
  D d;
  D_init(&d);
  C_foo(&c, 10); // calls c_foo_impl
  C_foo((C*)&d, 10); // calls d_foo_impl
}