动态库、可执行文件符号表分析&编译问题

  • Post author:
  • Post category:其他


动态库内容分析

文章目录

动态库内容分析

1. 动态库编译

1.1 第一个C文件:basic.c

1.2第二个C文件:demo.c

1.3第三个C文件:main.c

2.动态库编译

3.二进制内容分析

3.1 libbasic.so分析

3.1.1 basic.c内容汇总

3.1.2 libbasic.so符号表

3.1.3 小结

3.2 libdemo.so分析

3.2.1 demo.c内容汇总

3.2.2 demo.so符号表

3.2.3 小结

3.3 可执行文件a.out分析

3.3.1 main.c内容汇总

3.3.2 a.out符号表

3.3.3 小结

4.总结

1. 动态库编译

基本思路为:

先编写两个C文件,其中各自实现几个函数,变量,然后将其分别编译为动态库;

再编写一个实现main函数的C文件,分别调用上述第一步动态库中的函数;

分析最后的可执行文件和动态库文件的符号表;

1.1 第一个C文件:basic.c

这个C文件只定义并实现了四个不同形参的函数、五个静态变量、一个全局变量。由于只关心符号表或者其他二进制内容,因此不具体实现特定功能。

/*************************************************************************

> File Name: basic.c

> Author: Toney Sun

> Mail: vip_13031075266@163.com

> Created Time: 2020年04月20日 星期一 09时50分51秒

************************************************************************/

#include<stdio.h>

int basic_func=4;

static char *Author=”Toney Sun”;

void func1()

{


int tmp_var;

static char *Mail=”vip_13031075266@163.com”;

}

void func2(int x)

{


static char *Mail=”vip_13031075266@163.com”;

}

int func3(char *a)

{


static char *Mail=”vip_13031075266@163.com”;

}

char * func4(int x, int y)

{


static char *Mail=”vip_13031075266@163.com”;

}

1.2第二个C文件:demo.c

​ 在demo.c中我定义一个结构体udphdr。然后分别定义了两个全局变量,实现了三个函数:func5, func6, fun7。

/*************************************************************************

> File Name: demo.c

> Author: Toney Sun

> Mail: vip_13031075266@163.com

> Created Time: 2020年04月19日 星期日 22时33分39秒

************************************************************************/

#include<stdio.h>

struct udphdr{


short dstport;

short srcport;

short checksum;

short length;

};

enum Date{


Monday,

Tuesday,

Wensday,

Thursday,

Friday,

Saturday,

Sunday,

};

struct udphdr udp1;

enum Date today = Monday;

int iphdr1=10;

extern void func1();

extern void func2(int x);

extern int func3(char *);

extern char * func4(int x, int y);

int fun5(int a)

{


struct udphdr udp2;

func1();

printf(“aaaaaaaaaaa\n”);

}

int fun6(char *a)

{


static struct udphdr udp1;

func2(10);

printf(“aaaaaaaaaaa\n”);

}

int fun7(int a, char *b)

{


func3(“test”);

printf(“aaaaaaaaaaa\n”);

}

1.3第三个C文件:main.c

​ main.c主要用来实现main函数,并调用其他C文件中实现的函数和全局变量。从而观察对比不同的函数、变量在符号表中的异同。

/*************************************************************************

> File Name: main.c

> Author: Toney Sun

> Mail: vip_13031075266@163.com

> Created Time: 2020年04月20日 星期一 09时44分38秒

************************************************************************/

#include<stdio.h>

extern void func1();

extern int fun5(int a);

extern int fun6(char *a);

extern int fun7(int a, char *b);

extern struct udphdr udp;

extern int iphdr;

int myAge=25;

char *mail=”vip_13031075266@163.com”;

int show()

{


printf(“Author: Toney Sun\n”);

}

int main(int argc, char **argv)

{


int a=10;

int b=11;

fun5(a);

fun6(“aaaaa”);

fun7(a, “Toney Sun”);

show();

udp.srcport=4500;

iphdr=10;

return 0;

}

2.动态库编译

使用gcc工具将basic.c编译为libbasic.so;

使用gcc工具将demo.c编译为libdemo.so;

使用gcc工具将main.c链接上述两个动态库后编译为a.out

**注意:**我们不是为了执行该a.out, 而是想查看上述三个二进制文件的内容(符号表)。

toney@ubantu$ gcc -shared -fpic -o libdemo.so demo.c

toney@ubantu$ gcc -shared -fpic -o libbasic.so basic.c

toney@ubantu$ gcc main.c -L./ -ldemo -lbasic

toney@ubantu$ ls -l

total 35

-rwxrwxrwx 1 root root 8552 4月  20 10:18 a.out

-rwxrwxrwx 1 root root  454 4月  20 09:52 basic.c

-rwxrwxrwx 1 root root  763 4月  20 09:49 demo.c

-rwxrwxrwx 1 root root 8016 4月  20 09:43 demo.so

