【问题标题】:Merging dedicated ELF sections from libraries into application dedicated ELF section将库中的专用 ELF 部分合并到应用程序专用 ELF 部分
【发布时间】:2018-08-19 12:55:50
【问题描述】:

这是我的测试。我有一个由main.cmisc.c 组成的main 应用程序和一个由lib.c 组成的静态库。

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

问题:我只能从主应用程序中看到 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)
    
  • ma​​in.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

【问题讨论】:

  • “我只能看到主应用程序中的模块”,我的意思是主应用程序声明的“结构模块”变量(main.cmisc.c)。我想将我的所有struct module 声明声明到专用 ELF 部分的原因是,这是检索所有这些声明而无需将它们列出到全局数组中的最简单方法。 Linux内核中使用了类似的机制。 my_lib()是静态库static_lib声明的函数。
  • BTW 在链接器脚本中,您没有说明该部分属于哪个内存。我不明白你要归档什么。这些部分在内存中而不是在精灵中。
  • 您正在混合ELFmemoryELF sections 也定义了存储它们所属符号的位置。例如,您可以在 ROM 中定义属于 .text 的符号,在 RAM 中定义属于 .bss 的符号,谢谢。我不知道您是否阅读过我的问题,或者您是否理解它,但我没有兴趣定义 ELF 部分在内存中的位置。我提供的示例旨在构建为 ELF 应用程序,任何人都可以轻松测试。我想归档 struct module module_lib 并将其公开给主应用程序,而无需将其显式声明为 main.c

标签: c linux gcc linker elf


【解决方案1】:

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

【讨论】:

  • 非常感谢!有效地使用target_link_libraries(main -Wl,--whole-archive static_lib -Wl,--no-whole-archive) 解决了我的问题
猜你喜欢
  • 2018-10-23
  • 1970-01-01
  • 2013-02-09
  • 1970-01-01
  • 2012-12-01
  • 1970-01-01
  • 2010-11-08
  • 2016-06-20
  • 1970-01-01
相关资源
最近更新 更多