如何将 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,我解决了。必须将x64
和x86
代码放在一个.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 项目中?的主要内容,如果未能解决你的问题,请参考以下文章
x64 asm如何将函数指针设置为_cdecl C函数并调用它?