如何在Visual Studio项目中正确添加汇编代码

引用注明>>作者:张佩】【镜像www.yiiyee.cn/blog


1.      问题描述


在以往的编程经历中,本人最常使用的汇编代码是__asm {int 3}。它可以在我的代码中插入一个软件断点。如果没有一个连接到当前程序的调试器,则程序将停止在这行语句处无法继续执行。

上面的这种方式称为高级语言和汇编语言混编。当我用得正爽的时候,迎头碰到了64位平台这员猛将。它大手一张,挑出一张禁令通知单:在64位编程中,高级语言和汇编混编将再也不被支持!兄弟我不禁暗暗垂泪,因为当我固执而行的时候,若干恶心的编译错误赫然出现在我的面前:

  1. 1>test.cpp(98):error C4235: nonstandard extension used : '__asm' keyword not supported on thisarchitecture  
  2. 1>test.cpp(98):warning C4091: '' : ignored on left of 'int' when no variable is declared  
  3. 1>test.cpp(98):error C2143: syntax error : missing ';' before 'constant'  
1>test.cpp(98):error C4235: nonstandard extension used : '__asm' keyword not supported on thisarchitecture
1>test.cpp(98):warning C4091: '' : ignored on left of 'int' when no variable is declared
1>test.cpp(98):error C2143: syntax error : missing ';' before 'constant'
 上面的几行所示的并非什么惊天动地的大错误,意思非常简单:当前架构不支持__asm关键字。

既然被踢出了体制外,我们要想生存,就必须得另谋出路。


 2.      使用.asm文件


在64位平台上,我们遇到了翩然而至的.asm文件。在和她共舞的过程中,下面几个步骤必须遵守:

  1. 使用.asm文件包含汇编代码;.asm文件以关键字.CODE开始,关键字END结束
  2. 所有的汇编代码以函数方式组织在一起,一个典型的函数声明如下:

  1. FunName PROC  
  2.     // 此处包含汇编指令   
  3. FunName ENDP  
    FunName PROC
        // 此处包含汇编指令
    FunName ENDP
这里面有两个关键字分别表示函数的开始和结束:PROC和ENDP。我们看一个简单的包含中断指令的函数应当怎么写。我们假设一个.asm文件中仅有一个函数实现,下面是一个.asm汇编源文件的全部内容:
  1. //   
  2. // FILE: test.asm   
  3. // Description: 汇编源文件。当前文件仅在x64平台上编译,并不包含于x86平台,可通过设置源文件的属性实现。   
  4. //    
  5.   
  6. .CODE // 文件开始   
  7.   
  8. // 函数原型: void Int_3()   
  9. // 函数描述:函数实现中断指令,没有输入/输出参数,也没有返回值   
  10. Int_3 PROC  
  11.        int 3 // 中断指令   
  12.        ret   // 函数返回指令   
  13. Int_3 ENDP  
  14.   
  15. END  // 文件结束  
//
// FILE: test.asm
// Description: 汇编源文件。当前文件仅在x64平台上编译,并不包含于x86平台,可通过设置源文件的属性实现。
// 

.CODE // 文件开始

// 函数原型: void Int_3()
// 函数描述:函数实现中断指令,没有输入/输出参数,也没有返回值
Int_3 PROC
       int 3 // 中断指令
       ret   // 函数返回指令
Int_3 ENDP

END  // 文件结束

这个文件名为test.asm,文件包含名为Int_3的汇编函数,函数本身仅有两行代码:中断指令,返回指令。


 3.      X86与X64的兼容


现在澄清一下状况:

  1. 在X86平台上,我们应该使用混编方式执行汇编指令;
  2. 在X64平台上,我们应该使用.asm添加汇编函数。

为了让一段包含汇编指令的代码能够同时在X86和X64平台上编译通过,我们要有办法让编译器自己判断硬件平台。编译器提供了名为_M_AMD64的宏,只有在X64平台上,这个宏才是被定义的。所以我们可以用类似下面的语法进行编程:

  1. #ifdef _M_AMD64   
  2.   // 这是x64平台   
  3. #else   
  4.   // 这是x86平台   
  5. #endif  
