【问题标题】:Is there a way to specify the base address of a shared library using dlopen()?有没有办法使用 dlopen() 指定共享库的基地址?
【发布时间】:2020-09-15 18:35:18
【问题描述】:

似乎当我们 dlopen() 一些库时,它们会被加载到一些首选的(但不是固定的)地址。我查看了dlopen()的源代码,一个核心函数说

static __always_inline const char *
_dl_map_segments (struct link_map *l, int fd,
                  const ElfW(Ehdr) *header, int type,
                  const struct loadcmd loadcmds[], size_t nloadcmds,
                  const size_t maplength, bool has_holes,
                  struct link_map *loader)
{
  const struct loadcmd *c = loadcmds;
  if (__glibc_likely (type == ET_DYN))
    {
      /* This is a position-independent shared object.  We can let the
         kernel map it anywhere it likes, but we must have space for all
         the segments in their specified positions relative to the first.
         So we map the first segment without MAP_FIXED, but with its
         extent increased to cover all the segments.  Then we remove
         access from excess portion, and there is known sufficient space
         there to remap from the later segments.
         As a refinement, sometimes we have an address that we would
         prefer to map such objects at; but this is only a preference,
         the OS can do whatever it likes. */
      ElfW(Addr) mappref
        = (ELF_PREFERRED_ADDRESS (loader, maplength,
                                  c->mapstart & GLRO(dl_use_load_bias))
           - MAP_BASE_ADDR (l));
      /* Remember which part of the address space this object uses.  */
      l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength,
                                            c->prot,
                                            MAP_COPY|MAP_FILE,
                                            fd, c->mapoff);
      if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED))
        return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
...
}

评论说您可以指定首选地址,但操作系统将决定是否使用它。

问题

  1. 有什么方法可以为每个 dlended 模块指定基地址吗?
  2. ELF_PREFERRED_ADDRESSS 默认设置为 0,但这个宏似乎推断可以更改首选地址,比如通过环境变量?但即使有一个,我怀疑它是否可以针对每个 dlopened 库进行更改。
  3. 如果我想自己实现这个功能,看来我需要包装一个新的 dlopen 函数并将首选地址传递给上述核心函数(并且可能使用 MAP_FIXED)。对吗?

谢谢!

【问题讨论】:

    标签: dynamic-linking dlopen


    【解决方案1】:

    有什么方法可以为每个 dlopened 模块指定基地址吗?

    没有。

    ELF_PREFERRED_ADDRESSS 默认设置为 0,但是这个宏似乎推断可以更改首选地址,比如通过环境变量?但即使有一个,我怀疑它可以为每个 dlopened 库更改。

    这段代码编译到动态加载器ld-linux.so,编译后无法更改。

    如果我想自己实现这个功能,似乎我需要包装一个新的 dlopen 函数并将首选地址传递给上述核心函数(并且可能使用 MAP_FIXED)。对吗?

    函数是私有ld-linux。您将无法包装它,或从ld-linux 之外调用它。

    附:您可能要查找的是prelink 命令。

    【讨论】:

    • 您好,感谢您的回复。我了解 dlopen 的核心功能是 ld-linux 私有的。 “包装”的方式实际上意味着我可以修改ld-linux的源代码并重新编译一个新的ld-linux.so。这是实现我的目标的可行方法吗?
    • 我还快速检查了预链接技术,这似乎很有用,除了我们的项目需要高度灵活,即我们不能在链接时间/之前预加载模块,但是必须输入模块的名称并决定将哪个(以及在何处)加载到二进制文件中。
    • @HaoLi 请根据您的实际要求编辑您的问题。否则我们正在解决xyproblem.info
    猜你喜欢
    • 2011-06-30
    • 2017-12-08
    • 2022-01-11
    • 2021-03-08
    • 2022-12-19
    • 1970-01-01
    • 2019-08-23
    • 2012-01-01
    • 2023-03-13
    相关资源
    最近更新 更多