将库中的专用ELF部分合并到应用程序专用ELF部分中

时间:2018-08-19 12:55:50

标签: c linux gcc linker elf

这是我的考试。我有一个main应用程序,它由源main.cmisc.c组成,还有一个由lib.c组成的静态库。

目标::我想在ELF部分struct module中声明所有.modules声明。

问题::我只能从主应用程序中看到struct module声明。这是我可以通过以下代码看到的输出:

Hello World
- module:module_a
- module:module_b

如果我将my_lib()呼叫到main()中,则会看到:

Hello World
MyLib
- module:module_a
- module:module_b
- module:module_lib

但是我不希望直接将模块的函数调用到我的主应用程序中。

  • CMakeLists.txt

    add_executable(main main.c misc.c)
    
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
    
    set(LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/linker.ld")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T ${LINKER_SCRIPT}")
    
    add_library(static_lib STATIC lib.c)
    
    target_link_libraries(main static_lib)
    
  • main.c

    #include "module.h"
    
    extern const struct module modules_start[];
    extern const struct module modules_end[];
    
    struct module __attribute__ ((section (".modules"))) module_a = {
        .name = "module_a",
    };
    
    int main(void) {
        puts("Hello World");
    
        const struct module *m = modules_start;
        while (m < modules_end) {
            printf("- module:%s\n", m->name);
            m++;
        }
    
        return 0;
    }
    
  • misc.c

    #include "module.h"
    
    struct module __attribute__ ((section (".modules"))) module_b = {
        .name = "module_b",
    };
    
  • module.h

    #include <stdio.h>
    
    struct module {
        const char* name;
    };
    
  • lib.c

    #include "module.h"
    
    struct module __attribute__ ((section (".modules"))) __attribute__ ((used)) module_lib = {
        .name = "module_lib",
    };
    
    int my_lib(void) {
        puts("MyLib");
        return 0;
    }
    
  • linker.ld

    SECTIONS
    {
        .modules : {
            modules_start = .;
            KEEP(*(.modules))
            modules_end = .;
        }
    }
    INSERT AFTER .rodata;
    

以下是一些ELF信息:

$ readelf --sections libstatic_lib.a | grep -A 1 modules
  [ 5] .modules          PROGBITS         0000000000000000  00000058
       0000000000000008  0000000000000000  WA       0     0     8
  [ 6] .rela.modules     RELA             0000000000000000  00000278
       0000000000000018  0000000000000018   I      13     5     8

$ readelf --sections main | grep -A 1 modules
  [17] .modules          PROGBITS         00000000000009c0  000009c0
       0000000000000010  0000000000000000  WA       0     0     8

$ nm libstatic_lib.a | grep module
0000000000000000 D module_lib

$ nm main | grep module
00000000000009c0 D module_a
00000000000009c8 D module_b
00000000000009d0 D modules_end
00000000000009c0 D modules_start

1 个答案:

答案 0 :(得分:2)

如果静态库中没有对目标文件的引用,则默认情况下该对象文件不包含在链接中。使用binutils链接器,您可以使用--whole-archive option禁用此优化。