C++ 将Visual Studio asm移植到g++;基本asm
我有以下简单但令人沮丧的问题:我使用的是g++编译器,但我作为示例使用的代码是为与Visual Studio一起使用而编写的。通常不是问题,但它们的内联汇编程序工作方式不同,因此需要更改代码 问题中的剪报如下: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
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;
}
};