-rwxrwxrwx 1 root root 7528 4月  20 10:17 libbasic.so

-rwxrwxrwx 1 root root 8128 4月  20 10:17 libdemo.so

-rwxrwxrwx 1 root root  846 4月  20 10:18 main.c

链接怎么还有个顺序问题:(

toney@ubantu$ gcc main.c -L./ -lbasic -ldemo

.//libdemo.so: undefined reference to `func3′

.//libdemo.so: undefined reference to `func1′

.//libdemo.so: undefined reference to `func2′

collect2: error: ld returned 1 exit status

toney@ubantu$ gcc main.c -L./ -ldemo -lbasic

toney@ubantu$

3.二进制内容分析

3.1 libbasic.so分析

3.1.1 basic.c内容汇总

序号    函数或变量    性质

1    void func1()    自定义函数

2    void func2(int x)    自定义函数

3    int func3(char *a)    自定义函数

4    char * func4(int x, int y)    自定义函数

5    int basic_func;    自定义全局变量

6    static char *Author;    自定义全局静态变量

7    static char *Mail;    func1内定义局部静态变量

8    static char *Mail;    func2内定义局部静态变量

9    static char *Mail;    func3内定义局部静态变量

10    static char *Mail;    func4内定义局部静态变量

3.1.2 libbasic.so符号表

使用nm工具查看符号表内容(当然也可以使用其他工具查看,例如objdump, readelf, ldd等):

toney@ubantu$ nm libbasic.so

0000000000201028 d Author        ==================全局静态变量=================

0000000000201020 D basic_func    ====================全局变量==================

0000000000201050 B __bss_start

0000000000201050 b completed.7698

w __cxa_finalize

00000000000005a0 t deregister_tm_clones

0000000000000630 t __do_global_dtors_aux

0000000000200e88 t __do_global_dtors_aux_fini_array_entry

0000000000201018 d __dso_handle

0000000000200e90 d _DYNAMIC

0000000000201050 D _edata

0000000000201058 B _end

00000000000006a4 T _fini

0000000000000670 t frame_dummy

0000000000200e80 t __frame_dummy_init_array_entry

00000000000007e8 r __FRAME_END__

000000000000067a T func1        ===================实现函数===================

0000000000000681 T func2        ===================实现函数===================

000000000000068b T func3        ===================实现函数===================

0000000000000696 T func4        ===================实现函数===================

0000000000201000 d _GLOBAL_OFFSET_TABLE_

w __gmon_start__

00000000000006d0 r __GNU_EH_FRAME_HDR

0000000000000568 T _init

w _ITM_deregisterTMCloneTable

w _ITM_registerTMCloneTable

0000000000201030 d Mail.2252    ================局部静态变量===================

0000000000201038 d Mail.2256    ================局部静态变量===================

0000000000201040 d Mail.2260    ================局部静态变量===================

0000000000201048 d Mail.2265    ================局部静态变量===================

00000000000005e0 t register_tm_clones

0000000000201050 d __TMC_END__


使用nm -Da 查看本动态库定义的内容信息

toney@ubantu$ nm -Da libbasic.so

0000000000201020 D basic_func        —————-1—————-

0000000000201050 B __bss_start

w __cxa_finalize

0000000000201050 D _edata

0000000000201058 B _end

00000000000006a4 T _fini

000000000000067a T func1            —————-2—————-

0000000000000681 T func2            —————-3—————-

000000000000068b T func3            —————-4—————-

0000000000000696 T func4            —————-5—————-

w __gmon_start__

0000000000000568 T _init

w _ITM_deregisterTMCloneTable

w _ITM_registerTMCloneTable

3.1.3 小结

本文件内定义的全局变量用‘D’来表示;

本文件内定义的全局静态变量用‘d’来表示;

本文件内实现的函数用‘T’来表示;

不同函数内定义的静态变量在符号表中的符号有所差别,因此不会出现混淆的问题。

从上述内容可以猜测:使用‘d’表示的变量不能被其他文件引用(上述‘d’标识的都是静态变量,这也比较合理)

3.2 libdemo.so分析

3.2.1 demo.c内容汇总

序号    函数或变量    性质

1    struct udphdr udp1;    自定义的全局结构体变量

2    static struct udphdr udp2;    自定义全局静态变量

3    struct udphdr udp2;    自定义局部变量

4    enum Date today    自定义全局枚举变量

5    int iphdr;    自定义全局变量

6    extern void func1();    外部函数

7    extern void func2(int x);    外部函数

8    extern int func3(char *);    外部函数

9    extern char * func4(int x, int y);    外部函数

10    int fun5(int a)    自定义函数

11    int fun6(char *a)    自定义函数

12    int fun7(int a, char *b)    自定义函数

3.2.2 demo.so符号表

同样的,我们使用nm工具来查看动态库符号表信息:

toney@ubantu$ nm libdemo.so

0000000000201044 B __bss_start

0000000000201048 b completed.7698

w __cxa_finalize@@GLIBC_2.2.5

00000000000006b0 t deregister_tm_clones

0000000000000740 t __do_global_dtors_aux

0000000000200e18 t __do_global_dtors_aux_fini_array_entry

0000000000201038 d __dso_handle

0000000000200e20 d _DYNAMIC

0000000000201044 D _edata

0000000000201068 B _end

0000000000000800 T _fini

0000000000000780 t frame_dummy

0000000000200e10 t __frame_dummy_init_array_entry

0000000000000908 r __FRAME_END__

000000000000078a T fun5                            =============================

00000000000007ae T fun6                            =============================

00000000000007d3 T fun7                            =============================

U func1                        =============================

U func2                        =============================

U func3                        =============================

0000000000201000 d _GLOBAL_OFFSET_TABLE_

w __gmon_start__

000000000000081c r __GNU_EH_FRAME_HDR

0000000000000638 T _init

0000000000201040 D iphdr1                        =============================

w _ITM_deregisterTMCloneTable

w _ITM_registerTMCloneTable

U puts@@GLIBC_2.2.5

00000000000006f0 t register_tm_clones

0000000000201048 d __TMC_END__

0000000000201050 B today                        =============================

0000000000201060 B udp1                            =============================

0000000000201058 b udp1.2278                    =============================

3.2.3 小结

结构体变量(非基本型变量)使用‘B’或‘b’来标识。

全局结构体变量使用‘B’标识

局部静态结构体变量使用‘b’标识

局部变量不会显示在符号表中

本文件内使用的函数使用‘T’标识

引用其他文件的函数使用‘U’标识

3.3 可执行文件a.out分析

3.3.1 main.c内容汇总

序号    函数或变量    性质

1    extern void func1();    引用外部函数

2    extern int fun5(int a);    引用外部函数

3    extern int fun6(char *a);    引用外部函数

4    extern int fun7(int a, char *b);    引用外部函数

5    extern struct udphdr udp1;    引用外部结构体变量

6    extern int iphdr1;    引用外部基本类型变量

7    int myAge=25;    本地全局变量

8    char *mail=“vip_13031075266@163.com”;    本地全局静态变量

3.3.2 a.out符号表

同样使用nm工具进行查看:

toney@ubantu$ nm a.out

0000000000201020 B __bss_start

0000000000201030 b completed.7698

w __cxa_finalize@@GLIBC_2.2.5

0000000000201000 D __data_start

0000000000201000 W data_start

00000000000007a0 t deregister_tm_clones

0000000000000830 t __do_global_dtors_aux

0000000000200d88 t __do_global_dtors_aux_fini_array_entry

0000000000201008 D __dso_handle

0000000000200d90 d _DYNAMIC

0000000000201020 D _edata

0000000000201038 B _end

0000000000000974 T _fini

0000000000000870 t frame_dummy

0000000000200d80 t __frame_dummy_init_array_entry

0000000000000b2c r __FRAME_END__

U fun5                    ============1==============

U fun6                    ============2==============

U fun7                    ============3==============

0000000000200fa0 d _GLOBAL_OFFSET_TABLE_

w __gmon_start__

00000000000009c0 r __GNU_EH_FRAME_HDR

00000000000006f8 T _init

0000000000200d88 t __init_array_end

0000000000200d80 t __init_array_start

0000000000000980 R _IO_stdin_used

0000000000201020 B iphdr1                ============4=============

w _ITM_deregisterTMCloneTable

w _ITM_registerTMCloneTable

0000000000000970 T __libc_csu_fini

0000000000000900 T __libc_csu_init

U __libc_start_main@@GLIBC_2.2.5

0000000000201018 d mail                    ============5==============

000000000000088d T main                    ============6==============

0000000000201010 D myAge                ============7==============

U puts@@GLIBC_2.2.5

00000000000007e0 t register_tm_clones

000000000000087a T show                    ============8==============

0000000000000770 T _start

0000000000201020 D __TMC_END__

0000000000201028 B udp1                    ============9==============

3.3.3 小结

引用的外部函数使用‘U’来标识

全局变量使用‘D’来标识

全局静态变量使用‘d’来标识

引用的外部全局变量(简单类型和复杂类型)使用‘B’来标识

4.总结

对符号表中常见的变量、函数标识总结如下:

序号    标识    说明

1    T    自定义函数(本文件内)

2    t    尚未分析

3    D    自定义标准类型全局变量(如int, char, float等)

4    d    自定义标准类型静态变量(包括全局静态变量、局部静态变量)

5    B    自定义扩展类型全局变量(如结构体类型,枚举型等)、引用的外部全局变量

6    b    自定义静态扩展类型变量(包括全局静态、局部静态类型变量)

7    U    引用的外部函数

8        局部变量在符号表中是不存在的。

注意:t是不存在符号表,T才是存在符号表。

比如:”DSO missing from command line”问题, 问题就是so找不到符号表,需要连接静态库