一,首先编写DLL (建win32空DLL工程)
头文件.h
extern "C" _declspec(dllexport) int Max(int a, int b); //extern "C"解决函数名由于不同编译器造成的名字匹配问题,通常c++编译器编译时会对函数进行改名,而c编译器不会
extern "C" _declspec(dllexport) int Min(int a, int b); //_declspec(dllexport)说明该函数为导出函数
实现文件.cpp
#include"TestDLL.h"
int Max(int a, int b)
{
return (a > b?a:b);
}
int Min(int a, int b)
{
return (a > b?b:a);
}
二,编程测试DLL的工程(建win32 空工程)
1,静态加载dll
a。将dll工程下的dll和lib文件拷到测试工程下
b。同时编写头文件.h
extern "C" _declspec(dllimport) int Max(int a, int b); //_declspec(dllimport)说明函数为导入函数
extern "C" _declspec(dllimport) int Min(int a, int b);
c。编写实现文件.cpp
#include "test.h"
#include
using namespace std;
#pragma comment(lib,"TestDLL001.lib")
int main()
{
int a=Min(3,4);
cout< system("pause");
return 0;
}
2.动态加载dll(仅用包含dll文件,同时不需要.h文件和lib文件)
a。将dll工程下的dll文件拷贝到测试工程下
b。编写实现文件.cpp
#include
#include
using namespace std;
int main()
{
HINSTANCE his = LoadLibraryA("TestDLL001.dll"); //用于加载dll
typedef int(*pmin)(int a, int b);
pmin mmi=(pmin)GetProcAddress(his, "Min"); //GetProcAddress()用于获得函数地址
int aa=mmi(3,4);
cout<
system("pause");
return 0;
}
C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接。编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程。链接是把目标文件、操作系统的启动代码和用到的库文件进行组织形成最终生成可加载、可执行代码的过程。
过程图解如下:
编译过程又可以分成两个阶段:编译和汇编。
编译是指编译器读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码。
源文件的编译过程包含两个主要阶段:
第一个阶段是预处理阶段,在正式的编译阶段之前进行。预处理阶段将根据已放置在文件中的预处理指令来修改源文件的内容。
主要是以下几方面的处理:
头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用,这涉及到头文件的定位即搜索路径问题。头文件搜索规则如下:
第二个阶段编译、优化阶段,编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。
汇编实际上指汇编器(as)把汇编语言代码翻译成目标机器指令的过程。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。目标文件由段组成。通常一个目标文件中至少有两个段:
静态库(static library)就是将相关的目标模块打包形成的单独的文件。使用ar命令。
静态库的优点在于:
动态库(dynamic library)是一种特殊的目标模块,它可以在运行时被加载到任意的内存地址,或者是与任意的程序进行链接。
动态库的优点在于:
链接器主要是将有关的目标文件彼此相连接生成可加载、可执行的目标文件。链接器的核心工作就是符号表解析和重定位。
链接器将函数的代码从其所在地(目标文件或静态链接库中)拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
为创建可执行文件,链接器必须要完成的主要任务:
关于符号表和符号解析以及重定位的分析后续学习。
在此种方式下,函数的定义在动态链接库或共享对象的目标文件中。在编译的链接阶段,动态链接库只提供符号表和其他少量信息用于保证所有符号引用都有定义,保证编译顺利通过。动态链接器(ld-linux.so)链接程序在运行过程中根据记录的共享对象的符号定义来动态加载共享库,然后完成重定位。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
加载器把可执行文件从外存加载到内存并进行执行。 Linux中进程运行时的内存映像如下:
加载过程如下:
加载器首先创建如上图所示的内存映像,然后根据段头部表,把目标文件拷贝到内存的数据和代码段中。然后,加载器跳转到程序入口点(即符号_start 的地址),执行启动代码(startup code),启动代码的调用顺序如所示:
UNIX系统提供了一系列工具帮助理解和处理目标文件。GNUbinutils 包也提供了很多帮助。这些工具包括: