aboutsummaryrefslogtreecommitdiff
path: root/elf/dl-reloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-reloc.c')
-rw-r--r--elf/dl-reloc.c99
1 files changed, 51 insertions, 48 deletions
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index da964b7948..4d4ca149ea 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -35,6 +35,16 @@ void
_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
int lazy, int consider_profiling)
{
+ struct textrels
+ {
+ caddr_t start;
+ size_t len;
+ int prot;
+ struct textrels *next;
+ } *textrels = NULL;
+ /* Initialize it to make the compiler happy. */
+ const char *errstring = NULL;
+
if (l->l_relocated)
return;
@@ -48,6 +58,9 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
_dl_printf ("\nrelocation processing: %s%s\n",
l->l_name[0] ? l->l_name : _dl_argv[0], lazy ? " (lazy)" : "");
+ /* DT_TEXTREL is now in level 2 and might phase out at some time.
+ But we rewrite the DT_FLAGS entry to a DT_TEXTREL entry to make
+ testing easier and therefore it will be available at all time. */
if (__builtin_expect (l->l_info[DT_TEXTREL] != NULL, 0))
{
/* Bletch. We must make read-only segments writable
@@ -56,15 +69,36 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph)
if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)
{
- caddr_t mapstart = ((caddr_t) l->l_addr +
- (ph->p_vaddr & ~(_dl_pagesize - 1)));
- caddr_t mapend = ((caddr_t) l->l_addr +
- ((ph->p_vaddr + ph->p_memsz + _dl_pagesize - 1)
- & ~(_dl_pagesize - 1)));
- if (__builtin_expect (__mprotect (mapstart, mapend - mapstart,
- PROT_READ|PROT_WRITE), 0) < 0)
- _dl_signal_error (errno, l->l_name, NULL, N_("\
-cannot make segment writable for relocation"));
+ struct textrels *newp;
+
+ newp = (struct textrels *) alloca (sizeof (*newp));
+ newp->len = (((ph->p_vaddr + ph->p_memsz + _dl_pagesize - 1)
+ & ~(_dl_pagesize - 1))
+ - (ph->p_vaddr & ~(_dl_pagesize - 1)));
+ newp->start = ((ph->p_vaddr & ~(_dl_pagesize - 1))
+ + (caddr_t) l->l_addr);
+
+ if (__mprotect (newp->start, newp->len, PROT_READ|PROT_WRITE) < 0)
+ {
+ errstring = N_("cannot make segment writable for relocation");
+ call_error:
+ _dl_signal_error (errno, l->l_name, NULL, errstring);
+ }
+
+#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7
+ newp->prot = (PF_TO_PROT
+ >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf;
+#else
+ newp->prot = 0;
+ if (ph->p_flags & PF_R)
+ newp->prot |= PROT_READ;
+ if (ph->p_flags & PF_W)
+ newp->prot |= PROT_WRITE;
+ if (ph->p_flags & PF_X)
+ newp->prot |= PROT_EXEC;
+#endif
+ newp->next = textrels;
+ textrels = newp;
}
}
@@ -122,8 +156,6 @@ cannot make segment writable for relocation"));
if (__builtin_expect (consider_profiling, 0))
{
- const char *errstring = NULL;
-
/* Allocate the array which will contain the already found
relocations. If the shared object lacks a PLT (for example
if it only contains lead function) the l_info[DT_PLTRELSZ]
@@ -152,45 +184,16 @@ cannot make segment writable for relocation"));
/* Mark the object so we know this work has been done. */
l->l_relocated = 1;
- /* DT_TEXTREL is now in level 2 and might phase out at some time.
- But we rewrite the DT_FLAGS entry to make testing easier and
- therefore it will be available at all time. */
- if (__builtin_expect (l->l_info[DT_TEXTREL] != NULL, 0))
+ /* Undo the segment protection changes. */
+ while (__builtin_expect (textrels != NULL, 0))
{
- /* Undo the protection change we made before relocating. */
- const ElfW(Phdr) *ph;
- for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph)
- if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)
- {
- caddr_t mapstart = ((caddr_t) l->l_addr +
- (ph->p_vaddr & ~(_dl_pagesize - 1)));
- caddr_t mapend = ((caddr_t) l->l_addr +
- ((ph->p_vaddr + ph->p_memsz + _dl_pagesize - 1)
- & ~(_dl_pagesize - 1)));
- int prot;
+ if (__mprotect (textrels->start, textrels->len, textrels->prot) < 0)
+ {
+ errstring = N_("cannot restore segment prot after reloc");
+ goto call_error;
+ }
-#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7
- prot = (PF_TO_PROT
- >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf;
-#else
- prot = 0;
- if (ph->p_flags & PF_R)
- prot |= PROT_READ;
- if (ph->p_flags & PF_W)
- prot |= PROT_WRITE;
- if (ph->p_flags & PF_X)
- prot |= PROT_EXEC;
-#endif
-
- if (__builtin_expect (__mprotect (mapstart, mapend - mapstart,
- prot), 0) < 0)
- _dl_signal_error (errno, l->l_name, NULL,
- N_("can't restore segment prot after reloc"));
-
-#ifdef CLEAR_CACHE
- CLEAR_CACHE (mapstart, mapend);
-#endif
- }
+ textrels = textrels->next;
}
}