about summary refs log tree commit diff
path: root/elf/dl-reloc.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2001-11-12 21:04:45 +0000
committerUlrich Drepper <drepper@redhat.com>2001-11-12 21:04:45 +0000
commitf133c09767993fddcdd790a361fd11d6410a84b2 (patch)
treeb0e0a253855418886e674d1818346036959812be /elf/dl-reloc.c
parente5b27fe5d1f72a82ea0b29125ad976f04449f7f0 (diff)
downloadglibc-f133c09767993fddcdd790a361fd11d6410a84b2.tar.gz
glibc-f133c09767993fddcdd790a361fd11d6410a84b2.tar.xz
glibc-f133c09767993fddcdd790a361fd11d6410a84b2.zip
Update.
2001-11-12  Ulrich Drepper  <drepper@redhat.com>

	* elf/dl-reloc.c (_dl_relocate_object): Avoid iterating over
	program header twice.  Construct list with the needed information.
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;
     }
 }