找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 5125|回复: 0

【混合编程】NASM与VC6合体编程

[复制链接]

1112

主题

1653

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
245
威望
744 点
宅币
24254 个
贡献
46222 次
宅之契约
0 份
在线时间
2298 小时
注册时间
2014-1-26
发表于 2014-2-16 22:53:26 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
其实编译的原理无非是各个编译器负责编译自己的文件为中间文件,然后让链接器把各个中间文件链接起来,得到可执行文件等。所以说VC6和NASM编程,无非就是让VC6的编译器编译程序的C语言、C艹部分,然后让NASM编译汇编部分,最后用链接器完成链接。
这个叫“外联汇编”。比起内联汇编,外联汇编更安全。如果你有很多需要重复运行的指令,如果是C语言编写,运行速度可能会受到影响,而如果交给汇编,运行速度就能得到保障。
此外外联汇编还能做到一些C语言做不到的事,比如调用CPUID指令查看CPU的型号、参数等,这样的话要么内联汇编,要么外联汇编。
废话不多说。第一步,用VC6打开一个VC6的工程。
VCNASM.JPG
切换到FileView(文件视图)。如下所示:
VCFILEVIEW.JPG
然后菜单“文件->新建”
NEW.JPG
选择“文件->C++ Source File”文件名的话,就输入“×××.ASM”。也就是自定文件名。但是最好是英文。
我不能保证就算NASM能正常编译中文名文件的源码LINK也能识别中文中间文件名。所以最好是英文。
然后点确定。正常的节奏应该是如下图所示的:
NASMSrc.JPG
然后就会多出一个“×××.ASM”在工程的文件视图。因为“×××.ASM”是新建的,因此它是空的。
没有问题的话是如下图所示的。
NASMINVC.JPG
这个时候,我觉得,为了便于管理,我会在文件视图专门给NASM的源码新建一个文件夹。
所以大家也跟着我建立文件夹吧。
NEWFOL.JPG
NASMFOL.JPG
然后把你刚才产生的“×××.ASM”拖进去,应该是下面这个样子的:
NASMFOL.GIF
关键的地方在这里!!在你建立的文件夹上点右键->设置,如下所示:
SETTINGS.JPG
在弹出的对话框中找到“自定义组建”,描述那里就填写“正在用NASM编译$(InputPath)”然后在“命令”那里输入编译的命令:
  1. nasm -f win32 $(InputPath) -o $(TargetDir)\$(InputName).obj
复制代码
再在“输出”那里输入编译器编译后的中间文件名,也就是编译器输出的文件名:
  1. $(TargetDir)\$(InputName).obj
复制代码
没有问题的话,应该是如下图所示的:
NASMSETTINGS.JPG
Ps:NASM的命令详见NASM说明文档:(全英文但是非常非常详细)
http://www.nasm.us/pub/nasm/releasebuilds/2.11/doc/nasmdoc.txt
嗯,这里输入好了以后点确定就行。设置好以后应该是这个样子的:
NASMPROJ.PNG
好!现在开始编程了。我在这里讲讲要点。
1、代码放在代码段.text
2、数据放在数据段.data
3、未初始化数据放在未初始化数据段.bss
然后NASM怎么引用C的符号呢?用extern声明外部符号。
NASM怎么导出符号给C用呢?用global导出内部符号。C语言的_cdecl形式的函数的特点从汇编的角度来讲就是:
1、参数逆序压栈。
2、返回的时候用ret
3、调用者自行将栈维持平衡。也就是说,调用者要把压入的参数弹掉
4、如果返回值是浮点数,那么返回值放在浮点处理器的浮点数栈的栈顶。而如果返回值是正数,那么返回值放在eax寄存器。
C语言的_stdcall形式的函数的特点从汇编的角度来讲就是:
1、参数逆序压栈。
2、返回的时候用“ret 参数占用字节数”指令。也就是被调用者要维护栈,把参数弹掉
3、返回值的特点和_cdecl是一样的。
寄存器的使用要点:
1、eax、ecx、edx、随便用。这三个寄存器不需要保护。
2、ebx要保护。esp是栈,要维持栈平衡。ebp是访问栈参数、临时变量的寄存器,要保护起来。
3、esi、edi是C、C艹用来当做一些常用变量的寄存器,比如for(int i=0;i<10;i++)这句很可能就是把esi当做变量i,从而省去了分配内存的间隔。
关于符号的使用要点:
1、C++输出的符号和C的不同点是C++输出的符号会有奇怪的修饰。其实是为了实现函数重载。因此对C++的函数要特殊考虑。
2、C语言输出的符号是带有下划线前缀的,也就是“_”,这点修饰比C++的简单多了。
3、_stdcall的函数的修饰是后面加一个“@参数占用字节数”。比如int _stdcall A(short);因为这个函数有一个参数,虽然这个参数是short类型的但是因为函数参数表是4字节对齐的,因此它输出的符号应该是“_A@4”,它最后的返回指令是“ret 4”
4、调用API的时候,我举个例,是这样的:
  1. extern __imp__MessageBoxA@16

  2. global _ShowMsgBox    ;void ShowMsgBox(void);

  3. segment .text
  4. _ShowMsgBox:
  5. push 0
  6. push msgTitle
  7. push msgPrompt
  8. push 0
  9. call dword[__imp__MessageBoxA@16]
  10. ret

  11. segment .data
  12. msgPrompt       db "这个是提示文本"
  13. msgTitle        db "这个是标题栏"
复制代码
这么说感觉文字好无力。那么我这里给出一个VC和NASM的源码,供大家下载研究。
GETCPUID.PNG
把上面这张图右键另存为ZIP就能解压看到源码啦。
回复

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-26 17:09 , Processed in 0.044647 second(s), 34 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表