C++ 将Visual Studio asm移植到g++;基本asm

C++ 将Visual Studio asm移植到g++;基本asm,c++,assembly,gcc,visual-c++,inline-assembly,C++,Assembly,Gcc,Visual C++,Inline Assembly,我有以下简单但令人沮丧的问题:我使用的是g++编译器,但我作为示例使用的代码是为与Visual Studio一起使用而编写的。通常不是问题,但它们的内联汇编程序工作方式不同,因此需要更改代码 问题中的剪报如下: float someotherfuncname(inputvar) { //For example purposes. Can be arbitrary amount of math. return 1; } void __declspec(naked)funcname

我有以下简单但令人沮丧的问题:我使用的是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”

—“调用”使用周围C++程序中的东西。在没有扩展ASM的情况下,G+ASM不能轻易使用C++的东西。__declspec(裸体)阻止我使用扩展asm

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

编辑:我正在使用Windows

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

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

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

包括“[文件名]”
包括
包括“Windows.h”
typedef无符号长UInt32
无效安全写入8(UInt32地址、UInt32数据)
{
UInt32-oldProtect;
VirtualProtect((void*)地址,第4页,执行、读写和旧保护);
*((UInt8*)addr)=数据;
VirtualProtect((void*)地址,4,oldProtect和oldProtect);
}
无效安全写入32(UInt32地址,UInt32数据)
{
UInt32-oldProtect;
VirtualProtect((void*)地址,第4页,执行、读写和旧保护);
*((UInt32*)addr)=数据;
VirtualProtect((void*)地址,4,oldProtect和oldProtect);
}
无效writerPaddedCall(UInt32 straddr、UInt32 retnAddr、UInt32 callbackAddr)
{
对于(UInt32 i=strtAddr;i
我不确定它是否适合您,但您可以使用叮当(
-fasm blocks
开关)编译msvc梯架组件

以下是成功编译的asm示例:


不确定这是否是一个好的选择,因为clang不是一个gcc,但只是想提一下。也许这会有帮助。请不要杀我。

g++asm没有“调用”-是的,它有,它是一个有效的x86助记符。你为什么不这么认为?(你的g++尝试)。
\uuuuuu属性(裸))
函数可能是唯一一次在语句中使用它的好方法,因此此代码应该易于移植。(顺便说一句,
retn
只是正常的
ret
(近而远)但是,如果您完全取消内联asm并使用纯C,而不是一些旧的32位堆栈参数调用约定,这肯定会使堆栈偏移16,因此即使您保留32位模式,它也无法移植到Linux。您是否在使用g++for Windows(如MinGW、TDM)?其他人似乎建议您移植到Linux,尽管我没有看到任何迹象表明您正在脱离Windows平台。我正在尝试为OBSE编写一个插件(用于TES遗忘)。我不知道这些东西,我基本上是在尝试复制另一个可以工作的插件的代码。如果我知道函数需要做什么,我可能可以用纯C语言复制它,但是,我不知道。我对代码一无所知,但我假设这里使用ECX是将CDECL调用转换为THISCALL调用约定。是e> funcname您在这里实际显示了您实际要转换的函数?@cpp:没关系,也许我应该把它作为一个答案发布出来。
#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
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;
}
};