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

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

 

1.      问题描述

 

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

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

[html] view plaincopy

  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. 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'

 上面的几行所示的并非什么惊天动地的大错误,意思非常简单:当前架构不支持__asm关键字。

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

 

 2.      使用.asm文件

 

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

 

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

 

 

 

[cpp] view plaincopy

  1. FunName PROC  
  2.     // 此处包含汇编指令   
  3. FunName ENDP  
 
  1. FunName PROC

  2. // 此处包含汇编指令

  3. FunName ENDP

这里面有两个关键字分别表示函数的开始和结束:PROC和ENDP。我们看一个简单的包含中断指令的函数应当怎么写。我们假设一个.asm文件中仅有一个函数实现,下面是一个.asm汇编源文件的全部内容:

[cpp] view plaincopy

  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  // 文件结束  
 
  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 // 文件结束

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

 

 3.      X86与X64的兼容

 

现在澄清一下状况:

 

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

 

 

 

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

[cpp] view plaincopy

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

  2. // 这是x64平台

  3. #else

  4. // 这是x86平台

  5. #endif

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

 

[cpp] view plaincopy

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

  2.  
  3. #ifdef _AMD64_

  4. // 这是x64平台

  5. #else

  6. // 这是x86平台

  7. #endif

如果我们只想在程序中添加一个软中断指令,则完整的实现示例如下:

 

[cpp] view plaincopy

  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. }  
 
  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. }

 

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等其他编程语言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/380983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多叉树的前序遍历_二叉树的非递归遍历的思考

封面图来自wikipedia1 简介二叉树的深度优先遍历&#xff08;前序遍历、中序遍历、后序遍历&#xff09;是一个比较基本的操作。如果使用递归的做法&#xff0c;很容易写出相应的程序&#xff1b;而如果使用非递归的做法&#xff0c;虽然也能写出相应的代码&#xff0c;但是由于…

delphi中Label中文显示不全的问题解决办法

有时候把Label的AutoSize属性设置为True&#xff0c;当窗体显示的时候&#xff0c;Label中的内容可能会显示不完全&#xff0c;只能把AutoSize设置为False&#xff0c; 把Label调整成能显示出内容的大小。还有一种更简单的解决方法。把Form的Font属性进行如下设置&#xff1a;字…

焊接空间臂_焊接烟尘净化器设备哪种好

焊接烟尘净化器设备采用滤筒除尘器&#xff0c;焊接烟尘净化器用于焊接、切割、打磨等工序中产生烟尘和粉尘的净化以及对稀有金属、贵重物料的回收等&#xff0c;可净化大量悬浮在空气中对人体有害的细小金属颗粒。具有净化效率高、噪声低、使用灵活、占地面积小等特点。 适用于…

【摘录】C语言中利用 strtok函数进行字符串分割

C语言不像Java,Php之类的高级语言&#xff0c;对象中直接封装了字符串的处理函数。C语言中进行普通的字符串处理也经常会让我们焦头烂额……不过好在C语言 中还是提供了像strtok这样功能强大的字符串处理函数&#xff0c;可以帮我们实现部分需要的功能。下面我们介绍一下strtok…

woe分析_Python数据分析—apply函数

在对海量数据进行分析的过程中&#xff0c;我们可能要把文本型的数据处理成数值型的数据&#xff0c;方便放到模型中进行使用。也可能需要把数值型的数据分段进行处理&#xff0c;比如变量的woe化。而这些操作都可以借助python中的apply函数进行处理。今天介绍数据分析的第四课…

树莓派3b安装ubuntu mate(在有显示器前提下看)

树莓派安装&#xff1a; 准备材料 tf卡&#xff08;建议16G&#xff09;数据线树莓派win32烧录软件 &#xff0c;百度云链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/16Dq2XrqeJScUO_DxHRIz_g 提取码&#xff1a;kfkbubtuntu mate系统&#xff08;建议不要下ubu…

打包mac应用_把网址链接打包成电脑软件的制作方法

前言&#xff1a;学习一下把web页面打包成运行在桌面的应用, 并支持win / mac / linux 等平台, 记一下使用过程, 有需要的大(同)佬(学)可以玩玩~第一步 – 安装 node.jsnode.js下载地址&#xff1a;http://nodejs.cn/download/下载 Windows 安装包 (.msi) 和 Windows 二进制文件…

对多个WCF服务进行统一的连接测试

先看下面的代码&#xff1a;代码代码 BasicHttpBinding myBinding newBasicHttpBinding(); EndpointAddress myEndpoint newEndpointAddress(endAddress); ChannelFactory<IMyService>myChannelFactory newChannelFactory<IMyService>(myBinding,my…

宜昌宝塔河项目_宜昌城区首个垃圾分类定时定点投放点启用 厨余垃圾破袋投放...

