这篇东西属于科普类的吧?

看着感觉听不错转载过来了

原文链接:http://www.55zm.com/a/20120215/23605.htm

下面是正文

摘要:本课中,我们将学习DLLs,它们到底是什么和如何创建它们。 理论: 如果您编程的时间非常长,就会发现很多的程序之间其实有相当多的重复代码。每编一个程序就重写一遍这些代码既没必要又浪费时间。在DOS时代,一般的做法是把这些重复的代码写成一个个的函数,

本课中,我们将学习DLLs,它们到底是什么和如何创建它们。

理论:

如果您编程的时间非常长,就会发现很多的程序之间其实有相当多的重复代码。每编一个程序就重写一遍这些代码既没必要又浪费时间。在DOS时代,一般的做法是把这些重复的代码写成一个个的函数,然后把它们按类别放到不同的库文件中去。当要使用这些函数时,只要把您的目标文件(.obj)文件和先前存放在库文件中的函数进行链接,链接时链接器会从库文件中抽取相关的信息并把它们插入到可执行文件中去。这个过程叫做静态链接。C运行时库就是一个好例子。这样的库的缺点是您在每一个调用库函数的程序中都必须嵌入同一函数的拷贝,这显然很浪费磁盘。在DOS时代毕竟每一时刻仅有一个程序在运行,所以浪费的还只是磁盘而已,在多任务的WINDOWS时代就不仅浪费磁盘,还要浪费宝贵的内存了。

在WINDOWS中,由于有多个程序同时运行,如果您的程序非常大的话,那将消耗相当多的内存。WINDOWS的解决办法是:使用动态链接库。动态链接库从表面上看也是一大堆的通用函数,不过即使有多个程序调用了它,在内存中也仅仅只有动态链接库的唯一一份拷贝。WINDOWS是通过分页机制来作到这一点的。当然,库的代码只有一份,但是每一个应用程序要有自己单独的数据段,要么就会乱掉。

不象旧时的静态链接库,它并不会把这些函数的可执行代码放入到应用程序中去,而是当程序已经在内存中运行时,如果需要调用该函数时才调入内存也即链接。这也就是为什么把它叫做“动态”的原因所在。另外您还可以动态地卸载动态链接库,当然要求这时没有其它的应用程序在使用它,否则就要一直等到最后一个使用它的函数也不再使用该动态链接库时才能去卸载它。

为了正确的调用库和给库函数分配内存空间,在编译和链接应用程序时,必须把重定位等一些消息插入到执行代码中去,以便载入正确的库,并给库函数分配正确的地址。

那么这些信息从哪里得到呢?引入库。引入库包含足够的信息,链接器从中抽取足够的信息(注意区别:静态链接库放入的是可执行代码)把它们放入到可执行文件中去。当WINDOWS的加载器装入应用程序查看到有DLL时,它会查找该库文件,如果没有查到,就报错退出,否则就把它映射进进程的地址空间,并修正函数调用语句的地址。

如果没有引入库呢?当然我们也可以调用动态链接库中的任意函数。只不过您必须知道调用的函数是否在库中而且是否在库的引出名字表中,另外还需要知道该函数的参数个数和参数的类型。

(译者加:说到这里,让我想起了一件很有名的事。<<Undocumented Windows>>一书的作者Angel Schudleman 曾经利用此方法来跟踪微软Win3x系统动态链接库中未公开的函数,因为在微软给程序员提供的系统动态链接库的引入库中没有提供这些函数的原型,所以您无法在链接时把这些函数的信息链接到可执行文件中去,而为了某种目的您又要使用这些函数,您就可以在执行时加载动态链接库并得到这些函数的地址,从而和调用其它的库函数一样使用这些未公开的函数。由于这本书的巨大影响,当时许多程序员纷纷在它们的程序中调用未公开函数,甚至在写商业程序时也这么做。这种走偏峰的做法引起了微软的反感,后来微软在它Win3x的改进版中不再把那些未公开函数列入系统动态链接库的引出名字表,这样也就无法再利用这种方法来调用未公开的函数了。)

当您让系统的加载器为您加载动态库时,如果不能找到库文件,它就会提示一条“A required .DLL file, xxxxx.dll is missing”,这样您的应用程序就无法运行,即使该库对您的应用程序来说并不重要。

如果您选择在程序运行时自己加载该库,就没有这种问题了。

如果您知道足够的信息,就可以调用系统未公开的函数。

如果您调用LoadLibrary函数加载库,就必须再调用GetProcAddress函数来得到每一个您想调用的函数的地址,GetProcAddress会在动态链接库中查找函数的入口地址。由于多余的步骤,这样您的程序执行起来会慢一点,但是并不明显。

明白了LoadLibrary函数的优缺点,下面我们就来看看如何产生一个动态链接库。下面的代码是一个动态链接库的框架:

;--------------------------------------------------------------------------------------

; DLLSkeleton.asm

