在 VC++ 中使用 内联汇编

 

From:https://blog.csdn.net/root19881111/article/details/8450266

VC++内联汇编(MSDN相关内容完整翻译):http://www.cppblog.com/xingkongyun/archive/2008/12/21/70003.html

调 call 和 偷功能 时,VC中内联汇编容易产生的错误:https://www.52pojie.cn/thread-977599-1-1.html

 

内联汇编 视频教程:https://edu.51cto.com/center/course/lesson/index?id=90306

在VC++中使用内联汇编:http://blog.sina.com.cn/s/blog_856d6d130102uzje.html

 

C++ 参数传递方式和压栈

 

 

一、内联汇编的优缺点

 

  因为在Visual C++中使用内联汇编不需要额外的编译器和联接器,且可以处理Visual C++中不能处理的一些事情,而且可以使用在C/C++中的变量,所以非常方便。内联汇编主要用于如下场合: 

  •   1. 使用汇编语言写函数;
  •   2. 对速度要求非常高的代码;
  •   3. 设备驱动程序中直接访问硬件;
  •   4. "Naked" Call 的初始化和结束代码。//(."Naked",理解了意思,但是不知道怎么翻译^_^,大概就是不需要C/C++的编译器(自作聪明)生成的函数初始化和收尾代码,请参看MSDN的"Naked <I>function</I>s"的说明)

内联汇编代码不易于移植,如果你的程序打算在不同类型的机器(比如x86和Alpha)上运行,应当尽量避免使用内联汇编。这时候你可以使用MASM,因为MASM支持更方便的的宏指令和数据指示符。

 

 

