__start_section和__stop_section符号链接到库时失踪 [英] __start_section and __stop_section symbols missing when linking to library

查看:1103
本文介绍了__start_section和__stop_section符号链接到库时失踪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用自定义的小精灵头与此类似线程的autotools的C ++项目:<一href=\"http://stackoverflow.com/questions/16552710/how-do-you-get-the-start-and-end-addresses-of-a-custom-elf-section-in-c-gcc\">How你得到一个定制的ELF节的开始和结束地址在C(GCC)?。问题是,该声明自定义部分的C文件连接成一个静态库,然后链接到最终的应用程序。

I'm using custom elf headers in an autotools C project similar to this thread: How do you get the start and end addresses of a custom ELF section in C (gcc)?. The problem is that the c files that declare the custom sections are linked into a static library which is then linked to the final application.

在这种结构中,符号__start_custom_section和__stop_custom_section没有得到产生。我定义了ELF段是这样的:

In this configuration the symbols __start_custom_section and __stop_custom_section do not get generated. I define the elf section like this:

struct mystruct __attribute((__section__("custom_section"))) __attribute((__used__) = {
...
};

如果我链接到目标文件,而不是符号得到创建的库,一切工作正常。这不是,但因为我想新的模块,只是它们编译成模块库工作,一个可扩展的解决方案。任何想法,为什么当部分在库VS存在一个单一的目标文件中的链接器不创建这些特殊符号?

If I link to the object file instead of the library the symbols get created and everything works as expected. This isn't a scalable solution though because I'd like new modules to just work by compiling them into the modules library. Any idea why the linker doesn't create these special symbols when the section exists in a library vs a single object file?

推荐答案

我已经做了一些类似的最近,和我的解决方案不依赖于任何特定的编译器实现,内部无证符号等。但是,它确实需要一个多做一些工作:)

I have done something similar to this recently, and my solution does not rely on any compiler specific implementations, internal undocumented symbols, etc. However, it does require a bit more work :)

背景

在磁盘上的ELF二进制文件可以被加载并知道它的格式,并使用所提供的一对夫妇的结构解析很容易:的 http://linux.die.net/man/5/elf 。你可以通过它的每个段和段迭代(段容器部分)。如果你这样做,你可以计算出你部分的相对开始/结束虚拟地址。按这个逻辑,你会认为你可以通过在段和的加载,内存版的ELF二进制文件的各个部分进行迭代在运行时做同样的事情。但很可惜,你只能通过自己的细分迭代(通过 http://linux.die.net/男人/ 3 / dl_iterate_phdr ),所有部分的元数据已经丢失。

The ELF binary on disk can be loaded and parsed quite easily by knowing its format and using a couple structures provided to us: http://linux.die.net/man/5/elf. You can iterate through each of its segments and sections (segments are containers for sections). If you do this, you can calculate the the relative start/end virtual addresses of your section. By this logic, you would think that you can do the same thing at runtime by iterating through the segments and sections of the loaded, in-memory version of the ELF binary. But alas, you can only iterate through the segments themselves (via http://linux.die.net/man/3/dl_iterate_phdr), and all section metadata has been lost.

那么,我们怎样才能留住部分元数据?存放自己。

So, how can we retain the section metadata? Store it ourselves.

解决方案

如果您有一个名为.mycustom自定义栏目,然后定义元数据结构应该以最低的店两个数字将显示相对起始地址和你的'.mycustom部分的大小。本身在名为.mycustom_meta另一个自定义部分创建元数据结构,将生活的的全局实例。

If you have a custom section named '.mycustom', then define a metadata struct that should at minimum store two numbers that will indicate the relative start address and the size of your '.mycustom' section. Create a global instance of this metadata struct that will live by itself in another custom section named '.mycustom_meta'.

例如:

typedef struct
{
    unsigned long ulStart;
    unsinged long ulSize;
} CustomSectionMeta;

__attribute((__section__(".mycustom_meta"))) CustomSectionMeta g_customSectionMeta = { 0, 0 };

