从MASM全局标识符谈模块化开发
博主学习的第一个编程语言是C语言(跟谭教授学的),其实,第一接触是basic,因为博主第一个接触的系统是DOS。Dos中自带一个qbasic编译器,所以就看资料写了一个hello,word!。但很快放弃了,因为qbasic不能编译成可执行程序,需要在编程环境中才能执行,感觉不够高大上。后打听到c语言可以编译成可以直接执行的文件,便把basic放弃了,并且还产生了basic很low的主观印象;后来再次遇到basic就是visual basic,生成的exe文件好像也需要安装vb运行环境。不知道Microsoft为什么一定要这样搞!盖茨不是很重视basic么!最近在Dos及编译器的发展历史,才发现qbasic是QuickBasic的阉割版,QuickBasic是可以直接生产exe文件的。
回到正题,当初疑惑一个问题,为什么要将源码分成多个文件,每个文件编译成目标文件(obj)文件后,再通过连接程序(link)将多个目标文件连接成单个执行文件。后来通过更深入的开发一些规模稍大一点的软件,及了解计算机的发展历史后,逐渐清晰起来:
一、原因
1、首先将源码分成多个文件,最初是因为计算机早期性能较低,如果编译稍大一点的源码,需要花费较长时间。且如果出现问题,更正后还需要再花费较长时间编译,如此往复。如果将源码分成多个小文件,如果发现其中一个有问题,只需修改并重新编译这个小文件即可,更加节省时间。
2、从软件工程方面讲,将一个复杂功能分解成多个简单功能(Linux系统原则),并且由多人共同开发,可加快大型软件的开发进度。
二、多文件开发的基本问题及实例(MASM)
多个源码之间涉及到一个最基本的问题是,如何调用不同源码间的程序和数据。masm使用public和extrn共同实现,public将可以被调用的数据和程序的地址,通过标识符的形式暴露出来(即用标识符表示数据和程序的地址),否则obj文件中不包含这部分信息;extrn告诉编译器调用的数据或符号在其他obj文件中,先留足空间,待Link时再确认具体地址。
1、public语法:
public identiferName[,...]
2、extrn语法
extrn identiferName:type
type的类型有表示立即数的abs(Absolute);变量的byte、word、dword、fword、qword和tbyte;程序的near、far、proc
3、示例如下
[masm5编译通过]
title t1.asm
extrn sayGreed:proc
.model small
.stack 100h
.data
.code
start:
mov ax,@data
mov ds,ax
call sayGreed
mov ax,4c00h
int 21h
end start
title t2.asm
public sayGreed
.model small
.data
msg db "hello,world!$"
.code
sayGreed proc near
lea dx,msg
mov ah,9h
int 21h
ret
sayGreed endp
end
三、操作静态库
上例中,t1掉用t2.obj中的程序实现显示hello,world。也可将部分常用的功能写好共享出来,高级语言中(如C、Bascic等),标准库函数就是这样。但高级语言中共享的形式不是obj文件,而是静态库(LIB)文件。
什么是静态库,就是多个目标文件(obj文件)组合在一起就是lib文件,所以lib中也可能只有一个obj文件。静态库都与头文件(.h)文件配合使用,因为obj文件是二进制文件,使用者并不知道obj中暴露出来的数据或程序的标识符(即标记为pubic的标识),所以要通过头文件的形式表示出来。如上例中的:extrn sayGreed:proc就可以。
Masm中可通过Lib创建静态库,语法如下:
lib libName[/pagesize:n] [command],list-file,outputfile
libName:表示当前需要操作的库名称,没有则新建。
outputfile:表示新的库名称,如在旧库文件中添加新的obj模块后,输出到新的库中。
command:表示需要对库进行的操作,添加目标文件:+objfile;删除库中的目标文件:-objfile;替换库的中目标文件-+objfle;拷贝库中的目标文件(不指定outfile,则生成相应的ojb文件):*objfile;移动库中的目标文件(跟复制不同的是删除库中的obj):-*objfile
静态库示例:
如上例,将t2.obj添加的库mylib.lib中,并使用库来编译t1.obj,生产t.exe。
★注意:Link连接目标文件(obj)和静态库(lib)文件的区别是:链接目标文件,无论代码中是否使用obj中的代码,都要复制到exe文件中去;静态库中的有多个obj模块,主程序(t1.obj)在执行时,需要用到的obj模块,link才连接到exe文件中去。
四、拓展示例(Turbo C2.0环境)
在tc2.0中,如果通过tcc将C源码编译成obj文件,然后再通过tlink编译ojb成exe文件。tlink在生成exe文件时,需要合并c0s.obj和连接cs.lib文件(内存模式是small情况下,large模式则是c0l.obj和cl.lib类推)。
示例代码如下:
#include<stdio.h>
int main(void){
printf("hello,world!");
return 0;
}
c0s.obj中包含exe文件的初始化代码,cs.lib中某个obj模块包含printf程序的代码。