【问题标题】:porting Visual Studio asm to g++ basic asm [closed]将 Visual Studio asm 移植到 g++ 基本 asm [关闭]
【发布时间】:2021-04-04 12:52:12
【问题描述】:

我有以下简单但令人沮丧的问题:我正在使用 g++ 编译器,但我用作示例的代码是为与 Visual Studio 一起使用而编写的。通常不是问题,但它们的内联汇编器工作方式不同,因此需要更改代码。

有问题的截图如下:

float someotherfuncname(inputvar)
{
    //For example purposes. Can be arbitrary amount of math.
    return 1;
}

void __declspec(naked)funcname(void)
{
    __asm
    {   
        push    ecx
        call    someotherfuncname
        pop     ecx
        retn
    }
}

我在这个话题上没有经验,基本上我正在精心复制一个更有经验的编码员编写的神秘公式,希望能重现结果(在其他部分取得了成功,但这个让我明白了)。

据我所知,主要问题是:

-g++ asm 没有“retn”。

-"call" 使用来自周围 c++ 程序的东西。没有extendend asm,g++ asm 不能轻易使用c++ 的东西。 __declspec(naked) 阻止我使用扩展 asm。

-我不知道“retn”是做什么的,所以我不能用等效的代码来伪造它。

编辑:我正在使用 Windows。

目的是构建一个 .dll 供 OBSE 用于 TES Oblivion。我正在用 g++(可能是 MinGW)构建它。

(不)工作代码的最小草图是:在 .h 文件中(不是问题,只是为了完整性):

#ifndef MSK_B
#define MSK_B

#ifdef __cplusplus
extern "C" {
#endif

#ifdef DLL_KOMP
#define SPECK __declspec(dllexport)
#else
#define SPECK __declspec(dllexport)
#endif

bool SPECK OBSEPlugin_Query(const OBSEInterface * obse, PluginInfo * info);

bool SPECK OBSEPlugin_Load(const OBSEInterface * obse);

#ifdef __cplusplus
}
#endif

#endif  // MMC_B_H

在 .cpp 文件中:注意,这里没有定义 OBSEInterface 和 PluginInfo,但它们不是必需的(只有一些骨架定义可以使编译器满意,所以我将它们省略了)。

include "[name of the .h file]"
include <fstream>
include "Windows.h"

typedef unsigned long UInt32

void SafeWrite8(UInt32 addr, UInt32 data)
{
    UInt32  oldProtect;

    VirtualProtect((void *)addr, 4, PAGE_EXECUTE_READWRITE, &oldProtect);
    *((UInt8 *)addr) = data;
    VirtualProtect((void *)addr, 4, oldProtect, &oldProtect);
}

void SafeWrite32(UInt32 addr, UInt32 data)
{
    UInt32  oldProtect;

    VirtualProtect((void *)addr, 4, PAGE_EXECUTE_READWRITE, &oldProtect);
    *((UInt32 *)addr) = data;
    VirtualProtect((void *)addr, 4, oldProtect, &oldProtect);
}

void WriteRelPaddedCall(UInt32 strtAddr, UInt32 retnAddr, UInt32 callbackAddr)
{
    for (UInt32 i = strtAddr; i < retnAddr; i++) SafeWrite8(i,0x90);
    WriteRelCall(strtAddr,callbackAddr);
}

extern "C" {
bool SPECK OBSEPlugin_Query(const OBSEInterface * obse, PluginInfo * info)
{
    return true;
}

bool SPECK OBSEPlugin_Load(const OBSEInterface * obse)
{
    UInt32 RuesDispAddrH = 0x005AB365;
    UInt32 RuesDispAddrR = 0x005AB36D;
    //RuestungECX is the function i posted above.
    //This line (as implemented here) causes the game to crash when loading a game (or starting a new game).
    WriteRelPaddedCall(RuesDispAddrH, RuesDispAddrR, (UInt32) &RuestungECX);
    return true;
}
};

【问题讨论】:

  • g++ asm 没有“调用” - 是的,它是有效的 x86 助记符。为什么你认为它没有? (你的 g++ 尝试的minimal reproducible example)。 __attribute__((naked)) 函数可能是唯一一次在语句中使用它是个好主意,所以这段代码应该很容易移植。 (顺便说一句,retn 只是普通的ret(近而不是远)。但实际上最好完全消除内联汇编并使用纯 C,而不是一些旧的 32 位堆栈参数调用约定肯定会使堆栈错位 16,因此即使您保持 32 位模式,它也不能移植到 Linux
  • 您在使用 g++ for Windows(如 MinGW、TDM)吗?其他人似乎建议您移植到 Linux,尽管我没有看到任何表明您正在离开 Windows 平台的信息。
  • 我正在尝试为 OBSE(用于 TES Oblivion)编写一个插件。我不知道这些东西,我基本上是在尝试复制另一个有效插件的代码。如果我知道该函数需要做什么,我也许可以在纯 C 中重现它,但是,我不知道。
  • 我对代码一无所知,但我假设在这里使用 ECX 是为了将 CDECL 调用按摩到 THISCALL 调用约定。 funcname 您实际上在这里显示的是您实际尝试转换的功能吗?
  • @CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP:没关系,也许我应该把它作为答案发布。

标签: c++ assembly gcc visual-c++ inline-assembly


【解决方案1】:

我不确定它是否适合您,但您可以使用 clang(-fasm-blocks 开关)编译 msvc stile 程序集。

这里是一个成功编译 asm 的例子:https://godbolt.org/z/o57sbq

不确定它是否适合您,因为 clang 不是 gcc,但只是想提一下。也许它会有所帮助。请不要杀我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 2017-11-06
    • 1970-01-01
    • 2015-12-29
    • 1970-01-01
    • 1970-01-01
    • 2022-11-25
    相关资源
    最近更新 更多