二、内联汇编关键字

 

  在Visual C++使用内联汇编用到的是__asm关键字,这个关键字有两种使用方法: 

  • 1.简单__asm块 ( 推荐这种方法写 内联汇编代码
__asm 
{ MOV   AL, 2 MOV   DX, 0xD007 OUT   AL, DX 
}
  • 2.在每条汇编指令之前加__asm关键字 
__asm MOV   AL, 2 
__asm MOV   DX, 0xD007 
__asm OUT   AL, DX 

因为__asm关键字是语句分隔符,因此你可以把汇编指令放在同一行: 

__asm MOV AL, 2   __asm MOV DX, 0XD007   __asm OUT AL, DX 

显然,第一种方法和 C/C++ 的风格很一致,并且有很多其它优点,因此推荐使用第一种方法。 

不象在C/C++中的 "{}" ,__asm块的 "{}" 不会影响 C/C++ 变量的作用范围。同时,__asm块可以嵌套,嵌套也不会影响变量的作用范围。

 

 

三、在 __asm块中使用汇编语言

 

  • 1.内联汇编指令集 :内联汇编完全支持的Intel 486指令集,允许使用MMX指令。不支持的指令可以使用_EMIT伪指令定义(_EMIT伪指令说明见下文)。 
  • 2.MASM表达式 :内联汇编可以使用MASM中的表达式。比如: MOV EAX, 1。 
  • 3.数据指示符和操作符 :虽然__asm块中允许使用C/C++的数据类型和对象,但它不能用MASM指示符和操作符定义数据对象。这里特别指出,__asm块中不允许MASM中 的定义指示符: DB、DW、DD、DQ、DT和DF,也不允许DUP和THIS操作符。MASM结构和记录也不再有效,内联汇编不接受STRUC、RECORD、 WIDTH或者MASK。 
  • 4.EVEN和ALIGN指示符 :尽管内联汇编不支持大多数MASM指示符,但它支持EVEN和ALIGN,当需要的时候,这些指示符在汇编代码里面加入NOP(空操作)指令使标号对齐到特定边界。这样可以使某些处理器取指令时具有更高的效率。 
  • 5.MASM宏指示符 :内联汇编不是宏汇编,不能使用MASM宏指示符(MACRO、REPT、IRC、IRP和ENDM)和宏操作符(<>、!、&、%和.TYPE)。 
  • 6.段说明 :必须使用寄存器来说明段,跨越段必须显式地说明,如ES:[BX]。 
  • 7.类型和变量大小 :我们可以使用LENGTH来取得C/C++中的数组中的元素个数,如果不是一个数组,则结果为一。使用SIZE来取得C/C++中变量的大小,一个变量的 大小是LENGTH和TYPE的乘积。TYPE用来取得一个变量的大小,如果是一个数组,它得到的一个数组中的单个元素的大小。 
  • 8.注释 :可以使用C/C++的注释,但推荐用ASM的注释,即";"号。 
  • 9._EMIT伪指令 :_EMIT伪指令相当于MASM中的DB,但一次只能定义一个字节,比如: 
    __asm
    { JMP   _CodeOfAsm _EMIT   0x00   ; 定义混合在代码段的数据 _EMIT   0x01 _CodeOfAsm: ; 这里是代码 _EMIT   0x90   ; NOP指令 
    }

     

 

四、在 __asm块中使用 C/C++ 语言元素

 

C/C++与汇编可以混合使用,在内联汇编可以使用 C/C++ 的变量和很多其它C/C++的元素。

在__asm块中可以使用以下C/C++元素: 

  • 1.符号,包括标号、变量和函数名; 
  • 2.常量,包括符号常量和枚举型(enum)成员; 
  • 3.宏定义和预处理指示符; 
  • 4.注释,包括"/**/"和"//"; 
  • 5.类型名,包括所有MASM中合法的类型 
  • 6.typedef 名称, 像PTR、TYPE、特定的结构成员或枚举成员这样的通用操作符。 

在 __asm块中,可以使用 C/C++ 或 ASM 的基数计数法(比如: 0x100和100H是相等的)。 
__asm块中不能使用像 << 一类的C/C++操作符。C/C++和MASM通用的操作符,比如 "*" 和 "[]" 操作符,都被认为是汇编语言的操作符。举个例子: 

示例 1:

#include <iostream>
using namespace std;int main()
{int array[10] = {0};        // 定义 int 类型 数组,全部初始化为0,每个大小都是 4 字节__asm {mov eax, 0x10        ; 寄存器 eax 存储 0x10, 十进制 为 16mov array[36], eax   ; 存储 EBX寄存器中的值 到 array + 36 (not scaled)	}cout << array[9] << endl;   // 汇编 __asm mov array[36], eax 是把 eax 内容存到 array 第9个位置//cout << "Hello World!\n";//cout << 7% -3 << endl;
}

示例 2:

#include <iostream>
using namespace std;int main()
{int array[10] = {0};        // 定义 int 类型 数组,全部初始化为0,每个大小都是 4 字节__asm mov eax, 0x10          ; 寄存器 eax 存储 0x10,十进制 为 16__asm mov array[36], eax     ; 存储 EBX寄存器中的值 到 array + 36 (not scaled)//array [6] = 0;             /* 存储 0 at array+12 (scaled) */cout << array[9] << endl;   // 汇编 __asm mov array[36], eax 是把 eax 内容存到 array 第9个位置//cout << "Hello World!\n";//cout << 7% -3 << endl;
}

* 小技巧: 内联汇编中,你可以使用 TYPE 操作符使作其与C一致。比如,下面两条语句是一样的: 

#include <iostream>
using namespace std;int main()
{int array[10] = {0};      __asm {mov eax, 0x10mov array[6 * TYPE int], eax	}cout << array[6] << endl;   
}

内联汇编能通过变两名直接引用C/C++的变量。__asm块中可以引用任何符号,包括变量名。 

如果C/C++中的类、结构或者枚举成员具有唯一的名称,如果在"."操作符之前不指定变量或者typedef名称,则__asm块中只能引用成员名称。 然而,如果成员不是唯一的,你必须在"."操作符之前加上变量名或typedef名称。例如,下面的两个结构都具有same_name 这个成员变量: 

struct first_type 
{ char *weasel; int same_name; 
}; struct second_type 
{ int wonton; long same_name; 
}; 

如果按下面声明变量: 

struct first_type hal; 
struct second_type oat; 

那么,所有引用 same_name 成员的地方都必须使用变量名,因为 same_name 不是唯一的。另外,上面的 weasel 变量具有唯一的名称,你可以仅仅使用它的成员名称来引用它: 

__asm 
{ MOV EBX, OFFSET hal MOV ECX, [EBX]hal.same_name ; 必须使用 'hal'MOV ESI, [EBX].weasel       ; 可以省略 'hal'
}

注意,省略了变量名仅仅是为了写代码的方便,生成的汇编指令的还是一样的。 可以不受限制地访问C++成员变量,但是不能调用C++的成员函数。

 

 

五、寄存器使用

 

  一般来说,在__asm块开始的时候,寄存器是空的,不能在两个__asm之间保存寄存器的值。(这是MSDN上说的,我在实际使用时发现,好像并不是这样。不过它是说"一般",我是特殊:)) 