您可以看到,我们的结构实例与零为启动和大小值初始化。当你编译这个code,你的对象文件将包含一个名为'.mycustom_meta这将是大小为8个字节的32位编译(或16个字节为64位),和值将所有部分零。运行的 objdump的的它,你会看到尽可能多。来吧并将它放入如果你想要一个静态库(.a)中,运行的 readelf 的就可以了,你会看到同样的事情。构建入,如果你想有一个共享对象(的.so),在其上运行的 readelf 的,再次你会看到同样的事情。它构建成一个可执行程序,运行的 readelf 的就可以了,瞧它仍然存在。

You can see that our struct instance is initialized with zero for both start and size values. When you compile this code, your object file will contain a section named '.mycustom_meta' which will be 8 bytes in size for a 32-bit compilation (or 16 bytes for 64-bit), and the values will be all zeroes. Run objdump on it and you will see as much. Go ahead and put that into a static lib (.a) if you want, run readelf on it, and you will see exactly the same thing. Build it into a shared object (.so) if you want, run readelf on it, and again you will see the same thing. Build it into an executable program, run readelf on it, and voila its still there.

现在招进来。你需要写一个小的可执行文件(可以称之为MetaWriter),将更新磁盘上的ELF文件填写开始和大小值。以下是基本步骤:

Now the trick comes in. You need to write a little executable (lets call it MetaWriter) that will update your ELF file on disk to fill in the start and size values. Here are the basic steps:


  1. 在二进制模式打开ELF文件(.o,。所以,或可执行文件),并读入一个连续的数组。或者,你可以的mmap到内存来实现相同的。

  2. 通过二进制用我上面列出的ELF链接找到的头结构和指令读取。

  3. 找到你的'.mycustom部分和阅读section.sh_addr和section.sh_size。

  4. 找到你的'.mycustom_meta部分。使用的开始和大小值从步骤3的memcpy()的结构在现有'.mycustom_meta部分的数据,这到现在是全零的顶部创建CustomSectionMeta的一个实例。

  5. 保存你的数据ELF回原来的文件。现在应该是除了你写到'.mycustom_meta部分的几个字节完全不变。

我所做的就是执行该程序MetaWriter在我的Makefile生成过程的一部分。所以,你会建立自己的.so或​​可执行文件,然后在其上运行MetaWriter填写元一节。在此之后,它准备好了。

What I did was executed this MetaWriter program as part of the build process in my Makefile. So, you would build your .so or executable, then run MetaWriter on it to fill in the meta section. After that, its ready to go.

现在,当code在你的.so或​​可执行文件运行时,它可以刚刚从g_customSectionMeta,这将与起始地址的抵消你的'.mycustom部分的填充阅读,以及它的大小,它可以用来容易地计算过程的结束。这开始的偏移必须添加到您的加载ELF二进制文件的基址。有一对夫妇的方式来得到这个,但我发现最简单的方法是运行的提供dladdr 的上,我知道存在一个符号二进制文件(如g_customSectionMeta!),并使用所产生的价值<青霉> dli_fbase 的知道模块的基址。

Now, when the code in your .so or executable runs, it can just read from g_customSectionMeta, which will be populated with the starting address offset of your '.mycustom' section, as well as the size of it, which can be used to easily calculate the end, of course. This start offset must be added to the base address of your loaded ELF binary. There are a couple ways to get this, but the easiest way I found was to run dladdr on a symbol that I know to exist in the binary (such as g_customSectionMeta!) and use the resulting value of dli_fbase to know the base address of the module.

例如:

#include <dlfcn.h>
Dl_info dlInfo;
if (dladdr(&g_customSectionMeta, &dlInfo) != 0)
{
    void * vpBase = dlInfo.dli_fbase;
    void * vpMyCustomStart = vpBase + g_customSectionMeta.ulStart;
    void * vpMyCustomEnd = vpMyCustomStart + g_customSectionMeta.ulSize;
}

这将是一个有点过分张贴到做这一切工作所需的全部金额code,特别是在MetaWriter的ELF二进制文件的解析。但是,如果你需要帮助,请随时与我联系。

It would be a bit overboard to post the full amount of code required to do all this work, especially the parsing of the ELF binary in MetaWriter. However, if you need some help, feel free to reach out to me.

这篇关于__start_section和__stop_section符号链接到库时失踪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