diff options
Diffstat (limited to 'sysdeps/nacl/dl-unmap-segments.h')
-rw-r--r-- | sysdeps/nacl/dl-unmap-segments.h | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/sysdeps/nacl/dl-unmap-segments.h b/sysdeps/nacl/dl-unmap-segments.h new file mode 100644 index 0000000000..02851e7dc3 --- /dev/null +++ b/sysdeps/nacl/dl-unmap-segments.h @@ -0,0 +1,65 @@ +/* Unmap a shared object's segments. NaCl version. + Copyright (C) 2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _DL_UNMAP_SEGMENTS_H +#define _DL_UNMAP_SEGMENTS_H 1 + +#include <link.h> +#include <sys/mman.h> + +/* There is always a big gap between the executable segment and the data + segments. Other code segments and data pages lie in there. So we must + unmap each segment individually (except for a codeless module). */ + +static void __always_inline +_dl_unmap_segments (struct link_map *l) +{ + if (l->l_contiguous) + /* Simple case. */ + __munmap ((void *) l->l_map_start, l->l_map_end - l->l_map_start); + else + { + /* Normally l_phdr points into the RODATA segment, which we will + unmap in one iteration of the loop. So we cannot use it directly + throughout. */ + + struct { ElfW(Addr) start, end; } segments[l->l_phnum], *seg = segments; + + for (const ElfW(Phdr) *ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph) + if (ph->p_type == PT_LOAD) + { + seg->start = (l->l_addr + ph->p_vaddr) & -GLRO(dl_pagesize); + seg->end = (l->l_addr + ph->p_vaddr + ph->p_memsz + + GLRO(dl_pagesize) - 1) & -GLRO(dl_pagesize); + if (seg > segments && seg[-1].end == seg->start) + /* Coalesce two adjacent segments into one munmap call. */ + seg[-1].end = seg->end; + else + ++seg; + } + + do + { + --seg; + __munmap ((void *) seg->start, seg->end - seg->start); + } + while (seg > segments); + } +} + +#endif /* dl-unmap-segments.h */ |