如果一个函数被声明成了__fastcall,则其参数将放在寄存器中,这将给寄存器的管理带来问题。所以,如果要将一个函数声明成 __fastcall,必须保存ECX寄存器。为了避免以上的冲突,在声明为__fastcall的函数中不要有__asm块。如果用了/Gr编译选项 (它全局的变成__fastcall),将每个函数声明成__cdecl或者__stdcall,这个属性告诉编译器用传统的C方法。 


如果使用EAX、EBX、ECX、EDX、ESI和EDI寄存器,你不需要保存它;但如果你用到了DS、 SS、SP、BP和标志寄存器,那就应该PUSH保存这些寄存器。 


如果程序中改变了用于STD和CLD的方向标志,你必须将其恢复到原来的值。

 

 

六、转跳

 

可以在 C 里面使用 goto 调到 __asm 块中的标号处,也可以在 __asm 块中转跳到 __asm 块里面和外面的标号处。

__asm 块内的标号 不区分大小写  ( 指令、指示符等也是不区分大小写的 ) 。例: 

void func() 
{ goto C_Dest;   /* 合法 */ goto c_dest;   /* 错误 */ goto A_Dest;   /* 合法 */ goto a_dest;   /* 合法 */ __asm { JMP C_Dest ; 合法JMP c_dest ; MSDN上说合法,但是我在VS.NET中编译,认为这样不合法JMP A_Dest ; 合法JMP a_dest ; 合法a_dest:    ; __asm 标号 }C_Dest:   /* C的标号 */ return; 
} 

不要使用函数名称当作标号,否则将使其跳到函数执行而不是标号处。如下所示: 

JNE exit  ; 错误: 使用函数名作为标号 
; 下面是更多的ASM代码 
nop
nop
nop
exit:
nop 
; 下面是更多的ASM代码 

美元符号 $ 用于指定当前位置,如下所用,常用于条件跳转: 

JNE $+5 ; 下面这条指令的长度是5个字节 
JMP farlabel 
;$+5,跳到了这里 
. 
. 
. 
farlabel: 

 

 

七、调用函数

 

  内联汇编调用C/C++函数必须自己清除堆栈,下面是一个调用C/C++函数例子: 

C 代码使用的是 __cdecl 约定,需要调用者手动平衡堆栈,所以下面的代码的代码有 3个 pop ebx,也可以 add esp, 12

