@@ -1032,8 +1032,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
{
/* Scan the program header table, collecting its load commands. */
struct loadcmd loadcmds[l->l_phnum];
+ struct loadcmd *first_loadcmd = NULL;
size_t nloadcmds = 0;
bool has_holes = false;
+ ElfW(Addr) last_alloc_end = 0, last_map_start = 0;
/* The struct is initialized to zero so this is not necessary:
l->l_ld = 0;
@@ -1083,9 +1085,28 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
c->allocend = ph->p_vaddr + ph->p_memsz;
c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize));
+ /* Determine size of the segments to be loaded */
+ if (nloadcmds == 1)
+ {
+ last_map_start = c->mapstart;
+ last_alloc_end = c->allocend;
+ first_loadcmd = c;
+ }
+ else
+ {
+ if (first_loadcmd->mapstart > c->mapstart)
+ first_loadcmd = c;
+ if (last_alloc_end < c->allocend)
+ last_alloc_end = c->allocend;
+ if (last_map_start < c->mapstart)
+ last_map_start = c->mapstart;
+ }
+
/* Determine whether there is a gap between the last segment
- and this one. */
- if (nloadcmds > 1 && c[-1].mapend != c->mapstart)
+ and this one. If the segments are not sorted by mapstart,
+ assume there is a gap */
+ if (nloadcmds > 1 && (c[-1].mapend != c->mapstart
+ || c[-1].mapstart > c->mapstart))
has_holes = true;
/* Optimize a common case. */
@@ -1177,14 +1198,15 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
}
/* Length of the sections to be loaded. */
- maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart;
+ maplength = last_alloc_end - first_loadcmd->mapstart;
/* Now process the load commands and map segments into memory.
This is responsible for filling in:
l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr
*/
errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds,
- maplength, has_holes, loader);
+ maplength, has_holes, loader, first_loadcmd,
+ last_map_start);
if (__glibc_unlikely (errstring != NULL))
goto call_lose;
}
@@ -87,7 +87,7 @@ static __always_inline void
_dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header,
const struct loadcmd *c)
{
- if (c->prot & PROT_EXEC)
+ if ((c->prot & PROT_EXEC) && l->l_text_end < l->l_addr + c->mapend)
l->l_text_end = l->l_addr + c->mapend;
if (l->l_phdr == 0
@@ -118,7 +118,9 @@ static const char *_dl_map_segments (struct link_map *l, int fd,
size_t nloadcmds,
const size_t maplength,
bool has_holes,
- struct link_map *loader);
+ struct link_map *loader,
+ const struct loadcmd *first_loadcmd,
+ const ElfW(Addr) last_map_start);
/* All the error message strings _dl_map_segments might return are
listed here so that different implementations in different sysdeps
@@ -30,9 +30,12 @@ _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)
+ struct link_map *loader,
+ const struct loadcmd *first_loadcmd,
+ const ElfW(Addr) last_map_start)
{
- const struct loadcmd *c = loadcmds;
+ const struct loadcmd *c = first_loadcmd;
+ size_t i = 0, first_i = first_loadcmd - loadcmds;
if (__glibc_likely (type == ET_DYN))
{
@@ -63,7 +66,7 @@ _dl_map_segments (struct link_map *l, int fd,
l->l_map_end = l->l_map_start + maplength;
l->l_addr = l->l_map_start - c->mapstart;
- if (has_holes)
+ if (has_holes && last_map_start > c->mapend)
{
/* Change protection on the excess portion to disallow all access;
the portions we do not remap later will be inaccessible as if
@@ -72,7 +75,7 @@ _dl_map_segments (struct link_map *l, int fd,
mapping. */
if (__glibc_unlikely
(__mprotect ((caddr_t) (l->l_addr + c->mapend),
- loadcmds[nloadcmds - 1].mapstart - c->mapend,
+ last_map_start - c->mapend,
PROT_NONE) < 0))
return DL_MAP_SEGMENTS_ERROR_MPROTECT;
}
@@ -87,8 +90,9 @@ _dl_map_segments (struct link_map *l, int fd,
l->l_map_end = l->l_map_start + maplength;
l->l_contiguous = !has_holes;
- while (c < &loadcmds[nloadcmds])
+ while (i < nloadcmds)
{
+ c = &loadcmds[(first_i + i) % nloadcmds];
if (c->mapend > c->mapstart
/* Map the segment contents from the file. */
&& (__mmap ((void *) (l->l_addr + c->mapstart),
@@ -146,7 +150,7 @@ _dl_map_segments (struct link_map *l, int fd,
}
}
- ++c;
+ ++i;
}
/* Notify ELF_PREFERRED_ADDRESS that we have to load this one