第 6 章教学重点第 6章介绍实际应用当中,
常见的混合编程问题,重点是参数传递方法
混合编程的两种方式
模块连接的约定规则
模块连接的参数传递方法第 6章 什么是混合编程
多种程序设计语言间,通过相互调用,
参数传递,共享数据结构和数据信息而形成程序的过程就是混合编程
程序的大部分采用高级语言编写,以提高程序的开发效率;在某些部分,
利用汇编语言编写,以提高程序的运行效率第 6章 混合编程方法
嵌入式汇编 ——
在 C/C++语言中直接使用汇编语言语句,
简洁直观,功能较弱
模块连接 ——
两种语言分别编写独立的程序模块,分别产生目标代码 OBJ文件,然后进行连接,
形成一个完整的程序
使用灵活,功能强,要解决参数传递问题第 6章 混合编程的关键问题
建立不同语言之间的接口
在不同格式的两种语言间提供有效的通讯方式,作出符合两种语言调用约定的某种形式说明,实现两种语言间的程序模块互相调用,变量的相互传送以及参数和返回值的正确使用第 6章 Turbo C嵌入式汇编方式
格式
asm 操作码 操作数 <;或换行 >
举例
asm mov ax,ds;
asm pop ax; asm pop ds; asm ret;
asm push ds
第 6章 若干注意事项
操作码支持 8086/8087指令或若干伪指令,db/dw/dd和 extern
操作数是操作码可接受的数据:立即数,
寄存器名,还可以是 C语言程序中的常量,变量和标号等
内嵌的汇编语句可以用分号,;”结束,
也可以用换行符结束
使用 C的注释,如 / * … * /
正确运用通用寄存器,标号等
/ * LT602.C */
#include <stdio.h>
void upper(char *dest,char *src)
{ asm mov si,src
/* dest和 src是地址指针 */
asm mov di,dest
asm cld
loop,asm lodsb /* C语言定义的标号 */
asm cmp al,'a'
asm jb copy /* 转移到 C的标号 */
asm cmp al,'z'
asm ja copy
/* 不是 ’ a’到 ’ z’之间的字符原样复制 */
例 6.2- 1/2
asm sub al,20h /*小写字母转换成大写 */
copy,asm stosb
asm and al,al
/* C语言中,字符串用 NULL( 0) 结尾 */
asm jnz loop}
main()/* 主程序 */
{
char str[]="This Started Out As Lowercase!";
char chr[100];
upper(chr,str);
printf("Origin string:\n%s\n",str);
printf("Uppercase String:\n%s\n",chr);
}
例 6.2- 2/2
第 6章 Turbo C模块连接的约定规则
命名约定
汇编语言过程中被 C语言调用的 标识符前要 加上下划线,_”
声明约定
C对调用的外部过程,变量等采用 EXTERN说明
汇编语言程序的标识符用 public操作符定义
寄存器使用约定
存储模式约定
采用 相同的存储模式
参数传递约定:堆栈和共享变量; 汇编语言子程序,lt603s.asm
.model small ;采用小型存储模式
.data
msg db ’Hello,C and Assembly ! $’
.code
PUBLIC _display
_display proc ;过程名加有下划线
mov ah,9 ;小型模式不必设置 DS
mov dx,offset msg;寄存器 AX和 DX无须保护
int 21h
ret
_display endp
end
例 6.3- 1/2
/* C语言程序,lt603.c */
extern void display(void);
/* 说明 display是外部函数 */
main()
{ display();
}
利用汇编程序编译汇编语言程序成目标代码文件:
ML/c lt603s.asm
利用 C编译程序编译 C程序,连接目标代码文件:
TCC -ms -Iinclude -Llib lt603.c lt603s.obj
例 6.3- 2/2; 汇编语言子程序,lt604s.asm
.model small
.code
PUBLIC _min
_min proc ;小型模式,为近过程
push bp
mov bp,sp
mov ax,[bp+4] ;取第 1个参数
cmp ax,[bp+6] ;与第 2个参数比较
jle minexit
mov ax,[bp+6] ;保存返回值
minexit,pop bp
ret
_min endp
end
例 6.4- 1/2
图示
large
6
8
8
L
/* C语言程序,lt604.c */
extern int min(int,int);
main()
{ printf(“%d”,min(100,200));
}
小型模式编译程序和连接:
TCC -ms -Iinclude -Llib lt604.c lt604s.obj
大型模式编译程序和连接:
TCC -ml -Iinclude -Llib lt604.c lt604l.obj
例 6.4- 2/2
第 6章 Visual C++的嵌入式汇编
格式
_ _asm { 指令 }
举例
int power2(int num,int power)
{
_ _asm
{
mov eax,num
mov ecx,power
shl eax,cl
} // 返回 EAX=EAX× (2^CL)
}
第 6章 模块连接的注意事项
必须遵循共同的约定规则
命名约定
声明约定
寄存器使用约定
存储模式约定
参数传递约定
采用一致的调用规范
声明共用函数和变量
正确传递入口参数和返回参数第 6章 32位汇编语言过程
用,386p等处理器伪指令说明采用的指令集
32位逻辑段环境
有些指令在 32位段与 16位段有差别
采用平展模式 ( flat)
汇编时采用选项 /coff;汇编语言子程序,lt614f.asm
.386p
.model flat,c
PUBLIC power2
.code
power2 proc
push ebp
mov ebp,esp
mov eax,[ebp+8] ;取第 1个参数
mov ecx,[bp+12] ;取第 2个参数
shl eax,cl
pop ebp
ret ;返回 EAX
power2 endp
end
例 6.14- 1/2
图示
// C++语言程序,lt614.cpp
# include <iostream.h>
extern,c”{int power2(int,int);}
void main(void)
{
cout<<“2的 6次方乘 5等于,\t”;
cout<<power2(5,6)<<endl;
}
将汇编语言程序汇编成目标代码文件:
ML/c /coff lt614f.asm
在 VisualC++6.0编译环境下创建项目,
插入汇编成的目标代码文,然后编译连接例 6.14- 2/2
如何简化利用堆栈的传递参数方法
要调用带参数过程定义的过程,不应采用
CALL指令,因为比较烦琐
应该采用过程调用伪指令 INVOKE
使用 INVOKE 伪指令的前提是需要用
PROTO伪指令对过程进行声明带参数过程的定义,声明和调用过程名 PROC 调用距离 语言类型 作用范围 <起始参数 >
USES 寄存器列表,参数,类型
LOCAL 参数表
… ;汇编语言语句过程名 ENDP
第 6章
过程声明伪指令,用于事先声明过程的结构过程名 PROTO 调用距离 语言类型,参数,类型
过程调用伪指令
INVOKE 过程名,参数,...
如何调用;汇编语言程序,lt615.asm
.model small
checksumd PROTO c,countp:word,arrayp:word;声明过程
.stack 256
.data
array db 12h,25h,0f0h,0a3h,3
db 68h,71h,0cah,0ffh,90h
count equ $-array ; 数 组 的 元 素 个 数
result db? ;校验和
.code
.startup
INVOKE checksumd,count,offset array;调用过程
mov result,al ;保存校验和
.exit 0
例 6.15- 1/2
对比
checksumd PROC c USES bx cx,\
countp:word,arrayp:word
mov bx,arrayp ;BX←数组的偏移地址
mov cx,countp ;CX←数组的元素个数
xor al,al
sumd,add al,[bx] ;求和,AL←AL+DS:[BX]
inc bx
loop sumd
ret
checksumd endp
end
例 6.15- 2/2
对比;汇编语言子程序,lt616s.asm
.model small,c ;采用 C语言类型
public min
.code
min proc,var1:word,var2:word
mov ax,var1 ;取第 1个参数 var1
cmp ax,var2 ;与第 2个参数 var2比较
jle minexit
mov ax,var2 ;保存返回值
minexit,ret
min endp
end
例 6.16
对比供 C语言主程序调用;汇编语言子程序,lt617f.asm
.386p
.model flat,c
PUBLIC power2
.code
power2 PROC,num:dword,power:dword
mov eax,num ;获取参数
mov ecx,power
shl eax,cl ;计算
ret ;EAX存放返回值
power2 ENDP
end
例 6.17
对比供 C++主程序调用
// C++程序,LT618.CPP
#include <iostream.h>
extern "C" {long isum(int,int *);}
int imin(int,int *);
void main(void)
{
const int SIZE=10;
int array[SIZE];
int temp;
cout<<"请输入 10个整数,"<<endl;
for(temp=0;temp<SIZE;temp++)
cin>>array[temp];
cout<<endl;
cout<<"整数数据之和,\t"<<isum(SIZE,array)<<endl;
cout<<"其中最小值为,\t"<<imin(SIZE,array)<<endl;
}
例 6.18- 1/4
//求 itmp个元素的数组 iarray的最小数
int imin(int itmp,int iarray[])
{
__asm {
mov ecx,itmp
jecxz minexit ;个数为 0,返回
dec ecx
mov esi,iarray
mov eax,[esi]
jecxz minexit ;个数为 1,返回
minlp,add esi,4
cmp eax,[esi] ;比较两个数据的大小
jle nochange
mov eax,[esi] ;取得较小值
nochange,loop minlp
minexit:
}}
例 6.18- 2/4;汇编语言子程序,LT618F.ASM
.386p
.model flat,c
.code;32位有符号数据的求和过程
isum proc uses ecx esi,\
count:dword,darray:PTR
mov ecx,count ;个数为 0,和为 0
xor edx,edx
xor eax,eax
jecxz sumexit
mov esi,darray ;个数为 1,和为本身
mov eax,[esi]
dec ecx
jecxz sumexit
例 6.18- 3/4
sumlp,add esi,4
add eax,[esi] ;计算低 32位
adc edx,0 ;计算高 32位
loop sumlp
sumexit,ret
isum endp
end
例 6.18- 4/4
将汇编语言程序汇编成目标代码文件:
ML/c /coff lt618f.asm
在 VisualC++6.0编译环境下创建项目,
插入汇编成的目标代码文,然后编译连接第 6章 教学要求 ( 1)
1,熟悉嵌入式和模块连接两种混合编程方法
2,了解模块连接混合编程的约定规则
3,熟悉模块链接混合编程的参数传递方法
4,熟悉带参数的过程定义 PROC和过程声明
PROTO,过程调用 INVOKE伪指令
5,了解 32位环境的混合编程方法
Have a Break