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
This commit is contained in:
arichardson 2018-10-29 21:08:02 +00:00
parent 024cdacaea
commit 4a1080a9d3
2 changed files with 11 additions and 4 deletions

View File

@ -93,6 +93,7 @@ map_object(int fd, const char *path, const struct stat *sb)
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 *sb)
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 *sb)
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 *sb)
}
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);

View File

@ -1390,13 +1390,15 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
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: