2014-04-04 01:47:14 +08:00
|
|
|
/* Map in a shared object's segments from the file.
|
2022-01-02 02:54:23 +08:00
|
|
|
Copyright (C) 1995-2022 Free Software Foundation, Inc.
|
2021-12-10 20:39:10 +08:00
|
|
|
Copyright The GNU Toolchain Authors.
|
2014-04-04 01:47:14 +08:00
|
|
|
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
|
Prefer https to http for gnu.org and fsf.org URLs
Also, change sources.redhat.com to sourceware.org.
This patch was automatically generated by running the following shell
script, which uses GNU sed, and which avoids modifying files imported
from upstream:
sed -ri '
s,(http|ftp)(://(.*\.)?(gnu|fsf|sourceware)\.org($|[^.]|\.[^a-z])),https\2,g
s,(http|ftp)(://(.*\.)?)sources\.redhat\.com($|[^.]|\.[^a-z]),https\2sourceware.org\4,g
' \
$(find $(git ls-files) -prune -type f \
! -name '*.po' \
! -name 'ChangeLog*' \
! -path COPYING ! -path COPYING.LIB \
! -path manual/fdl-1.3.texi ! -path manual/lgpl-2.1.texi \
! -path manual/texinfo.tex ! -path scripts/config.guess \
! -path scripts/config.sub ! -path scripts/install-sh \
! -path scripts/mkinstalldirs ! -path scripts/move-if-change \
! -path INSTALL ! -path locale/programs/charmap-kw.h \
! -path po/libc.pot ! -path sysdeps/gnu/errlist.c \
! '(' -name configure \
-execdir test -f configure.ac -o -f configure.in ';' ')' \
! '(' -name preconfigure \
-execdir test -f preconfigure.ac ';' ')' \
-print)
and then by running 'make dist-prepare' to regenerate files built
from the altered files, and then executing the following to cleanup:
chmod a+x sysdeps/unix/sysv/linux/riscv/configure
# Omit irrelevant whitespace and comment-only changes,
# perhaps from a slightly-different Autoconf version.
git checkout -f \
sysdeps/csky/configure \
sysdeps/hppa/configure \
sysdeps/riscv/configure \
sysdeps/unix/sysv/linux/csky/configure
# Omit changes that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/powerpc/powerpc64/ppc-mcount.S: trailing lines
git checkout -f \
sysdeps/powerpc/powerpc64/ppc-mcount.S \
sysdeps/unix/sysv/linux/s390/s390-64/syscall.S
# Omit change that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S: last line does not end in newline
git checkout -f sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S
2019-09-07 13:40:42 +08:00
|
|
|
<https://www.gnu.org/licenses/>. */
|
2014-04-04 01:47:14 +08:00
|
|
|
|
|
|
|
#ifndef _DL_LOAD_H
|
|
|
|
#define _DL_LOAD_H 1
|
|
|
|
|
|
|
|
#include <link.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
|
|
|
|
|
|
/* On some systems, no flag bits are given to specify file mapping. */
|
|
|
|
#ifndef MAP_FILE
|
|
|
|
# define MAP_FILE 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* The right way to map in the shared library files is MAP_COPY, which
|
|
|
|
makes a virtual copy of the data at the time of the mmap call; this
|
|
|
|
guarantees the mapped pages will be consistent even if the file is
|
|
|
|
overwritten. Some losing VM systems like Linux's lack MAP_COPY. All we
|
|
|
|
get is MAP_PRIVATE, which copies each page when it is modified; this
|
|
|
|
means if the file is overwritten, we may at some point get some pages
|
|
|
|
from the new version after starting with pages from the old version.
|
|
|
|
|
|
|
|
To make up for the lack and avoid the overwriting problem,
|
|
|
|
what Linux does have is MAP_DENYWRITE. This prevents anyone
|
|
|
|
from modifying the file while we have it mapped. */
|
|
|
|
#ifndef MAP_COPY
|
|
|
|
# ifdef MAP_DENYWRITE
|
|
|
|
# define MAP_COPY (MAP_PRIVATE | MAP_DENYWRITE)
|
|
|
|
# else
|
|
|
|
# define MAP_COPY MAP_PRIVATE
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Some systems link their relocatable objects for another base address
|
|
|
|
than 0. We want to know the base address for these such that we can
|
|
|
|
subtract this address from the segment addresses during mapping.
|
|
|
|
This results in a more efficient address space usage. Defaults to
|
|
|
|
zero for almost all systems. */
|
|
|
|
#ifndef MAP_BASE_ADDR
|
|
|
|
# define MAP_BASE_ADDR(l) 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* Handle situations where we have a preferred location in memory for
|
|
|
|
the shared objects. */
|
|
|
|
#ifdef ELF_PREFERRED_ADDRESS_DATA
|
|
|
|
ELF_PREFERRED_ADDRESS_DATA;
|
|
|
|
#endif
|
|
|
|
#ifndef ELF_PREFERRED_ADDRESS
|
|
|
|
# define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref)
|
|
|
|
#endif
|
|
|
|
#ifndef ELF_FIXED_ADDRESS
|
|
|
|
# define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* This structure describes one PT_LOAD command.
|
|
|
|
Its details have been expanded out and converted. */
|
|
|
|
struct loadcmd
|
|
|
|
{
|
2021-12-10 20:39:10 +08:00
|
|
|
ElfW(Addr) mapstart, mapend, dataend, allocend, mapalign;
|
2014-04-04 01:47:14 +08:00
|
|
|
ElfW(Off) mapoff;
|
|
|
|
int prot; /* PROT_* bits. */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* This is a subroutine of _dl_map_segments. It should be called for each
|
|
|
|
load command, some time after L->l_addr has been set correctly. It is
|
|
|
|
responsible for setting up the l_text_end and l_phdr fields. */
|
2019-02-07 01:16:43 +08:00
|
|
|
static __always_inline void
|
2014-04-04 01:47:14 +08:00
|
|
|
_dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header,
|
|
|
|
const struct loadcmd *c)
|
|
|
|
{
|
|
|
|
if (c->prot & PROT_EXEC)
|
|
|
|
l->l_text_end = l->l_addr + c->mapend;
|
|
|
|
|
|
|
|
if (l->l_phdr == 0
|
|
|
|
&& c->mapoff <= header->e_phoff
|
|
|
|
&& ((size_t) (c->mapend - c->mapstart + c->mapoff)
|
|
|
|
>= header->e_phoff + header->e_phnum * sizeof (ElfW(Phdr))))
|
|
|
|
/* Found the program header in this segment. */
|
|
|
|
l->l_phdr = (void *) (uintptr_t) (c->mapstart + header->e_phoff
|
|
|
|
- c->mapoff);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This is a subroutine of _dl_map_object_from_fd. It is responsible
|
|
|
|
for filling in several fields in *L: l_map_start, l_map_end, l_addr,
|
|
|
|
l_contiguous, l_text_end, l_phdr. On successful return, all the
|
|
|
|
segments are mapped (or copied, or whatever) from the file into their
|
|
|
|
final places in the address space, with the correct page permissions,
|
|
|
|
and any bss-like regions already zeroed. It returns a null pointer
|
|
|
|
on success, or an error message string (to be translated) on error
|
|
|
|
(having also set errno).
|
|
|
|
|
|
|
|
The file <dl-map-segments.h> defines this function. The canonical
|
|
|
|
implementation in elf/dl-map-segments.h might be replaced by a sysdeps
|
|
|
|
version. */
|
|
|
|
static const char *_dl_map_segments (struct link_map *l, int fd,
|
|
|
|
const ElfW(Ehdr) *header, int type,
|
|
|
|
const struct loadcmd loadcmds[],
|
|
|
|
size_t nloadcmds,
|
|
|
|
const size_t maplength,
|
|
|
|
bool has_holes,
|
|
|
|
struct link_map *loader);
|
|
|
|
|
|
|
|
/* All the error message strings _dl_map_segments might return are
|
|
|
|
listed here so that different implementations in different sysdeps
|
|
|
|
dl-map-segments.h files all use consistent strings that are
|
|
|
|
guaranteed to have translations. */
|
|
|
|
#define DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT \
|
|
|
|
N_("failed to map segment from shared object")
|
|
|
|
#define DL_MAP_SEGMENTS_ERROR_MPROTECT \
|
|
|
|
N_("cannot change memory protections")
|
|
|
|
#define DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL \
|
|
|
|
N_("cannot map zero-fill pages")
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* dl-load.h */
|