#ifdef _M_AMD64
  // 这是x64平台
#else
  // 这是x86平台
#endif

实际上,大多数软件都不使用_M_AMD64宏,而是使用在windows.h中定义的另一个表达同一含义的名为_AMD64_的宏。所以上文的另一种写法如下:

  1. #include <windows.h>   
  2.   
  3. #ifdef _AMD64_   
  4.   // 这是x64平台   
  5. #else   
  6.   // 这是x86平台   
  7. #endif  
#include <windows.h>

#ifdef _AMD64_
  // 这是x64平台
#else
  // 这是x86平台
#endif
如果我们只想在程序中添加一个软中断指令,则完整的实现示例如下:

  1. #include <windows.h>   
  2.   
  3. extern "C" void Int_3();  
  4.   
  5. int _tmain()  
  6. {  
  7. #ifdef _AMD64_   
  8.    printf("这是x64平台,使用.asm汇编文件中定义的中断函数\n");  
  9.    Int_3();  
  10. #else   
  11.    printf("这是x86平台,使用__asm混编方式插入中断指令\n");  
  12.    __asm int 3;  
  13. #endif   
  14.   
  15.   return 0;  
  16. }  
#include <windows.h>

extern "C" void Int_3();

int _tmain()
{
#ifdef _AMD64_
   printf("这是x64平台,使用.asm汇编文件中定义的中断函数\n");
   Int_3();
#else
   printf("这是x86平台,使用__asm混编方式插入中断指令\n");
   __asm int 3;
#endif

  return 0;
}

 

4.      Visual Studio编译


将.asm文件添加到项目中后,如果不做任何操作即直接编译,我们会惊奇地发现.asm文件被编译器无视了(未被编译)。为弄清个中缘由,请在.asm文件上右击并选择属性,在弹出的属性对话框中,你是否看到如下设置?

 

由于这个文件的"项类型"被默认设置为“不参与生成”,所以在编译的时候,编译器就不会带上它。不晓得这一点在新的Visual Studio里面会不会有改正。这时候各位也不要慌了手脚,Visual Studio看上去对.asm这个灰头土脸的家伙有点不客气,觉得它好面生,所以有什么活动都不愿意带上它。没有关系,让我们想办法来让它们熟悉起来吧。

  1. 首先,确保你当前的平台是x64平台。切记不要对x86平台下的.asm文件做任何修改,因为.asm文件在x86平台上是无法编译的(目前为止,据我所知)。
  2. 其次,请确保“从生成中排除”项的值是“否”。
  3. 第三,让我们点击"项类型"的下标箭头,会看到如下所示的众多可选项:


第一个选项“C/C++编译器”,是用来编译.C/.cpp文件的,如果点击一个.cpp文件看到的就会是它被默认选中。但汇编文件不能使用C/C++编译器,读者不信可以试一试,一定有乱七八糟的编译错误秀出来。正确的做法是选择“自定义生成工具”项,点击“应用”后左列将出现名为“自定义生成工具”的子项,如下图所示:


在右列面板中,我们有一些设置需要添加进去,上图中已由红色方框标出。

  1. 首先在“命令行”项中,我们应当输入指定的编译语句:ml64 /c %(fileName).asm。这条命令的意思是使用ml64.exe.asm文件进行编译,这里面的宏%(FileName)用来代指当前文件(test.asm)。命令行中的ml64乃指Ml64.exe编译程序,它在Visual Studio的默认执行路径中。把这条执行语句直接放在控制台里面执行,一样是能够通过的。
  2. 在“输出”项中,我们设定输出文件为:%(fileName).obj。即编译后所生成的中间文件,而宏%(filename)含义如上。

确定并退出属性对话框后,再次尝试,会发现x86和x64平台下的编译都能够成功了。我们通过上述方法,成功地在C/C++项目中添加汇编指令,并能够在32/64位平台上顺利编译通过。虽然我还没有亲自试验,但相信相同的方法也能够使用于.net等其他编程语言。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值