【发布时间】: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;
...
}
评论说您可以指定首选地址,但操作系统将决定是否使用它。
问题
- 有什么方法可以为每个 dlended 模块指定基地址吗?
-
ELF_PREFERRED_ADDRESSS默认设置为 0,但这个宏似乎推断可以更改首选地址,比如通过环境变量?但即使有一个,我怀疑它是否可以针对每个 dlopened 库进行更改。 - 如果我想自己实现这个功能,看来我需要包装一个新的 dlopen 函数并将首选地址传递给上述核心函数(并且可能使用 MAP_FIXED)。对吗?
谢谢!
【问题讨论】: