C/C++汇编的接口设计
例程用C语言编写主程序,汇编语言编写子程序,主程序中要声明子程序的原型。主程序CMAIN.CPP如下:
//主程序cmain.cpp
#include <stdio.h>
extern ″C″ int addition(int x,int y);
//此处声明子程序的原型,C必须大写,最后有分号。
void main()
{ int x=120,y=15,z;
z=addition(x,y);
printf(″x,y,z:%d,%d,%d″,x,y,z);}
Borland C 3.1中带有用于80X86的汇编工具TASM。汇编语言中须说明为何种语言调用,调用的参数以及类型。主程序调用子程序时,从后往前向堆栈中压入参数,然后是主程序的返回地址(80X86中堆栈向低地址方向生长)。前面的主程序调用子程序时堆栈情况如^08020401a^所示:
当从堆栈中取有关参数时要用到寄存器BP,因此还须要保存BP;如果子程序中有自己的数据段,也要保存原有的DS。返回的结果如果是短整数,请放在AX中;长整数放在DX∶AX中。子程序ADDITION.ASM如下:
;子程序addition.asm
.model small,c ;声明此为C/C++的子程序。
.486 ;可以使用486的指令,包括387。
public addition ;addition公用,可为其它程序远调用。
.code ;代码段开始。
addition proc c x:word,y:word ;addition子程序的格式。
push bp ;保存BP,
mov bp,sp ;把SP值传给BP。
mov ax,[bp+6] ;取出X。
mov bx,[bp+8] ;取出Y。
add ax,bx ;(AX)←X+Y。
pop bp ;恢复BP。
ret ;返回主程序。
addition endp
end
现在主程序和子程序都已经完成,下面可以用Borland C 3.1来编译和连接了。
首先,进入C主程序,选择“Options/Linker/Libraries”,在Libraries对话框中,选择“Turbo Vision”,以保证与tv.lib连接。
其次,新建或打开ADDITION.ASM,确认无误后选择“≡/Turbo As-sembler”,汇编成功后,选择“File/Dos Shell”,在DOS提示符下键入:
tlib tv.lib +addition.obj
如果以后ADDITION.ASM修改了,相应ADDITION.OBJ也改变了,只需键入:
tlib tv.lib -+addition.obj
现在,键入exit回到Borland C 3.1环境。
接着,新建或打开cmain.cpp,选中“Compile/Compile”,对cmain.cpp编译;选中“Compile/Link”,进行连接。
至此,一个名为cmain.exe的可执文件产生了。
下面,将浮点数的调用和返回加以介绍。
C/C++中,浮点数有两种:float,占四字节;doble,占八字节。浮点参数调进汇编语言时,仍然压入堆栈,可以用上面的方法找到参数;值返回时,只需把结果保留在80X87的TOS中即可。其余与上相同。例程如下:
//主程序fmain.cpp
#include <stdio.h>
extern ″C″ double fsqr(double x);
void main()
{double x,y;
printf(″Enter x:″);
scanf(″%e″,&x);
y=fsqrt(x);
printf(″\nx=%e\ny=%e\n″,x,y);}
;子程序fsqr.asm
.model small,c
. 486
public fsqrt
.code
fsqr proc c x:qword ;X为double型,占8字节。
push bp
mov bp,sp
finit ;协处理器初始化。
fld qword ptr [bp+6] ;载入X至TOS。
fsqrt ;TOS开方,结果仍在TOS内。
fwait ;与主处理器同步。
pop bp
ret
fsqr exdp
end