@@ -691,6 +691,7 @@ _dl_close_worker (struct link_map *map, bool force)
GL(dl_initfirst) = NULL;
free (imap->l_dlopen_args);
+ free (imap->l_loadcmds);
free (imap);
}
@@ -950,6 +950,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
int type;
/* Initialize to keep the compiler happy. */
const char *errstring = NULL;
+ struct loadcmd *loadcmds = NULL;
int errval = 0;
/* Get file information. To match the kernel behavior, do not fill
@@ -969,6 +970,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
lose_errno:
errval = errno;
lose:
+ if (loadcmds)
+ free (loadcmds);
/* The file might already be closed. */
if (fd != -1)
__close_nocancel (fd);
@@ -1080,18 +1083,23 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
}
}
- /* On most platforms presume that PT_GNU_STACK is absent and the stack is
- * executable. Other platforms default to a nonexecutable stack and don't
- * need PT_GNU_STACK to do so. */
- unsigned int stack_flags = DEFAULT_STACK_PERMS;
+ /* On most platforms presume that PT_GNU_STACK is absent and the stack is
+ * executable. Other platforms default to a nonexecutable stack and don't
+ * need PT_GNU_STACK to do so. */
+ unsigned int stack_flags = DEFAULT_STACK_PERMS;
{
/* Scan the program header table, collecting its load commands. */
- struct loadcmd loadcmds[l->l_phnum];
- size_t nloadcmds = 0;
+ #define nloadcmds l->l_nloadcmds
bool empty_dynamic = false;
ElfW(Addr) p_align_max = 0;
+ loadcmds = (struct loadcmd *) malloc (sizeof (struct loadcmd) * l->l_phnum);
+ if (loadcmds == NULL)
+ goto lose;
+ l->l_loadcmds = loadcmds;
+ nloadcmds = 0;
+
/* The struct is initialized to zero so this is not necessary:
l->l_ld = 0;
l->l_phdr = 0;
@@ -1225,8 +1233,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
}
/* Align all PT_LOAD segments to the maximum p_align. */
- for (size_t i = 0; i < nloadcmds; i++)
- loadcmds[i].mapalign = p_align_max;
+ l->l_map_align = p_align_max;
/* dlopen of an executable is not valid because it is not possible
to perform proper relocations, handle static TLS, or run the
@@ -1263,9 +1270,13 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
l->l_map_start = l->l_map_end = 0;
goto lose;
}
- errstring = _dl_finalize_segments (l, type, loadcmds, nloadcmds);
- if (__glibc_unlikely (errstring != NULL))
- goto lose;
+ /* dlopen()ed solibs are finalized on a relocation step. */
+ if (!(mode & __RTLD_DLOPEN))
+ {
+ errstring = _dl_finalize_segments (l, type, loadcmds, nloadcmds);
+ if (__glibc_unlikely (errstring != NULL))
+ goto lose;
+ }
}
if (l->l_ld != 0)
@@ -75,7 +75,7 @@ ELF_PREFERRED_ADDRESS_DATA;
Its details have been expanded out and converted. */
struct loadcmd
{
- ElfW(Addr) mapstart, mapend, dataend, allocend, mapalign, maphole;
+ ElfW(Addr) mapstart, mapend, dataend, allocend, maphole;
ElfW(Off) mapoff;
int prot; /* PROT_* bits. */
};
@@ -100,7 +100,7 @@ _dl_map_segments (struct link_map *l, int fd,
- MAP_BASE_ADDR (l));
/* Remember which part of the address space this object uses. */
- l->l_map_start = _dl_map_segment (mappref, maplength, c->mapalign);
+ l->l_map_start = _dl_map_segment (mappref, maplength, l->l_map_align);
if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED))
return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
@@ -150,6 +150,9 @@ _dl_finalize_segments (struct link_map *l, int type,
{
const struct loadcmd *c = loadcmds;
+ if (l->l_map_completed)
+ return NULL;
+
while (c < &loadcmds[nloadcmds])
{
ElfW(Addr) hole_start, hole_size;
@@ -234,5 +237,7 @@ _dl_finalize_segments (struct link_map *l, int type,
++c;
}
+ l->l_map_completed = 1;
+
return NULL;
}
@@ -40,7 +40,8 @@
#include <dl-dst.h>
#include <dl-prop.h>
-
+#include "dl-load.h"
+#include "dl-map-segments.h"
/* We must be careful not to leave us in an inconsistent state. Thus we
catch any error and re-raise it after cleaning up. */
@@ -543,6 +544,8 @@ do_reloc_1 (struct link_map *new, int mode, Lmid_t nsid, bool call_ctors)
for (unsigned int i = last; i-- > first; )
{
+ const char *errstring;
+
l = new->l_initfini[i];
if (l->l_real->l_relocated)
@@ -555,6 +558,11 @@ do_reloc_1 (struct link_map *new, int mode, Lmid_t nsid, bool call_ctors)
relocation_in_progress = 1;
}
+ errstring = _dl_finalize_segments (l, ET_DYN, l->l_loadcmds,
+ l->l_nloadcmds);
+ if (__glibc_unlikely (errstring != NULL))
+ _dl_signal_error (EINVAL, l->l_libname->name, NULL, errstring);
+
#ifdef SHARED
if (__glibc_unlikely (GLRO(dl_profile) != NULL))
{
@@ -179,6 +179,7 @@ struct link_map
} l_type:2;
unsigned int l_dt_relr_ref:1; /* Nonzero if GLIBC_ABI_DT_RELR is
referenced. */
+ unsigned int l_map_completed:1; /* Nonzero if object fully mapped. */
unsigned int l_relocated:1; /* Nonzero if object's relocations done. */
unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */
unsigned int l_global:1; /* Nonzero if object in _dl_global_scope. */
@@ -252,7 +253,7 @@ struct link_map
/* Start and finish of memory map for this object. l_map_start
need not be the same as l_addr. */
- ElfW(Addr) l_map_start, l_map_end;
+ ElfW(Addr) l_map_start, l_map_end, l_map_align;
/* End of the executable part of the mapping. */
ElfW(Addr) l_text_end;
@@ -349,6 +350,8 @@ struct link_map
unsigned long long int l_serial;
void *l_dlopen_args;
+ void *l_loadcmds;
+ size_t l_nloadcmds;
};
#include <dl-relocate-ld.h>
This is needed so that the segment finalization can be delayed, together with the relocation process. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev <stsp2@yandex.ru> --- elf/dl-close.c | 1 + elf/dl-load.c | 33 ++++++++++++++++++++++----------- elf/dl-load.h | 2 +- elf/dl-map-segments.h | 7 ++++++- elf/dl-open.c | 10 +++++++++- include/link.h | 5 ++++- 6 files changed, 43 insertions(+), 15 deletions(-)