;--------------------------------------------------------------------------------------

.386

.model flat,stdcall

option casemap:none

include \masm32\include\windows.inc

include \masm32\include\user32.inc

include \masm32\include\kernel32.inc

includelib \masm32\lib\user32.lib

includelib \masm32\lib\kernel32.lib

.data

.code

DllEntry proc hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD

mov eax,TRUE

ret

DllEntry Endp

;---------------------------------------------------------------------------------------------------

;下面是一个空函数,您可以象下面一样插入您的函数。

;----------------------------------------------------------------------------------------------------

TestFunction proc

ret

TestFunction endp

End DllEntry

;-------------------------------------------------------------------------------------

; DLLSkeleton.def

;-------------------------------------------------------------------------------------

LIBRARY DLLSkeleton

EXPORTS TestFunction

上面是一个动态链接库的框架,每一个DLL必须有一个入口点函数,WINDOWS每一次在做下面的动作时会调用该入口点函数:

当动态链接库被加载时

当动态链接库卸载时

同一进程的线程生成时

同一进程的线程退出时

DllEntry proc hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD

mov eax,TRUE

ret

DllEntry Endp

入口点函数的名称无所谓只要您让语句“END<函数名>”中的函数名和前面的相同就可以了。该函数共有三个参数,只有前面两个是重要的。

hInstDLL是该动态链接库模块的句柄。它和进程的实例句柄不一样。如果您以后要用,可以保存它,因为以后再要获得它不容易。

根据不同的时机,reason传入的值可能是下面的四个值中的一个:

DLL_PROCESS_ATTACH 动态链接库第一次插入进程的地址空间时。当传入的参数是该值时,您可以做一些初始化的工作。

DLL_PROCESS_DETACH 动态链接库从进程的地址空间卸出时。您可以在此做一些清理的工作。譬如:释放内存等。

DLL_THREAD_ATTACH 新线程生成。

DLL_THREAD_DETACH 线程销毁。

如果想要库中的代码继续执行,返回TRUE,否则返回FALSE,那样动态链接库就不会加载了。譬如:您想分配一块内存,如果不成功的话就退出,这时您就可以返回FALSE。那样动态链接库就不会加载了。

您可以加入的函数,它们的位置并不重要,把它们放在入口点函数的前面或后面都可以。只是如果您想要它们能被其它的程序调用的话,就必须把它们的名字放到模块定义文件(.def)中去。

动态链接库在它们自己的编译过程就需要,而不只是提供给其它要引用它的程序参考。他们如下:

LIBRARY DLLSkeleton

EXPORTS TestFunction

第一行是必须的。LIBRARY 定义了DLL的模块名称。它必须和动态链接库的名称相同。

EXPORTS关键字告诉链接器该DLL的引出函数,也就是其它程序可以调用的函数。举个例子:其它的程序想要调用函数TestFunction ,我们就把它放到EXPORTS中。

还有就是,链接器的选项中必须放入开关项:/DLL 和/DEF<DLL文件名>,就像下面这样:

link /DLL /SUBSYSTEM:WINDOWS /DEF:DLLSkeleton.def /LIBPATH:c:\masm32\lib DLLSkeleton.obj

编译器的开关选项是一样的,即:/c /coff /Cp。在您链接好后,链接器会生成.lib 和.dll文件。前者是引入库,当其它的程序要调用您的动态链接库中的函数时就需要该引入库,以便把必要的信息加入到其可执行文件中去。

接下来我们来看看如何使用LoadLibrary函数来加载一个DLL。

;---------------------------------------------------------------------------------------------

; UseDLL.asm

;----------------------------------------------------------------------------------------------

.386

.model flat,stdcall

option casemap:none

include \masm32\include\windows.inc

include \masm32\include\user32.inc

include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

includelib \masm32\lib\user32.lib

.data

LibName db "DLLSkeleton.dll",0

FunctionName db "TestHello",0

DllNotFound db "Cannot load library",0

AppName db "Load Library",0

FunctionNotFound db "TestHello function not found",0

.data?

hLib dd ? ; 动态链接库的句柄 (DLL)

TestHelloAddr dd ? ; TestHello 函数的地址

.code

start:

invoke LoadLibrary,addr LibName

;---------------------------------------------------------------------------------------------------------

; 调用LoadLibrary,其参数是欲加载的动态链接库的名称。如果调用成功,将返回该DLL的句柄。 否则返回NULL。该句柄可以传给 :library函数和其它需要动态链接库句柄的函数。

;-----------------------------------------------------------------------------------------------------------

.if eax==NULL

invoke MessageBox,NULL,addr DllNotFound,addr AppName,MB_OK

.else

mov hLib,eax

invoke GetProcAddress,hLib,addr FunctionName

;-----------------------------------------------------------------------------------------------------------

; 当您得到了动态链接库的句柄后,把它传给GetProcAddress函数,再把您要调用的函数的名称 也传给该函数。如果成功的话,它:会返回想要的函数的地址,失败的话返回NULL。除非卸载该

