GCC 内联程序集 JMP 地址;裸函数

gcc inlined assembly jmp address; Naked functions

本文关键字:函数 地址 JMP 程序集 GCC      更新时间:2023-10-16

我可以使用Visual Studio 2012jmp到一个地址。当谈到 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.

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

TL;DR 在 GCC 中,这仅适用于:ARM、AVR、MCORE、MSP430、NDS32、RL78、RX 和 SPU 端口

它在 x86不可用

解决方法(由布伦登在评论中提出)。

完整答案

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

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

引用MSDN关于__declspec的参考:

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

您应该改用或并行使用 GCC 函数属性语法。

另请注意这篇 GCC 文章中的以下引述:

注意:Windows和此GCC之间的语义不同 功能 - 例如,__declspec(dllexport) void (*foo)(void) 和 void (__declspec(dllexport) *foo)(void) 的意思完全不同 而这会生成有关无法应用的警告 GCC 上非类型的属性。

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

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

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

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

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

noreturn 属性适用于声明的所有函数; 格式属性仅适用于 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
}

编辑:

请务必注意,此属性是特定于平台的。我引用:

裸体

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

引自 GCC 关于函数属性的文档。

旁注

可能进一步阅读 clang 属性可能会有所帮助(主要与 GCC 兼容),但这些评论似乎表明希望匹配 GCC 行为。

若要执行等效的 Visual C++ 代码,请完全在程序集中实现它,要么在单独的文件中,要么在顶级(而不是函数中)asm语句中实现它。