【问题标题】:gcc inlined assembly jmp address; Naked functionsgcc 内联汇编 jmp 地址;裸函数
【发布时间】:2013-10-24 22:21:33
【问题描述】:

我可以使用 Visual Studio 2012 跳转到一个地址。当涉及到 gcc/mingw 时,我无法判断我的跳转是否正确。

如何跳转到 gcc 中的地址?

我试过了:

__declspec(naked) void DXHook_D3DPERF_BeginEvent()
{
    #ifdef _MSC_VER  //If using visual studio..
    __asm{jmp[Addr]} //Jump to: Address stored in Addr.
    #else            //else using gcc..
    __asm("jmp *%0"
          : /*No Outputs*/
          : "r" (Addr)
          : "%eax");
    #endif
}

这是正确的吗?另外,有没有办法让 gcc 不再打扰我:

warning: 'naked' attribute directive ignored.

为什么它忽略了我的裸属性?

【问题讨论】:

  • 裸属性被忽略,因为它不是为 x86 实现的。想做什么?寄存器的值会发生什么变化?变量是否应该在跳转前写回内存?
  • 你试过clang吗?它应该支持与 GCC 相同的语法,我认为他们也在致力于 MVC 支持......

标签: c++ c gcc inline-assembly


【解决方案1】:

TL;DR 在 GCC 中,这是 only available on: ARM, AVR, MCORE, MSP430, NDS32, RL78, RX and SPU ports

是NOT available on x86。

Workaround (proposed by Brendon in the comments).

完整答案

(此答案的其余部分假设您使用的是受支持的目标)

那是因为您使用的是 Windows 属性语法,__declspec 与 GCC。

引用自MSDN reference on __declspec:

扩展的属性语法简化并标准化了 Microsoft 特定 对 C 和 C++ 语言的扩展。

您应该使用GCC function attribute syntax 代替或并行使用。

还请注意this GCC article 的以下引用:

注意:Windows 和这个 GCC 之间的语义不同 功能 - 例如 __declspec(dllexport) void (*foo)(void) 和 void (__declspec(dllexport) *foo)(void) 意味着完全不同的东西 而这会产生关于无法申请的警告 GCC 上非类型的属性。

因此,您在 GCC 中使用 __declspec 语法的方式也可能存在问题(如果它甚至支持的话)。

您还应该注意,GCC 声明它支持的唯一__declspec 属性是__declspec(dllexport)(如已经提到的GCC attribute syntax link 中所述)。

因此,让我们为您的问题寻找通用解决方案,但首先我们需要阅读实际的 GCC attribute syntax 并找到以下内容:

属性说明符列表可能会出现在声明符之前 (除了第一个)在逗号分隔的声明符列表中 使用单个列表声明多个标识符 说明符和限定符。此类属性说明符仅适用于 它们出现在其声明符之前的标识符。例如,在

 __attribute__((noreturn)) void d0 (void),
     __attribute__((format(printf, 1, 2))) d1 (const char *, ...),
      d2 (void)

noreturn 属性适用于所有声明的函数;这 format 属性仅适用于 d1。

因此,您的问题的解决方案如下:

#ifdef __GNUC__
#define ATTRIBUTE_NAKED __attribute__((naked))
#else
#define ATTRIBUTE_NAKED __declspec(naked)
#endif

ATTRIBUTE_NAKED void DXHook_D3DPERF_BeginEvent()
{
    #ifdef _MSC_VER  //If using visual studio..
    __asm{jmp[Addr]} //Jump to: Address stored in Addr.
    #else            //else using gcc..
    __asm("jmp *%0"
          : /*No Outputs*/
          : "r" (Addr)
          : "%eax");
    #endif
}

编辑:

需要注意的是,这个属性是platform specific。我引用:

裸体

此属性在 ARM、AVR、MCORE、MSP430、NDS32、RL78、RX 和 SPU 端口上可用。它允许编译器构造 必要的函数声明,同时允许 函数为汇编代码。指定的功能不会有 由编译器生成的序言/尾声序列。只有基本的asm 语句可以安全地包含在裸函数中(参见 Basic Asm)。 在使用扩展 asm 或基本 asm 和 C 代码的混合时,可能 似乎可以工作,但不能依赖它们可靠地工作,并且 不支持。

引自GCC documentation on function attributes。

旁注

对clang attributes 的进一步阅读可能会有所帮助(大部分与 GCC 兼容),但these comments 似乎表明希望匹配 GCC 行为。

【讨论】:

  • i.imgur.com/IfZsecR.png 和 i.imgur.com/hIzpIsW.png 你有没有测试过你的代码,因为我确实做过.. GCC 4.9.2
  • 唉,看来您使用的是不受支持的目标。我假设您正在使用 ARM,但似乎我的假设不正确。它在 documentation 中明确指出,在裸属性旁边不支持 x86。还有一个关于这个的bug。我已经更新了我的答案来解释这一点。
  • @Brandon 看看你的内联汇编,很明显这是 x86 ......哎呀,不知道我以前是怎么错过的。
  • x86 的解决方法是添加一个函数声明并使用 asm 实现主体:stackoverflow.com/a/8375416/1462718
【解决方案2】:

要执行与 Visual C++ 代码等效的操作,请在单独的文件或顶层(而不是函数)asm 语句中完全在汇编中实现它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    • 1970-01-01
    • 2011-12-20
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    相关资源
    最近更新 更多