精华内容
下载资源
问答
  • 动态链接

    千次阅读 2006-10-12 20:24:00
    Windows运作机制的核心是一个称作「动态链接」的概念。Windows提供了应用程序丰富的可呼叫函数,大多数用于实作其使用者接口和在视讯显示器上显示文字和图形。这些函数采用动态链接库(Dynamic Linking Library,DLL...

    Windows运作机制的核心是一个称作「动态链接」的概念。Windows提供了应用程序丰富的可呼叫函数,大多数用于实作其使用者接口和在视讯显示器上显示文字和图形。这些函数采用动态链接库(Dynamic Linking Library,DLL)的方式撰写。这些动态链接库是些具有.DLL或者有时是.EXE扩展名的文件,在Windows 98中通常位于/WINDOWS/SYSTEM子目录中,在Windows NT中通常位于/WINNT/SYSTEM和/WINNT/SYSTEM32子目录中。

    在早期,Windows的主要部分仅通过三个动态链接库实作。这代表了Windows的三个主要子系统,它们被称作Kernel、User和GDI。当子系统的数目在Windows最近版本中增多时,大多数典型的Windows程序产生的函数呼叫仍对应到这三个模块之一。Kernel(日前由16位的KRNL386.EXE和32位的KERNEL32.DLL实现)处理所有在传统上由操作系统核心处理的事务-内存管理、文件I/O和多任务管理。User(由16位的USER.EXE和32位的USER32.DLL实作)指使用者接口,实作所有窗口运作机制。GDI(由16位的GDI.EXE和32位的GDI32.DLL实作)是一个图形设备接口,允许程序在屏幕和打印机上显示文字和图形。

    Windows 98支持应用程序可使用的上千种函数呼叫。每个函数都有一个描述名称,例如CreateWindow。该函数(如您所猜想的)为程序建立新窗口。所有应用程序可以使用的Windows函数都在表头文件里预先声明过。

    在Windows程序中,使用Windows函数的方式通常与使用如strlen等C语言链接库函数的方式相同。主要的区别在于C语言链接库函数的机械码连结到您的程序代码中,而Windows函数的程序代码在您程序执行文件外的DLL中。

    当您执行Windows程序时,它通过一个称作「动态链接」的过程与Windows相接。一个Windows的.EXE文件中有使用到的不同动态链接库的参考数据,所使用的函数即在那些动态链接库中。当Windows程序被加载到内存中时,程序中的呼叫被指向DLL函数的入口。如果该DLL不在内存中,就把它加载到内存中。

    当您连结Windows程序以产生一个可执行文件时,您必须连结程序开发环境提供的特定「引用链接库(import library)」。这些引用链接库包含了动态链接库名称和所有Windows函数呼叫的引用信息。连结程序使用该信息在.EXE文件中建立一个表格,在加载程序时,Windows使用它将呼叫转换为Windows函数。

     1、什么是动态链接库?
    它不是应用程序,不能直接运行,也不能接收消息。dll是一系列函数的集合,可以简单理解为把一些函数放到了一个文件里面,这些函数可以被其它程序和dll调用。一个dll可以同时被几个程序或其它dll调用,这应该是它的特点。
    2、windows api与dll
    windows api中的所有函数均包含在dll中,当然不会是一个dll。其中最为重要的3个windows api的dll文件是:Kernel32.dll 主要是管理内存、进程和线程的函数的集合;User32.dll 执行用户界面的任务的函数(比如:窗口的创建销毁放大缩小、消息的传递等等与用户相关的操作);GDI32.dll 包含用于画图和显示文本的各个函数;
    3、静态库和动态库
    静态库是把程序运行时需要使用的函数编译在一个二进制文件中,扩展名为.lib。当程序link时把静态库中的二进制数据和程序其它数据放到一起。程序运行时不在需要lib和dll文件的支持。这样做的坏处是开发出来的程序占用磁盘空间较大。特别是windows系统中本来就有或很多程序运行都需要的函数完全没有必要每次开发程序时都要使用各自的静态库。
    而动态库在开发时仅是把dll中的函数名和参数放到应用程序中,应用程序运行时根据函数名和参数调用dll中的函数来运行,这样操作系统中的应用程序可以同时使用同一个dll。可以有效地节省硬盘空间,当然这样做使得程序设计更有层次。也有利于软件工程师的分工和信息安全。
    4、引入库和动态库
    引入库和动态库是成对出现的,在编译dll的时候会同时产生一个引入库,扩展名为lib。lib中仅含有dll中的函数名和参数,真正的函数体在动态库中。两个的关系大概相当于.h和.cpp文件之间的关系。在编写程序的过程中
    5、引入库和静态库
    引入库和静态库的扩展名均为*.lib,但是引入库仅包含一些函数名和参数信息,没有函数体,是为调用动态库服务的,它和动态库的关系相当于.h文件和.cpp文件之间的关系;

    什么是动态链接和动态链接库

             动态链接(Dynamic Linking)是相对于静态链接(Static Linking)而言的。程序设计中,为了能做到代码和模块的重用,程序设计者常常将常用的功能函数做成库,当程序需要实现某种功能时,就直接调用库文件中的函数,从而实现了代码的重用。早期的程序设计中,可重用的函数模块以编译好的二进制代码形式放于静态库文件中,在MS的操作系统中是Lib为后缀的文件。程序编写时,如果用户程序调用到了静态库文件中的函数,则在程序编译时,编译器会自动将相关函数的二进制代码从静态库文件中复制到用户目标程序,与目标程序一起编译成可执行文件。这样做的确在编码阶段实现了代码的重用,减轻了程序设计者的负担,但并未在执行期实现重用。如一个程序a.exe使用了静态库中的 f() 函数,那么当a.exe有多个实例运行时,内存中实际上存在了多份f()的拷贝,造成了内存的浪费。
            随着技术的进步,出现了新的链接方式,即动态链接,从根本上解决了静态链接方式带来的问题。动态链接的处理方式与静态链接很相似,同样是将可重用代码放在一个单独的库文件中(在MS的操作系统中是以dll为后缀的文件,Linux下也有动态链接库,被称为Shared Object的so文件),所不同的是编译器在编译调用了动态链接库的程序时并不将库文件中的函数执行体复制到可执行文件中,而是只在可执行文件中保留一个函数调用的标记。当程序运行时,才由操作系统将动态链接库文件一并加载入内存,并映射到程序的地址空间中,这样就保证了程序能够正常调用到库文件中的函数。同时操作系统保证当程序有多个实例运行时,动态链接库也只有一份拷贝在内存中,也就是说动态链接库是在运行期共享的。
            使用动态链接方式带来了几大好处:首先是动态链接库和用户程序可以分开编写,这里的分开即可以指时间和空间的分开,也可以指开发语言的分开,这样就降低了程序的耦合度;其次由于动态链接独特的编译方式和运行方式,使得目标程序本身体积比静态链接时小,同时运行期又是共享动态链库,所以节省了磁盘存储空间和运行内存空间;最后一个是增加了程序的灵活性,可以实现诸如插件机制等功能。用过winamp的人都知道,它的很多功能都是以插件的形式提供的,这些插件就是一些动态链接库,主程序事先规定好了调用接口,只要是按照规定的调用接口写的插件,都能被winamp调用。
            WIndow 95、98、NT系列等系统都提供了动态链接库的功能,并且这些操作系统的系统调用大多都是通过动态链接库实现的,最常见的NT系列OS中的KENEL32.dll,USER32.dll,GDI32.dll等动态链接库文件就包含了大量的系统调用。在windows家族中,NT内核的操作系统在动态链接库机制上较之前的95、98系统要更安全。95、98系统在程序调用动态链接库时,将动态链接库加载到2G-3G之间的被称为进程共享空间的虚拟地址空间,并且所有进程关于这1G的虚拟地址空间的页表都是相同的,也就是说对于所有的进程,这片共享区的页表都指向同一组物理页,这样一来,加载入内存的的动态链接库对所有正在运行的进程都是可见的。如果一个动态链接库被其中一个进程更改,或其自身崩溃,将影响到所有调用它的进程,如果该动态链接库是系统的动态链接库,那么将导致系统的崩溃。在Windows NT系统中,动态链接库被映射到进程的用户地址空间中,并用Copy On Write机制保证动态链接库的共享安全,Copy On Write可以理解为写时拷贝。一般情况下,多个运行的进程还是按原来的模式共享同一个动态链接库,直到有进程需要向动态链接库的某个页面写数据时,系统将该页做一个拷贝,并将新复制页面的属性置为可读可写,最后修改进程的页表使之指向新拷贝的物理页。这样无论该进程怎么修改此页的数据,也不会影响到其他调用了此动态链接库的进程了。


    Windows下动态链接库的编写


             因为本人对linux没有太多研究,所以这里只介绍windwos环境下动态链接库的编写。
             在VC中新建一个空的Win32动态链接库工程(Win32 Domanic Library),然后添加一个C++ Sourse File到工程,我这里的文件名取DllTest.cpp。然后在文件中添加如下内容:
     //DllTest.cpp
     
     _declspec(dllexport) int add(int a,int b)
     {
      return a+b;
     }
     
     _declspec(dllexport) int subtract(int a,int b)
     {
      return a-b;
     }
            接下来编译链接,就会在debug目录下生成一个调试版本的动态链接库,该链接库包含了add和subtract两个可供外部调用的函数。我们注意到,在源文件中多了一个没有见过的语句 _declspec(dllexport) ,这个语句的作用就是向编译器指出我需要在生成的动态链接库中导出的函数,没有导出的函数是不能被其他程序调用的。要知道一个动态链接库导出了什么函数,可以在命令提示行用命令"dumpbin -exports DllTest.dll"来查看(也可以用VC工具包中的depends使用程序来查看)。以下是用dumpbin命令查看DllTest.dll而生成的信息:


    Dump of file DllTest.dll
     
    File Type: DLL
     
      Section contains the following exports for DllTest.dll
     
               0 characteristics
        4420BEA4 time date stamp Wed Mar 22 11:04:04 2006
            0.00 version
               1 ordinal base
               2 number of functions
               2 number of names
     
        ordinal hint RVA      name
     
              1    0 0000100A ?add@@YAHHH@Z
              2    1 00001005 ?subtract@@YAHHH@Z
     
      Summary
     
            7000 .data
            1000 .idata
            3000 .rdata
            2000 .reloc
           2A000 .text
     
            可以看到,我们编写的动态链接库导出了两个函数,分别名为?add@@YAHHH@Z 和 ?subtract@@YAHHH@Z,为什么名字不是addsubtract呢?这是因为C++为了支持函数的重载,会在编译时将函数的参数类型信息以及返回值类型信息加入到函数名中,这样代码中名字一样的重载函数,在经过编译后就互相区分开了,调用时函数名也经过同样的处理,就能找到对应的函数了。编译器对函数的重命名规则是与调用方式相关的,在这里采用的是C++的默认调用方式。以此对应的还有stdcall方式、cdecl方式、fastcall方式和thiscall方式,不同调用方式的重命名规则不一样。
            需要特别说一下的是stdcall方式和cdecl方式:
            stdcall方式(标准调用方式)也即pascal调用方式,它的重命名规则是函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数所占字节数,之所以要跟参数字节数,是因为stdcall采用被调函数平衡堆栈方式,用函数名最后的数字告诉编译器需要为函数平衡的字节数。例如,如果我们的DllTest.dll采用stdcall方式编译的话,导出的函数名将会是 _add@8_subtract@8 ,而函数编译后的汇编代码最后一句一定是 ret8。
            cdecl方式即C语言调用方式,它的重命名规则仅仅是在函数名前加下划线(奇怪的是我用vc6编译的c语言函数,名字没有任何改变),因为C语言采用的是调用函数平衡堆栈的方式,所以不需要在函数名中加入参数所占的字节数,这样的堆栈平衡方式也使C语言可以编写出参数不固定的函数;同时C语言不支持函数重载,因此不需要在函数名中加入参数类型信息和返回值类型信息。
            更多关于调用方式的介绍请看我收藏的文章《C语言函数调用约定 》
            动态链接库已经生成了,接下来就是调用的工作了。调用动态链接库有两种方式:隐式调用和显式调用,下面我们分别来看两种调用方式的具体过程:


    动态链接库的隐式调用


            新建一个空的Win32 Console Application,命名为DllCaller,向工程中添加名为DllCaller.cpp 的C++ Sourse File,在文件中写入如下代码:


    #include <iostream>
    using namespace std;


    //extern int add(int a,int b);
    _declspec(dllimport) int add(int a,int b);


    int main()
    {
             cout<<"3+5="<<add(3,5)<<endl;
             return 1;
    }


            编译,没有错误,链接,有两个错误:找不到外部引用符号。要怎样才能让我们的程序找到动态连接库中的函数呢?这里是关键的一步。到刚才的DllTest工程目录下,从debug文件夹中拷贝生成的DllTest.dll文件和DllTest.lib文件到DllCaller工程目录。然后依次在vc中选择菜单:Project -->Settings-->Liink, 在Object/library Modules中加入一项文件名:DllTest.lib,这里的DllTest.lib并不是静态库文件,而是DllTest.dll的导入库文件,它包含了DllTest.dll动态链接库导出的函数信息,只有在工程链接设置里添加了该文件,才能够使调用了该动态链接库的工程正确链接。完成以上步骤后,我们再编译链接工程,这次没有任何错误!程序可以顺利调用动态连接库文件,正常运行了(为了能使程序找到并加载需要的动态链接库,动态链接库文件必须与调用程序在同一个目录下,或在path环境变量指定的目录下)。
            这里需要说明一点,工程中的源文件在调用动态链接库中的函数时,需要提前声明,声名有两种方式,一种是传统的extern方式,一种是_declspec(dllimport)方式,这两种方式在代码中我都给出了。其中,第二种方式能使编译过程更快,所以推荐使用。


    动态链接库的显式调用


            比起隐式调用,显示调用更加灵活,而且在编译链接时不需要lib导入库文件,也不需要提前声明函数。我们通过windows提供的API函数来动态加载动态连接库并调用其中的函数,用完后可以马上释放内存中的动态链接库,十分方便。下面就是显示调用动态链接库的代码:


    #include <iostream>
    #include <windows.h>
    using namespace std;


    int main()
    {
             HINSTANCE hInstance=LoadLibrary("DllTest.dll");
             typedef int (*AddProc)(int,int);
             AddProc Add=(AddProc)GetProcAddress(hInstance,?add@@YAHHH@Z);
             if(!Add)
             {
                      cout<<"动态连接库库函数未找到"<<endl;
                      return 0;
             }
             cout<<"3+5="<<Add(3,5)<<endl;
             FreeLibrary(hInstance);
             return 1;
    }
            以上代码并不复杂,首先定义一个实例句柄用来引用由Windows API 函数LoadLibrary加载的动态链接库,LoadLibrary函数的参数是一个字符串指针,具体调用时我们需要填入需要加载的动态链接库的位置及文件名,加载成功后返回一个实例句柄。接下来我们定义一个函数指针类型,用该类型声明一个函数指针,用来存储GetProcAddress函数返回的动态库函数入口地址。GetProcAddress能从指定的动态库中查找指定名字的函数,如果查找成功则返回该函数的入口地址,如果失败则返回NULL。更多GetProcAddress函数的用法请参看MSDN。有人可能注意到,GetProcAddress函数中指定的函数名并不是add,而是?add@@YAHHH@Z。这里就和前面将的函数调用方式联系起来了,在GetProcAddress函数中,我们指定的函数名必须是编译后经过重命名的函数名,而不是源文件中定义的函数名。这样实际上给我们的调用带来了相当大的麻烦,因为我们不可能去了解每一个经过重命名的导出函数名。好在微软已经给出了解决方法,那就是在编写动态链接库时同时编写一个以def为后缀的编译命名参考文件,如果动态链接库工程中有该文件,则编译器会根据该文件指定的函数名来导出动态库函数,关于def文件的详细使用方法请参考MSDN,这里就不一一赘述。找到需要的动态库函数后,我们就可以按需要对它进行调用,之后调用FreeLibrary函数释放动态库。因为动态库是多进程共享的,因此调用FreeLibrary函数并不意味着动态库在内存中被释放,每个动态库都有一个变量用来记录它的共享引用计数,而FreeLibrary的功能只是将这个记数减一,只有当一个动态库的引用计数为0时,它才会被操作系统释放。
           


    隐式调用与显式调用的对比


             前面已经详细介绍了动态链接库的两种调用方法,相比之下,隐式调用在编程时比较简单,指定导入库文件后,不必考虑函数的重命名,就可以直接调用动态库函数。但由于隐式调用不能指定动态库的加载时机,因此在一个程序开始运行时,操作系统会将该程序需要的动态链接库都加载入内存,势必造成程序初始化的时间过长,影响用户体验。而显式调用采用动态加载的方法,用到什么加载什么,用完即释放,灵活性较高,可以使程序得到优化。具体运用中到底采用哪种方法,还要依实际情况而定。



    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=638156
    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=583439

     

    展开全文
  • 动态链接库在企业级开发中无处不在,本课程包含Windows动态链接库相关知识点,通过浅显易懂的代码与讲解,让你熟悉掌握动态链接库技术!
  • 动态链接

    千次阅读 2019-09-28 21:21:41
    C语言动态链接库1. 概述1.1 静态库和动态库1.2 动态链接库的优点2. 生成动态链接库2.1 windows版本2.2 Linux版本3. 调用动态链接库3.1 windows版本3.1.1 隐式调用3.1.2 显示调用(推荐)3.2 Linux版本 1. 概述 在...

    1. 概述

    在实际编程中,我们可以把完成某项功能的函数放在一个动态链接库里,然后提供给其他程序调用。

    1.1 静态库和动态库

    • 静态库:这类库的名字一般是libxxx.a,在使用静态库的情况下,在编译链接可执行文件时,链接器从静态库中复制这些函数和数据,并把它们和应用程序的其他模块组合起来创建最终的可执行文件(.exe)。当发布产品时,只需要发布这个可执行文件,并不需要发布被使用的静态库。
    • 动态库:是一种不可执行的二进制程序文件,它允许程序共享执行特殊任务所必需的代码和其他资源。Windows平台上动态链接库的后缀名是”.dll”,Linux平台上的后缀名是“.so”。Linux上动态库一般是libxxx.so;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。

    1.2 动态链接库的优点

    • 复用性:DLL的编制与具体的编程语言以及编译器无关,不同语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数
    • 可扩展性:DLL文件与EXE文件独立,只要接口不变,升级程序只需更新DLL文件不需要重新编译应用程序
    • 节省内存:如果多个应用程序使用同一个dll,该dll的页面只需要存入内存一次,所有的应用程序都可以共享它的页面,从而节省内存

    2. 生成动态链接库

    2.1 windows版本

    下面以codeblocks编译器为例,其他编译器也就是建立dll工程不一样:
    File->New->Projects->Dynamic Link library->Go
    项目的命名就是最后dll的名字,新建main.c和main.h
    main.c

    #include "main.h"
    #include <stdio.h>
    
    /* 输入年月日计算一年中第几天 */
    int Day_of_year(int year, int month, int day)
    {
       int sum,leap;
       switch(month) // 先计算某月以前月份的总天数
       {
           case 1:sum=0;break;
           case 2:sum=31;break;
           case 3:sum=59;break;
           case 4:sum=90;break;
           case 5:sum=120;break;
           case 6:sum=151;break;
           case 7:sum=181;break;
           case 8:sum=212;break;
           case 9:sum=243;break;
           case 10:sum=273;break;
           case 11:sum=304;break;
           case 12:sum=334;break;
           default:printf("data error");break;
       }
       sum=sum+day; // 再加上某天的天数
       if(year%400==0||(year%4==0&&year%100!=0)) {// 判断是不是闰年
           leap=1;
       } else {
          leap=0;
       }
       if(leap==1&&month>2) { // *如果是闰年且月份大于2,总天数应该加一天
           sum++;
       }
       return sum;
    }
    

    main.h

    #ifndef __MAIN_H__
    #define __MAIN_H__
    
    #include <windows.h>
    
    #ifdef __cplusplus
    #define EXPORT extern "C" __declspec (dllexport)
    #else
    #define EXPORT __declspec (dllexport)
    #endif // __cplusplus
    
    EXPORT int Day_of_year(int year, int month, int day);
    
    #endif // __MAIN_H__
    

    编译成功后在bin\Debug目录下生成3个文件:dll.dll,libdll.a,libdll.def

    2.2 Linux版本

    main.c

    #include "main.h"
    #include <stdio.h>
    
    /* 输入年月日计算一年中第几天 */
    int Day_of_year(int year, int month, int day)
    {
       int sum,leap;
       switch(month) // 先计算某月以前月份的总天数
       {
           case 1:sum=0;break;
           case 2:sum=31;break;
           case 3:sum=59;break;
           case 4:sum=90;break;
           case 5:sum=120;break;
           case 6:sum=151;break;
           case 7:sum=181;break;
           case 8:sum=212;break;
           case 9:sum=243;break;
           case 10:sum=273;break;
           case 11:sum=304;break;
           case 12:sum=334;break;
           default:printf("data error");break;
       }
       sum=sum+day; // 再加上某天的天数
       if(year%400==0||(year%4==0&&year%100!=0)) {// 判断是不是闰年
           leap=1;
       } else {
          leap=0;
       }
       if(leap==1&&month>2) { // *如果是闰年且月份大于2,总天数应该加一天
           sum++;
       }
       return sum;
    }
    

    main.h

    #ifndef __MAIN_H__
    #define __MAIN_H__
    
    int Day_of_year(int year, int month, int day);
    
    #endif
    

    在命令行下输入 gcc -shared -fPIC main.c -o libday.so
    即可生成一个名为libday.so的动态链接库

    3. 调用动态链接库

    3.1 windows版本

    3.1.1 隐式调用

    新建工程,把上面生成的dll.dll和libdll.a(不可缺)拷贝到新工程的bin\Debug目录下
    main.c

    #include <stdio.h>
    #include "main.h"
    int main()
    {
        printf("day = %d\n",  Day_of_year(2015,10,1) );
        system("pause");
        return 0;
    }
    

    main.h 保持一样

    #ifndef __MAIN_H__
    #define __MAIN_H__
    
    #include <windows.h>
    
    #ifdef __cplusplus
    #define EXPORT extern "C" __declspec (dllexport)
    #else
    #define EXPORT __declspec (dllexport)
    #endif // __cplusplus
    
    EXPORT int Day_of_year(int year, int month, int day);
    
    #endif // __MAIN_H__
    

    Project - Build options - Linker settings - Add 选择 bin\Debug\libdll.a - 确定,然后再编译即可
    在这里插入图片描述

    3.1.2 显示调用(推荐)

    新建工程,把dll.dll拷贝到新工程的bin\Debug目录下
    main.c

    #include <stdio.h>
    #include <windows.h>
    
    typedef int(*Getday)(int, int, int); //定义函数类型
    HINSTANCE hDll; //DLL句柄
    Getday getday;
    int main()
    {
        hDll = LoadLibrary("dll.dll"); //加载 dll
        getday = (Getday)GetProcAddress(hDll, "Day_of_year");//通过指针获取函数方法
        printf("day = %d\n",  getday(2015, 10, 1) );//调用函数
        FreeLibrary(hDll);//释放Dll句柄
        system("pause");
        return 0;
    }
    

    编译就可以使用,当dll程序升级时,只需要替换dll,而不用重新编译exe

    3.2 Linux版本

    linux版本动态链接库没有windows版本那么多文件,只有一个so文件

    3.2.1 隐式调用

    test.c

    #include <stdio.h>
    #include "main.h"
    
    int main()
    {
        printf("day = %d\n", Day_of_year(2015, 10, 1));
    }
    

    在命令行输入 gcc -o test test.c -L./ libday.so
    然后执行编译生成的可执行文件 ./test
    注意加上导出函数头文件main.h,-L指定动态链接库的搜索路径

    3.2.2 显式调用(推荐)

    test.c

    #include <stdio.h>
    #include <dlfcn.h> // 显式加载需要用到的头文件
    
    int  main()
    {
        void *pdlHandle = dlopen("./libday.so", RTLD_LAZY); // RTLD_LAZY 延迟加载
        char *pszErr = dlerror();
        if( !pdlHandle || pszErr )
        {
            printf("Load lib.so failed!\n");
            return 1;
        }
    
        int (*Day_num)() = dlsym(pdlHandle, "Day_of_year"); // 定位动态链接库中的函数
        if( !Day_num )
        {
            pszErr = dlerror();
            printf("Find symbol failed!%s\n", pszErr);
            dlclose(pdlHandle);
            return 1;
        }
    
        printf("day = %d\n", Day_num(2015, 10, 1)); // 调用动态链接库中的函数
    
        dlclose(pdlHandle); // 系统动态链接库引用数减1
    
        return 0;
    }
    

    在命令行输入 gcc -o test test.c -ldl
    然后执行编译生成的可执行文件 ./test
    优点:不必在编译时就确定要加载哪个动态链接库,可以在运行时再确定。

    3.2.3 调试案例

    1)错误一

    /tmp/ccMpgzNu.o: In function `main':
    test.c:(.text+0x13): undefined reference to `dlopen'
    test.c:(.text+0x1c): undefined reference to `dlerror'
    test.c:(.text+0x53): undefined reference to `dlsym'
    test.c:(.text+0x63): undefined reference to `dlerror'
    test.c:(.text+0x89): undefined reference to `dlclose'
    test.c:(.text+0xc7): undefined reference to `dlclose'
    collect2: error: ld returned 1 exit status
    

    解决方案:

    • 头文件添加:#include <dlfcn.h>
    • 编译选项加上- ldl,即 gcc -o test test.c -ldl ,网上有gcc -ldl -o test test.c,这种方式也是会报这个错误的

    2)错误二

    error while loading shared libraries: libtiger.so: cannot open shared object file: No such file or direct
    

    我的这段代码里则会打印Load lib.so failed!

    解决方案:

    • 在程序代码里配置路径void *pdlHandle = dlopen(“libday.so”, RTLD_LAZY);
      将动态链接库配上路径,如 ./libday.so表示可执行文件与链接库同一路径
    • 将动态链接库的目录放到程序搜索路径中,可以将库的路径加到环境变量
      export LD_LIBRARY_PATH=pwd:$LD_LIBRARY_PATH(pwd带反撇号的哈)
    • 拷贝libday.so到绝对目录 /lib 下(但是要超级用户才可以,因此要使用sudo哦)
    展开全文
  • Firebase动态链接

    千次阅读 2019-11-26 17:04:02
    Firebase 动态链接可用于多种平台,无论用户是否已经安装了您的应用,这类链接都能按照您所需的方式工作。 通过动态链接,您的用户可以在他们打开您的链接的平台上获得最佳体验。如果用户在 iOS 或 Android 上...

    Firebase 动态链接可用于多种平台,无论用户是否已经安装了您的应用,这类链接都能按照您所需的方式工作。

     

    通过动态链接,您的用户可以在他们打开您的链接的平台上获得最佳体验。如果用户在 iOS 或 Android 上打开一个动态链接,则可以直接转到您的原生应用中的链接内容。如果用户在桌面浏览器中打开相同的动态链接,则可以转到您网站上的同等内容。

    此外,无论应用是否已安装,动态链接都可以工作:如果用户在 iOS 或 Android 上打开一个动态链接,但还没有安装您的应用,则可以提示该用户安装您的应用;安装后,您的应用就会启动并可以访问该链接。

    工作原理

    您可以通过以下方法来创建动态链接:使用 Firebase 控制台;使用 REST API、iOS 版 Builder API 或 Android 版 Builder API;或者将动态链接参数添加到应用专用的域名中以生成网址。这些参数会指定您想要打开的链接,具体取决于用户所用的平台以及是否已安装您的应用。

    当用户打开您的某个动态链接时,如果他们尚未安装您的应用,系统会将其转到 Play 商店或 App Store(您也可以另行指定其他网站)来安装您的应用,安装之后该应用即会打开。然后,您就可以获取之前传递给您的应用的链接,并根据情况为您的应用适当处理该深层链接。

    自定义链接网域

    您可以使用自己的域名创建动态链接

    https://example.com/summer-sale
    https://example.com/links/promos/summer-sale
    https://links.example.com/summer-sale
    https://ex.amp.le/summer-sale
    

     

    如果您的应用没有网域,您可以使用免费的自定义 page.link 子网域:

    https://example.page.link/summer-sale

     

    在 Firebase 控制台中创建您的免费子网域。

    所有动态链接功能,包括分析、安装后归因和 SDK 集成,都支持自定义 page.link 网域和您自己的网域。

    实现流程

      设置 Firebase 和 Dynamic Links SDK 在 Firebase 控制台中为您的 Firebase 项目启用 Firebase 动态链接功能。然后,在您的应用中加入 Dynamic Links SDK。
      创建动态链接 您可以通过编程方式或使用 Firebase 控制台创建动态链接。
      在您的应用中处理动态链接 当您的应用打开时,使用 Dynamic Links SDK 来检查系统是否已将一个动态链接传递给了该应用。如果已传递,可从动态链接数据中获取该深层链接,并根据需要对其进行处理。
      查看分析数据 在 Firebase 控制台中跟踪动态链接的效果。

    后续步骤

    展开全文
  • Android 动态链接库隔离

    千次阅读 2021-02-22 22:19:07
    Android 动态链接库隔离 转链接:Android 动态链接库隔离

    Android 动态链接库隔离

    转链接:Android 动态链接库隔离
    相关问题:浅谈Android系统编译apk后so文件在dlopen时出现linker权限问题

    系统库共享

    Treble架构将系统和应用分离,应用理论上只可以访问NDK提供的本地库和应用自带的本地库。但实际上应用也经常需要使用系统库,每个应用都将系统库打包到自己中未免太浪费了。所以Android还提供了应用访问系统库的方法,通过public.libraries.txt设置白名单。

    将本地系统库的名字加入到public.libraries.txt,可以开放给应用。本地系统库放置的位置为,

    • /vendor/lib(芯片供应商的 32 位库)和 /vendor/lib64(芯片供应商的 64 位库)
    • /system/lib(设备制造商的 32 位库)和 /system/lib64(设备制造商的 64 位库)

    public.libraries.txt存在多个文件,分别代表不同的意义:

    • /vendor/etc/public.libraries.txt(芯片供应商的库)。
    • /system/etc/public.libraries-COMPANYNAME.txt(设备制造商的库),其中 COMPANYNAME 指的是制造商的名称(例如 awesome.company)。如果某些库来自外部解决方案提供商,则可以在设备中包含多个此类 .txt 文件。
    • /system/etc/public.libraries.txt(标准公共本地库),原生代码system/core/rootdir/etc/中的文件,理论上不应该修改。

    注意:由设备制造商公开的本地库必须命名为 lib*COMPANYNAME.so,例如 libFoo.awesome.company.so。换句话说,没有公司名称后缀的 libFoo.so 不得公开。库文件名中的 COMPANYNAME 必须与列出库名称的 txt 文件的名称中的 COMPANYNAME 匹配。

    从 Android 8.0 开始,供应商的本地库需要遵循以下额外限制,需要进行相应设置:

    1. 必须给供应商的本地库赋予适当的权限,以便应用可以访问。如过有任何应用(包括第三方应用)要求访问一个供应商的本地库,则该库必须在供应商特定的 file_contexts中被标记为same_process_hal_file。例如,设置libnative.so权限以供应用使用,
    /vendor/lib(64)?/libnative.so u:object_r:same_process_hal_file:s0
    
    1. 库不得依赖(无论是直接依赖,还是通过其依赖项间接依赖)VNDK-SP 库和 LLNDK 库之外的任何系统库。您可以在 development/vndk/tools/definition/tool/datasets/eligible-list–release.csv 中找到 VNDK-SP 库和 LLNDK 库的列表。
    展开全文
  • 静态链接和动态链接区别

    万次阅读 2019-09-22 22:17:18
    1.静态链接与动链接的区别 在C语言中,我们知道要生成可执行文件,必须经历两个阶段,即编译、链接。 在编译过程中,只有编译,不会涉及到链接。 在链接过程中,静态链接和...而动态链接这个过程却没有把内容链接...
  • 实现链接的方法有三种:静态链接、装入时动态链接和运行时动态链接。 ①静态链接 图5.2.2示出了经编译后所得到的三个目标模块A、B、C,他们的长度分别为 L、M、N。在模块A中,有 一条语句CALL B,用于调用模块B。在...
  • // DllImport调用动态链接库自动寻找windowsAPI kernel32.dll库包含内存管理等 [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern SafeFileHandle CreateFile(string ...
  • C++ 动态链接

    万次阅读 2021-06-01 09:01:19
    2>静态加载方式(.h .lib .dll三件套加载) 1>认识DLL(动态链接库) 动态链接库DLL(Dynamic-Link Library)通常包含程序员自定义的变量和函数, 可以在运行时动态链接到可执行文件(我们的exe程序)中。 2 >格式后缀 ...
  • 首先DLL大家应该都知道,动态链接库(Dynamic Link Library 或者 Dynamic-link Library,缩写为 DLL),不知道的网上搜一下,稍微开发过Windows程序的小白都应该比较清楚,具体的概念不是本文的重点。 动态链接 是...
  • 1. 动态链接技术的诉求来源 静态链接:从目标文件到可执行文件,将所需的所有的模板链接,最终生成单一的可执行文件模块; 动态链接:单一的可执行文件模块被拆分成若干个模块,在程序运行过程中动态进行链接的...
  • Python 调用动态链接

    千次阅读 2018-05-30 22:55:24
    Python 调用动态链接库 ctypes是Python调用c的动态链接库的一个内置模块。 通过 CMake 构建动态链接库 项目结构 ├── CMakeLists.txt # CMake 构建配置文件 ├── library.h # 动态链接库头文件 └── ...
  • 静态链接库和动态链接

    千次阅读 2017-09-05 10:50:18
    1.静态链接库和动态链接库的优缺点?共有两种链接方式: 动态链接使用动态链接库,允许可执行模块(.dll文件或.exe文件)仅包含在运行时定位DLL函数的可执行代码所需的信息。 静态链接使用静态链接库,链接器从...
  • Linux动态链接

    千次阅读 2018-05-16 11:03:57
    我开始以为动态链接器ld-linux.so.x是linux内核的一部分,其实这种想法是错误的。分析完ELF可执行文件在内核中加载启动的源码后,可以参考博主的这两篇博客Linux加载启动可执行程序的过程(一)内核空间加载ELF的...
  • 静态链接库与动态链接

    千次阅读 2014-05-31 22:37:47
    静态链接库与动态链接库 静态链接库(static link library),也就是你经常看到的*.lib文件;动态链接库(Dynamic Link Library),也就是你经常看到的*.dll文件。如果你是初学者或者对静态库与动态库还没有概念,...
  • C语言 静态链接与动态链接

    千次阅读 2020-10-15 13:45:05
    使用C 语言 静态连接与动态链接,环境:debian 10 , gcc 8.3.0 源码 //simplemath.c int max_int(int x,int y){ if (x>y){ return x; }else{ return y; } } int plus_int(int x,int y){ return x+y; } //...
  • 静态链接库、动态链接库使用方法

    千次阅读 2017-08-27 20:18:44
    总结一下动态链接库和静态链接库。
  • 动态链接库与静态链接库的区别

    千次阅读 多人点赞 2017-01-19 15:19:47
    大家都知道应用程序有两种链接方式,一种是静态链接,一种是动态链接,这两种链接方式各有好处。 所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。换句话说,函数和过程的代码...
  • 深入浅出静态链接和动态链接

    万次阅读 多人点赞 2018-05-06 09:24:48
    作为一名C/C++程序员,对于编译链接的过程要了然于胸。首先大概介绍一下,编译分为3步,首先对源文件进行预处理,这个过程主要是处理一些#号定义的命令或语句(如宏、#include、预编译指令#ifdef等),生成*.i文件;...
  • 静态链接和动态链接 1.动态库 1.1 分类 windows下:后缀为.dll的文件为动态库 linux下:后缀为.so,前缀为lib的文件为动态库 1.2 生成动态库 命令:gcc/g++   必选项的命令行参数: -shared==>...
  • Qt笔记_动态链接

    千次阅读 2018-09-16 20:26:15
    Qt程序加载动态链接库 &nbsp;&nbsp;&nbsp;&nbsp;加载动态链接库(windows下的.dll文件)的方式: 1、静态加载动态链接库 2、动态加载静态链接库 3、非完整动态链接库 1 静态加载动态链接库 1...
  • 静态链接与动态链接的区别

    千次阅读 2015-10-09 17:38:23
    链接可以分为静态链接与动态链接,下文将分别讲解这两种方式的特点与其区别。 静态链接 特点:在生成可执行文件的时候(链接阶段),把所有需要的函数的二进制代码都包含到可执行文件中去。因此,链接器需要知道...
  • 动态链接的整个过程

    千次阅读 多人点赞 2017-08-29 20:57:37
    1.静态链接的缺点 (1)同一个模块被多个模块链接时,那么这个模块在磁盘和内存中都有多个副本,导致很大一部分空间被浪费了...也就是说,把链接这个过程推迟到了运行时再进行,这就是动态链接(Dynamic Linking)的基
  • 装入时动态链接是指:用户源程序编译后,得到一组目标模块,在装入内存时,采用边装入,边链接的方式。即在装入一个目标模块时,若发生一个外部模事件,将引起装入程序去找出相应的外部目标模块,并将他装入内存。 ...
  • 我们调用动态链接库有两种方法:一种是编译的时候,指明所依赖的动态链接库,这样loader可以在程序启动的时候,来所有的动态链接映射到内存中;一种是在运行过程中,通过dlopen和dlfree的方式加载动态链接库,动态将...
  • 动态链接和静态链接的区别

    千次阅读 2018-12-16 21:16:44
    动态链接和静态链接的区别 动态链接和静态链接的区别 https://www.cnblogs.com/njczy2010/p/5793477.html 一、分别编译与链接(Linking) 大多数高级语言都支持分别编译,程序员可以显式地把程序划分为独立的...
  • 静态链接库与动态链接库区别

    千次阅读 2016-02-25 18:19:56
    一、 静态链接库与动态链接库区别 静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL ...
  • Media Encoder 动态链接

    千次阅读 2018-11-15 13:17:57
    Media Encoder 动态链接 适用情况 安装好将ME移动至其他位置(注册表信息没有改变) 由于注册表信息没有改变,默认会到注册表的安装位置寻找,因为移动,自然是找不到 免安装版(没有注册表信息) 没有注册表信息,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 803,328
精华内容 321,331
关键字:

动态链接