注意下面第一个方法用到的配置文件只能编译win32格式的汇编,要是有其他需求自己改配置文件
@1:
下载nasm后安装,在环境变量path中添加其安装目录,下载地址http://www.nasm.us/
将下载的三个配置文件放到C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\BuildCustomizations文件夹下,ok。下载地址http://download.****.net/detail/x356982611/9504205
@2:
下面就说下怎么在vs工程中使用:
工程目录右击->"工程依赖项"->"生成自定义",然后勾选nasm这一项
在添加的.asm文件上右击打开属性
这样就可以了,F7编译 -------》通过
另一个要注意的点是,如果是c++工程,一定要用extern “c” 去导入函数
参考文献 http://www.codeproject.com/Articles/410776/Integrating-a-compiler-assembler-in-VS-Using-NASM
————————————————
原文链接:https://blog.****.net/x356982611/article/details/51260841
参考了以下两个博客文章
http://blog.****.net/x356982611/article/details/51260841
http://www.cnblogs.com/antoniozhou/archive/2008/10/23/1318287.html
首先到CodeProject下载NASM的VS配置文件
https://www.codeproject.com/Articles/410776/Integrating-a-compiler-assembler-in-VS-Using-NASM
解压3个配置文件到
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\BuildCustomizations
也就是和masm的配置文件相同的位置
然后把NASM加入到系统环境变量
D:\nasm-2.13.01
新建一个控制台空工程,同之前MASM的一样,只不过这次选NASM
http://www.cnblogs.com/kileyi/p/7257852.html
建立1个cpp和1个asm文件
cpp01.cpp
- #include <iostream>
- extern "C" void nasm_function(void);
- void main()
- {
- nasm_function();
- system("pause");
- }
asm01.asm
- segment .text
- global _nasm_function
- _nasm_function:
- mov eax, 1234h
- ret
asm文件上,鼠标右键属性设置
需要注意的一点是,cpp和asm文件要放到NASMTest.vcxproj与.vcproj相同的目录下才能编译,不像MASM可以放在任意目录下,只要把文件添加到
工程就可以编译,NASM的不行,似乎只能放到根目录下才有效,原因不明,说不定可以设置,但是我没找到。
编译应该就能通过了。
有趣的是MASM可以在ASM汇编代码上下断点,而NASM的却不行。不太清楚怎么回事,不过反正可以在cpp函数前下断点,也差不了太多。
在cpp中的nasm_function函数处下断点,单步就能在寄存器中看到eax变成1234了
接下来搞个纯ASM的测试
pure01.asm
- ;filename: sayhellon.asm
- ;cmd> nasm -fcoff -Xvc sayhellon.asm
- ;cmd> link sayhellon.obj
- extern [email protected] ;in user32.dll
- extern [email protected] ;in kernel32.dll
- global SayHello
- global _WinMain
- [SECTION .drectve info align=8]
- db " /subsystem:windows"
- db " /out:sayhellon.exe"
- db " /defaultlib:kernel32.lib"
- db " /defaultlib:user32.lib"
- db " /export:SayHello"
- db " /entry:WinMain"
- db " /merge:.rdata=.text",0
- [SECTION .text USE32 align=16]
- szTitle:
- db "SayHello",0
- szMsg:
- db "Hello World!", 0
- SayHello:
- push 0 ;uType
- push dword szTitle ;lpCaption
- push dword szMsg ;lpText
- push 0 ;hWnd
- call [email protected]
- ret 16
- _WinMain:
- call SayHello
- push 0
- call [email protected]
编译应该就能通过,如果不行,手动设置下工程属性中的入口函数
============================================================
试了下x64不能编译,google了一阵发现是命令行参数的问题。要手动修改一下。
参考了以下例子
http://www.davidgrantham.com/nasm-console64/
64位命令行是类似这样调用的
nasm -f win64 ConsoleMessage64.asm -o ConsoleMessage64.obj
打开nasm.xml文件
搜索
Object File
字符串
把原fwin修改为
- <EnumValue
- Name="0"
- DisplayName="Object File 32"
- Switch="-f win32" />
- <EnumValue
- Name="1"
- DisplayName="Object File 64"
- Switch="-f win64" />
- <EnumValue
- Name="2"
- DisplayName="LINUX ELF FORMAT"
- Switch="-f elf" />
- <EnumValue
- Name="3"
- DisplayName="FLAT BINARY"
- Switch="-f bin" />
这样在asm文件上右键属性就可以选64位的参数来编译链接了
新的CPP中调用ASM方法如下
CPP部分不变
- #include <iostream>
- extern "C" void nasm_function(void);
- void main()
- {
- nasm_function();
- system("pause");
- }
ASM去掉前面的下划线就行了
- segment .text
- global nasm_function
- nasm_function:
- mov eax, 1234h
- ret
纯ASM如下
- [SECTION .drectve info align=8]
- db " /subsystem:console"
- db " /defaultlib:kernel32.lib"
- db " /defaultlib:user32.lib"
- db " /entry:main"
- db " /merge:.rdata=.text",0
- NULL EQU 0 ; Constants
- STD_OUTPUT_HANDLE EQU -11
- extern GetStdHandle ; Import external symbols
- extern WriteFile ; Windows API functions, not decorated
- extern ExitProcess
- global main ; Export symbols. The entry point
- section .data ; Initialized data segment
- Message db "Console Message 64", 0Dh, 0Ah, 0
- section .bss ; Uninitialized data segment
- alignb 8
- StandardHandle resq 1
- Written resq 1
- section .text ; Code segment
- main:
- and RSP, 0FFFFFFFFFFFFFFF0h ; Align the stack to a multiple of 16 bytes
- sub RSP, 32 ; 32 bytes of shadow space
- mov RCX, STD_OUTPUT_HANDLE
- call GetStdHandle
- mov qword [REL StandardHandle], RAX
- add RSP, 32 ; Remove the 32 bytes
- lea RSI, [REL Message]
- xor RDI, RDI
- .LengthLoop: ; Find the string length by searching for
- cmp byte [RSI + RDI], 0 ; the null terminator
- je .LengthDone
- add RDI, 1 ; Maximum length, prevents buffer overrun
- cmp RDI, 21 ; if there is no null terminator
- jne .LengthLoop
- .LengthDone:
- sub RSP, 32 + 8 + 8 ; Shadow space + 5th parameter + align stack
- ; to a multiple of 16 bytes
- mov RCX, qword [REL StandardHandle] ; 1st parameter
- lea RDX, [REL Message] ; 2nd parameter
- mov R8, RDI ; 3rd parameter
- lea R9, [REL Written] ; 4th parameter
- mov qword [RSP + 4 * 8], NULL ; 5th parameter
- call WriteFile ; Output can be redirect to a file using >
- add RSP, 48 ; Remove the 48 bytes
- xor RCX, RCX
- call ExitProcess