精华内容
下载资源
问答
  • 静态链接库反编译
    2021-05-15 15:53:24

    在实际的项目开发过程中,我们会经常碰见上下文中重复率较高的代码(函数或者功能模块等)。这样就会是整个程序代码显得十分臃肿,维护起来困难,而且可扩展性不强。为此,我们将重复性强的代码独立出来,并编译为特定的文件,让主程序是需要使用的地方调用,这种文件就成为动态链接库文件和静态链接库文件。有了这些文件能使项目中通用代码模块化,和主程序代码解耦;同时也使通用代码的复用性高,开发高效。

    程序调用静态链接库,主要是主程序在编译时期就把库文件的代码拷贝加载到编译后的目标文件,类似于宏定义,这样导致编译后的文件会膨胀,可执行文件不需要外部的调用,运行时间相对较少;而程序调用动态链接库则是在程序中保留库文件名和函数名,在运行时根据库文件和函数名去加载库所需模块,这样编译后的文件空间变化不大,但是运行时间较长。总之,静态链接库是以空间换时间,增加可执行程序代码量,减少运行时间;动态链接库则是以时间换空间,减少可执行程序代码量,增加部分运行时间。

    如何编写静态链接库

    静态连接库一般以.a结尾,假设用重用一个简单的求和函数,函数输入一个正整数,求出正整数到1之间的所有正整数之和,并生成一个sum.a的静态链接库并在主程序中调用。

    1.       编写头文件(sum.h),实现文件(sum.c)和调用主程序(test.c)。

    //sum.h

    #ifndef _SUM_H

    #define _SUM_H

    int sum(int n);

    #endif

    // sum.c

    #include “sum.h”

    int sum(int n)

    {

    if(n<1)

    return 0;

    else

    return n+sum(n-1);

    }

    //test.c

    #include

    #include “sum.h”

    int main(void)

    {

    printf(“%d\n”,sum(10));

    return 0;

    }

    2.       将sum.h和sum.c放入自己定义的库文件目录slibdir,并编译复用代码。

    gcc –c –g – fPIC sum.c –o sum.o

    注释:-fPIC指通过这个选项来生成与位置无关的代码,可以在任何地址被连接和装载;-c指只编译而不连接原程序;-g是可调试选项。

    3.       将用ar命令归档,将复用代码归档为静态连接库,格式为ar –rc。 再次提醒,注意,链接库文件名一定要以lib打头, .a(静态库)或者.so(动态库)为后缀。

    ar –rc libsum.asum.o

    4.       编译主文件,调用静态链接库。

    gcc –g –c –I slibdir test.c –o test.o  (注释:-I slibdir 为指定test.c调用头文件的目录)

    gcc –g –L slibdir test.o –o test –lsum (注释:-L slibdir 为指定静态链接库文件目录,-lsum就会在slibdir目录中寻找 libsum.a的静态链接库文件)

    如何编写动态链接库

    动态链接库的使用相对于静态链接库来说稍微复杂。通常生成的动态链接库是以 libName.so形式命名,其中Name是自己定义的名称, so也即shared object的意思。

    1.      生成动态链接库。

    同样以求和函数sum复用代码作为动态链接库的内容,并编写头文件sum.h和实现内容文件sum.cpp(这次要生成c++动态链接库),并将这两个文件放入dlibdir的目录中。编译生成动态链接库文件。

    g++ -g –shared –fPICsum.cpp –o libsum.so   (注释:-shared 表明共享选项,-fPIC与编译静态链接库一样)

    2.主程序链接动态链接库。

    2.1  动态链接库隐式调用

    动态链接库隐式调用过程就像调用静态连接库一样。编译主文件:

    g++ -c -g – Idlibdir test.cpp –o test.o

    g++ -g test.o –otest –L dlibdir –lsum

    生成 test可执行文件,但是执行 ./test 后发现报错,信息如下:

    ./test: errorwhile loading shared libraries: libsum.so: can not open shared object file: Nosuch file or directory.

    前面讲过动态链接库是在程序运行是加载,所以要加载动态链接库必须告诉其目录,这样才能加载成功。上面出错正是因为没有主程序告诉自定义的链接库目录。解决办法有以下几种:

    (1)            将libsum.so直接copy到默认的动态的链接库目录(通过 ldconfig –v 查看系统的目录),比如复制到/usr/lib目录下,在./test就成功了。

    (2)            在系统默认的库目录下建立软或硬链接,链接到dlibdir目录下的libsum.so。

    ln -s `pwd`/libsum.so /usr/lib (``是反单引号)。

    (3)            系统所有的动态链接库配置文件都在 /etc/ld.so.conf配置文件中,只要在该配置文件中添加dlibdir 目录(另起一行,不需要添加include),在重新 ldconfig 就可以,同样也可以通过命令行 ldconfig –v 来查看是否添加成功。

    (4)            利用动态链接库管理命令ldconfig,强制其搜索指定目录,并更新缓存文件,便于动态装入.  ldconfig `pwd` 。

    上述四种解决办法中(1)-(3)可以永久解决问题,但是(4)种只是临时性解决,如果在 ldconfig 之后就不行了,因为修改了/etc/ld.so.cache文件内容。

    2.2  动态链接库显示调用

    显示调用动态链接库,顾名思义就是要在主程序中显示调用库函数,要管理动态链接库的相关操作。

    动态链接库操作相关操作的头文件为 dlfcn.h (/usr/include目录下),主要有以下几个系统函数:

    (1)打开动态链接库文件函数:extern void*dlopen(const char *file, int mode) ;file 为动态链接库的文件名;mode为打开的模式,主要有两种模式:①RTLD_NOW:将共享库中的所有函数加载到内存, ②RTLD_LAZY:会推后共享库中的函数的加载操作,直到调用dlsym()时方加载某函数。如果打开成功则返回不为空。

    (2)检查执行操作后状态函数:extern char *dlerror(void); 检查操作状态,如果成功则返回空指针。

    (3)获取动态链接库中函数或全局变量地址函数:extern void *dlsym(void*handle, const char *funname); handle为动态链接库打开后的句柄,funname 为调用动态链接库的函数符号名。

    显示调用的主程序不同于隐式调用的主程序,显示调用主程序test.cpp 需要显示调用动态链接库中的函数和全局变量。假设主程序要实现隐式调用同样的功能,代码如下:

    /test.cpp 测试动态库显式调用的程式

    #include      //用于动态库管理的系统头文件

    #include

    #include "sum.h"    //要把函数的头文件包含进来,否则编译时会报错

    int main(void)

    {

    int (*pTest)(int);  //声明对应的函数的函数指针

    void *pdlHandle =dlopen("libtest.so", RTLD_LAZY);  //加载动态库

    if(pdlHandle == NULL )   {      //错误处理

    printf("Failed load library\n");

    return -1;

    }

    char* pErr = dlerror();  //检查状态

    if(pErr != NULL)

    {

    printf("%s\n", pErr);

    dlclose(pdlHandle);

    return -1;

    }

    pTest =(int(*)(int))dlsym(pdlHandle,"sum");   //获取函数的地址,记住指针类型转换,不能获取重载函数的地址(只根据函数名获取地址)

    pErr = dlerror();

    if(pErr != NULL)

    {

    printf("%s\n", pErr);

    dlclose(pdlHandle);

    return -1;

    }

    std::cout<

    dlclose(pdlHandle); //程式结束时关闭动态库

    return 0;

    }

    整个获取库函数的流程和读取流、ASCII文件相似。编译主程序:

    g++ -I dlibtest.cpp –o test –ldl; (使用-ldl选项指明生成的对象模块需要使用共享库注意 –ldl 编译选项一定要放在目标文件后面,如果放在目标文件前面,编译会报错:undefined reference to ‘dlopen’)。

    更多相关内容
  • 今天看到了之前的笔记,看到之前写的笔记,感觉自己都不认得了~~一、静态链接库(lib)首先创建 “在VC6中创建项目:Win32 Static Library”在项目中创建两个文件:xxx.h 和 xxx.cpp头文件的话就写函数声明,cpp正常来...

    今天看到了之前的笔记,看到之前写的笔记,感觉自己都不认得了~~一、静态链接库(lib)

    首先创建    “在VC6中创建项目:Win32 Static Library”

    在项目中创建两个文件:xxx.h 和 xxx.cpp

    头文件的话就写函数声明,cpp正常来写函数实现即可!

    例如:

    [C] 纯文本查看 复制代码x.h代码:int Plus(int x,int y);

    x.cpp代码 int Plus(int x,int y){

    return x+y;

    }

    通过编译,则得到x.h和x.lib头文件

    接下来创建一个普通的c语言程序引入h和lib文件即可

    8f3ff2fbfdd7c7c8339951a6542705fa.gif

    QQ截图20201201151652.png (122.49 KB, 下载次数: 2)

    2020-12-1 18:35 上传

    通过以上代码,咱们就可以使用lib里面的Plus函数了,当然,前提是要包含lib文件和头文件才可以!

    二、动态链接库

    VC6创建项目--Win32 Dynamic-Link Livrary

    之后操作和创建静态链接库一样,头文件写函数声明,Cpp文件写函数实现,这里就不反复说了。

    生成之后,导入x.lib与x.dll即可!

    8f3ff2fbfdd7c7c8339951a6542705fa.gif

    QQ截图20201201155742.png (129.13 KB, 下载次数: 0)

    2020-12-1 18:36 上传

    具体看下面代码~~~~

    1.隐式链接

    将dll和lib文件放到工程目录下面,

    将#pragma comment(lib,"dongtai.lib") 添加到调用文件中

    加入extern函数声明就可以使用了

    [C] 纯文本查看 复制代码extern "C" __declspec(dllimport) int Plus (int x,int y);

    extern "C" __declspec(dllimport) int Sub (int x,int y);

    extern "C" __declspec(dllimport) int Mul (int x,int y);

    extern "C" __declspec(dllimport) int Div (int x,int y);

    2.显示链接

    1.定义函数指针

    2.声明函数指针变量

    3.动态加载dll到内存中

    4.获取函数地址 GetProcAddress()

    5.调用函数

    [C] 纯文本查看 复制代码#include "stdafx.h"

    #include

    #pragma comment(lib,"dongtai.lib")

    /* 隐式链接

    extern "C" __declspec(dllimport) int Plus (int x,int y);

    extern "C" __declspec(dllimport) int Sub (int x,int y);

    extern "C" __declspec(dllimport) int Mul (int x,int y);

    extern "C" __declspec(dllimport) int Div (int x,int y);

    */

    //定义函数指针

    typedef int (*lpPlus)(int,int);

    typedef int (*lpSub)(int,int);

    typedef int (*lpMul)(int,int);

    typedef int (*lpDiv)(int,int);

    int main(int argc, char* argv[])

    {

    lpPlus myPlus;//声明函数指针变量

    HINSTANCE hModule = LoadLibrary("dongtai.dll");//动态加载dll到内存

    myPlus = (lpPlus)GetProcAddress(hModule,"Plus");//通过GetProcAddress获取函数地址

    printf("%d\n",myPlus(1,2));

    return 0;

    }

    经过上面的简单学习,可能还有人分不清静态与动态的区别,接下来把生成的exe文件放到OD里分析

    首先来看动态的,可以看到我们的程序是加载的dll文件,也就是说主要功能还是在dll里面,当函数要进行修正的时候,我们只需要修正dll文件即可。

    8f3ff2fbfdd7c7c8339951a6542705fa.gif

    QQ图片20201201162046.png (84.48 KB, 下载次数: 0)

    2020-12-1 18:37 上传

    静态与动态不同的区别是,静态类似于假模块化,什么是假模块呢?看似是引入了外部文件,其实在运行的时候,lib文件里的代码都贴到了exe程序里面。

    接下来看反汇编,我们的lib按道理是引入进来的,但是在程序使用的时候,地址已经到了exe里面。所以当我们的lib静态库文件修改的时候,也要重新编译我们的exe文件!

    8f3ff2fbfdd7c7c8339951a6542705fa.gif

    QQ截图20201201162319.png (80.38 KB, 下载次数: 3)

    2020-12-1 18:37 上传

    就到这啦~

    展开全文
  • VSCode开发C、C++环境搭建系列(二)——GCC/G++编译器对头文件、静态库、动态的搜索路径详解 一、从动态编译说起 下面通过一个例子来介绍如何生成一个动态。 这里有一个头文件:so_test.h, 三个.c文件...

    前言:关于Linux中环境的配置,编译等工作,有很多的坑,前面的一片文章中已经比较详细的介绍了GCC编译套件的一些东西,具体请参考:

    VSCode开发C、C++环境搭建系列(二)——GCC/G++编译器对头文件、静态库、动态库的搜索路径详解


    一、从动态库的编译说起

    下面通过一个例子来介绍如何生成一个动态库。

    这里有一个头文件:so_test.h,

    三个.c文件:test_a.c、test_b.c、test_c.c,

    我们将这几个文件编译成一个动态库:libtest.so。

    //so_test.h:
    #include "stdio.h"
    void test_a();
    void test_b();
    void test_c();
    //test_a.c:
    #include "so_test.h"
    void test_a()
    {
      printf("this is in test_a...\n");
    }
    //test_b.c:
    #include "so_test.h"
    void test_b()
    {
      printf("this is in test_b...\n");
    }
    //test_c.c:
    #include "so_test.h"
    void test_c()
    {
      printf("this is in test_c...\n");
    }


    将这几个文件编译成一个动态库:libtest.so

    $ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so

    关于gcc编译的这几个参数后面会再说明的。

    二、动态链接库的使用


    在上面的一中,我们已经成功生成了一个自己的动态链接库libtest.so,下面我们通过一个程序来调用这个库里的函数。程序的源文件为:test.c。

    //test.c:
    #include "so_test.h"
    int main()
    {
    test_a();
    test_b();
    test_c();
    return 0;
    }

    将test.c与动态库libtest.so链接生成执行文件test:

    $ gcc test.c -L. -ltest -o test

    现在生成了一个可执行文件test,那么这个可执行文件到底有没有成功链接到动态链接库呢?我么可以使用下面的命令来查看:

    ldd test

    测试是否动态连接,如果列出libtest.so,那么应该是连接正常了
    执行test,可以看到它是如何调用动态库中的函数的。

    关于ldd命令后面也会有所总结,这是一个专门查看应用程序中使用了哪一些动态链接库的程序。

    三、GCC编译参数解析


    3.1 动态编译

    最主要的是GCC命令行的一个选项:

    • (1)-shared 。该选项指定gcc编译器生成动态连接库,而不是可执行文件
    • (2)-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。正是使用这个,使得动态链接库不用再编译时拷贝库函数的完整代码,实现真正的动态链接。
    • (3)-L:指定编译的时候动态链接库的位置,这里使用  -L. 后面跟了一个点表示要连接的库在当前目录中
    • (4)-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称

    另外:

    (1)LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。

    (2)当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。

    动态链接库详细的顺序请参考前面一篇文章。

    3.2 静态编译

    注意,gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件,因此,我们在写需要连接的库时,只写名字就可以,如libmyhello.a的库,只写:-lmyhello 
     

    gcc -o hello main.c -static -L. -lmyhello 

    -static代表使用静态链接库,-L.代表静态链接库搜索路径 .代表当前路径

    3.3 动态编译可能存在的问题

    使用如下命令进行编译,使用libmyhello.so动态链接库编译成一个hello的可执行文件

    gcc -o hello main.c -L. -lmyhello

    生成hello可执行文件,注意执行的时候可能会报错,说找不到这个 
    libmyhello.so文件,如果放在/lib或者/usr/lib下,那么默认就能找到,如果放在其他目录下,需要编辑/etc/ld.so.conf文件,加入库文件所在目录的路径,然后 运行ldconfig 目录名字,该命令会重建/etc/ld.so.cache文件即可。

    注意:关于什么是 /etc/ld.so.conf、/etc/ld.so.conf.d、/etc/ld.so.cache、什么是ldconfig?后面会介绍

     

    四、Linux下静态库,动态库,以及arm平台下库的基本概念

    4.1、什么是库

    在 windows 平台和 Linux 平台下都大量存在着库。

    本质上来说库是 一种可执行代码的二进制形式,可以被操作系统载入内存执行。

    由于 windows 和 linux 的平台不同(主要是编译器、汇编器和连接器 的不同),因此二者库的二进制是不兼容的。

    本文仅限于介绍 linux 下的库。

    4.2、 库的种类

    linux 下的库有两种:静态库共享库(动态库)

    二者的不同点在于代码被载入的时刻不同。

    (1)静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。

    静态用.a为后缀, 例如: libhello.a

    (2)共享库(动态库)的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。

    动态通常用.so为后缀, 例如:libhello.so

    共享库(动态库)的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

    为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,例如: libhello.so.1.0,由于程序连接默认以.so为文件后缀名。所以为了使用这些库,通常使用建立符号连接的方式。

    ln -s libhello.so.1 libhello.so

    4.3、静态库,动态库文件在linux下是如何生成的

    以下面的代码为例,生成上面用到的hello库:

    /* hello.c */
    
    #include "hello.h"
    
    void sayhello()
    
    {
    
    printf("hello,world ");
    
    }

    首先用gcc编绎该文件,在编绎时可以使用任何合法的编绎参数,例如-g加入调试代码等:

    $gcc -c hello.c -o hello.o

    (1)生成静态库 生成静态库使用 ar工具,其实ar是archive的意思

    $ar cqs libhello.a hello.o

    (2)生成动态库 用gcc来完成,由于可能存在多个版本,因此通常指定版本号:

    $gcc -shared -o libhello.so.1.0 hello.o

    4.4、库文件是如何命名的,有没有什么规范:

    在 linux 下,库文件一般放在/usr/lib和/lib下,

    • 静态库的名字一般为libxxxx.a,其中 xxxx 是该lib的名称;
    • 动态库的名字一般为libxxxx.so.major.minor,xxxx 是该lib的名称,major是主版本号,minor是副版本号

    注意:

    在静态库和动态库中,Linux有自己的命名约定,我们在使用的时候可以使用全名,也可以使用简单缩写名,即

    • libxxxx.a    等价于 -lxxxx
    • libxxxx.so  等价于  -lxxxx

    所以如果是一个程序中需要同时链接到同名称的静态库和动态库怎么办呢?

    当一个库同时存在静态库和动态库时,比如libmysqlclient.alibmysqlclient.so同时存在时:

    在Linux下,动态库和静态库同事存在时,gcc/g++的链接程序,默认链接的动态库。

    可以使用下面的方法,给连接器传递参数,看是否链接动态库还是静态库。

    -WI,-Bstatic -llibname    //指定让gcc/g++链接静态库

    使用:

    gcc/g++ test.c -o test -WI,-Bstatic -llibname
    -WI,-Bdynamic -llibname //指定让gcc/g++链接动态库

    使用:

    gcc/g++ test.c -o test -WI,-Bdynamic -llibname

    如果要完全静态加在,使用-static参数,即将所有的库以静态的方式链入可执行程序,这样生成的可执行程序,不再依赖任何库,同事出现的问题是,这样编译出来的程序非常大,占用空间。

     

    1.5、可执行程序在执行的时候如何定位静态库与共享库(动态库)文件 :

    当系统加载可执行代码(即库文件)的时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径,此时就需要系统动态载入器 (dynamic linker/loader),一般有如下的搜索顺序

    (1)静态库链接时搜索路径的顺序:

    • ld会去找gcc/g++命令中的参数-L;ld 指的就是GNU套件中的 ld工具
    • 再找gcc的环境变量LIBRARY_PATH,它指定程序静态链接库文件搜索路径;
    • 再找默认库目录 /lib /usr/lib /usr/local/lib,这是当初compile gcc时写在程序内的。

    (2)动态链接时、执行时搜索路径顺序:

    • 编译目标代码时指定的动态库搜索路径;
    • 环境变量LD_LIBRARY_PATH指定动态库搜索路径,它指定程序动态链接库文件搜索路径;
    • 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
    • 默认的动态库搜索路径/lib;/usr/lib。

    五、一些常用的可执行程序工具

    (1)ldd工具

    使用ldd工具,查看可执行程序依赖那些动态库或着动态库依赖于那些动态库

    ldd 命令可以查看一个可执行程序依赖的共享库,

    例如

    ldd /bin/lnlibc.so.6
    
    => /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2
    
    => /lib/ld- linux.so.2 (0×40000000)

    (2)nm工具

    使用nm工具,查看静态库和动态库中有那些函数名(T类表示函数是当前库中定义的,U类表示函数是被调用的,在其它库中定义的,W类是当前库中定义,被其它库中的函数覆盖)。:

    有时候可能需要查看一个库中到底有哪些函数,nm工具可以打印出库中的涉及到的所有符号,这里的库既可以是静态的也可以是动态的。

    nm列出的符号有很多, 常见的有三种::

    • 一种是在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示;
    • 一种是在库中定义的函数,用T表示,这是最常见的;
    • 另外一种是所 谓的"弱态"符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示。

    例如,假设开发者希望知道上文提到的hello库中是否引用了 printf():

    $nm libhello.so | grep printf

    发现printf是U类符号,说明printf被引用,但是并没有在库中定义。

    由此可以推断,要正常使用hello库,必须有其它库支持,使用ldd工具查看hello依赖于哪些库:

    $ldd hello libc.so.6=>/lib/libc.so.6(0x400la000) /lib/ld-linux.so.2=>/lib/ld-linux.so.2 (0x40000000)

    从上面的结果可以继续查看printf最终在哪里被定义。

    (3)ar工具

    使用ar工具,可以生成静态库,同时可以查看静态库中包含那些.o文件,即有那些源文件构成。

    可以使用 ar -t libname.a 来查看一个静态库由那些.o文件构成。

    可以使用 ar q libname.a xxx1.o xxx2.o xxx3.o ... xxxn.o 生成静态库

    静态库的后缀是.a,它的产生分两步 

    • 由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表 
    • ar命令将很多.o转换成.a,成为静态库 

    (4)ld工具

    ld 命令是二进制工具集 GNU Binutils 的一员,是 GNU 链接器,用于将目标文件(.o)与库链接为可执行文件或库文件

    展开全文
  • 一 gcc编译过程我们知道gcc是一个强大的编译器,很多Linux下的GNU工具都是用C语言写的,并且用gcc编译的,那么gcc的编译过程是怎样的呢,先来看一个总的流程图,我自己简单画的,凑合着看 1首先是源文件经过预加载...

    一 gcc编译过程

    我们知道gcc是一个强大的编译器,很多Linux下的GNU工具都是用C语言写的,并且用gcc编译的,那么gcc的编译过程是怎样的呢,先来看一个总的流程图,我自己简单画的,凑合着看

    2dbb2fdae199995af52a3fa94dd2b2fd.png

    1首先是源文件经过预加载变成了.i结尾的文件,可以通过-E这个参数来生成这个中间文件,这里主要是把一些include的头文件和一些宏定义,放到源文件中。

    2从预加载的文件经过编译就会变成汇编语言的文件,这一步可以通过-S这个参数来生成这个中间文件

    3从汇编语言的文件通过汇编,就会变成目标代码.o的文件,这一步可以通过-C这个参数来生成这个中间文件

    4最后经过链接,生成最终的可执行文件

    可能这样说比较难懂,我们通过一个例子来说明下:

    我新建了一个hello.c的文件

    b5f58b7b240382210eb42d92392bd572.png

    然后我先生成.i结尾的预加载文件

    gcc -E hello.c -o hello.i

    243ff3c4887f4219ce43a662f42aa831.png

    我们看到这个文件生成了,我们看一下这个文件的内容

    ea53ced382a5b70925044243255de163.png

    大家会发现这个文件的内容非常多,但是最后是我们本来的代码,上面的代码都是头文件和一些宏的内容,全加载进来了

    下面我们通过编译生成汇编文件.s

    gcc -S hello.i -o hello.s

    6bfee54e7e84970851287648de6270bd.png

    然后我们看一下这个hello.s

    82582769f8d4ae05e0b725fb4745317d.png

    看到了我们熟悉的汇编语言

    我们继续,经过汇编器,生成.o的目标文件

    gcc -c hello.s -o hello.o

    459a774b2c47a376e0835d79f58bdb95.png

    依然来看下内容

    e876f45dd84e31a870f1eda696b4a486.png

    看到了一堆二进制的感觉

    最后通过链接器,生成可执行文件

    gcc hello.o -o hello

    然后执行

    f26745ad306cb869f2c7dfcff2f64964.png

    当然如果你不想做这么多步骤,直接gcc hello.c -o hello即可完成上面所有的步骤了。

    二 静态链接库和动态链接库

    静态链接库就是在程序编译的时候就被加载进来,这样的可执行文件会比较大一些,还不能共享

    动态链接库是在程序执行的时候加载,可共享

    看下面一个例子

    7d98262520ac2b18b044655b6945fd26.png

    现在有这么三个文件

    4d59226d0fa6c714e86ae3f3cf6bb419.png

    d29115169d7e9bd36dafae1bdd92f98f.png

    0f61043dbbdb770f63e97c322c3711fe.png

    如果直接编译hello.c肯定会报错,因为这里没有main函数,那么我们该怎么处理呢

    1 都编译成.o文件,然后链接,生成可执行文件

    f21cf2fd0e08ec41706e333b7660f6ec.png

    2 利用静态链接库

    在linux下,库文件一般放在/usr/lib和/lib下,

    静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称

    动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本号

    静态库的后缀是.a,它的产生分两步

    由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表

    ar命令将很多.o转换成.a,成为静态库

    ar rcs libmyhello.a hello.o

    6c827424c8dffa1e63ebf1fd7a42003f.png

    注意,gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件,因此,我们在写需要连接的库时,只写名字就可以,如libmyhello.a的库,只写:-lmyhello

    60591427396c6f845f942c063d471abe.png

    gcc -o hello main.c -static -L. -lmyhello

    -static代表使用静态链接库,-L.代表静态链接库搜索路径 .代表当前路径

    3 动态链接库

    gcc -shared -fPIC -c hello.c

    gcc -shared -fPIC -o libmyhello.so hello.o

    -share代表是动态链接库

    -fPIC命令行标记告诉GCC产生的代码不要包含对函数和变量具体内存位置的引用,这是因为现在还无法知道使用该消息代码的应用程序会将它连接到哪一段内存地址空间。这样编译出的hello.o可以被用于建立共享链接库

    最后gcc -o hello main.c -L. -lmyhello生成hello可执行文件,注意执行的时候可能会报错,说找不到这个

    libmyhello.so文件,如果放在/lib或者/usr/lib下,那么默认就能找到,如果放在其他目录下,需要编辑/etc/ld.so.conf文件,加入库文件所在目录的路径,然后

    运行ldconfig 目录名字,该命令会重建/etc/ld.so.cache文件即可。

    好了,Linux下gcc编译过程,静态链接库和动态链接库就总结到这里,如有问题,欢迎指正,谢谢。

    0b1331709591d260c1c78e86d0c51c18.png

    展开全文
  • 反编译链接库查看函数名 静态库:nm -g --defined-only libxxx.a 动态库:nm -D --defined-only libxxx.so   查看链接库之间的依赖关系 x86 ldd libxxx.so arm架构 arm-linux-readelf -d libxxx.so...
  • 目录一、空间与地址的分配1.1 相似段合并并确定装载地址1.2 确定...简单来说将各个.o的内容组织成一个可执行文件的过程就是链接,而静态链接之所以叫静态是因为是在编译期提前做好,相对的有动态链接,后面也会写文章
  • 文章目录说明一、静态链接库1.建立2.使用(1).方式一(2).方式二3汇编层,lib的调用3.静态链接库的特点二、动态链接库1.建立2.使用(1).方式一:隐身链接(2).方式二:显示链接(3).动态链接库的特点三、使用....
  • 静态链接库 符号表 strip 不strip 查看符号表 1.使用objdump命令。 objdump -tT xxx.so 2.使用nm命令(个人觉得使用nm方式查看更方便。) nm -D xxx.so # -D或-dynamic选项表示:显示动态符号。该选项仅对于动态库...
  • 在使用赛普拉斯开发USB相机时,由于官网只提供了C++的静态编译,虽然也有C#的动态库编译,但我还是想要调用C++的动态库,所以用官网提供的CyAPI_lib_cpp工程源码建立了一个动态链接库工程,其中还外加入了一个...
  • 我在c中编写了这个简单的:library.h:int sum(int a, int b);LIBRARY.C:#include ...}我用cl.exe(visual studio 2012)使用以下命令编译它:cl /c /EHsc library.cpplib library.obj它将其编译静态链接.li...
  • 的制作2.1 如何生成静态库2.1.1 书写相关函数2.1.1 静态库的命名规则2.1.2 静态库的制作2.2 动态的制作2.2.1 文件命名规则2.2.2 动态的制作2.2.3 如何让程序找到共享2.2.4 在环境变量中声明动态2.2.5 在...
  • Linux静态库与动态

    千次阅读 2021-05-15 15:27:29
    一、简介实际开发工程中,一般会有很多函数只是声明,而找不到实现的代码,因为那些实现代码已经编译了。在Linux系统中.o、.a、*.so...==.so==:为共享,是shared object,用于动态链接的,和dill差不多(共享...
  • lib静态库逆向分析

    2022-02-24 08:17:42
    当我们要分析一个lib库里的代码时,首先需要判断这是一个静态库还是一个导入库。 类型判断 lib文件其实是一个压缩文件。 我们可以直接使用7z打开lib文件,以查看里面的内容。 如果里面的内容是obj文件,表明是...
  • gcc,g++编译/制作并调用静态库,动态/makefile
  • 先来看静态链接库吧,说白了,静态链接库就是你使用的.lib文件,库中得代码最后需要连接到你的可执行文件中去,所以静态连接的可执行文件一般比较大一些。DLL的全称是Dynamic Link Library, 中文叫做“动态链接库...
  • 静态链接库(linux: .a \ win: .lib) 之所以称为 静 态 库 静态库 静态库,是因为在链接过程会将汇编生成的目标文件.o和引用用到的库一起链接打包到可执行文件中。因此对应的链接方式为静态链接。试想一下,静态库...
  • 静态编译与动态编译的区别

    千次阅读 2019-04-18 21:23:28
     动态编译的可执行文件需要附带一个的动态链接库,在执行时,需要调用其对应动态链接库中的命令。所以其优点一方面是缩小了执行文件本身的体积,另一方面是加快了编译速度,节省了系统资源。缺点一是哪怕是很简单的...
  • 主要原因:libssl.a与libcrypto.a这两个链接顺序了。 报错: 修改前的CMakeLists.txt: cmake_minimum_required(VERSION 3.4.1) set(CMAKE_VERBOSE_MAKEFILE on) file(GLOB_RECURSE SOURCES1 "...../*.cpp...
  • 很久就想写一篇关于动态静态库互相引用的一篇文章,但是总感觉准备不充分,而一直没有勇气下笔...(例如:应用用到了静态库a,而静态库a里使用了b,那么应用程序是不是只要链接a就可以了呢) 5.动态的两种加载方
  • gcc分别链接静态库和动态生成可执行文件gcc分别链接静态库和动态生成可执行文件本文分别通过链接静态库和动态编译可执行文件,在使用gcc编译的过程中了解链接静态库和动态的区别与联系,同时深入理解Linux...
  •  最近,在研究某代码时,遇到这样一个问题:整个解决方案中,有一个工程没有cpp源码,只有头文件跟一个静态链接库,虽然整个程序可以编译通过,但是lib文件中做了一些时间限制,导致程序启动的时候会弹出一个...
  • (接上篇)反编译两种可执行文件

    千次阅读 2017-11-27 20:56:28
    上篇内容介绍了静态编译生成静态库,然后链接静态库生成可执行文件的过程;也对比介绍了动态编译生成动态然后链接动态生成可执行文件的过程。我们也得出了结论: 链接静态库生成的可执行文件main运行不依赖与...
  • 如果你的系统已经按照所安装配置,那么下面的动作将正常执行:从启动菜单出进入开始->程序->MinGW->MSys->msys一个米色背景的窗口会...目录名使用正斜杠来分割,而不是Windows所使用的斜杠(象"C:/f...
  • 开发环境123cd C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat amd64# 选择架构:x86 amd64 amd64_x86set PATH=D:...%PATH%# 设置Perl所在路径到环境变量静态编译zlib123cd D:\test\zlib-1....
  • 35.静态链接库和动态链接库

    千次阅读 2016-07-02 11:05:16
    35.1.函数库的前世今生 35.2.静态库和动态库 35.3.字符串库函数 35.4.数学库函数 35.5.自己制作静态链接库并使用 35.6.自己制作动态链接库并使用
  • GCC生成静态库和动态

    千次阅读 2021-10-17 19:13:35
    1)阅读、理解和学习材料“用gcc生成静态库和动态.pdf”和“静态库.a与.so文件的生成与使用.pdf”,请在Linux系统(Ubuntu)下如实仿做一遍。 (1) 第 1 步:编辑生成例子程序 hello.h、hello.c 和 main.c。 先...
  • .a文件即静态库文件,静态库文件把.o文件打包,一方面易于移植使用,一方面可以保护源码不被汇编或者被泄露。 ps:arduino推崇开源共享,非必要情况下建议大家开源源码,使用他人制作静态库需遵循开源许可。 1 ...
  • C编译器编译hello.c的四个阶段Stage 1. 预处理Stage 2. 编译Stage 3. 汇编Stage 4. 链接结束语  本文展示一个hello.c源文件在linux系统下被翻译成可执行目标文件的四个阶段。本文中的操作在 Ubuntu18.04 LTS,64-bit...
  • GCC编译步骤及静态库动态制作

    千次阅读 2019-08-20 22:27:08
    GCC编译的4个步骤 -D:编译的之后添加宏定义 //测试gcc -D选项,编译的时候指定宏定义. #include<stdio.h> int main(int argc, char const *argv[]) { #ifdef DEBUG printf("hello\n"); #else printf...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 43,368
精华内容 17,347
热门标签
关键字:

静态链接库反编译