Mon Oct 9 02:54:14 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>

* Makeconfig (config-LDFLAGS): Define to
	-Wl-dynamic-linker=$(libdir)$(rtld-installed-name).
	(rtld-installed-name): New variable.
	* elf/Makefile (install-lib): Variable removed.
	(install-others): Define this instead, to
	$(libdir)(rtld-installed-name). 
	($(libdir)(rtld-installed-name)): New target; install from ld.so.

	* elf/ldd.sh.in: New file.
	* elf/Makefile (distribute): Add ldd.sh.in.
	(install-bin): Add ldd.
	($(objpfx)ldd: ldd.sh.in): New rule.

	* sysdeps/mach/hurd/dl-sysdep.c: Use __hurd_fail throughout.
	* hurd/hurd.h (__hurd_fail): Replace macro with inline function.
	Translate some Mach errors to Hurd errors.

	* elf/rtld.c (dl_main): Under --list, print msg if executable is
	statically linked.

	* elf/dl-load.c (_dl_map_object_from_fd): Rewrote program header
	table processing.

Sat Oct  7 01:25:48 1995  Roland McGrath  <roland@churchy.gnu.ai.mit.edu>

	* sysdeps/stub/machine-gmon.h: Add #error.

Fri Oct  6 01:49:48 1995  Roland McGrath  <roland@churchy.gnu.ai.mit.edu>

	* elf/dynamic-link.h (elf_get_dynamic_info): If DYN is null, don't
	examine it.
This commit is contained in:
Roland McGrath 1995-10-09 07:06:29 +00:00
parent 80fd73873b
commit b122c7038e
11 changed files with 303 additions and 175 deletions

View File

@ -1,3 +1,37 @@
Mon Oct 9 02:54:14 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
* Makeconfig (config-LDFLAGS): Define to
-Wl-dynamic-linker=$(libdir)$(rtld-installed-name).
(rtld-installed-name): New variable.
* elf/Makefile (install-lib): Variable removed.
(install-others): Define this instead, to
$(libdir)(rtld-installed-name).
($(libdir)(rtld-installed-name)): New target; install from ld.so.
* elf/ldd.sh.in: New file.
* elf/Makefile (distribute): Add ldd.sh.in.
(install-bin): Add ldd.
($(objpfx)ldd: ldd.sh.in): New rule.
* sysdeps/mach/hurd/dl-sysdep.c: Use __hurd_fail throughout.
* hurd/hurd.h (__hurd_fail): Replace macro with inline function.
Translate some Mach errors to Hurd errors.
* elf/rtld.c (dl_main): Under --list, print msg if executable is
statically linked.
* elf/dl-load.c (_dl_map_object_from_fd): Rewrote program header
table processing.
Sat Oct 7 01:25:48 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
* sysdeps/stub/machine-gmon.h: Add #error.
Fri Oct 6 01:49:48 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
* elf/dynamic-link.h (elf_get_dynamic_info): If DYN is null, don't
examine it.
Fri Sep 29 03:43:51 1995 Paul Eggert <eggert@twinsun.com>
Rewrite mktime from scratch for performance, and for correctness

View File

@ -272,6 +272,11 @@ ifndef +link
$(^:$(common-objpfx)libc.a=$(link-libc)) \
$(addprefix $(csu-objpfx),$(+postinit))
endif
ifndef config-LDFLAGS
ifeq (yes,$(build-shared))
config-LDFLAGS = -Wl,-dynamic-linker=$(libdir)$(rtld-installed-name)
endif
endif
ifndef link-libc
ifeq (yes,$(build-shared))
link-libc = -L$(common-objdir) -lc $(gnulib)
@ -292,6 +297,12 @@ else
csu-objpfx = $(..)csu/
endif
ifeq (yes,$(build-shared))
ifndef rtld-installed-name
rtld-installed-name = ld.so
endif
endif
ifndef LD
LD := ld -X
endif

View File

