Author: arichardson
Date: Mon Oct 29 21:08:02 2018
New Revision: 339876
URL: https://svnweb.freebsd.org/changeset/base/339876

Log:
  rtld: set obj->textsize correctly
  
  With lld-generated binaries the first PT_LOAD will usually be a read-only
  segment unless you pass --no-rosegment. For those binaries the textsize is
  determined by the next PT_LOAD. To allow both LLD and bfd 2.17 binaries to
  be parsed correctly use the end of the last PT_LOAD that is marked as
  executable instead.
  
  I noticed that the value was wrong while adding some debug prints for some 
rtld
  changes for CHERI binaries. `obj->textsize` only seems to be used by PPC so 
the
  effect is untested. However, the value before was definitely wrong and the new
  result matches the phdrs.
  
  Reviewed By:  kib
  Approved By:  brooks (mentor)
  Differential Revision: https://reviews.freebsd.org/D17117

Modified:
  head/libexec/rtld-elf/map_object.c
  head/libexec/rtld-elf/rtld.c

Modified: head/libexec/rtld-elf/map_object.c
==============================================================================
--- head/libexec/rtld-elf/map_object.c  Mon Oct 29 21:03:43 2018        
(r339875)
+++ head/libexec/rtld-elf/map_object.c  Mon Oct 29 21:08:02 2018        
(r339876)
@@ -93,6 +93,7 @@ map_object(int fd, const char *path, const struct stat
     Elf_Addr note_end;
     char *note_map;
     size_t note_map_len;
+    Elf_Addr text_end;
 
     hdr = get_elf_header(fd, path, sb);
     if (hdr == NULL)
@@ -116,6 +117,7 @@ map_object(int fd, const char *path, const struct stat
     note_map = NULL;
     segs = alloca(sizeof(segs[0]) * hdr->e_phnum);
     stack_flags = RTLD_DEFAULT_STACK_PF_EXEC | PF_R | PF_W;
+    text_end = 0;
     while (phdr < phlimit) {
        switch (phdr->p_type) {
 
@@ -130,6 +132,10 @@ map_object(int fd, const char *path, const struct stat
                    path, nsegs);
                goto error;
            }
+           if ((segs[nsegs]->p_flags & PF_X) == PF_X) {
+               text_end = MAX(text_end,
+                   round_page(segs[nsegs]->p_vaddr + segs[nsegs]->p_memsz));
+           }
            break;
 
        case PT_PHDR:
@@ -280,8 +286,7 @@ map_object(int fd, const char *path, const struct stat
     }
     obj->mapbase = mapbase;
     obj->mapsize = mapsize;
-    obj->textsize = round_page(segs[0]->p_vaddr + segs[0]->p_memsz) -
-      base_vaddr;
+    obj->textsize = text_end - base_vaddr;
     obj->vaddrbase = base_vaddr;
     obj->relocbase = mapbase - base_vaddr;
     obj->dynamic = (const Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr);

Modified: head/libexec/rtld-elf/rtld.c
==============================================================================
--- head/libexec/rtld-elf/rtld.c        Mon Oct 29 21:03:43 2018        
(r339875)
+++ head/libexec/rtld-elf/rtld.c        Mon Oct 29 21:08:02 2018        
(r339876)
@@ -1390,13 +1390,15 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t e
            if (nsegs == 0) {   /* First load segment */
                obj->vaddrbase = trunc_page(ph->p_vaddr);
                obj->mapbase = obj->vaddrbase + obj->relocbase;
-               obj->textsize = round_page(ph->p_vaddr + ph->p_memsz) -
-                 obj->vaddrbase;
            } else {            /* Last load segment */
                obj->mapsize = round_page(ph->p_vaddr + ph->p_memsz) -
                  obj->vaddrbase;
            }
            nsegs++;
+           if ((ph->p_flags & PF_X) == PF_X) {
+               obj->textsize = MAX(obj->textsize,
+                   round_page(ph->p_vaddr + ph->p_memsz) - obj->vaddrbase);
+           }
            break;
 
        case PT_DYNAMIC:
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to