【问题标题】:The __declspec(dllimport) necessity__declspec(dllimport) 的必要性
【发布时间】:2013-03-26 14:03:27
【问题描述】:

我正在看这个:Importing Function Calls Using __declspec(dllimport),但我不明白为什么真的需要 __declspec(dllimport)?为什么链接器不能在链接阶段将调用 func1 修补为调用 DWORD PTR __imp_func1(IAT 表地址),从而避免在源代码中单独声明?

【问题讨论】:

  • 这会有帮助吗:stackoverflow.com/a/4490536?
  • @Joulukuusi 是的,这是避免 jmp 的优化,但我不明白为什么链接器无法执行此优化。
  • 因为 call func 的长度为 5 个字节,而 call dword ptr [__imp__func] 的长度为 6 个字节。补丁不适合。一个字节太大了。
  • @RaymondChen 我明白了,并且在它之后添加一个 NOP 以便它可能是六个字节长,我认为,这被认为是浪费空间。您能否将其发布为答案,以便我将其标记为已接受。谢谢。
  • 您可以自己写答案并接受。在每条调用指令之后添加一个 nop(以防万一它被导入)听起来非常过分。

标签: windows winapi linker


【解决方案1】:

修补指令空间不足可能是一个原因,但不是主要原因。即使有足够的空间,链接器仍然不会修补它以获得更好的性能。原因是链接器不会执行或修改编译器后端生成的代码,它只是用重定位信息修补位置。下面的例子不是很好的编码风格,但清楚地解释了这个问题。为bar() 生成的指令是call dword[_imp__bar],它有6 个字节长,即使链接器知道bar() 是在最终图像中定义的,它也不会用call OffsetOfBar 修补它,它只需要5 个字节字节。将代码生成延迟到链接时间(将/GL传递给cl.exe)可以解决这个问题,因为链接器会在链接时间调用编译器后端,后端会生成优化的call指令,因为它知道@ 987654326@目标在同一个模块中。

// main.c
// compile it with 'cl.exe /Zi /O2 main.c bar.c'

__declspec(dllimport) void bar();

int main() {
  bar();
}

// bar.c
void __declspec(noinline) bar() {}

【讨论】:

    【解决方案2】:

    引用 Raymond Chen 的话:call func 是 5 个字节长,但是 call dword ptr [_imp_func] 是 6 个字节长。补丁不适合。它太大了一个字节。在每条调用指令之后添加一个 nop(以防万一它被导入)听起来非常过分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-18
      • 2011-05-28
      • 1970-01-01
      • 2013-07-29
      • 1970-01-01
      • 2012-02-10
      • 1970-01-01
      相关资源
      最近更新 更多