找回密码
 注册
搜索
热搜: 回贴

关于BCB和MASM的混合编程,编程,Win32/64编程

2010-1-30 18:28| 发布者: admin| 查看: 122| 评论: 0|原作者: 夙瑶


关于BCB和MASM的混合编程,编程,Win32/64编程
2008年06月23日 星期一 下午 09:39
最近受了点刺激 ,不过佛曰:不可说,不可说。那只能说点别得,以前想写小程序,研究过BCB与MASM的混合编程,现在没有时间进一步深入了,现在整理一下当时的笔记,仅作个抛砖引玉。









¥为什么?



关于混合编程

masm的优势在于macro的强大,对细节的精确控制;

C/C 的优势在于模块化,GUI容易控制

为什么不用TASm:支持库不全,它的macro不太会用,现在不升级

为什么不是BCB而不是VC:首先不会VC;好像VC也不存在与masm的兼容问题。BCB需要你用OMF方式来编译asm模块,在api的使用上有很大麻烦,本文主要是解决这个问题





¥怎样做?



一、在高级语言中用 asm{ }或宏定义方式,可应用在小范围内,缺点是只能用最初级的asm,C的编译器很难支持masm的高级应用

二、C中使用masm编译的obj或lib,优势明显,缺点是很难保证兼容性,即编译器难以通过

三、使用dll,很方便,但是要多出文件了





具体方法:

1、__cdecl 方式:

masm中类似于:

.386

.model flat

option casemap:none

...

PUBLIC _Add3



.code

...

_Add3:

...

ret

end



注意开始的.model 中无stdcall开关,所以标号的声明前面需要加个_

然后编译(不可以应用任何系统lib、任何api)

在C中,声明

#ifdef __cplusplus

extern "C" {

#endif



int __cdecl Add3(int, int);



#ifdef __cplusplus

} /* extern "C" */

#endif

注意声明中无_,因__cdecl的应用会加上_

此方式的缺点就是masm中不能应用api,因masm的lib都是stdcall方式(BCB的lib可不可以用??)









2、__stdcall 方式:

masm中类似于:

.386

.model flat, stdcall

option casemap:none

...

PUBLIC Add3



.code

...

Add3:

...

ret

end



注意开始的.model 中有stdcall开关,所以标号的声明前面不需要加_,可以应用api

然后编译

在C中,声明

#ifdef __cplusplus

extern "C" {

#endif



int __stdcall _Add3(int, int);



#ifdef __cplusplus

} /* extern "C" */

#endif

注意声明中需要加_,因__stdcall的应用不会加_

在无api引用时,此方式可以正常使用,但如果masm中使用了api,BCB编译时提示masm的lib不是OMF格式

解决:可以用BCB的lib..下一个问题是masm生成的obj中引入的api前面有_(因stdcall方式),现在是在obj中删除



如果api被声明成syscall方式,则不产生_,但调用者会错误的修复stack(in masm)

如果api被声明成c方式,产生_,而且调用者会错误的修复stack(in masm)

如果api被声明成stdcall方式(应该是默认方式),则产生_,调用者不会修复stack(in masm),但生成的api索引还会加上一个@8之类的尾巴,BCB的lib是非常干净的,_和尾巴导致BCB编译器不认。解决方法是手工在obj清除api名称中的垃圾,这差不多是目前最佳解决方案。







¥例:



in masm:



.386

.model flat, stdcall ;使用flat, stdcall模式

option casemap:none ;大小写敏感

includelib kernel32.lib ;要使用BCB的lib, 它是omf格式,不要用masm带的lib

GetModuleHandleA proto :dword ;声明要使用的api,考虑包含masm的inc文件

PUBLIC c Add3 ; :dword, :dword ;声明对外的过程,注意我们使用C模式,编译后前面会加上_



.code

Add3 proc near c aa:dword, bb:dword ;proc定义部分,编译后会加上push ebp...因在下面我们用到了变量

;Add3:

;jmp @f

invoke GetModuleHandleA, 0 ;测试使用api,正常

@@:

mov eax, aa ;测试使用变量

add eax, bb ;

ret ;返回,由调用者自行清理stack

Add3 endp ;过程结束

end ;汇编结束



注意BCB需要OMF格式的obj,要用bldomf.bat编译asm模块



这样生成的obj中api name前后都有多余的内容,为使之与BCB的lib兼容,必须手动清除。清除办法就是用objfixer清理一下,之后就可以在BCB里面连接了。



in BCB

in *.h file:

#ifdef __cplusplus

extern "C" { ;声明外部C过程

#endif



int __cdecl Add3(int, int); ;用C declare 方式,与masm中保持一致



#ifdef __cplusplus

} /* extern "C" */

#endif



in *.cpp file:

...

ShowMessage(Add3(33,42));

...



这样就可以通过编译









¥现存难点:

变量及过程的相互引用还是很麻烦的,需要很小心的处理。另外不同call模式及编译器的工作方式可能会导致堆栈平衡问题,需要仔细的debug





¥写得比较乱,如遇问题,自己解决,也欢迎QQ交流:6565XXX











¥附:关于不同调用模式(摘自masm、bcb帮助)

Calling Conventions



C SYSCALL STDCALL BASIC FORTRAN PASCAL

------- ------- ------- ------- ------- -------

Leading Underscore | X | | X | | | |

|------- ------- ------- ------- ------- -------|

Capitalize All | | | | X | X | X |

|------- ------- ------- ------- ------- -------|



Arguments Left to Right | | | | X | X | X |

|------- ------- ------- ------- ------- -------|

Arguments Right to Left | X | X | X | | | |

|------- ------- ------- ------- ------- -------|

Caller Stack Cleanup | X | | * | | | |

|------- ------- ------- ------- ------- -------|

BP Saved | | | | X | X | X |



|------- ------- ------- ------- ------- -------|

:VARARG Allowed | X | X | X | | | |

------- ------- ------- ------- ------- -------



* The STDCALL language type uses caller stack cleanup if the :VARARG

parameter is used. Otherwise, the called routine must clean up the

stack.



The language type (langtype) determines the naming and calling conventions

used by the assembler. This allows you to share code and data with



modules written with other languages. Set the language type with the

.MODEL or OPTION LANGTYPE: directives or with the /G command-line

option. Several directives allow you to specify a langtype

parameter to temporarily override the language type.



You can use the /H command-line option to limit the length of names

sent to the object file. Use this option to work with languages that

limit the maximum length of identifiers.

-o-





in BCB



Calling Convention options tell the compiler which calling sequences to generate for function calls. The C, Pascal, and Register calling conventions differ in the way each handles stack cleanup, order of parameters, case, and prefix of global identifiers.



You can use the ___cdecl, ___pascal, ___fastcall, or ___stdcall keywords to override the default calling convention on specific functions.



In C Builder code, you will normally use the default C calling convention.



MSVC __fastcall



(Command-line switch: -pm)



This option tells the compiler to substitute the __msfastcall calling convention for any function without an explicitly declared calling convention.



C



(Command-line switch: -pc, -p-)



This option tells the compiler to generate a C calling sequence for function calls (generate underbars, case sensitive, push parameters right to left). This is the same as declaring all subroutines and functions with the ___cdecl keyword. Functions declared using the C calling convention can take a variable parameter list (the number of parameters does not need to be fixed).



You can use the ___pascal, ___fastcall, or ___stdcall keywords to specifically declare a function or subroutine using another calling convention.



Pascal



(Command-line switch: -p)



This option tells the compiler to generate a Pascal calling sequence for function calls (do not generate underbars, all uppercase, calling function cleans stack, pushes parameters left to right). This is the same as declaring all subroutines and functions with the

___pascal keyword. The resulting function calls are usually smaller and faster than those made with the C (-pc) calling convention. Functions must pass the correct number and type of arguments.



You can use the ___cdecl, ___fastcall, or ___stdcall keywords to specifically declare a function or subroutine using another calling convention.



Register



(Command-line switch: -pr)



This option forces the compiler to generate all subroutines and all functions using the Register parameter-passing convention, which is equivalent to declaring all subroutine and functions with the ___fastcall keyword. With this option enabled, functions or routines expect parameters to be passed in registers.



You can use the ___pascal, ___cdecl, or ___stdcall keywords to specifically declare a function or subroutine using another calling convention.



Standard Call



(Command-line switch: -ps)



This option tells the compiler to generate a Stdcall calling sequence for function calls (does not generate underscores, preserve case, called function pops the stack, and pushes parameters right to left). This is the same as declaring all subroutines and functions with the ___stdcall keyword. Functions must pass the correct number and type of arguments.



You can use the ___cdecl, ___pascal, ___fastcall keywords to specifically declare a function or subroutine using another calling convention.



Default = C (-pc)






最新评论

QQ|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )

GMT+8, 2024-9-29 13:20 , Processed in 0.158937 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

返回顶部