如何将 x86 和 x64 asm 文件包含到单个 Visual Studio 项目中?

Posted

技术标签:

【中文标题】如何将 x86 和 x64 asm 文件包含到单个 Visual Studio 项目中?【英文标题】:How to enable inclusion of x86 and x64 asm files into a single Visual Studio project? 【发布时间】:2018-07-06 21:04:39 【问题描述】:

我正在使用 Visual Studio 2017 Community 构建一个测试控制台 C++ 应用程序。我需要在该项目中包含一个汇编函数:

extern "C" void* __fastcall getBaseFS(void);

要包含一个 asm 文件,我右键单击项目并转到“构建依赖项”->“构建自定义”并在列表中选中“masm”。

然后我可以通过右键单击我的项目 -> 添加新项目 -> 添加一个 asm 文件,然后在我编写 x86-64 asm 代码的位置添加“asm_x64.asm”文件:

.code

getBaseFS PROC

mov ecx, 0C0000100H   ; IA32_FS_BASE
rdmsr

shl rdx, 32
or rax, rdx

ret

getBaseFS ENDP

END

这适用于 64 位项目。

问题是当我将解决方案平台从 x64 切换到 x86 时:

我的 asm 文件需要更改。所以从某种意义上说,我需要在编译中包含一个不同的“asm_x86.asm”文件,该文件仅用于 x86 构建与 x64 构建。

自动化此切换的最佳方法是什么?

【问题讨论】:

Windows 应用程序不能使用 RDMSR 指令,因为它是特权指令。此外,IA32_FS_BASE MSR 仅存在于 64 位 CPU 上。 @RossRidge:好的。但这不是我在这里要问的。 所以你的一般问题是如何让构建系统为目标架构选择一个.asm 文件。您可能应该在该特定示例上花费更少的时间,或者只是编造一个(例如,利用更多寄存器的同一函数的不同版本)。假设 MASM 允许您检测当前的 BITS 模式,一个文件中的宏将是获得此功能的另一种方法。 (NASM 使用 %if __BITS__ == 32 / %else / %endif)。 你可能想试试这个技巧***.com/a/9155436/3857942 @DavidBS:它可能会这样工作。身份证。我不是预构建脚本和其他配置内容的忠实粉丝。这一切都有一种趋势,要么无缘无故地被重置,要么在解决方案移动时丢失。我想我通过一个 asm 文件中的预处理器定义解决了这个问题。 【参考方案1】:

好的,感谢Michael Petch,我解决了。必须将x64x86 代码放在一个.asm 文件中。

(还有另一个建议的选项来处理构建配置,但我更喜欢我在这里展示的方法。当解决方案从一台计算机移动到另一台计算机时,这些构建配置消失了,我运气不好。) em>

所以,我不知道为什么 using IFDEF RAX works 和 Microsoft's own proposed ifndef X64 不知道。但是哦,好吧。如果有人知道,请发表评论。

asm_code.asm文件:

IFDEF RAX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; x64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; WinAPI to call
extrn Beep : proc


.data

align   8
beep_freq:
    dq  700 ; hz
beep_dur:
    dq  200 ; ms
str_from:
    db  "Hail from x64 asm", 0



.code

useless_sh_t_function__get_GS_a_string_and_beep PROC
    ; parameter = CHAR** for a string pointer
    ; return = value of GS register selector

    mov     rax, str_from
    mov     [rcx], rax

    mov     rdx, qword ptr [beep_dur]
    mov     rcx, qword ptr [beep_freq]
    call    Beep

    mov     rax, gs
    ret
useless_sh_t_function__get_GS_a_string_and_beep ENDP




ELSE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; x86 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.686p  
.XMM  
.model flat, C  


.data

align   4
beep_freq   dd  700 ; hz
beep_dur    dd  200 ; ms
str_from    db  "Hail from x86 asm", 0


.code

; WinAPI to call
extrn stdcall Beep@8 : proc


useless_sh_t_function__get_GS_a_string_and_beep PROC
    ; parameter = CHAR** for a string pointer
    ; return = value of GS register selector

    mov     eax, [esp + 4]
    mov     [eax], OFFSET str_from

    push    dword ptr [beep_dur]
    push    dword ptr [beep_freq]
    call    Beep@8

    mov     eax, gs
    ret
useless_sh_t_function__get_GS_a_string_and_beep ENDP


ENDIF

END

main.cpp文件:

#include "stdafx.h"
#include <Windows.h>

extern "C" 
    size_t useless_sh_t_function__get_GS_a_string_and_beep(const CHAR** ppString);
;

int main()

    const char* pString = NULL;
    size_t nGS = useless_sh_t_function__get_GS_a_string_and_beep(&pString);
    printf("gs=0x%Ix, %s\n", nGS, pString);

    return 0;

【讨论】:

Microsoft 解决方案可以工作,但您必须修改您的 masm (ml64) 构建参数以传递 -DX64 命令行选项。 我假设 IFDEF RAX 有效,因为解析器使用关键字、宏和寄存器名称(可能还有符号/标签)的统一表。但它不是 32 位的寄存器名称,因此除非您将其定义为符号(在 32 位代码中可以)或宏,否则它只是另一个未定义的标识符。无论如何,这就是我可以从它确实有效的事实中得出的结论。如果它得到官方支持,那么该实现细节就可以保证继续工作。【参考方案2】:

很高兴您找到了处理用例的方法。

但是,如果您有更多的 asm 文件,或者仅在某些构建类型中需要它们,您还可以更改每个单独文件的设置,以用于与项目默认值不同的部分。

只需右键单击文件名即可访问其各个属性。

要让 asm 文件仅包含在 x64 构建中,您可以使用以下设置:

然后将其从 32 位构建中排除:

这些设置适用于所有文件类型,不仅适用于 .asm 文件。

【讨论】:

以上是关于如何将 x86 和 x64 asm 文件包含到单个 Visual Studio 项目中?的主要内容,如果未能解决你的问题,请参考以下文章

内联 asm 到 x64 - 理解

如何获取基堆栈指针的地址

如何获取基本堆栈指针的地址

x64 asm如何将函数指针设置为_cdecl C函数并调用它?

如何知道在构建中使用哪个 cpu(x86 x64 或 AnyCpu)?

如何从WOW64进程注入x86 DLL到x64进程