@ -27,18 +27,18 @@ extra-libs = libelf libdl
libelf-routines := elf_hash
libdl-routines := dlopen dlclose dlsym dlerror
libdl-inhibit-o = $(filter-out .so,$(object-suffixes)) # Build only shared.
LDFLAGS-dl.so := -e 0 # work around ld bug
rtld-routines := rtld $(addprefix dl-,load lookup object reloc \
runtime sysdep error init fini)
distribute = $(rtld-routines:=.c) dynamic-link.h do-rel.h \
soinit.c sofini.c
soinit.c sofini.c ldd.sh.in
include ../Makeconfig
ifeq (yes,$(build-shared))
extra-objs = $(rtld-routines:=.so) soinit.so sofini.so
install-lib = ld.so
install-others = $(libdir)(rtld-installed-name)
install-bin = ldd
endif
include ../Rules
@ -54,3 +54,9 @@ $(objpfx)libdl.so: $(objpfx)libdl_pic.a $(common-objpfx)libc.so $(objpfx)ld.so
$(LINK.o) -shared -o $(@:$(objpfx)%=%) \
$(LDFLAGS.so) $(LDFLAGS-dl.so) \
-Wl,--whole-archive $(^:$(objpfx)%=%)
$(libdir)$(rtld-installed-name): $(objpfx)ld.so; $(do-install-program)
$(objpfx)ldd: ldd.sh.in
sed 's%@RTLD@%$(libdir)/$(rtld-installed-name)%g' < $< > $@.new
mv -f $@.new $@

View File

