Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何防止加载静态库中的所有符号,以及为什么在链接静态库时将同一.o文件中的其他符号导出到测试中_C_Linux_Linker_Static Libraries - Fatal编程技术网

C 如何防止加载静态库中的所有符号,以及为什么在链接静态库时将同一.o文件中的其他符号导出到测试中

C 如何防止加载静态库中的所有符号,以及为什么在链接静态库时将同一.o文件中的其他符号导出到测试中,c,linux,linker,static-libraries,C,Linux,Linker,Static Libraries,假设有三个c文件,例如a.c包含函数xx(),yy()和b.c包含nn(),mm()和c.c包含qq(),rr() 我用a.o、b.o和c.o制作了一个静态库stat.a。如果我将stat.a链接到调用xx()的测试中,那么符号yy()也会被导出:nm test既有符号xx也有符号yy 我想知道为什么没有导出符号qq和rr 是否有任何方法防止加载xx以外的任何其他符号 我想知道为什么qq和rr的符号不能导出 你必须将你的意图告知链接者 gcc-L./-o test test.c-Wl,--整个归

假设有三个c文件,例如
a.c
包含函数
xx()
yy()
b.c
包含
nn()
mm()
c.c
包含
qq()
rr()

我用
a.o
b.o
c.o
制作了一个静态库
stat.a
。如果我将
stat.a
链接到调用
xx()
的测试中,那么符号
yy()
也会被导出:
nm test
既有符号
xx
也有符号
yy

  • 我想知道为什么没有导出符号
    qq
    rr
  • 是否有任何方法防止加载
    xx
    以外的任何其他符号
  • 我想知道为什么qq和rr的符号不能导出
  • 你必须将你的意图告知链接者

    gcc-L./-o test test.c-Wl,--整个归档stat.a-Wl,--没有整个归档

  • 是否有任何方法防止加载xx以外的任何其他符号
  • gcc-功能部分-c a.c

    gcc-L./-o测试c-Wl,--gc章节统计a


    下面是您的场景的一个实现:

    a.c

    #include <stdio.h>
    
    void xx(void)
    {
        puts(__func__);
    }
    
    void yy(void)
    {
        puts(__func__);
    }
    
    #include <stdio.h>
    
    void nn(void)
    {
        puts(__func__);
    }
    
    void mm(void)
    {
        puts(__func__);
    }
    
    #include <stdio.h>
    
    void qq(void)
    {
        puts(__func__);
    }
    
    void rr(void)
    {
        puts(__func__);
    }
    
    extern void xx(void);
    
    int main(void)
    {
        xx();
        return 0;
    }
    
    将所有
    *.c
    文件编译为
    *.o
    文件:

    $ gcc -Wall -c a.c b.c c.c test.c
    
    制作一个静态库
    stat.a
    ,包含
    a.o
    b.o
    c.o

    $ ar rcs stat.a a.o b.o c.o
    
    $ objdump -d a.o
    
    a.o:     file format elf64-x86-64
    
    
    Disassembly of section .text.xx:
    
    0000000000000000 <xx>:
       0:   55                      push   %rbp
       1:   48 89 e5                mov    %rsp,%rbp
       4:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi        # b <xx+0xb>
       b:   e8 00 00 00 00          callq  10 <xx+0x10>
      10:   90                      nop
      11:   5d                      pop    %rbp
      12:   c3                      retq
    
    Disassembly of section .text.yy:
    
    0000000000000000 <yy>:
       0:   55                      push   %rbp
       1:   48 89 e5                mov    %rsp,%rbp
       4:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi        # b <yy+0xb>
       b:   e8 00 00 00 00          callq  10 <yy+0x10>
      10:   90                      nop
      11:   5d                      pop    %rbp
      12:   c3                      retq
    
    链接程序
    test
    ,输入
    test.o
    stat.a

    $ gcc -o test test.o stat.a
    
    $ nm stat.a
    
    a.o:
    0000000000000000 r __func__.2250
    0000000000000003 r __func__.2254
                     U _GLOBAL_OFFSET_TABLE_
                     U puts
    0000000000000000 T xx
    0000000000000013 T yy
    
    b.o:
    0000000000000000 r __func__.2250
    0000000000000003 r __func__.2254
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000013 T mm
    0000000000000000 T nn
                     U puts
    
    c.o:
    0000000000000000 r __func__.2250
    0000000000000003 r __func__.2254
                     U _GLOBAL_OFFSET_TABLE_
                     U puts
    0000000000000000 T qq
    0000000000000013 T rr
    
    运行:

    让我们在
    stat.a
    中查看对象文件的符号表:

    $ gcc -o test test.o stat.a
    
    $ nm stat.a
    
    a.o:
    0000000000000000 r __func__.2250
    0000000000000003 r __func__.2254
                     U _GLOBAL_OFFSET_TABLE_
                     U puts
    0000000000000000 T xx
    0000000000000013 T yy
    
    b.o:
    0000000000000000 r __func__.2250
    0000000000000003 r __func__.2254
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000013 T mm
    0000000000000000 T nn
                     U puts
    
    c.o:
    0000000000000000 r __func__.2250
    0000000000000003 r __func__.2254
                     U _GLOBAL_OFFSET_TABLE_
                     U puts
    0000000000000000 T qq
    0000000000000013 T rr
    
    xx
    yy
    的定义(
    T
    )在成员
    stat.a(a.o)
    中。
    nn
    mm
    都在统计a(b.o)中。
    qq
    rr
    的定义见
    stat.a(c.o)

    让我们看看哪些符号也在程序的符号表中定义
    测试

    $ nm test | egrep 'T (xx|yy|qq|rr|nn|mm)'
    000000000000064a T xx
    000000000000065d T yy
    
    已定义程序中调用的
    xx
    yy
    ,它不被调用,也是 定义
    nn
    mm
    qq
    rr
    都没有被调用

    这就是你观察到的

    我想知道为什么没有导出符号
    qq
    rr

    什么是静态库,例如
    stat.a
    ,它在链接中的特殊作用是什么

    这是一种传统上(但不一定)不包含任何内容的方法 但是对象文件。您可以向链接器提供这样的存档,从中选择 对象文件,如果有,它需要进行链接。链接器需要这些对象 归档文件中的文件,这些文件为已删除的符号提供定义 在已链接的输入文件中引用但尚未定义。这个 链接器从存档中提取所需的对象文件并将其输入到 链接,就像它们分别命名为输入文件和静态库一样 根本没有提到

    因此,链接器对输入静态库所做的与它所做的不同 使用输入对象文件。任何输入对象文件都无条件链接到输出文件 (无论是否需要)

    有鉴于此,让我们重做
    test
    与一些诊断(
    -trace)
    的链接,以显示什么 文件实际上是链接的:

    $ gcc -o test test.o stat.a -Wl,--trace
    /usr/bin/x86_64-linux-gnu-ld: mode elf_x86_64
    /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
    /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
    /usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
    test.o
    (stat.a)a.o
    libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
    /lib/x86_64-linux-gnu/libc.so.6
    (/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
    /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
    /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
    libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
    /usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
    /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
    
    除了所有用于C程序链接的锅炉板文件之外,
    gcc
    通过 默认情况下,链接中我们的唯一文件是两个对象文件:

    test.o
    (stat.a)a.o
    
    联系:

    $ gcc -o test test.o stat.a
    
    $ gcc -o test test.o a.o
    
    与悬挂机构完全相同:

    $ gcc -o test test.o stat.a
    
    $ gcc -o test test.o a.o
    
    让我们仔细想想

    • test.o
      是第一个链接器输入。此目标文件已无条件链接到程序中
    • test.o
      包含对
      xx
      的引用(特别是函数调用),但没有函数
      xx
      的定义
    • 因此,链接器现在需要找到
      xx
      的定义来完成链接
    • 下一个链接器输入是静态库
      stat.a
    • 链接器在
      stat.a
      中搜索包含定义为
      xx
      的对象文件
    • 它查找
      a.o
      。它从存档中提取a.o
    ,并将其链接到程序中
  • 链接中没有其他未解析的符号引用 链接器可以在
    stat.a(b.o)
    stat(c.o)
    中找到定义。所以这两个都不是 提取并链接对象文件
  • 通过提取一个链接(just)
    stat.a(a.o)
    ,链接器得到了一个定义 它需要在
    test.o
    中解析函数调用。但是
    a.o
    也包含
    yy
    的定义。因此,该定义也链接到程序中。
    nn
    mm
    qq
    rr
    未在程序中定义,因为它们都未定义 在链接到程序的对象文件中定义

    这就是你第一个问题的答案。第二个问题是:

    是否有任何方法防止加载
    xx
    以外的任何其他符号

    至少有两种方法

    一种是简单地定义源代码中的
    xx
    yy
    nn
    mm
    qq
    rr
    文件本身。然后编译对象文件
    xx.o
    yy.o
    nn.o
    mm.o
    qq.o
    rr.o
    并将所有文件归档到
    stat.a
    中。然后,如果链接器需要找到 定义
    xx
    stat.a
    中的对象文件,它将查找
    xx.o
    ,提取并链接它, 以及
    xx的定义$ gcc -o test test.o stat.a -Wl,-gc-sections,-trace,-Map=mapfile
    /usr/bin/x86_64-linux-gnu-ld: mode elf_x86_64
    /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
    /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
    /usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
    test.o
    (stat.a)a.o
    libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
    /lib/x86_64-linux-gnu/libc.so.6
    (/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
    /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
    /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
    libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
    /usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
    /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
    
    $ nm test | egrep 'T (xx|yy|qq|rr|nn|mm)'
    000000000000064a T xx
    
    $ ./test
    xx
    
    ...
    Discarded input sections
    ...
    ...
     .text.yy       0x0000000000000000       0x13 stat.a(a.o)
    ...
    ...