(原文出处:吾吾织梦WwW.55zM.CoM)

l

汇编教程之动态链接库相关推荐

  1. 汇编为什么分段执行总是执行不了_iOS汇编教程(六)CPU 指令重排与内存屏障...

    系列文章 iOS 汇编入门教程(一)ARM64 汇编基础 iOS 汇编入门教程(二)在 Xcode 工程中嵌入汇编代码 iOS 汇编入门教程(三)汇编中的 Section 与数据存取 iOS 汇编教程 ...

  2. 性能比拼!超详细的Tengine GEMM矩阵乘法汇编教程

    点击我爱计算机视觉标星,更快获取CVML新技术 Tengine 是OPEN AI LAB 针对前端智能设备开发的软件开发包,核心部分是一个轻量级,模块化,高性能的AI 推断引擎,并支持用DLA.GPU ...

  3. linux 编译汇编,linux下的汇编教程

    linux下的汇编教程 第一部分 Linux下ARM汇编语法尽管在Linux下使用C或C++编写程序很方便,但汇编源程序用于系统最基本的初始化,如初始化堆栈指针.设置页表.操作 ARM的协处理器等.初 ...

  4. iOS汇编教程:ARM(2)

    感谢唐巧抽出时间对本文进行double-check. 本文是iOS汇编教程:ARM第二篇. iOS汇编教程:ARM目录如下[共分为两篇]: iOS汇编教程:ARM(1) 开始:什么是汇编 函数调用约定 ...

  5. Linux汇编教程04:寻址方式

    Linux汇编教程04:寻址方式 这一节,我们主要来讨论寻址方式,这一点十分重要. 我们上一节有稍微提了一下,内存地址引用的通用格式: 地址或偏移(%基址寄存器, %索引寄存器, 比例因子 ) 结果地 ...

  6. stc_8051_汇编教程_翻译

    因为最近在弄8051的汇编程序,但是发现网上没有专门的教程,所以我就找了一篇英语的入门手册渣翻了一下...方便自己方便大家嘛... 介绍 汇编语言是介于机器语言和高级语言(如Pascal或C)之间的一 ...

  7. att汇编教程 linux,ATT 汇编语法

    6 个段寄存器:%cs(code),%ds(data),%ss(stack), %es,%fs,%gs; 3 个控制寄存器:%cr0,%cr2,%cr3; 6 个 debug 寄存器:%db0,%db ...

  8. att汇编教程 linux,att 汇编 helloworld

    博主在 archlinux x86_64 下测试, gcc版本 Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/g ...

  9. linux 汇编 教程,Linux下实现 MASM汇编

    sudo apt-get install dosbox 步骤二:打开DOSbox,模拟C盘,在DOSbox输入 mount c /home/bao/ms-dos c 后面为自己指定的Linux下的目录 ...

最新文章

  1. Service Manager 的系统要求
  2. 算法也是颜值控,Twitter AI更青睐肤白貌美图
  3. 【AMAD】import-string -- 通过字符串来import一个对象
  4. 玩转百度地图(二)之画圆,高德地图、搜搜地图、搜狗地图等稍微修改即可...
  5. Python视频制作工具Manim入门,文本使用详细介绍
  6. es6语法-箭头函数
  7. 惠新宸php教程_惠新宸:首位国人加入PHP语言官方开发组
  8. Android_Kotlin 代码学习
  9. Spring中注解大全
  10. NVIDIA发布三款新品,各自侧重点有何不同? | GTC China 2016
  11. Android系统(23)---Android 应用分屏
  12. ajax异步下载文件并判断状态
  13. 对费曼来说,“不可能”意味着什么?
  14. python实现爬虫收集图片 花瓣网_利用Python抓取花瓣网美图实例
  15. STM32应用开发实践教程:初识STM32
  16. axios 封装数据请求
  17. bootice添加黑苹果引导_手把手教你安装黑苹果之U盘安装篇
  18. Android Studio连接安卓模拟器教程
  19. kafka数据同步Elasticsearch深入详解
  20. GNSS抗干扰和GNSS抗欺骗

热门文章

  1. 【Android UI】Path 测量 PathMeasure ② ( PathMeasure API 简介 | nextContour 函数 | getPosTan 函数 ★ | 曲线切线处理 )
  2. 博学谷java单选题_java单选题库 博学谷
  3. 揭开集成芯片的面纱:物理意义上的
  4. python 图灵完备_微软:进化版Excel已是图灵完备的语言
  5. 面试官:对于 JavaScript 的加载问题你怎杨理解?
  6. tzoj3315 买火车票(线段树+区间修改+区间查询)
  7. 名创优品搭建私域流量池,公众号引流企微,实现社群粉丝快速增长
  8. 普通中学生的心理特点
  9. SpringBoot集成Mybatis项目实操
  10. VCIP2020:VVC中的ACT