@ -166,6 +166,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
void *file_mapping = NULL;
size_t mapping_size = 0;
#define LOSE(s) lose (0, (s))
void lose (int code, const char *msg)
{
(void) close (fd);
@ -174,6 +175,17 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
_dl_signal_error (code, l ? l->l_name : name, msg);
}
inline caddr_t map_segment (Elf32_Addr mapstart, size_t len,
int prot, int fixed, off_t offset)
{
caddr_t mapat = mmap ((caddr_t) mapstart, len, prot,
fixed|MAP_COPY|MAP_FILE|MAP_INHERIT,
fd, offset);
if (mapat == (caddr_t) -1)
lose (errno, "failed to map segment from shared object");
return mapat;
}
/* Make sure LOCATION is mapped in. */
void *map (off_t location, size_t size)
{
@ -194,6 +206,9 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
}
const Elf32_Ehdr *header;
const Elf32_Phdr *phdr;
const Elf32_Phdr *ph;
int type;
/* Look again to see if the real name matched another already loaded. */
for (l = _dl_loaded; l; l = l->l_next)
@ -210,8 +225,6 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
/* Map in the first page to read the header. */
header = map (0, sizeof *header);
#undef LOSE
#define LOSE(s) lose (0, (s))
/* Check the header for basic validity. */
if (*(Elf32_Word *) &header->e_ident != ((ELFMAG0 << (EI_MAG0 * 8)) |
(ELFMAG1 << (EI_MAG1 * 8)) |
@ -242,27 +255,26 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
_dl_signal_error (errno, NULL, "cannot open zero fill device");
}
{
/* Copy the program header table into stack space so we can then unmap
the headers. */
Elf32_Phdr phdr[header->e_phnum];
const Elf32_Phdr *ph;
int anywhere, type;
type = header->e_type;
anywhere = type == ET_DYN || type == ET_REL;
/* Extract the remaining details we need from the ELF header
and then map in the program header table. */
l->l_entry = header->e_entry;
ph = map (header->e_phoff, header->e_phnum * sizeof (Elf32_Phdr));
memcpy (phdr, ph, sizeof phdr);
type = header->e_type;
l->l_phnum = header->e_phnum;
phdr = map (header->e_phoff, l->l_phnum * sizeof (Elf32_Phdr));
/* We are done reading the file's headers now. Unmap them. */
munmap (file_mapping, mapping_size);
{
/* Scan the program header table, collecting its load commands. */
struct loadcmd
{
Elf32_Addr mapstart, mapend, dataend, allocend;
off_t mapoff;
int prot;
} loadcmds[l->l_phnum], *c;
size_t nloadcmds = 0;
/* Scan the program header table, processing its load commands. */
l->l_addr = 0;
l->l_ld = 0;
l->l_phdr = 0;
l->l_addr = 0;
for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)
switch (ph->p_type)
{
@ -277,98 +289,113 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
break;
case PT_LOAD:
/* 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. */
if (ph->p_align % pagesize != 0)
LOSE ("ELF load command alignment not page-aligned");
if ((ph->p_vaddr - ph->p_offset) % ph->p_align)
LOSE ("ELF load command address/offset not properly aligned");
{
Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
Elf32_Addr mapend = ((ph->p_vaddr + ph->p_filesz + ph->p_align - 1)
struct loadcmd *c = &loadcmds[nloadcmds++];
c->mapstart = ph->p_vaddr & ~(ph->p_align - 1);
c->mapend = ((ph->p_vaddr + ph->p_filesz + ph->p_align - 1)
& ~(ph->p_align - 1));
off_t mapoff = ph->p_offset & ~(ph->p_align - 1);
caddr_t mapat;
int prot = 0;
c->dataend = ph->p_vaddr + ph->p_filesz;
c->allocend = ph->p_vaddr + ph->p_memsz;
c->mapoff = ph->p_offset & ~(ph->p_align - 1);
c->prot = 0;
if (ph->p_flags & PF_R)
prot |= PROT_READ;
c->prot |= PROT_READ;
if (ph->p_flags & PF_W)
prot |= PROT_WRITE;
c->prot |= PROT_WRITE;
if (ph->p_flags & PF_X)
prot |= PROT_EXEC;
if (anywhere)
{
/* XXX this loses if the first segment mmap call puts
it someplace where the later segments cannot fit. */
mapat = mmap ((caddr_t) (l->l_addr + mapstart),
mapend - mapstart,
prot, MAP_COPY|MAP_FILE|MAP_INHERIT |
/* Let the system choose any convenient
location if this is the first segment.
Following segments must be contiguous in
virtual space with the first. */
(l->l_addr == 0 ? 0 : MAP_FIXED),
fd, mapoff);
if (l->l_addr == 0)
/* This was the first segment mapped, so MAPAT is
the address the system chose for us. Record it. */
l->l_addr = (Elf32_Addr) mapat - mapstart;
c->prot |= PROT_EXEC;
break;
}
else
{
mapat = mmap ((caddr_t) mapstart, mapend - mapstart,
prot, MAP_COPY|MAP_FILE|MAP_INHERIT|MAP_FIXED,
fd, mapoff);
/* This file refers to absolute addresses. So consider its
"load base" to be zero, since that is what we add to the
file's addresses to find them in our memory. */
l->l_addr = 0;
}
if (mapat == (caddr_t) -1)
lose (errno, "failed to map segment from shared object");
if (ph->p_memsz > ph->p_filesz)
/* We are done reading the file's headers now. Unmap them. */
munmap (file_mapping, mapping_size);
/* Now process the load commands and map segments into memory. */
c = loadcmds;
if (type == ET_DYN || type == ET_REL)
{
/* This is a position-independent shared object. We can let the
kernel map it anywhere it likes, but we must have space for all
the segments in their specified positions relative to the first.
So we map the first segment without MAP_FIXED, but with its
extent increased to cover all the segments. Then we unmap the
excess portion, and there is known sufficient space there to map
the later segments. */
caddr_t mapat;
mapat = map_segment (c->mapstart,
loadcmds[nloadcmds - 1].allocend - c->mapstart,
c->prot, 0, c->mapoff);
l->l_addr = (Elf32_Addr) mapat - c->mapstart;
/* Unmap the excess portion, and then jump into the normal
segment-mapping loop to handle the portion of the segment past
the end of the file mapping. */
munmap (mapat + c->mapend,
loadcmds[nloadcmds - 1].allocend - c->mapend);
goto postmap;
}
while (c < &loadcmds[nloadcmds])
{
if (c->mapend > c->mapstart)
/* Map the segment contents from the file. */
map_segment (l->l_addr + c->mapstart, c->mapend - c->mapstart,
c->prot, MAP_FIXED, c->mapoff);
postmap:
if (c->allocend > c->dataend)
{
/* Extra zero pages should appear at the end of this segment,
after the data mapped from the file. */
caddr_t zero, zeroend, zeropage;
Elf32_Addr zero, zeroend, zeropage;
mapat += ph->p_vaddr - mapstart;
zero = mapat + ph->p_filesz;
zeroend = mapat + ph->p_memsz;
zeropage = (caddr_t) ((Elf32_Addr) (zero + pagesize - 1)
& ~(pagesize - 1));
zero = l->l_addr + c->dataend;
zeroend = l->l_addr + c->allocend;
zeropage = (zero + pagesize - 1) & ~(pagesize - 1);
if (zeroend < zeropage)
/* All the extra data is in the last page of the segment.
We can just zero it. */
zeropage = zeroend;
if (zeropage > zero)
{
/* Zero the final part of the last page of the segment. */
if ((prot & PROT_WRITE) == 0)
if ((c->prot & PROT_WRITE) == 0)
{
/* Dag nab it. */
if (mprotect ((caddr_t) ((Elf32_Addr) zero
& ~(pagesize - 1)),
pagesize,
prot|PROT_WRITE) < 0)
if (mprotect ((caddr_t) (zero & ~(pagesize - 1)),
pagesize, c->prot|PROT_WRITE) < 0)
lose (errno, "cannot change memory protections");
}
memset (zero, 0, zeropage - zero);
if ((prot & PROT_WRITE) == 0)
mprotect ((caddr_t) ((Elf32_Addr) zero
& ~(pagesize - 1)),
pagesize, prot);
memset ((void *) zero, 0, zeropage - zero);
if ((c->prot & PROT_WRITE) == 0)
mprotect ((caddr_t) (zero & ~(pagesize - 1)),
pagesize, c->prot);
}
if (zeroend > zeropage)
{
/* Map the remaining zero pages in from the zero fill FD. */
mapat = mmap (zeropage, zeroend - zeropage, prot,
caddr_t mapat;
mapat = mmap ((caddr_t) zeropage, zeroend - zeropage, c->prot,
MAP_ANON|MAP_PRIVATE|MAP_FIXED|MAP_INHERIT,
_dl_zerofd, 0);
if (mapat == (caddr_t) -1)
lose (errno, "cannot map zero pages");
}
}
++c;
}
}
if (l->l_ld == 0)
@ -383,9 +410,6 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname)
l->l_phdr = (void *) ((const Elf32_Ehdr *) l->l_addr)->e_phoff;
(Elf32_Addr) l->l_phdr += l->l_addr;
l->l_entry += l->l_addr;
}
elf_get_dynamic_info (l->l_ld, l->l_info);
if (l->l_info[DT_HASH])
_dl_setup_hash (l);

View File

@ -32,6 +32,9 @@ elf_get_dynamic_info (Elf32_Dyn *dyn, Elf32_Dyn *info[DT_NUM])
for (i = 0; i < DT_NUM; ++i)
info[i] = NULL;
if (! dyn)
return;
while (dyn->d_tag != DT_NULL)
{
assert (dyn->d_tag < DT_NUM);

26
elf/ldd.sh.in Normal file
View File

@ -0,0 +1,26 @@
#! /bin/sh
# This is the `ldd' command, which lists what shared libraries are
# used by given dynamically-linked executables. It works by invoking the
# run-time dynamic linker as a command and giving it the special `--list'
# switch.
RTLD=@RTLD@
case $# in
0)
echo >&2 "Usage: $0 FILE..."
exit 1 ;;
1)
# We don't list the file name when there is only one.
exec ${RTLD} --list "$1" && exit 1
exit ;;
*)
set -e # Bail out immediately if ${RTLD} loses on any argument.
for file; do
echo "${file}:"
${RTLD} --list "$file"
done
esac
exit 0

View File

@ -281,6 +281,13 @@ of this helper program; chances are you did not intend to run this program.\n",
if (list_only)
{
if (! _dl_loaded->l_info[DT_NEEDED])
{
_dl_sysdep_message (_dl_loaded->l_name, ": statically linked\n",
NULL);
_exit (1);
}
for (l = _dl_loaded->l_next; l; l = l->l_next)
{
char buf[20], *bp;

View File

@ -42,7 +42,33 @@ Cambridge, MA 02139, USA. */
#include <hurd/port.h>
#include <errno.h>
#define __hurd_fail(err) (errno = (err), -1)
_EXTERN_INLINE int
__hurd_fail (error_t err)
{
switch (err)
{
case EMACH_SEND_INVALID_DEST:
case EMIG_SERVER_DIED:
/* The server has disappeared! */
err = EIEIO;
break;
case KERN_NO_SPACE:
err = ENOMEM;
break;
case KERN_INVALID_ARGUMENT:
err = EINVAL;
break;
case 0:
return 0;
default:
}
errno = err;
return -1;
}
/* Basic ports and info, initialized by startup. */

View File

@ -262,41 +262,38 @@ open (const char *file_name, int mode, ...)
file_t startdir, newpt, fileport;
int dealloc_dir;
int nloops;
error_t err;
assert (mode == O_RDONLY);
startdir = _dl_hurd_data->portarray[file_name[0] == '/' ?
INIT_PORT_CRDIR : INIT_PORT_CWDIR];
while (file_name[0] == '/')
file_name++;
if (errno = __dir_lookup (startdir, file_name, mode, 0,
if (err = __dir_lookup (startdir, file_name, mode, 0,
&doretry, retryname, &fileport))
return -1;
return __hurd_fail (err);
dealloc_dir = 0;
nloops = 0;
errno = 0;
while (1)
{
if (dealloc_dir)
__mach_port_deallocate (__mach_task_self (), startdir);
if (errno)
return -1;
if (err)
return __hurd_fail (err);
switch (doretry)
{
case FS_RETRY_REAUTH:
{
mach_port_t ref = __mach_reply_port ();
errno = __io_reauthenticate
(fileport, ref, MACH_MSG_TYPE_MAKE_SEND);
if (! errno)
errno = __auth_user_authenticate
err = __io_reauthenticate (fileport, ref, MACH_MSG_TYPE_MAKE_SEND);
if (! err)
err = __auth_user_authenticate
(_dl_hurd_data->portarray[INIT_PORT_AUTH],
fileport,
ref, MACH_MSG_TYPE_MAKE_SEND,
@ -304,18 +301,15 @@ open (const char *file_name, int mode, ...)
__mach_port_destroy (__mach_task_self (), ref);
}
__mach_port_deallocate (__mach_task_self (), fileport);
if (errno)
return -1;
if (err)
return __hurd_fail (err);
fileport = newpt;
/* Fall through. */
case FS_RETRY_NORMAL:
#ifdef SYMLOOP_MAX
if (nloops++ >= SYMLOOP_MAX)
{
errno = ELOOP;
return -1;
}
return __hurd_fail (ELOOP);
#endif
/* An empty RETRYNAME indicates we have the final port. */
@ -327,11 +321,11 @@ open (const char *file_name, int mode, ...)
opened:
/* We have the file open. Now map it. */
errno = __io_map (fileport, &memobj_rd, &memobj_wr);
err = __io_map (fileport, &memobj_rd, &memobj_wr);
if (dealloc_dir)
__mach_port_deallocate (__mach_task_self (), fileport);
if (errno)
return -1;
if (err)
return __hurd_fail (err);
if (memobj_wr != MACH_PORT_NULL)
__mach_port_deallocate (__mach_task_self (), memobj_wr);
@ -359,26 +353,20 @@ open (const char *file_name, int mode, ...)
{
int fd;
char *end;
errno = 0;
err = 0;
fd = (int) strtol (retryname, &end, 10);
if (end == NULL || errno || /* Malformed number. */
if (end == NULL || err || /* Malformed number. */
/* Check for excess text after the number. A slash
is valid; it ends the component. Anything else
does not name a numeric file descriptor. */
(*end != '/' && *end != '\0'))
{
errno = ENOENT;
return -1;
}
return __hurd_fail (ENOENT);
if (fd < 0 || fd >= _dl_hurd_data->dtablesize ||
_dl_hurd_data->dtable[fd] == MACH_PORT_NULL)
{
/* If the name was a proper number, but the file
descriptor does not exist, we return EBADF instead
of ENOENT. */
errno = EBADF;
return -1;
}
return __hurd_fail (EBADF);
fileport = _dl_hurd_data->dtable[fd];
if (*end == '\0')
{
@ -459,13 +447,13 @@ open (const char *file_name, int mode, ...)
}
case '\0':
if (errno = opentty (&fileport))
return -1;
if (err = opentty (&fileport))
return __hurd_fail (err);
dealloc_dir = 1;
goto opened;
case '/':
if (errno = opentty (&startdir))
return -1;
if (err = opentty (&startdir))
return __hurd_fail (err);
dealloc_dir = 1;
strcpy (retryname, &retryname[4]);
break;
@ -478,17 +466,15 @@ open (const char *file_name, int mode, ...)
default:
bad_magic:
errno = EGRATUITOUS;
return -1;
return __hurd_fail (EGRATUITOUS);
}
break;
default:
errno = EGRATUITOUS;
return -1;
return __hurd_fail (EGRATUITOUS);
}
errno = __dir_lookup (startdir, file_name, mode, 0,
err = __dir_lookup (startdir, file_name, mode, 0,
&doretry, retryname, &fileport);
}
}
@ -504,6 +490,7 @@ close (int fd)
caddr_t
mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
{
error_t err;
vm_prot_t vmprot;
vm_address_t mapaddr;
@ -516,14 +503,14 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
vmprot |= VM_PROT_EXECUTE;
mapaddr = (vm_address_t) addr;
errno = __vm_map (__mach_task_self (),
err = __vm_map (__mach_task_self (),
&mapaddr, (vm_size_t) len, 0 /*ELF_MACHINE_USER_ADDRESS_MASK*/,
!(flags & MAP_FIXED),
(mach_port_t) fd, (vm_offset_t) offset,
flags & (MAP_COPY|MAP_PRIVATE),
vmprot, VM_PROT_ALL,
(flags & MAP_INHERIT) ? VM_INHERIT_COPY : VM_INHERIT_NONE);
return errno ? (caddr_t) -1 : (caddr_t) mapaddr;
return err ? (caddr_t) __hurd_fail (err) : (caddr_t) mapaddr;
}
void

View File

@ -26,3 +26,5 @@ void mcount (u_long arg) \
{ \
_mcount (caller return PC, my return PC); \
}
#error "sysdeps/MACHINE/machine-gmon.h missing"

View File

@ -65,7 +65,7 @@ for unix_function in \
getitimer setitimer \
getdomainname/getdomain=bsd/bsd4.4 \
setdomainname/setdomain=bsd/bsd4.4 \
profil=bsd \
profil=bsd readv=bsd writev=bsd \
getpriority setpriority \
getrlimit setrlimit
do
@ -78,7 +78,7 @@ do
eval "unix_syscall=`echo $unix_function | \
sed -e 's@=\(.*\)$@ unix_srcdir=\1@' \
-e 's@/\(.*\)$@ unix_srcname=\1@'`"
test -z "$unix_srcname" && unix_srcname=$unix_function
test -z "$unix_srcname" && unix_srcname=$unix_syscall
unix_implementor=none
for unix_dir in $sysnames; do
@ -90,11 +90,13 @@ do
fi
done
case $unix_syscall in
mkdir|rmdir)
# mkdir and rmdir have implementations in unix/sysv, but
# the simple syscall versions are preferable if available.
test $unix_syscall = mkdir -o $unix_syscall = rmdir && \
test $unix_implementor = unix/sysv && \
unix_implementor=generic
test $unix_implementor = unix/sysv && unix_implementor=generic
;;
esac
case $unix_implementor in
none|stub|generic|posix)