#include <stdio.h> char szformat[] = "%s %s\n"; 
char szHello[] = "Hello"; 
char szWorld[] = " world"; void main() 
{ __asm { MOV   EAX, OFFSET szWorld PUSH   EAX MOV   EAX, OFFSET szHello PUSH   EAX MOV   EAX, OFFSET szformat PUSH   EAX CALL   printf //内联汇编调用C函数必须自己清除堆栈 //用不使用的EBX寄存器清除堆栈,或ADD ESP, 12 POP   EBX POP   EBX POP   EBX } 
} 

 

注意:函数参数是从右向左压栈。 不能够访问C++中的类成员函数,但是可以访问 extern "C" 函数。 如果调用 Windows API 函数,则不需要自己清除堆栈,因为API的返回指令是 RET n,会自动清除堆栈 。比如下面的例子: 

#include <windows.h> char szAppName[] = "API Test";void main()
{char szHello[] = "Hello, world!";__asm{PUSH   MB_OK OR MB_ICONINFORMATIONPUSH   OFFSET szAppName; 全局变量用OFFSETLEA   EAX, szHello; 局部变量用LEA; 或者; LEA   EAX, [szHello]; 局部变量用LEA; lea是将一个地址装入寄存中,mov是将值放入寄存器中,; [] 是用来取地址内容(中间包含的值是一个地址),相当C语言中的* pPUSH   EAXPUSH   0CALL   DWORD PTR[MessageBoxA]; 注意这里,我费了好大周折才发现不是CALL MessageBoxA}
}

或者:

#include <windows.h>TCHAR appname[] = TEXT("API Test");void main()
{TCHAR tszHello[] = TEXT("hello,word");__asm{PUSH MB_OK OR MB_ICONINFORMATIONPUSH OFFSET appnameLEA  EAX, tszHelloPUSH EAXPUSH 0CALL DWORD PTR[MessageBoxW]//这个地方; 注意这里不是 MessageBoxW, 而是重定位过的函数地址}
}

在汇编查找代码小技巧:加花指令

_asm
{//查找命令序列mov edi, edimov edi, edi
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

OFD 版式技术解析系列(一):开篇

在版式电子文件领域&#xff0c;大家比较熟悉的就是 PDF(Portable Document Format)格式&#xff0c;该格式由 Adobe 公司在 1992 年发布&#xff0c;迄今已经有 28 个年头&#xff0c;2008 年 7 月 1 日&#xff0c;IS 组织正式发布 PDF 的国际标准&#xff0c;PDF 成为了独立…

无人驾驶急需解决:规划控制和传感器价格高两大问题

来源&#xff1a;AI科技大本营 作者 &#xff1a;Mavis2017 年百度 AI 开发者大会上&#xff0c;现场视频连线了正乘坐无人驾驶汽车行驶在五环上朝会场赶来的李彦宏&#xff0c;他坐在副驾驶上解说&#xff0c;身边司机的双手并没有触碰方向盘&#xff0c;也正是因为这句话&am…

CString 与 LPCWSTR、LPSTR、char*、LPWSTR 等类型的转换

From&#xff1a;https://www.cnblogs.com/leanee/articles/2940088.html char [] 到 LPWSTR转换的一个具体应用&#xff1a;http://www.cppblog.com/lateCpp/articles/153358.html CString详细讲解&#xff1a;https://blog.csdn.net/qq_41786318/article/details/81989217 …

ofd电子文档内容分析工具(分析文档、签章和证书)

前言 ofd是国家文档标准&#xff0c;其对标的文档格式是pdf。ofd文档是容器格式文件&#xff0c;ofd其实就是压缩包。将ofd文件后缀改为.zip&#xff0c;解压后可看到文件包含的内容。 加入QQ交流群&#xff1a;618168615。获取下载程序。 ofd文件解压后&#xff0c;可以看到…

关于信任

[caption id"attachment_349" align"alignnone" width"374" caption"Trust is the most important thing to the team!"][/caption] 偶然间看到一张截图&#xff0c;是杭州小马哥不知何年何月何地做的show&#xff0c;这句话从他嘴里讲…

ES的安装和RestClient的操作

目录 初识elasticsearch 什么是elasticsearch elasticsearch的发展 Lucene的优缺点 elasticsearch的优势 倒排索引 es与mysql的概念对比 文档 索引 概念对比 架构 安装es 安装kibana 安装ik分词器 分词器 安装ik分词器 ik分词器的拓展和停用词典 操作索引库…

深度 | 智慧•城市,基于国际视野下的思考

来源&#xff1a;智慧城市决策参考智慧城市的兴起&#xff0c;得益于ICT技术的迅猛发展。经过这些年国内外诸多城市的探索和实践&#xff0c;智慧城市已经从最初的营销概念&#xff0c;逐渐发展成为一种支持城市发展的新理念。然而在实际应用中&#xff0c;智慧城市的内涵仍然是…

__cdecl、__stdcall、__fastcall 与 __pascal 浅析

X86调用约定 calling convention&#xff1a;https://www.cnblogs.com/shangdawei/p/3323252.html__cdecl、__stdcall、__fastcall 与 __pascal 浅析&#xff1a;https://www.cnblogs.com/yenyuloong/p/9626658.html王爽 汇编语言第三版 第9章 转移指令的原理&#xff1a;https…

全文详解:「深度学习」如何协助处理医疗中的「数据难题」

原文来源&#xff1a;WordPress作者&#xff1a;Luke Oakden-Rayner「雷克世界」编译&#xff1a;嗯~是阿童木呀、KABUDA、EVA医疗数据很难处理。在医学成像中&#xff0c;数据存储&#xff08;档案&#xff09;是基于临床假设进行操作的。不幸的是&#xff0c;这意味着当你想提…

Android应用程序变量

Android应用程序开发中&#xff0c;有的时候我们在应用程序的任何一个地方都需要访问一个全局变量&#xff0c;也就是在任何一个Activity中都可以访问的变量。它不会因为Activity的生命周期结束而消失。要实现应用程序级的变量&#xff0c;我们可以通过Application这个类来实现…

百度谷歌等联合推出机器学习基准 加速AI软硬件发展

来源&#xff1a;中国新闻网5月2日&#xff0c;由包括百度、谷歌、斯坦福大学、哈佛大学在内的多家企业和高校联合发布了一套用于测量和提高机器学习软硬件性能的国际基准MLPerf。其巨大的学术和产业价值获业界肯定&#xff0c;被认为不仅将加速推进机器学习硬件软件相关技术创…

王爽 汇编语言第三版 第10章 call 和 ret 指令 以及 子程序设计

第10章 call 和 ret 指令 10.1 ret 和 reft 指令 call 和 ret 指令都是转移指令&#xff0c;他们都修改 IP&#xff0c;或同事修改 CS 和 IP 。他们经常被共同来实现子程序的设计。 10.2 call 指令 和 根据位移 转移的call指令 段间转移 的 call 指令 转移地址 在 寄存器 中 的…

org/apache/maven/cli/MavenCli : Unsupported major.minor version 51.0

一、错误现象&#xff1a; 当改变了jdk版本时&#xff0c;在编译java时&#xff0c;会遇到Unsupported major.minor version错误。 jdk版本和stanford parser对应关系 JDK版本和Java编译器内部的版本号 J2SE 8 52, J2SE 7 51, J2SE 6.0 50, J2SE 5.0 49, JDK 1.4 48, J…

ip, tcp, udp, icmp header

Figure 1. IPv4 header Figure 2. TCP header Figure 3. UDP header Figure 4. ICMP header reference:TCP/IP Reference转载于:https://www.cnblogs.com/lbsx/archive/2010/11/30/1891814.html

人民日报三问人工智能,给法律制度带来哪些挑战?

来源&#xff1a;亿欧网 作者&#xff1a;倪弋摘要&#xff1a;人工智能生成物是否具有知识产权&#xff1f;人工智能可以替代司法者吗&#xff1f;人工智能侵权责任如何认定&#xff1f;人工智能的出现会给现行的法律制度带来了不少挑战&#xff0c;只有在法律研究上未雨绸缪…

测试用例设计--判定表

一. 判定表 定义判定表通常由四部分组成&#xff0c;如上图&#xff1a; 条件桩 : 它列出决定一组条件的对象&#xff1b; 条件项: 它列出各种可能的条件组合&#xff1b; 动作桩: 它列出所有的操作; 动作项: 它列出在对应的条件组合下的动作. 应用的范围在多个条件决定多个动…

王爽 汇编语言第三版 第11章 标志寄存器

条件码&#xff1a; ① OF(Overflow Flag)溢出标志&#xff0c;溢出时为1&#xff0c;否则置0.标明一个溢出了的计算&#xff0c;如:结构和目标不匹配.② SF(Sign Flag)符号标志&#xff0c;结果为负时置1&#xff0c;否则置0.③ ZF(Zero Flag)零标志&#xff0c;运算结果为0时…

Gartner:预计2018年人工智能行业总价值达1.2万亿美元

来源&#xff1a;网络大数据市场研究公司Gartner周三发布最新研究报告称&#xff0c;人工智能行业的总价值将在2018年达到1.2万亿美元&#xff0c;比2017年增长70%。其中&#xff0c;创造商业价值最大的领域是客户体验解决方案。该公司还预计&#xff0c;到2022年的时候&#x…

JAVA将html[动态]页面转成图片

近日项目上接到一个任务&#xff0c;设计并编写住院病案首页页面&#xff0c;然后将其转换成图片显示给医生查看。 天哪&#xff0c;住院病案内容那么多&#xff0c;光编写这个页面就已经够呛了&#xff0c;转图片我也没弄过&#xff0c;于是百度了一下&#xff0c;花了两天时间…

王爽 汇编语言第三版 课程设计 1

From&#xff1a;https://www.cnblogs.com/Since-natural-ran/p/6938133.html 汇编语言-课程设计1: https://www.cnblogs.com/tsembrace/p/3267158.html 王爽课程设计1(汇编语言编写): https://www.imooc.com/article/18785 王爽《汇编语言》课程设计1: https://blog.csdn.net/…