vs2010怎么用内联汇编 call 参数调用call

1380人阅读
VC++ 内联汇编(4)
#include "stdafx.h"
int g_nC=10;
void UseParameter()
int a = 5,b=6,c;
xor edx,edx=0
add edx,edx +=a
add edx,edx +=b
add edx,g_nC使用全局变量
mov c,c=edx
printf("UseParameter : %d/n",c);
__stdcall int stdcall_sub(int a,int b)
return a-b;
void UseStdCall()
int nRet=0;
call stdcall_sub
mov nRet,eax
printf("UseStdCall : %d/n",nRet);
__cdecl int cdecl_sub(int a,int b)
return a-b;
void UseCdecl()
int nRet=0;
call cdecl_sub
add esp,8调用者维护栈平衡
mov nRet,eax
printf("UseCdecl : %d/n",nRet);
int main(int argc, char* argv[])
UseParameter();
UseStdCall();
UseCdecl();
//使用naked关键字,编译器将会以纯汇编编码函数
void __declspec(naked) MyNakedFunction()
// Naked functions must provide their own prolog.
MOV ESP, EBP
SUB ESP, __LOCAL_SIZE
// And we must provide epilog.
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:93985次
积分:1678
积分:1678
排名:第15230名
原创:70篇
评论:61条
(1)(1)(3)(2)(1)(1)(1)(1)(3)(4)(4)(4)(2)(2)(1)(4)(10)(1)(2)(2)(2)(3)(5)(3)(2)(1)(5)(3)下次自动登录
现在的位置:
& 综合 & 正文
关于内联汇编的几个技巧
关于内联汇编的几个技巧作者:
有时我们的需要一些很高的执行效率或者执行系统底层的功能模块,这些关键的部分我们可以采用内联汇编直接插入汇编指令来达到我们的要求,以下是几个技巧与大家共同探讨.
1. 内联汇编嵌入VC语句:
在VC中内联汇编非常方便,只需要按照如下格式__asm{
//汇编语句
请看如下示例
void CAlcmemDlg::OnButton3()
DWORD d=(m_size*)/sizeof(DWORD);
DWORD*p=(DWORD*)m_p;
m_pr.SetMin(0);
m_pr.SetMax((float)d);
m_pr.SetEnabled(TRUE);
if(NULL!=m_p){
mov edx,DWORD ptr p
mov [edx+eax],1
//随便写入数据,此处写入1
m_pr.SetValue((float)s);
请注意示例代码中两个__asm块中的pushad 和 popad 语句,pushad保存了寄存器环境,popad恢复了寄存器环境,使得m_pr.SetValue((float)s);语句对寄存器的影响被抵销,你还可以调用其他任何语句。但建议是尽量少打断内联汇编块,以减少运行时来回倒腾寄存器环境的时间。笔者的测试是,当删除m_pr.SetValue((float)s);并且合并两个__asm块,同时删除pushad,和popad后,速度明显提高。可见这种打断通常是得不偿失。通常要保存的寄存器环境还有Flags寄存器等,这些视具体情况而定。
2. 自由使用FPU,MMX等指令
void CAlcmemDlg::OnButton4()
float f_t=.132;
float f_s=0;
可以利用设置断点的方法来观察FPU寄存器的情况,通常你用VC写的代码,不会被编译为引用特殊指令集的代码,虽然微软号称编译器支持这些指令。所以你必须用内联汇编方法来调用这些指令以优化程序,充分利用资源。示例中的代码调用了FPU处理器的指令,使操作浮点数的能力被充分发挥。但当然你还可以调用3DNOW!指令,SSE,SSE2等指令,但笔者没有试过,如果你有什么新的发现,还望赐教,再此先谢了!总的来说内联汇编提高了速度,尤其是游戏编程,更应该努力使用内联汇编,把CPU充分榨干,但坏处就是有些低端的机器无法运行,兼容性差。同时微软又号称,编译器不会去优化你写的汇编码,他只是简单的翻译为等价的机器码,优化的事情交给你自己来完成,所以你不但得是C++高手,同时还得是汇编高手。不过据我所知这种人十有八九是黑客。我是不鼓励你成为那类人的,撰写此文只为抛砖引玉。
作者信息:姓名:孙原(于西安)E-mail:rock.QQ:
&&&&推荐文章:
【上篇】【下篇】&&& 使用内联汇编可以在 C/C++ 代码中嵌入汇编语言指令,而且不需要额外的汇编和连接步骤。在 Visual C++ 中,内联汇编是内置的编译器,因此不需要配置诸如 MASM 一类的独立汇编工具。这里,我们就以 Visual Studio .NET 2003 为背景,介绍在 Visual C++ 中使用内联汇的相关知识(如果是早期的版本,可能会有些许出入)。
&&& 内联汇编代码可以使用 C/C++ 变量和函数,因此它能非常容易地整合到 C/C++ 代码中。它能做一些对于单独使用 C/C++ 来说非常笨重或不可能完成的任务。
&&& 内联汇编的用途包括:
&&& * 使用汇编语言编写特定的函数;&&& * 编写对速度要求非常较高的代码;&&& * 在设备驱动程序中直接访问硬件;&&& * 编写 naked 函数的初始化和结束代码。
二、 关键字
&&& 使用内联汇编要用到 __asm 关键字,它可以出现在任何允许 C/C++ 语句出现的地方。我们来看一些例子:
&&& * 简单的 __asm 块:
&&&&&&& __asm&&&&&&& {&&&&&&&&&&& MOV AL, 2&&&&&&&&&&& MOV DX, 0xD007&&&&&&&&&&& OUT AL, DX&&&&&&& }
&&& * 在每条汇编指令之前加 __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 块的&{}&不会影响 C/C++ 变量的作用范围。同时,__asm 块可以嵌套,而且嵌套也不会影响变量的作用范围。
&&& 为了与低版本的 Visual C++ 兼容,_asm 和 __asm 具有相同的意义。另外,Visual C++ 支持标准 C++ 的 asm 关键字,但是它不会生成任何指令,它的作用仅限于使编译器不会出现编译错误。要使用内联汇编,必须使用 __asm 而不是 asm 关键字。
三、 汇编语言
&&& 内联汇编支持 Intel Pentium 4 和 AMD Athlon 的所有指令。更多其它处理器的指令可以通过 _EMIT 伪指令来创建(_EMIT 伪指令说明见下文)。
2. MASM 表达式
&&& 在内联汇编代码中,可以使用所有的 MASM 表达式(MASM 表达式是指用来计算一个数值或一个地址的操作符和操作数的组合)。
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)。
&&& 必须使用寄存器而不是名称来指明段(段名称&_TEXT&是无效的)。并且,段跨越必须显式地说明,如 ES:[EBX]。
7. 类型和变量大小
&&& 在内联汇编中,可以用 LENGTH、SIZE 和 TYPE 来获取 C/C++ 变量和类型的大? ?
&&& * LENGTH 操作符用来取得 C/C++ 中数组的元素个数(如果不是一个数组,则结果为 1)。&&& * SIZE 操作符可以获取 C/C++ 变量的大小(一个变量的大小是 LENGTH 和 TYPE 的乘积)。&&& * TYPE 操作符可以返回 C/C++ 类型和变量的大小(如果变量是一个数组,它得到的是数组中单个元素的大小)。
&&& 例如,程序中定义了一个 8 维的整数型变量:
&&&&&&& int iArray[8];
&&& 下面是 C 和汇编表达式中得到的 iArray 及其元素的相关值:
&&&&&&& __asm&&&&&&&&&&&&&&&&&& C&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Size
&&&&&&& LENGTH iArray&&&&&&&&&& sizeof(iArray)/sizeof(iArray[0])&&& 8&&&&&&& SIZE iArray&&&&&&&&&&&& sizeof(iArray)&&&&&&&&&&&&&&&&&&&&& 32&&&&&&& TYPE iArray&&&&&&&&&&&& sizeof(iArray[0])&&&&&&&&&&&&&&&&&& 4
&&& 内联汇编中可以使用汇编语言的注释,即&;&。例如:
&&&&&&& __asm MOV EAX, OFFSET pbB Load address of pbBuff
&&& 因为 C/C++ 宏将会展开到一个逻辑行中,为了避免在宏中使用汇编语言注释带来的混乱,内联汇编也允许使用 C/C++ 风格的注释。
9. _EMIT 伪指令
&&& _EMIT 伪指令相当于 MASM 中的 DB,但是 _EMIT 一次只能在当前代码段(.text 段)中定义一个字节。例如:
&&&&&&& __asm&&&&&&& {&&&&&&&&&&& JMP _CodeLabel
&&&&&&&&&&& _EMIT 0x00&&&&&&& ; 定义混合在代码段的数据&&&&&&&&&&& _EMIT 0x01
&&&&&&& _CodeLabel:&&&&&&&&&& ; 这里是代码&&&&&&&&&&& _EMIT 0x90&&&&&&& ; NOP指令&&&&&&& }
10. 寄存器使用
&&& 一般来说,不能假定某个寄存器在 __asm 块开始的时候有已知的值。寄存器的值将不能保证会从 __asm 块保留到另外一个 __asm 块中。
&&& 如果一个函数声明为 __fastcall 调用方式,则其参数将通过寄存器而不是堆栈来传递。这将会使 __asm 块产生问题,因为函数无法被告知哪个参数在哪个寄存器中。如果函数接收了 EAX 中的参数并立即储存一个值到 EAX 中的话,原来的参数将丢失掉。另外,在所有声明为 __fastcall 的函数中,ECX 寄存器是必须一直保留的。为了避免以上的冲突,包含 __asm 块的函数不要声明为 __fastcall 调用方式。
&&& * 提示:如果使用 EAX、EBX、ECX、EDX、ESI 和 EDI 寄存器,你不需要保存它。但如果你用到了 DS、SS、SP、BP 和标志寄存器,那就应该用 PUSH 保存这些寄存器。
&&& * 提示:如果程序中改变了用于 STD 和 CLD 的方向标志,必须将其恢复到原来的值。
四、 使用 C/C++ 元素
1. 可用的 C/C++ 元素
&&& C/C++ 与汇编语言可以混合使用,在内联汇编中可以使用 C/C++ 变量以及很多其它的 C/C++ 元素,包括:
&&& * 符号,包括标号、变量和函数名;&&& * 常量,包括符号常量和枚举型成员;&&& * 宏定义和预处理指示符;&&& * 注释,包括&/**/&和&//&;&&& * 类型名,包括所有 MASM 中合法的类型;&&& * typedef 名称,通常使用 PTR 和 TYPE 操作符,或者使用指定的的结构或枚举成员。
&&& 在内联汇编中,可以使用 C/C++ 或汇编语言的基数计数法。例如,0x100 和 100H 是相等的。
2. 操作符使用
&&& 内联汇编中不能使用诸如&&&&一类的 C/C++ 操作符。但是,C/C++ 和 MASM 共有的操作符(比如&*&和&[]&操作符),都被认为是汇编语言的操作符,是可以使用的。举个例子:
&&&&&&& int iArray[10];
&&&&&&& __asm MOV iArray[6], BX&&&&&&&&&&&& ; Store BX at iArray + 6 (Not scaled)&&&&&&& iArray[6] = 0;&&&&&&&&&&&&&&&&&&&&& // Store 0 at iArray+12 (Scaled)
&&& * 提示:在内联汇编中,可以使用 TYPE 操作符使其与 C/C++ 一致。比如,下面两条语句是一样的:
&&&&&&& __asm MOV iArray[6 * TYPE int], 0&& ; Store 0 at iArray + 12&&&&&&& iArray[6] = 0;&&&&&&&&&&&&&&&&&&&&& // Store 0 at iArray + 12
3. C/C++ 符号使用
&&& 在 __asm 块中可以引用所有在作用范围内的 C/C++ 符号,包括变量名称、函数名称和标号。但是不能访问 C++ 类的成员函数。
&&& 下面是在内联汇编中使用 C/C++ 符号的一些限制:
&&& * 每条汇编语句只能包含一个 C/C++ 符号。在一条汇编指令中,多个符号只能出现在 LENGTH、TYPE 或 SIZE 表达式中。&&& * 在 __asm 块中引用函数必须先声明。否则,编译器将不能区别 __asm 块中的函数名和标号。&&& * 在 __asm 块中不能使用对于 MASM 来说是保留字的 C/C++ 符号(不区分大小写)。MASM 保留字包含指令名称(如 PUSH)和寄存器名称(如 ESI)等。&&& * 在 __asm 块中不能识别结构和联合标签。
4. 访问 C/C++ 中的数据
&&& 内联汇编的一个非常大的方便之处是它可以使用名称来引用 C/C++ 变量。例如,如果 C/C++ 变量 iVar 在作用范围内:
&&&&&&& __asm MOV EAX, iV Stores the value of iVar in EAX
&&& 如果 C/C++ 中的类、结构或者枚举成员具有唯一的名称,则在 __asm 块中可以只通过成员名称来访问(省略&.&操作符之前的变量名或 typedef 名称)。然而,如果成员不是唯一的,你必须在&.&操作符之前加上变量名或 typedef 名称。例如,下面的两个结构都具有 SameName 这个成员变量:
&&&&&&& struct FIRST_TYPE&&&&&&& {&&&&&&&&&&& char *pszW&&&&&&&&&&& int SameN&&&&&&& };
&&&&&&& struct SECOND_TYPE&&&&&&& {&&&&&&&&&&& int iW&&&&&&&&&&& long SameN&&&&&&& };
&&& 如果按下面方式声明变量:
&&&&&&& struct FIRST_TYPE ftT&&&&&&& struct SECOND_TYPE stT
&&& 那么,所有引用 SameName 成员的地方都必须使用变量名,因为 SameName 不是唯一的。另外,由于上面的 pszWeasel 变量具有唯一的名称,你可以仅仅使用它的成员名称来引用它:
&&&&&&& __asm&&&&&&& {&&&&&&&&&&& MOV EBX, OFFSET ftTest&&&&&&&&&&& MOV ECX, [EBX]ftTest.SameName&&&&&& ; 必须使用&ftTest&&&&&&&&&&&& MOV ESI, [EBX]. pszWeasel&&&&&&&&&& ; 可以省略&ftTest&&&&&&&& }
&&& * 提示:省略变量名仅仅是为了书写代码方便,生成的汇编指令还是一样的。
5. 用内联汇编写函数
&&& 如果用内联汇编写函数的话,要传递参数和返回一个值都是非常容易的。看下面的例子,比较一下用独立汇编和内联汇编写的函数:
&&&&&&& ; PowerAsm.asm&&&&&&& ; Compute the power of an integer
&&&&&&& PUBLIC&&&&& GetPowerAsm&&&&&&& _TEXT&&&&&& SEGMENT WORD PUBLIC 'CODE'&&&&&&& GetPowerAsm PROC&&&&&&&&&&& PUSH&&& EBP&&&&&&&&&&&& ; Save EBP&&&&&&&&&&& MOV&&&& EBP, ESP&&&&&&& ; Move ESP into EBP so we can refer&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ; to arguments on the stack&&&&&&&&&&& MOV&&&& EAX, [EBP+4]&&& ; Get first argument&&&&&&&&&&& MOV&&&& ECX, [EBP+6]&&& ; Get second argument&&&&&&&&&&& SHL&&&& EAX, CL&&&&&&&& ; EAX = EAX * (2 ^ CL)&&&&&&&&&&& POP&&&& EBP&&&&&&&&&&&& ; Restore EBP&&&&&&&&&&& RET&&&&&&&&&&&&&&&&&&&& ; Return with sum in EAX&&&&&&& GetPowerAsm ENDP&&&&&&& _TEXT&&&&&& ENDS&&&&&&&&&&&&&&&&&&& END
&&& C/C++ 函数一般用堆栈来传递参数,所以上面的函数中需要通过堆栈位置来访问它的参数(在 MASM 或其它一些汇编工具中,也允许通过名称来访问堆栈参数和局部堆栈变量)。
&&& 下面的程序是使用内联汇编写的:
&&&&&&& // PowerC.c
&&&&&&& #include &Stdio.h&
&&&&&&& int GetPowerC(int iNum, int iPower);
&&&&&&& int main()&&&&&&& {&&&&&&&&&&& printf("3 times 2 to the power of 5 is %d\n", GetPowerC( 3, 5));&&&&&&& }
&&&&&&& int GetPowerC(int iNum, int iPower)&&&&&&& {&&&&&&&&&&& __asm&&&&&&&&&&& {&&&&&&&&&&&&&&& MOV EAX, iNum&& ; Get first argument&&&&&&&&&&&&&&& MOV ECX, iP Get second argument&&&&&&&&&&&&&&& SHL EAX, CL&&&& ; EAX = EAX * (2 to the power of CL)&&&&&&&&&&& }&&&&&&&&&&& // Return with result in EAX&&&&&&& }
&&& 使用内联汇编写的 GetPowerC 函数可以通过参数名称来引用它的参数。由于 GetPowerC 函数没有执行 C 的 return 语句,所以编译器会给出一个警告信息,我们可以通过 #pragma warning 禁止生成这个警告。
&&& 内联汇编的其中一个用途是编写 naked 函数的初始化和结束代码。对于一般的函数,编译器会自动帮我们生成函数的初始化(构建参数指针和分配局部变量等)和结束代码(平衡堆栈和返回一个值等)。使用内联汇编,我们可以自己编写干干净净的函数。当然,此时我们必须自己动手做一些有关函数初始化和扫尾的工作。例如:
&&&&&&& void __declspec(naked) MyNakedFunction()&&&&&&& {&&&&&&&&&&& // Naked functions must provide their own prolog.&&&&&&&&&&& __asm&&&&&&&&&&& {&&&&&&&&&&&&&&& PUSH EBP&&&&&&&&&&&&&&& MOV ESP, EBP&&&&&&&&&&&&&&& SUB ESP, __LOCAL_SIZE&&&&&&&&&&& }
&&&&&&&&&&& .&&&&&&&&&&& .&&&&&&&&&&& .
&&&&&&&&&&& // And we must provide epilog.&&&&&&&&&&& __asm&&&&&&&&&&& {&&&&&&&&&&&&&&& POP EBP&&&&&&&&&&&&&&& RET&&&&&&&&&&& }&&&&&&& }
6. 调用 C/C++ 函数
&&& 内联汇编中调用声明为 __cdecl 方式(默认)的 C/C++ 函数必须由调用者清除参数堆栈,下面是一个调用 C/C++ 函数例子:
&&&&&&& #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
&&&&&&&&&&&&&&& // 压入了 3 个参数在堆栈中,调用函数之后要调整堆栈&&&&&&&&&&&&&&& ADD&&&& ESP, 12&&&&&&&&&&& }&&&&&&& }
&&& * 提示:参数是按从右往左的顺序压入堆栈的。
&&& 如果调用 __stdcall 方式的函数,则不需要自己清除堆栈。因为这种函数的返回指令是 RET n,会自动清除堆栈。大多数&&API 函数均为 __stdcall 调用方式(仅除 wsprintf 等几个之外),下面是一个调用 MessageBox 函数的例子:
&&&&&&& #include &.h&
&&&&&&& TCHAR g_tszAppName[] = TEXT("API Test");
&&&&&&& void main()&&&&&&& {&&&&&&&&&&& TCHAR tszHello[] = TEXT("Hello, world!");
&&&&&&&&&&& __asm&&&&&&&&&&& {&&&&&&&&&&&&&&& PUSH&&& MB_OK OR MB_ICONINFORMATION&&&&&&&&&&&&&&& PUSH&&& OFFSET g_tszAppName&&&&&&&& ; 全局变量用 OFFSET&&&&&&&&&&&&&&& LEA&&&& EAX, tszHello&&&&&&&&&&&&&& ; 局部变量用 LEA&&&&&&&&&&&&&&& PUSH&&& EAX&&&&&&&&&&&&&&& PUSH&&& 0&&&&&&&&&&&&&&& CALL&&& DWORD PTR [MessageBox]&&&&& ; 注意这里不是 CALL MessageBox,而是调用重定位过的函数地址&&&&&&&&&&& }&&&&&&& }
&&& * 提示:可以不受限制地访问 C++ 成员变量,但是不能访问 C++ 的成员函数。
7. 定义 __asm 块为 C/C++ 宏
&&& 使用 C/C++ 宏可以方便地把汇编代码插入到源代码中。但是这其中需要额外地注意,因为宏将会扩展到一个逻辑行中。为了不会出现问题,请按以下规则编写宏:
&&& * 使用括号把 __asm 块包围住;&&& * 把 __asm 关键字放在每条汇编指令之前;&&& * 使用经典 C 风格的注释(&/* comment */&),不要使用汇编风格的注释(&; comment&)或单行的 C/C++ 注释(&// comment&);
&&& 举个例子,下面定义了一个简单的宏:
&&&&&&& #define PORTIO __asm&&&&&&& \&&&&&&& /* Port output */&&&&&&&&&& \&&&&&&& {&&&&&&&&&&&&&&&&&&&&&&&&&& \&&&&&&&&&&& __asm MOV AL, 2&&&&&&&& \&&&&&&&&&&& __asm MOV DX, 0xD007&&& \&&&&&&&&&&& __asm OUT DX, AL&&&&&&& \&&&&&&& }
&&& 乍一看来,后面的三个 __asm 关键字好像是多余的。其实它们是需要的,因为宏将被扩展到一个单行中:
&&&&&&& __asm /* Port output */ {__asm MOV AL, 2 __asm MOV DX, 0xD007 __asm OUT DX, AL}
&&& 从扩展后的代码中可以看出,第三个和第四个 __asm 关键字是必须的(作为语句分隔符)。在 __asm 块中,只有 __asm 关键字和换行符会被认为是语句分隔符,又因为定义为宏的一个语句块会被认为是一个逻辑行,所以必须在每条指令之前使用 __asm 关键字。
&&& 括号也是需要的,如果省略了它,编译器将不知道汇编代码在哪里结束,__asm 块后面的 C/C++ 语句看起来会被认为是汇编指令。
&&& 同样是由于宏展开的原因,汇编风格的注释(&; comment&)和单行的 C/C++ 注释(&// commen&)也可能会出现错误。为了避免这些错误,在定义 __asm 块为宏时请使用经典 C 风格的注释(&/* comment */&)。
&&& 和 C/C++ 宏一样 __asm 块写的宏也可以拥有参数。和 C/C++ 宏不一样的是,__asm 宏不能返回一个值,因此,不能使用这种宏作为 C/C++ 表达式。
&&& 不要不加选择地调用这种类型的宏。比如,在声明为 __fastcall 的函数中调用汇编语言宏可能会导致不可预料的结果(请参看前文的说明)。
&&& 可以在 C/C++ 里面使用 goto 转跳到 __asm 块中的标号处,也可以在 __asm 块中转跳到 __asm 块里面或外面的标号处。__asm 块内的标号是不区分大小写的(指令、指示符等也是不区分大小写的)。例如:
&&&&&&& void MyFunction()&&&&&&& {&&&&&&&&&&& goto C_D&&& /* 正确 */&&&&&&&&&&& goto c_&&& /* 错误 */
&&&&&&&&&&& goto A_D&&& /* 正确 */&&&&&&&&&&& goto a_&&& /* 正确 */
&&&&&&&&&&& __asm&&&&&&&&&&& {&&&&&&&&&&&&&&& JMP C_D 正确&&&&&&&&&&&&&&& JMP c_ 错误
&&&&&&&&&&&&&&& JMP A_D 正确&&&&&&&&&&&&&&& JMP a_ 正确
&&&&&&& a_dest:&&&&&&&&&&&& ; __asm 标号&&&&&&&&&&& }
&&&&&&& C_Dest:&&&&&&&&&&&& /* C/C++ 标号 */&&&&&&&&&&&&&&&&&& }
&&& 不要使用函数名称当作标号,否则将转跳到函数中执行,而不是标号处。例如,由于 exit 是 C/C++ 的函数,下面的转跳将不会到 exit 标号处:
&&&&&&& ; 错误:使用函数名作为标号&&&&&&& JNE exit&&&&&&& .&&&&&&& .&&&&&&& .&&&&&&& exit:&&&&&&& .&&&&&&& .&&&&&&& .
&&& 美元符号&$&用于指定当前指令位置,常用于条件跳转中,例如:
&&&&&&& JNE $+5&&&& ; 下面这条指令的长度是 5 个字节&&&&&&& JMP _Label&&&&&&& NOP&&&&&&&& ; $+5,转跳到了这里&&&&&&& .&&&&&&& .&&&&&&& .&&&&&&& _Label:&&&&&&& .&&&&&&& .&&&&&&& .
五、在 Visual C++ 工程中使用独立汇编
&&& 内联汇编代码不易于移植,如果你的程序打算在不同类型的机器(比如 x86 和 Alpha)上运行,你可能需要在不同的模块中使用特定的机器代码。这时候你可以使用 MASM(Microsoft Macro Assembler),因为 MASM 支持更多方便的宏指令和数据指示符。
&&& 这里简单介绍一下在 Visual Studio .NET 2003 中调用 MASM 编译独立汇编文件的步骤。
&&& 在 Visual C++ 工程中,添加按 MASM 的要求编写的 .asm 文件。在解决方案资源管理器中,右击这个文件,选择&属性&菜单项,在属性对话框中,点击&自定义生成步骤&,设置如下项目:
&&& 命令行:ML.exe /nologo /c /coff "-Fo$(IntDir)\$(InputName).obj" "$(InputPath)"&&& 输出:$(IntDir)\$(InputName).obj
&&& 如果要生成调试信息,可以在命令行中加入&/Zi&参数,还可以根据需要生成 .lst 和 .sbr 文件。
&&& 如果要在汇编文件中调用&&API,可以从网上下载 MASM32 包(包含了 MASM 汇编工具、非常完整的&&API 头文件/库文件、实用宏以及大量的 Win32 汇编例子等)。相应地,应该在命令行中加入&/I X:\MASM32\INCLUDE&参数指定&&API 汇编头文件(.inc)的路径。MASM32 的主页是:,里面可以下载最新版本的 MASM32 包。
阅读(...) 评论()当前访客身份:游客 [
码农的杯具命运。。。
:哥们,你这个异步操做在哪?epoll本身并不算做异...
:这个参数 有时候改了还不成功!!
:问下,什么情况账号会被封
:引用来自“被风遗忘”的评论在sqlserver2008下导...
:在sqlserver2008下导入txt文件有个问题,UTF-8的...
:引用来自“虎眼豆丁”的评论win7可以设置,可能楼...
:win7可以设置,可能楼主用的笔记本,需要网上搜搜...
:123sys的更垃圾,30$年付的,离线下载个东西一觉...
:引用来自“Cnlouds”的评论比阿里云强些,阿里云...
:比阿里云强些,阿里云一扫就封,很蛋疼,国外网速...
今日访问:16
昨日访问:34
本周访问:287
本月访问:100
所有访问:44201
VC++ 内联汇编
发表于3年前( 15:37)&&
阅读(498)&|&评论()
0人收藏此文章,
&记住一下几条
&&&& 调用api& call dword ptr[API]
&&&& 调用CRT函数 直接 call xxx
&&&& windows 中的所有函数调用都不会改写 esi edi 寄存器
&&& mov eax,dowrd ptr[esp]& 别忘了加上 dowrd ptr 编译器在无法确认的时候 会选择 BYTE ptr
#include &windows.h&
#include &stdio.h&
void __declspec(naked) ShowEnvValue(char *pName)
push DWORD ptr[esp + 28]
call DWORD ptr[GetEnvironmentVariableA]
test eax,eax
call malloc
push DWORD ptr[esp + 24]
call DWORD ptr[GetEnvironmentVariableA]
test eax,eax
_free: push esi
_ok: push esi
call printf
int main(int argc, char* argv[])
ShowEnvValue(&path&);
更多开发者职位上
1)">1)">1" ng-class="{current:{{currentPage==page}}}" ng-repeat="page in pages"><li class='page' ng-if="(endIndex<li class='page next' ng-if="(currentPage
相关文章阅读后使用快捷导航没有帐号?
查看: 3251|回复: 6
内联汇编方式本地调用某游戏CALL的列子
本帖最后由 xiaomeimei 于
15:28 编辑
发个内联汇编方式调用某宿主程序CALL的列子,其实这样的列子还可以演变成不用系统ReadProcessMemory与WriteProcessMemory读取和写入内存数据.前提是注入到宿主程序里面直接本地调用.其中需要的汇编支持库可在易官方论坛上找到.当然在没有汇编支持库的环境下还是可以用易自身的置入代码()命令把汇编指令转变成字节集的形式的.只是那样麻烦些.
.子程序 Id_选目标
.参数 目标地址, 整数型, , 汇编中第一个参数为[ebp+8]
.局部变量 CALL入口, 文本型, , , 汇编中第一个变量地址为[ebp-4]
' 007A734B&&|& \8B8F F8000000 MOV ECX,DWORD PTR DS:[EDI+F8]& && && && &;&&选择目标CALL
' 007A7351&&|.&&51& && && && &PUSH ECX& && && && && && && && && && && &; /Arg1
' 007A7352&&|.&&8BCE& && && & MOV ECX,ESI& && && && && && && && && && &; |
' 007A7354&&|.&&E8 079EFFFF& &CALL sro_clie.007A1160& && && && && && & ; \sro_clie.007A1160
' 上面的为选择目标CALL原形实际上可以简化成如下模式传入参数ECX即可ECX为目标ID
' PUSH ECX
' MOV ECX,ESI
' CALL sro_clie.007A1160
CALL入口 = “007A1160”
置入代码 (“mov esi dword ptr ss:[]”)
置入代码 (“mov edi,dword ptr ss:[ebp+8]”)&&' 这里EBP+8即为子程序参数目标地址
置入代码 (“MOV ECX,DWORD PTR DS:[EDI+F8]”)
置入代码 (“PUSH ECX”)
置入代码 (“MOV ECX,ESI”)
置入代码 (“CALL dword ptr ss:[ebp-4]”)&&' 这里的EBP-4即为变量CALL入口
我还是不太懂, 我知道你这个是 丝路的选怪CALL&&但是你的 EBP没有值啊~ 这样可以吗?
我还是不太懂, 我知道你这个是 丝路的选怪CALL&&但是你的 EBP没有值啊~ 这样可以吗?
在反汇编当中得知易程序的特征[ebp+8]为子程序的第一个传入参数地址.[ebp-4]为第一个局部变量的存放地址EBP没值?你真逗.
水平太差,真没能看懂
说实在的,这种方式我也不太懂~~
主要是注入还没有整懂,呵呵~ 命令基本上懂了
不是要要转换成{000,000,000}这样的形式吗

我要回帖

更多关于 汇编 call 的文章

 

随机推荐