1999-02-19  Ulrich Drepper  <drepper@cygnus.com>

	* elf/ldsodefs.h (_dl_signal_error): Mark as __noreturn__.
	* elf/dl-load.c (lose): Make it a function at the toplevel, mark as
	noreturn, and prevent it from being inlined.
	Define LOSE appropriately.
	(_dl_map_object_from_fd): Compare all bytes in e_ident at once.
	Optimize decoding of p_flags for certain platforms.
This commit is contained in:
Ulrich Drepper 1999-02-19 20:37:20 +00:00
parent 4ac5087baf
commit 126b06f99e
3 changed files with 135 additions and 72 deletions

View File

@ -1,3 +1,12 @@
1999-02-19 Ulrich Drepper <drepper@cygnus.com>
* elf/ldsodefs.h (_dl_signal_error): Mark as __noreturn__.
* elf/dl-load.c (lose): Make it a function at the toplevel, mark as
noreturn, and prevent it from being inlined.
Define LOSE appropriately.
(_dl_map_object_from_fd): Compare all bytes in e_ident at once.
Optimize decoding of p_flags for certain platforms.
1999-02-19 Philip Blundell <pb@nexus.co.uk> 1999-02-19 Philip Blundell <pb@nexus.co.uk>
* Makeconfig (link-libc): When doing a static link, make sure that * Makeconfig (link-libc): When doing a static link, make sure that

View File

