资源预览内容
第1页 / 共20页
第2页 / 共20页
第3页 / 共20页
第4页 / 共20页
第5页 / 共20页
第6页 / 共20页
第7页 / 共20页
第8页 / 共20页
第9页 / 共20页
第10页 / 共20页
亲,该文档总共20页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
昨天好好研究了一下内嵌汇编的情况。 。 。 。 。更进一步的,该是看看独立编译的汇编程序与C/C+互相调用的情况了。呵呵,最近怎么好像老在搞这个,想当年学习的时候,一门心思的学 C+,到现在老是在弄诸如怎么在 C/C+中调用 LUA 函数,或者反过来,怎么 C/C+中调用 Python 函数,或者反过来,今天又是怎么在 C/C+中调用汇编的函数,或者反过来。 。 。 。 。 。 。 。 。 。 。 。 。呵呵,自从学习的语言越来越多,类似的情况碰到的也就越来越多了,但是,只懂一门语言就不能在合适的时候使用合适的语言来解决问题,并且看问题会带有狭隘的偏见,谁说的来着?毕竟无论是 lua,python,asm 都会有用的上的时候,我最近似乎老是喜欢说闲话。 。 。 。这是某些哥们说的自己的见解,还是某些时候无聊的牢骚呢?谁知道呢,过年了嘛,还不让人多说几句话啊。 。 。 。 。 。-_-!首先来看C 中调用汇编的函数先添加一个汇编文件写的函数吧,在 VS2005 中对此有了明显的进步,因为就加密与解密一书描述,在 2003 中需要自己配置编译选项,但是在 VS2005 中很明显的,当你添加asm 文件后,可以自己选定 masm 的编译规则,然后一切就由 IDE 把你做好了,这也算是IDE 的一个好用的地方吧。 。 。 。非常不好的一点就是,VS2005 中对于汇编没有任何语法高亮。 。 。 。damnit!IDE 怎么做的?就这点而言,其甚至不如一般的文本编辑工具!。 。 。又是废话了。 。因为是 C,这个目前全世界可能是最具有可移植性的语言,所以问题要简单的多。但是。 。也不全是那么简单,先看看直觉的写法:汇编代码:PUBLIC GetArgument.486 ; create 32 bit code.model flat ; 32 bit memory model;option casemap :none ; case sensitive_TEXT SEGMENT PUBLIC CODEGetArgument PROCMOV EAX, ESP+4RETNGetArgument ENDP_TEXT ENDSENDC 语言代码:#include #include int GetArgument(int);int _tmain(int argc, _TCHAR* argv)printf(%d/n,GetArgument(10);system(PAUSE); return 0;声明是必不可少的,毕竟汇编没有头文件给你包含,不过多的话,可以考虑组织一个专门用于包含汇编函数实现的头文件。但是在编译时却不会通过。1InlineAsm.obj : error LNK2001: 无法解析的外部符号_GetArgument1 D:/My Document/Visual Studio 2005/Projects/InlineAsm/Release/InlineAsm.exe : fatal error LNK1120: 1 个无法解析的外部命令看到错误原因也知道是怎么回事了,C 中的函数名被编译器处理时多了个前置的下划线,当然,这个问题好解决。一种方式是改变汇编代码的函数,直接添加一个前置下划线就完了,一种方式是将其声明为 C 语言的方式,那么链接程序也知道正确的链接了。两种方式分别如下:直接改变函数名:PUBLIC _GetArgument.486 ; create 32 bit code.model flat ; 32 bit memory model;option casemap :none ; case sensitive_TEXT SEGMENT PUBLIC CODE_GetArgument PROCMOV EAX, ESP+4RETN_GetArgument ENDP_TEXT ENDSEND改变.model 声明:PUBLIC GetArgument.486 ; create 32 bit code.model flat,c ; 32 bit memory model;option casemap :none ; case sensitive_TEXT SEGMENT PUBLIC CODEGetArgument PROCMOV EAX, ESP+4RETNGetArgument ENDP_TEXT ENDSEND个人推荐第 2 种方式,因为看起来最舒服,将改变函数名的工作交给编译和链接程序吧。假如是在 C+中调用 ASM 函数的话,相对复杂一点,因为没有.model C+的生命方式。 。 。这个世界是不公平对待 C 和 C+的。 。 。 。呵呵,但是 C+有完整的向 C 靠拢的机制,这就够了。汇编代码不变,C+调用时用如下形式:#include #include extern C int _cdecl GetArgument(int);int _tmain(int argc, _TCHAR* argv)printf(%d/n,GetArgument(10);system(PAUSE);return 0;即将 C+函数完整的声明为 C 语言的形式。 。 。 。 。但是我在 MSDN 中看到了.model 起码有stdcall 的声明方式,有这种声明方式为什么不用呢?呵呵,用一下。将汇编语言的.model 声明改成下面这样:.model flat,c,stdcall ; 32 bit memory modelC+中函数声明为下面这样:extern C int _stdcall GetArgument(int);结果却是链接错误:1 InlineAsm.obj : error LNK2001: 无法解析的外部符号_GetArgument4当我自以为声明一致时,却不知道发生了什么,假如是以前,我可能得一筹莫展。 。 。但是现在嘛。 。 。 。既然知道 obj 文件其实也是可读的,那么,看看链接的时候出了什么问题,为什么汇编出来的 obj 文件中没有这个符号呢?可以在 obj 文件的最后一行看到答案:原来汇编的代码声明 stdcall 后函数符号被解析成_GetArgument0 了,那不是表示没有参数吗?看来是我汇编写错了。改成如下形式:PUBLIC GetArgument.486 ; create 32 bit code.model flat,c,stdcall ; 32 bit memory model;option casemap :none ; case sensitive_TEXT SEGMENT PUBLIC CODEGetArgument PROC x:DWORDMOV EAX, xRETN 4GetArgument ENDP_TEXT ENDSEND然后再运行程序,崩溃。 。 。 。 。 。看看原因:GetArgument PROC x:DWORD00401030 push ebp 00401031 mov ebp,espMOV EAX, x00401033 mov eax,dword ptr xRETN 400401036 ret 4 很明显汇编编译后自动加了 push ebp;mov ebp,esp 这两句来保护栈指针 esp,问题是却没有自动生成还原的代码。 。 。那还不崩溃?典型的栈错误。可以用下面的方式修复GetArgument PROC x:DWORDMOV EAX, xpop ebpRETN 4但 是这样做个人感觉实在是太不优美了。 。 。 。 。 。 。奇怪的是编译器为什么要这样解析代码。 。 。呵呵,即便你是用汇编。 。 。特别是伪汇编。 。 。你都会发现编 译器在你的背后动了太多手脚,很多,是你根本不想要它去做的。这一点也可能是我汇编代码声明或写的有问题,导致编译器奇怪的处理了,有知道正确结果的高人 请指点一下.下面,在汇编中调用 C/C+函数:在此不分辨 C 和 C+了,差别仅在于一个 extern “C”而已,调用约定采用_stdcall 其他请参考汇编代码如下:PUBLIC GetArgument2.486 ; create 32 bit code.model flat,stdcall ; 32 bit memory model;option casemap :none ; case sensitiveGetArgument PROTO :DWORD ; 函数声明_TEXT SEGMENT PUBLIC CODEGetArgument2 PROC x:DWORDINVOKE GetArgument,xMOV EAX, xPOP EBPRETN 4GetArgument2 ENDP_TEXT ENDSENDC+代码:#include #include extern C int _stdcall GetArgument(int ai)return ai;extern C int _stdcall GetArgument2(int ai);int _tmain(int argc, _TCHAR* argv)printf(%d/n,GetArgument2(10);system(PAUSE);return 0;至此,你会高兴的发现,一个 10,从 C+中调用汇编的函数 GetArgument2,再从汇编中调用 C+的函数 GetArgument 再返回,得到正确结果。 。 。真不容易啊。 。 。这例子举得真够折腾的:)呵呵,说明问题就好了。最重要的一句就在于 GetArgument PROTO :DWORD ; 函数声明一行,另外,这一行应该在.model 声明以后,不然编译器不知道你该采用那种调用约定和名字编码方式。汇编函数与 C 函数的相互调用2010-08-30 07:22汇编函数与 C 函数的相互调用初看这个标题,也许很多读者会认为很深奥!有这种想法就错了,其实无论是 C 调用汇编还是汇编调用 C,都没有想象中的那么复杂。上一节 1_4 例中的 delay_nms 函数,只要把delay_nms 改为 _delay_nms 就可以不做其它任何修改而被 C 函数调用了。是不是很简单?_之所以要做这样修改,是因为 C51 的函数转换为汇编的时候,函数名根据实际情况有可能会改动,这种改动是很有规律而且简单的,只要记下来就行。看下表-+-+-声明 | 符号 | 说明-+-+-void func(void). | FUNC | 没有参数或参数不通过寄存器传递的| | 函数名没有改变。函数名改为大写。void func1(char). | _FUNC1 | 参数通过寄存器传递的函数,函数名前| | 有一个下划线 _。这确定这些函数通过| | 通过 CPU 寄存器传递参数
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号