伍家岗区宝联社区黄龙小区的垃圾分类定时定点投放点启用。(市环境卫生管理处供图)(记者郑璐、通讯员陈赞)1月1日&#xff0c;宜昌城区首个垃圾分类定时定点投放点在伍家岗区宝塔河街办宝联社区黄龙小区正式启用。该投放点每天开放5小时&#xff0c;上午7&#xff1a;00-9:30&am…

装配图位置偏转怎么调整_物理微课|匀变速直线运动、电容器动态分析及磁偏转技巧、方法、模型...

匀变速直线运动三大推论是什么&#xff1f;如何利用它们快速解题&#xff1f;电容器动态分析的重点是什么&#xff1f;磁偏转问题有什么严谨好用的技巧和方法&#xff1f;物理侯老师为您详细解答以上问题。高一匀变速直线运动三大推论 匀变速直线运动是我们高中学的第一个变速…

Cooki模拟登陆(人人网)

我们在爬取网上一些数据时&#xff0c;必须登陆才能爬取到数据&#xff0c;这是我们就需要Cookie了&#xff0c;Cookie简单说就是服务器返回给我们的一些数据&#xff0c;保存到客户端&#xff0c;下次登陆时&#xff0c;服务器会识别这些数据&#xff0c;可以返回我们上次的数…

基本图形怎么改字体_PPT做得慢怎么办?掌握这6个技巧,你也能快速做出精美的PPT...

相信很多人做PPT的速度都比较慢&#xff0c;从新建一个空白PPT开始&#xff0c;再到排版设计&#xff0c;需要耗费大量的时间&#xff0c;下面就来教你这6个技巧&#xff0c;你也能快速做出精美的PPT。01.一键禁止动画最近&#xff0c;有很多小伙伴向我求助&#xff0c;问我怎样…

三菱880彩铅和uni的区别_孟祥雷丨清华美院毕业,彩铅界的“冷军”(附彩铅教程哦!)...

今天要分享的是妥妥的一个高冷帅气、又有才华的艺术家&#xff0c;毕业于清华大学美术学院。有20多年的绘画经验&#xff0c;设计、绘画等艺术多面手&#xff0c;彩铅是他最出名的作品之一。人物篇(逆光)(麻花辫)用彩铅画肖像人物的人很多&#xff0c;但能把人物塑造得维妙维俏…

substring()分解字符串

substring解决了如何在指定位置将一个字符串划分为子串 单参数形式&#xff1a;返回从起始位置到结尾之间的子串**&#xff08;起始索引从0开始&#xff09;** public class SubStringReview {public static void main(String[] args) {String s "Java is great";…

11g oracle xe启动_详解Oracle等待事件的分类、发现及优化

一、等待事件由来大家可能有些奇怪&#xff0c;为什么说等待事件&#xff0c;先谈到了指标体系。其实&#xff0c;正是因为指标体系的发展&#xff0c;才导致等待事件的引入。总结一下&#xff0c;Oracle的指标体系&#xff0c;大致经历了下面三个阶段&#xff1a;以命中率为主…

StringTokenizer将一个字符串分解为单词或者标记

原理&#xff1a;StringTokenizer方法实现了Iterator的设计模式&#xff0c;也直接实现了枚举接口&#xff0c;通常情况下StringTotkenizer对象根据欧洲语言的单词分割将对字符串分解为若干单词&#xff0c;例如&#xff1a; public class StringTokenizerReview {public stat…

hystrix 单独使用_Hystrix学习

学习主题&#xff1a;Hystrix解决灾难性雪崩效应-服务熔断-服务熔断处理熔断参数circuitBreaker.enabled的作用是什么&#xff1f;熔断参数circuitBreaker.requestVolumeThreshold的作用是什么&#xff1f;熔断参数circuitBreaker.sleepWindowInMiliseconds的作用是什么&#x…

WebClient与WebRequest差异

WebRequst的使用 WebClient和HttpWebRequst是用来获取数据的2种方式&#xff0c;在我的这篇数据访问(2)中主要是讲的WebClient的使用&#xff0c;一般而言&#xff0c;WebClient更倾向于“按需下载”&#xff0c;事实上掌握它也是相对容易的&#xff0c;而HttpWebRequst则允许你…

连接字符串

方式一&#xff1a;可以使用运算符**“”**来连接字符串 public class StringBufferReview {/*** 方式一&#xff1a;使用连接* param args*/public static void main(String[] args) {String s1 "hello";String s2 "Java";String s3 s1s2;System.out.…

的使用_面部精华使用方法和使用步骤;

核心提示&#xff1a;精华液&#xff0c;是护肤品中之极品&#xff0c;成分精致、功效强大、效果显著&#xff0c;始终保持着它拥有的高贵和神秘。精华液中的基质是水&#xff0c;含有硅树脂&#xff0c;有利于渗透进皮肤和推开&#xff0c;其它添加成分&#xff0c;则带有治疗…