将 VS 转换为 GCC 内联汇编

Converting VS to GCC inline assembly

我有这段代码

__asm
{
    mov eax, fs:[18h]
    mov eax, [eax + 30h]
    mov eax, [eax + 0Ch]
    mov pmInfo, eax
}

这里应该是检索第一行的TEB,第二行的PEB,最后一个是包含进程模块信息的结构。

typedef struct _ProcessModuleInfo
{
    unsigned int size;
    unsigned int initialized;
    HANDLE SsHandle;
    LIST_ENTRY LoadOrder;
    LIST_ENTRY InitOrder;
    LIST_ENTRY MemoryOrder;
} ProcessModuleInfo, *pProcessModuleInfo;

我的问题是,如何将那段程序集转换为 codeblocks 的 GCC 编译器?

您可以详细了解 GCC assembler templates in the GCC documentation. Peter Cordes has a Whosebug answer with a list of if you wish to learn more. MSVC and GCC differ greatly. GCC has no knowledge of what a template does or the instructions executes. GCC instead does substitutions based upon a list of constraints - 输入、输出和破坏。

一个 GCC 扩展汇编器模板,它非常接近 MSVC 内联汇编器,看起来像:

__asm__ (
    "mov %%fs:0x18, %0\n\t"
    "mov 0x30(%0), %0\n\t"
    "mov 0x0C(%0), %0\n\t"
    : "=r"(pmInfo));

在您的情况下,您需要一个寄存器供内部使用。它不需要是 EAX 但可以是 GCC 可用的任何寄存器。我们使用 "=r" 输出约束 表示我们希望 GCC 选择可用的寄存器。我们通过汇编器模板中的 %0 引用第一个(在本例中是唯一的)约束。 "=r"(pmInfo) 约束表示当模板中的指令完成时,所选寄存器中的值将放入 pmInfo 中。

GCC 扩展汇编程序使用起来很棘手,而且很容易出错。您最好创建一个汇编程序文件,其中包含 returns 指向 ProcessModuleInfo 结构的指针的函数。这消除了理解 GCC 的扩展汇编器模板和处理其复杂性的需要。

Whosebug 用户 DavidWohlferd 写了一个 GCC wiki article 给出了为什么应该避免使用 GCC 内联汇编程序的原因 如果 可能。


如果 %0 看起来有点混乱,可以为每个输入和输出操作数指定一个符号名称,可以用作替代 % 和模板中的数字.代码可能如下所示:

__asm__ (
    "mov %%fs:0x18, %[tempreg]\n\t"
    "mov 0x30(%[tempreg]), %[tempreg]\n\t"
    "mov 0x0C(%[tempreg]), %[tempreg]\n\t"
    : [tempreg]"=r"(pmInfo));

方括号中的 [tempreg] 为操作数提供了一个名称,作为使用序数位置的替代方法。这也让阅读模板变得更容易一些。