@ -555,6 +555,33 @@ _dl_init_paths (const char *llp)
} }
#define LOSE(code, s) lose (code, fd, name, realname, l, s)
static void volatile
__attribute__ ((noreturn))
lose (int code, int fd, const char *name, char *realname, struct link_map *l,
const char *msg)
{
/* The use of `alloca' here looks ridiculous but it helps. The goal
is to avoid the function from being inlined. There is no official
way to do this so we use this trick. gcc never inlines functions
which use `alloca'. */
int *a = alloca (sizeof (int));
a[0] = fd;
(void) __close (a[0]);
if (l != NULL)
{
/* Remove the stillborn object from the list and free it. */
if (l->l_prev)
l->l_prev->l_next = l->l_next;
if (l->l_next)
l->l_next->l_prev = l->l_prev;
free (l);
}
free (realname);
_dl_signal_error (code, name, msg);
}
/* Map in the shared object NAME, actually located in REALNAME, and already /* Map in the shared object NAME, actually located in REALNAME, and already
opened on FD. */ opened on FD. */
@ -565,25 +592,23 @@ struct link_map *
_dl_map_object_from_fd (const char *name, int fd, char *realname, _dl_map_object_from_fd (const char *name, int fd, char *realname,
struct link_map *loader, int l_type) struct link_map *loader, int l_type)
{ {
/* This is the expected ELF header. */
#define ELF32_CLASS ELFCLASS32
#define ELF64_CLASS ELFCLASS64
static const unsigned char expected[EI_PAD] =
{
[EI_MAG0] = ELFMAG0,
[EI_MAG1] = ELFMAG1,
[EI_MAG2] = ELFMAG2,
[EI_MAG3] = ELFMAG3,
[EI_CLASS] = ELFW(CLASS),
[EI_DATA] = byteorder,
[EI_VERSION] = EV_CURRENT,
[EI_OSABI] = ELFOSABI_SYSV,
[EI_ABIVERSION] = 0
};
struct link_map *l = NULL; struct link_map *l = NULL;
#define LOSE(s) lose (0, (s))
void lose (int code, const char *msg)
{
(void) __close (fd);
if (l)
{
/* Remove the stillborn object from the list and free it. */
if (l->l_prev)
l->l_prev->l_next = l->l_next;
if (l->l_next)
l->l_next->l_prev = l->l_prev;
free (l);
}
free (realname);
_dl_signal_error (code, name, msg);
}
inline caddr_t map_segment (ElfW(Addr) mapstart, size_t len, inline caddr_t map_segment (ElfW(Addr) mapstart, size_t len,
int prot, int fixed, off_t offset) int prot, int fixed, off_t offset)
{ {
@ -591,7 +616,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
fixed|MAP_COPY|MAP_FILE, fixed|MAP_COPY|MAP_FILE,
fd, offset); fd, offset);
if (mapat == MAP_FAILED) if (mapat == MAP_FAILED)
lose (errno, "failed to map segment from shared object"); LOSE (errno, "failed to map segment from shared object");
return mapat; return mapat;
} }
@ -605,8 +630,8 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
struct stat st; struct stat st;
/* Get file information. */ /* Get file information. */
if (__fstat (fd, &st) < 0) if (__fxstat (_STAT_VER, fd, &st) < 0)
lose (errno, "cannot stat shared object"); LOSE (errno, "cannot stat shared object");
/* Look again to see if the real name matched another already loaded. */ /* Look again to see if the real name matched another already loaded. */
for (l = _dl_loaded; l; l = l->l_next) for (l = _dl_loaded; l; l = l->l_next)
@ -631,48 +656,52 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
/* Read the header directly. */ /* Read the header directly. */
readbuf = alloca (_dl_pagesize); readbuf = alloca (_dl_pagesize);
readlength = __libc_read (fd, readbuf, _dl_pagesize); readlength = __libc_read (fd, readbuf, _dl_pagesize);
if (readlength < (ssize_t) sizeof(*header)) if (readlength < (ssize_t) sizeof (*header))
lose (errno, "cannot read file data"); LOSE (errno, "cannot read file data");
header = (void *) readbuf; header = (void *) readbuf;
/* Check the header for basic validity. */ /* Check the header for basic validity. */
if (*(Elf32_Word *) &header->e_ident != if (memcmp (header->e_ident, expected, EI_PAD) != 0)
{
/* Something is wrong. */
if (*(Elf32_Word *) &header->e_ident !=
#if BYTE_ORDER == LITTLE_ENDIAN #if BYTE_ORDER == LITTLE_ENDIAN
((ELFMAG0 << (EI_MAG0 * 8)) | ((ELFMAG0 << (EI_MAG0 * 8)) |
(ELFMAG1 << (EI_MAG1 * 8)) | (ELFMAG1 << (EI_MAG1 * 8)) |
(ELFMAG2 << (EI_MAG2 * 8)) | (ELFMAG2 << (EI_MAG2 * 8)) |
(ELFMAG3 << (EI_MAG3 * 8))) (ELFMAG3 << (EI_MAG3 * 8)))
#else #else
((ELFMAG0 << (EI_MAG3 * 8)) | ((ELFMAG0 << (EI_MAG3 * 8)) |
(ELFMAG1 << (EI_MAG2 * 8)) | (ELFMAG1 << (EI_MAG2 * 8)) |
(ELFMAG2 << (EI_MAG1 * 8)) | (ELFMAG2 << (EI_MAG1 * 8)) |
(ELFMAG3 << (EI_MAG0 * 8))) (ELFMAG3 << (EI_MAG0 * 8)))
#endif #endif
) )
LOSE ("invalid ELF header"); LOSE (0, "invalid ELF header");
#define ELF32_CLASS ELFCLASS32 if (header->e_ident[EI_CLASS] != ELFW(CLASS))
#define ELF64_CLASS ELFCLASS64 LOSE (0, "ELF file class not " STRING(__ELF_NATIVE_CLASS) "-bit");
if (header->e_ident[EI_CLASS] != ELFW(CLASS)) if (header->e_ident[EI_DATA] != byteorder)
LOSE ("ELF file class not " STRING(__ELF_NATIVE_CLASS) "-bit"); LOSE (0, "ELF file data encoding not " byteorder_name);
if (header->e_ident[EI_DATA] != byteorder) if (header->e_ident[EI_VERSION] != EV_CURRENT)
LOSE ("ELF file data encoding not " byteorder_name); LOSE (0, "ELF file version ident not " STRING(EV_CURRENT));
if (header->e_ident[EI_VERSION] != EV_CURRENT) /* XXX We should be able so set system specific versions which are
LOSE ("ELF file version ident not " STRING(EV_CURRENT)); allowed here. */
/* XXX We should be able so set system specific versions which are if (header->e_ident[EI_OSABI] != ELFOSABI_SYSV)
allowed here. */ LOSE (0, "ELF file OS ABI not " STRING(ELFOSABI_SYSV));
if (header->e_ident[EI_OSABI] != ELFOSABI_SYSV) if (header->e_ident[EI_ABIVERSION] != 0)
LOSE ("ELF file OS ABI not " STRING(ELFOSABI_SYSV)); LOSE (0, "ELF file ABI version not 0");
if (header->e_ident[EI_ABIVERSION] != 0) LOSE (0, "internal error");
LOSE ("ELF file ABI version not 0"); }
if (header->e_version != EV_CURRENT) if (header->e_version != EV_CURRENT)
LOSE ("ELF file version not " STRING(EV_CURRENT)); LOSE (0, "ELF file version not " STRING(EV_CURRENT));
if (! elf_machine_matches_host (header->e_machine)) if (! elf_machine_matches_host (header->e_machine))
LOSE ("ELF file machine architecture not " ELF_MACHINE_NAME); LOSE (0, "ELF file machine architecture not " ELF_MACHINE_NAME);
if (header->e_phentsize != sizeof (ElfW(Phdr))) if (header->e_phentsize != sizeof (ElfW(Phdr)))
LOSE ("ELF file's phentsize not the expected size"); LOSE (0, "ELF file's phentsize not the expected size");
#ifndef MAP_ANON #ifndef MAP_ANON
#define MAP_ANON 0 # define MAP_ANON 0
if (_dl_zerofd == -1) if (_dl_zerofd == -1)
{ {
_dl_zerofd = _dl_sysdep_open_zero_fill (); _dl_zerofd = _dl_sysdep_open_zero_fill ();
@ -687,7 +716,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
/* Enter the new object in the list of loaded objects. */ /* Enter the new object in the list of loaded objects. */
l = _dl_new_object (realname, name, l_type, loader); l = _dl_new_object (realname, name, l_type, loader);
if (! l) if (! l)
lose (ENOMEM, "cannot create shared object descriptor"); LOSE (ENOMEM, "cannot create shared object descriptor");
l->l_opencount = 1; l->l_opencount = 1;
/* Extract the remaining details we need from the ELF header /* Extract the remaining details we need from the ELF header
@ -704,7 +733,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
phdr = alloca (maplength); phdr = alloca (maplength);
__lseek (fd, SEEK_SET, header->e_phoff); __lseek (fd, SEEK_SET, header->e_phoff);
if (__libc_read (fd, (void *) phdr, maplength) != maplength) if (__libc_read (fd, (void *) phdr, maplength) != maplength)
lose (errno, "cannot read file data"); LOSE (errno, "cannot read file data");
} }
{ {
@ -717,9 +746,10 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
} loadcmds[l->l_phnum], *c; } loadcmds[l->l_phnum], *c;
size_t nloadcmds = 0; size_t nloadcmds = 0;
/* The struct is initialized to zero so this is not necessary:
l->l_ld = 0; l->l_ld = 0;
l->l_phdr = 0; l->l_phdr = 0;
l->l_addr = 0; l->l_addr = 0; */
for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph) for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)
switch (ph->p_type) switch (ph->p_type)
{ {
@ -737,9 +767,9 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
/* A load command tells us to map in part of the file. /* A load command tells us to map in part of the file.
We record the load commands and process them all later. */ We record the load commands and process them all later. */
if (ph->p_align % _dl_pagesize != 0) if (ph->p_align % _dl_pagesize != 0)
LOSE ("ELF load command alignment not page-aligned"); LOSE (0, "ELF load command alignment not page-aligned");
if ((ph->p_vaddr - ph->p_offset) % ph->p_align) if ((ph->p_vaddr - ph->p_offset) % ph->p_align)
LOSE ("ELF load command address/offset not properly aligned"); LOSE (0, "ELF load command address/offset not properly aligned");
{ {
struct loadcmd *c = &loadcmds[nloadcmds++]; struct loadcmd *c = &loadcmds[nloadcmds++];
c->mapstart = ph->p_vaddr & ~(ph->p_align - 1); c->mapstart = ph->p_vaddr & ~(ph->p_align - 1);
@ -748,13 +778,34 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
c->dataend = ph->p_vaddr + ph->p_filesz; c->dataend = ph->p_vaddr + ph->p_filesz;
c->allocend = ph->p_vaddr + ph->p_memsz; c->allocend = ph->p_vaddr + ph->p_memsz;
c->mapoff = ph->p_offset & ~(ph->p_align - 1); c->mapoff = ph->p_offset & ~(ph->p_align - 1);
c->prot = 0;
if (ph->p_flags & PF_R) /* Optimize a common case. */
c->prot |= PROT_READ; if ((PF_R | PF_W | PF_X) == 7
if (ph->p_flags & PF_W) && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7)
c->prot |= PROT_WRITE; {
if (ph->p_flags & PF_X) static const unsigned char pf_to_prot[8] =
c->prot |= PROT_EXEC; {
[0] = PROT_NONE,
[PF_R] = PROT_READ,
[PF_W] = PROT_WRITE,
[PF_R | PF_W] = PROT_READ | PROT_WRITE,
[PF_X] = PROT_EXEC,
[PF_R | PF_X] = PROT_READ | PROT_EXEC,
[PF_W | PF_X] = PROT_WRITE | PROT_EXEC,
[PF_R | PF_W | PF_X] = PROT_READ | PROT_WRITE | PROT_EXEC
};
c->prot = pf_to_prot[ph->p_flags & (PF_R | PF_W | PF_X)];
}
else
{
c->prot = 0;
if (ph->p_flags & PF_R)
c->prot |= PROT_READ;
if (ph->p_flags & PF_W)
c->prot |= PROT_WRITE;
if (ph->p_flags & PF_X)
c->prot |= PROT_EXEC;
}
break; break;
} }
} }
@ -842,7 +893,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
/* Dag nab it. */ /* Dag nab it. */
if (__mprotect ((caddr_t) (zero & ~(_dl_pagesize - 1)), if (__mprotect ((caddr_t) (zero & ~(_dl_pagesize - 1)),
_dl_pagesize, c->prot|PROT_WRITE) < 0) _dl_pagesize, c->prot|PROT_WRITE) < 0)
lose (errno, "cannot change memory protections"); LOSE (errno, "cannot change memory protections");
} }
memset ((void *) zero, 0, zeropage - zero); memset ((void *) zero, 0, zeropage - zero);
if ((c->prot & PROT_WRITE) == 0) if ((c->prot & PROT_WRITE) == 0)
@ -858,7 +909,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED, c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
ANONFD, 0); ANONFD, 0);
if (mapat == MAP_FAILED) if (mapat == MAP_FAILED)
lose (errno, "cannot map zero-fill pages"); LOSE (errno, "cannot map zero-fill pages");
} }
} }
@ -880,7 +931,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
break; break;
} }
if (l->l_phdr == 0) if (l->l_phdr == 0)
LOSE ("program headers not contained in any loaded segment"); LOSE (0, "program headers not contained in any loaded segment");
} }
else else
/* Adjust the PT_PHDR value by the runtime load address. */ /* Adjust the PT_PHDR value by the runtime load address. */
@ -896,7 +947,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
if (l->l_ld == 0) if (l->l_ld == 0)
{ {
if (type == ET_DYN) if (type == ET_DYN)
LOSE ("object file has no dynamic section"); LOSE (0, "object file has no dynamic section");
} }
else else
(ElfW(Addr)) l->l_ld += l->l_addr; (ElfW(Addr)) l->l_ld += l->l_addr;
@ -951,7 +1002,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
(struct link_map **) malloc (sizeof (struct link_map *)); (struct link_map **) malloc (sizeof (struct link_map *));
if (l->l_symbolic_searchlist.r_list == NULL) if (l->l_symbolic_searchlist.r_list == NULL)
lose (ENOMEM, "cannot create searchlist"); LOSE (ENOMEM, "cannot create searchlist");
l->l_symbolic_searchlist.r_list[0] = l; l->l_symbolic_searchlist.r_list[0] = l;
l->l_symbolic_searchlist.r_nlist = 1; l->l_symbolic_searchlist.r_nlist = 1;
@ -1280,9 +1331,11 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|| (l = _dl_new_object (name_copy, name, type, loader)) == NULL) || (l = _dl_new_object (name_copy, name, type, loader)) == NULL)
_dl_signal_error (ENOMEM, name, _dl_signal_error (ENOMEM, name,
"cannot create shared object descriptor"); "cannot create shared object descriptor");
/* We use an opencount of 0 as a sign for the faked entry. */ /* We use an opencount of 0 as a sign for the faked entry.
Since the descriptor is initialized with zero we do not
have do this here.
l->l_opencount = 0; l->l_opencount = 0;
l->l_reserved = 0; l->l_reserved = 0; */
l->l_buckets = &dummy_bucket; l->l_buckets = &dummy_bucket;
l->l_nbuckets = 1; l->l_nbuckets = 1;
l->l_relocated = 1; l->l_relocated = 1;

View File

@ -1,5 +1,5 @@
/* Run-time dynamic linker data structures for loaded ELF shared objects. /* Run-time dynamic linker data structures for loaded ELF shared objects.
Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -205,7 +205,8 @@ extern int _dl_secure;
extern void _dl_signal_error (int errcode, extern void _dl_signal_error (int errcode,
const char *object, const char *object,
const char *errstring) const char *errstring)
internal_function; internal_function
__attribute__ ((__noreturn__));
/* Call OPERATE, catching errors from `dl_signal_error'. If there is no /* Call OPERATE, catching errors from `dl_signal_error'. If there is no
error, *ERRSTRING is set to null. If there is an error, *ERRSTRING is error, *ERRSTRING is set to null. If there is an error, *ERRSTRING is