Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 10 Oct 2001 10:15:56 +0100 (BST)
From:      Doug Rabson <dfr@nlsystems.com>
To:        <ia64@freebsd.org>
Subject:   rtld
Message-ID:  <20011010100824.Y549-100000@salmon.nlsystems.com>

next in thread | raw e-mail | index | archive | help
Some patches to get rtld working, for your amusement. I'll commit them as
soon as jdp takes a look. Be warned that the new toolchain will generate
objects which are totally incompatible with the old toolchain due to a
change in the format of the .hash section.

Also, this set of patches assumes that the kernel is using my new calling
convention for execve (a three entry register frame containing &args,
ps_strings and NULL cleanup value). It could be changed to work with the
existing convention (sp points at &argv, r14 at ps_strings, sp needs to be
realigned and have 16 subtracted from it for scratch space) but I'm going
to commit the new calling convention soon anyway.

Index: rtld.c
===================================================================
RCS file: /home/ncvs/src/libexec/rtld-elf/rtld.c,v
retrieving revision 1.53
diff -u -r1.53 rtld.c
--- rtld.c	2001/07/26 11:02:32	1.53
+++ rtld.c	2001/10/10 08:54:15
@@ -437,9 +437,19 @@
       defobj->strtab + def->st_name, basename(obj->path),
       (void *)target, basename(defobj->path));

+#ifdef __ia64__
+    /*
+     * On ia64 we need to return an @fptr for the target.
+     * Conveniently, the jmpslot serves this purpose nicely.
+     */
+    reloc_jmpslot(where, target, defobj);
+    rlock_release();
+    return (Elf_Addr) where;
+#else
     reloc_jmpslot(where, target);
     rlock_release();
     return target;
+#endif
 }

 /*
@@ -572,7 +582,7 @@

 	case DT_HASH:
 	    {
-		const Elf_Addr *hashtab = (const Elf_Addr *)
+		const Elf_Hashelt *hashtab = (const Elf_Hashelt *)
 		  (obj->relocbase + dynp->d_un.d_ptr);
 		obj->nbuckets = hashtab[0];
 		obj->nchains = hashtab[1];
Index: rtld.h
===================================================================
RCS file: /home/ncvs/src/libexec/rtld-elf/rtld.h,v
retrieving revision 1.22
diff -u -r1.22 rtld.h
--- rtld.h	2001/05/05 23:20:59	1.22
+++ rtld.h	2001/10/09 19:19:50
@@ -137,9 +137,9 @@
     const char *strtab;		/* String table */
     unsigned long strsize;	/* Size in bytes of string table */

-    const Elf_Addr *buckets;	/* Hash table buckets array */
+    const Elf_Hashelt *buckets;	/* Hash table buckets array */
     unsigned long nbuckets;	/* Number of buckets */
-    const Elf_Addr *chains;	/* Hash table chain array */
+    const Elf_Hashelt *chains;	/* Hash table chain array */
     unsigned long nchains;	/* Number of chains */

     const char *rpath;		/* Search path specified in object */
Index: ia64/lockdflt.c
===================================================================
RCS file: lockdflt.c
diff -N lockdflt.c
--- /dev/null	Wed Oct 10 10:02:46 2001
+++ lockdflt.c	Wed Oct 10 09:50:32 2001
@@ -0,0 +1,181 @@
+/*-
+ * Copyright 1999, 2000 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Thread locking implementation for the dynamic linker.
+ *
+ * We use the "simple, non-scalable reader-preference lock" from:
+ *
+ *   J. M. Mellor-Crummey and M. L. Scott. "Scalable Reader-Writer
+ *   Synchronization for Shared-Memory Multiprocessors." 3rd ACM Symp. on
+ *   Principles and Practice of Parallel Programming, April 1991.
+ *
+ * In this algorithm the lock is a single word.  Its low-order bit is
+ * set when a writer holds the lock.  The remaining high-order bits
+ * contain a count of readers desiring the lock.  The algorithm requires
+ * atomic "compare_and_store" and "add" operations, which we implement
+ * using assembly language sequences in "rtld_start.S".
+ *
+ * These are spinlocks.  When spinning we call nanosleep() for 1
+ * microsecond each time around the loop.  This will most likely yield
+ * the CPU to other threads (including, we hope, the lockholder) allowing
+ * them to make some progress.
+ */
+
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "debug.h"
+#include "rtld.h"
+
+/*
+ * This value of CACHE_LINE_SIZE is conservative.  The actual size
+ * is 32 on the  21064, 21064A, 21066, 21066A, and 21164.  It is 64
+ * on the 21264.  Compaq recommends sequestering each lock in its own
+ * 128-byte block to allow for future implementations with larger
+ * cache lines.
+ */
+#define CACHE_LINE_SIZE		128
+
+#define WAFLAG		0x1	/* A writer holds the lock */
+#define RC_INCR		0x2	/* Adjusts count of readers desiring lock */
+
+typedef struct Struct_Lock {
+	volatile int lock;
+	void *base;
+} Lock;
+
+static const struct timespec usec = { 0, 1000 };	/* 1 usec. */
+static sigset_t fullsigmask, oldsigmask;
+
+static void *
+lock_create(void *context)
+{
+    void *base;
+    char *p;
+    uintptr_t r;
+    Lock *l;
+
+    /*
+     * Arrange for the lock to occupy its own cache line.  First, we
+     * optimistically allocate just a cache line, hoping that malloc
+     * will give us a well-aligned block of memory.  If that doesn't
+     * work, we allocate a larger block and take a well-aligned cache
+     * line from it.
+     */
+    base = xmalloc(CACHE_LINE_SIZE);
+    p = (char *)base;
+    if ((uintptr_t)p % CACHE_LINE_SIZE != 0) {
+	free(base);
+	base = xmalloc(2 * CACHE_LINE_SIZE);
+	p = (char *)base;
+	if ((r = (uintptr_t)p % CACHE_LINE_SIZE) != 0)
+	    p += CACHE_LINE_SIZE - r;
+    }
+    l = (Lock *)p;
+    l->base = base;
+    l->lock = 0;
+    return l;
+}
+
+static void
+lock_destroy(void *lock)
+{
+    Lock *l = (Lock *)lock;
+
+    free(l->base);
+}
+
+static void
+rlock_acquire(void *lock)
+{
+    Lock *l = (Lock *)lock;
+
+    atomic_add_int(&l->lock, RC_INCR);
+    while (l->lock & WAFLAG)
+	    nanosleep(&usec, NULL);
+}
+
+static void
+wlock_acquire(void *lock)
+{
+    Lock *l = (Lock *)lock;
+    sigset_t tmp_oldsigmask;
+
+    for ( ; ; ) {
+	sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask);
+	if (cmp0_and_store_int(&l->lock, WAFLAG) == 0)
+	    break;
+	sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL);
+	nanosleep(&usec, NULL);
+    }
+    oldsigmask = tmp_oldsigmask;
+}
+
+static void
+rlock_release(void *lock)
+{
+    Lock *l = (Lock *)lock;
+
+    atomic_add_int(&l->lock, -RC_INCR);
+}
+
+static void
+wlock_release(void *lock)
+{
+    Lock *l = (Lock *)lock;
+
+    atomic_add_int(&l->lock, -WAFLAG);
+    sigprocmask(SIG_SETMASK, &oldsigmask, NULL);
+}
+
+void
+lockdflt_init(LockInfo *li)
+{
+    li->context = NULL;
+    li->lock_create = lock_create;
+    li->rlock_acquire = rlock_acquire;
+    li->wlock_acquire = wlock_acquire;
+    li->rlock_release = rlock_release;
+    li->wlock_release = wlock_release;
+    li->lock_destroy = lock_destroy;
+    li->context_destroy = NULL;
+    /*
+     * Construct a mask to block all signals except traps which might
+     * conceivably be generated within the dynamic linker itself.
+     */
+    sigfillset(&fullsigmask);
+    sigdelset(&fullsigmask, SIGILL);
+    sigdelset(&fullsigmask, SIGTRAP);
+    sigdelset(&fullsigmask, SIGABRT);
+    sigdelset(&fullsigmask, SIGEMT);
+    sigdelset(&fullsigmask, SIGFPE);
+    sigdelset(&fullsigmask, SIGBUS);
+    sigdelset(&fullsigmask, SIGSEGV);
+    sigdelset(&fullsigmask, SIGSYS);
+}
Index: ia64/reloc.c
===================================================================
RCS file: reloc.c
diff -N reloc.c
--- /dev/null	Wed Oct 10 10:02:46 2001
+++ reloc.c	Wed Oct 10 09:58:10 2001
@@ -0,0 +1,391 @@
+/*-
+ * Copyright 1996, 1997, 1998, 1999 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Dynamic linker for ELF.
+ *
+ * John Polstra <jdp@polstra.com>.
+ */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "debug.h"
+#include "rtld.h"
+
+extern Elf_Dyn _DYNAMIC;
+
+/*
+ * Macros for cracking ia64 function pointers.
+ */
+struct fptr {
+	Elf_Addr	target;
+	Elf_Addr	gp;
+};
+
+#define FPTR_TARGET(f)	(((struct fptr *) (f))->target)
+#define FPTR_GP(f)	(((struct fptr *) (f))->gp)
+
+/*
+ * Macros for loading/storing unaligned 64-bit values.  These are
+ * needed because relocations can point to unaligned data.  This
+ * occurs in the DWARF2 exception frame tables generated by the
+ * compiler, for instance.
+ *
+ * We don't use these when relocating jump slots and GOT entries,
+ * since they are guaranteed to be aligned.
+ *
+ * XXX dfr stub for now.
+ */
+#define load64(p)	(*(u_int64_t *) (p))
+#define store64(p, v)	(*(u_int64_t *) (p) = (v))
+
+/* Allocate an @fptr. */
+
+#define FPTR_CHUNK_SIZE		64
+
+struct fptr_chunk {
+	struct fptr fptrs[FPTR_CHUNK_SIZE];
+};
+
+static struct fptr_chunk first_chunk;
+static struct fptr_chunk *current_chunk = &first_chunk;
+static struct fptr *next_fptr = &first_chunk.fptrs[0];
+static struct fptr *last_fptr = &first_chunk.fptrs[FPTR_CHUNK_SIZE];
+
+/*
+ * We use static storage initially so that we don't have to call
+ * malloc during init_rtld().
+ */
+static struct fptr *
+alloc_fptr(Elf_Addr target, Elf_Addr gp)
+{
+	struct fptr* fptr;
+
+	if (next_fptr == last_fptr) {
+		current_chunk = malloc(sizeof(struct fptr_chunk));
+		next_fptr = &current_chunk->fptrs[0];
+		last_fptr = &current_chunk->fptrs[FPTR_CHUNK_SIZE];
+	}
+	fptr = next_fptr;
+	next_fptr++;
+	fptr->target = target;
+	fptr->gp = gp;
+	return fptr;
+}
+
+/* Relocate a non-PLT object with addend. */
+static int
+reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
+		  SymCache *cache, struct fptr **fptrs)
+{
+	Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
+
+	switch (ELF_R_TYPE(rela->r_info)) {
+	case R_IA64_REL64LSB:
+		/*
+		 * We handle rtld's relocations in rtld_start.S
+		 */
+		if (obj != obj_rtld)
+			store64(where,
+				load64(where) + (Elf_Addr) obj->relocbase);
+		break;
+
+	case R_IA64_DIR64LSB: {
+		const Elf_Sym *def;
+		const Obj_Entry *defobj;
+		Elf_Addr target;
+
+		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
+				  false, cache);
+		if (def == NULL)
+			return -1;
+		target = (Elf_Addr) (defobj->relocbase + def->st_value);
+		store64(where, target + rela->r_addend);
+		break;
+	}
+
+	case R_IA64_FPTR64LSB: {
+		/*
+		 * We have to make sure that all @fptr references to
+		 * the same function are identical so that code can
+		 * compare function pointers. We actually only bother
+		 * to ensure this within a single object. If the
+		 * caller's alloca failed, we don't even ensure that.
+		 */
+		const Elf_Sym *def;
+		const Obj_Entry *defobj;
+		struct fptr *fptr = 0;
+		Elf_Addr target, gp;
+
+		/*
+		 * Not sure why the call to find_symdef() doesn't work
+		 * properly (it fails if the symbol is local). Perhaps
+		 * this is a toolchain issue - revisit after we
+		 * upgrade the ia64 toolchain.
+		 */
+#if 0
+		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
+				  false, cache);
+		if (def == NULL)
+			return -1;
+#else
+		def = &obj->symtab[ELF_R_SYM(rela->r_info)];
+		defobj = obj;
+#endif
+		target = (Elf_Addr) (defobj->relocbase + def->st_value);
+		gp = (Elf_Addr) defobj->pltgot;
+
+		/*
+		 * Find the @fptr, using fptrs as a helper.
+		 */
+		if (fptrs)
+			fptr = fptrs[ELF_R_SYM(rela->r_info)];
+		if (!fptr) {
+			fptr = alloc_fptr(target, gp);
+			if (fptrs)
+				fptrs[ELF_R_SYM(rela->r_info)] = fptr;
+		}
+		store64(where, (Elf_Addr) fptr);
+		break;
+	}
+
+	default:
+		_rtld_error("%s: Unsupported relocation type %d"
+			    " in non-PLT relocations\n", obj->path,
+			    ELF_R_TYPE(rela->r_info));
+		return -1;
+	}
+
+	return(0);
+}
+
+/* Process the non-PLT relocations. */
+int
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+{
+	const Elf_Rel *rellim;
+	const Elf_Rel *rel;
+	const Elf_Rela *relalim;
+	const Elf_Rela *rela;
+	SymCache *cache;
+	struct fptr **fptrs;
+
+	cache = (SymCache *)alloca(obj->nchains * sizeof(SymCache));
+	if (cache != NULL)
+		memset(cache, 0, obj->nchains * sizeof(SymCache));
+	fptrs = (struct fptr **)alloca(obj->nchains * sizeof(struct fptr *));
+	if (fptrs != NULL)
+		memset(fptrs, 0, obj->nchains * sizeof(struct fptr *));
+
+	/* Perform relocations without addend if there are any: */
+	rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
+	for (rel = obj->rel;  obj->rel != NULL && rel < rellim;  rel++) {
+		Elf_Rela locrela;
+
+		locrela.r_info = rel->r_info;
+		locrela.r_offset = rel->r_offset;
+		locrela.r_addend = 0;
+		if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache, fptrs))
+			return -1;
+	}
+
+	/* Perform relocations with addend if there are any: */
+	relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize);
+	for (rela = obj->rela;  obj->rela != NULL && rela < relalim;  rela++) {
+		if (reloc_non_plt_obj(obj_rtld, obj, rela, cache, fptrs))
+			return -1;
+	}
+	return 0;
+}
+
+/* Process the PLT relocations. */
+int
+reloc_plt(Obj_Entry *obj)
+{
+	/* All PLT relocations are the same kind: Elf_Rel or Elf_Rela. */
+	if (obj->pltrelsize != 0) {
+		const Elf_Rel *rellim;
+		const Elf_Rel *rel;
+
+		rellim = (const Elf_Rel *)
+			((char *)obj->pltrel + obj->pltrelsize);
+		for (rel = obj->pltrel;  rel < rellim;  rel++) {
+			Elf_Addr *where;
+
+			assert(ELF_R_TYPE(rel->r_info) == R_IA64_IPLTLSB);
+
+			/* Relocate the @fptr pointing into the PLT. */
+			where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+			*where += (Elf_Addr)obj->relocbase;
+		}
+	} else {
+		const Elf_Rela *relalim;
+		const Elf_Rela *rela;
+
+		relalim = (const Elf_Rela *)
+			((char *)obj->pltrela + obj->pltrelasize);
+		for (rela = obj->pltrela;  rela < relalim;  rela++) {
+			Elf_Addr *where;
+
+			assert(ELF_R_TYPE(rela->r_info) == R_IA64_IPLTLSB);
+
+			/* Relocate the @fptr pointing into the PLT. */
+			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+			*where += (Elf_Addr)obj->relocbase;
+		}
+	}
+	return 0;
+}
+
+/* Relocate the jump slots in an object. */
+int
+reloc_jmpslots(Obj_Entry *obj)
+{
+	if (obj->jmpslots_done)
+		return 0;
+	/* All PLT relocations are the same kind: Elf_Rel or Elf_Rela. */
+	if (obj->pltrelsize != 0) {
+		const Elf_Rel *rellim;
+		const Elf_Rel *rel;
+
+		rellim = (const Elf_Rel *)
+			((char *)obj->pltrel + obj->pltrelsize);
+		for (rel = obj->pltrel;  rel < rellim;  rel++) {
+			Elf_Addr *where;
+			const Elf_Sym *def;
+			const Obj_Entry *defobj;
+
+			assert(ELF_R_TYPE(rel->r_info) == R_IA64_IPLTLSB);
+			where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
+			def = find_symdef(ELF_R_SYM(rel->r_info), obj,
+					  &defobj, true, NULL);
+			if (def == NULL)
+				return -1;
+			reloc_jmpslot(where,
+				      (Elf_Addr)(defobj->relocbase
+						 + def->st_value),
+				      defobj);
+		}
+	} else {
+		const Elf_Rela *relalim;
+		const Elf_Rela *rela;
+
+		relalim = (const Elf_Rela *)
+			((char *)obj->pltrela + obj->pltrelasize);
+		for (rela = obj->pltrela;  rela < relalim;  rela++) {
+			Elf_Addr *where;
+			const Elf_Sym *def;
+			const Obj_Entry *defobj;
+
+			/* assert(ELF_R_TYPE(rela->r_info) == R_ALPHA_JMP_SLOT); */
+			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
+			def = find_symdef(ELF_R_SYM(rela->r_info), obj,
+					  &defobj, true, NULL);
+			if (def == NULL)
+				return -1;
+			reloc_jmpslot(where,
+				      (Elf_Addr)(defobj->relocbase
+						 + def->st_value),
+				      defobj);
+		}
+	}
+	obj->jmpslots_done = true;
+	return 0;
+}
+
+/* Fixup the jump slot at "where" to transfer control to "target". */
+void
+reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *obj)
+{
+	Elf_Addr stubaddr;
+
+	dbg(" reloc_jmpslot: where=%p, target=%p, gp=%p",
+	    (void *)where, (void *)target, (void *)obj->pltgot);
+	stubaddr = *where;
+	if (stubaddr != target) {
+
+		/*
+		 * Point this @fptr directly at the target. Update the
+		 * gp value first so that we don't break another cpu
+		 * which is currently executing the PLT entry.
+		 */
+		where[1] = (Elf_Addr) obj->pltgot;
+		ia64_mf();
+		where[0] = target;
+		ia64_mf();
+	}
+}
+
+/*
+ * XXX ia64 doesn't seem to have copy relocations.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int
+do_copy_relocations(Obj_Entry *dstobj)
+{
+
+	return 0;
+}
+
+/* Initialize the special PLT entries. */
+void
+init_pltgot(Obj_Entry *obj)
+{
+	const Elf_Dyn *dynp;
+	Elf_Addr *pltres = 0;
+
+	/*
+	 * Find the PLT RESERVE section.
+	 */
+	for (dynp = obj->dynamic;  dynp->d_tag != DT_NULL;  dynp++) {
+		if (dynp->d_tag == DT_IA64_PLT_RESERVE)
+			pltres = (u_int64_t *)
+				(obj->relocbase + dynp->d_un.d_ptr);
+	}
+	if (!pltres)
+		errx(1, "Can't find DT_IA64_PLT_RESERVE entry");
+
+	/*
+	 * The PLT RESERVE section is used to get values to pass to
+	 * _rtld_bind when lazy binding.
+	 */
+	pltres[0] = (Elf_Addr) obj;
+	pltres[1] = FPTR_TARGET(_rtld_bind_start);
+	pltres[2] = FPTR_GP(_rtld_bind_start);
+}
Index: ia64/rtld_machdep.h
===================================================================
RCS file: rtld_machdep.h
diff -N rtld_machdep.h
--- /dev/null	Wed Oct 10 10:02:46 2001
+++ rtld_machdep.h	Wed Oct 10 09:50:58 2001
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1999, 2000 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef RTLD_MACHDEP_H
+#define RTLD_MACHDEP_H	1
+
+/* Return the address of the .dynamic section in the dynamic linker. */
+#define rtld_dynamic(obj)	(&_DYNAMIC)
+
+struct Struct_Obj_Entry;
+
+void reloc_jmpslot(Elf_Addr *, Elf_Addr, const struct Struct_Obj_Entry *);
+
+/* Atomic operations. */
+int cmp0_and_store_int(volatile int *, int);
+void atomic_add_int(volatile int *, int);
+void atomic_incr_int(volatile int *);
+void atomic_decr_int(volatile int *);
+
+#endif
Index: ia64/rtld_start.S
===================================================================
RCS file: rtld_start.S
diff -N rtld_start.S
--- /dev/null	Wed Oct 10 10:02:46 2001
+++ rtld_start.S	Wed Oct 10 10:01:12 2001
@@ -0,0 +1,291 @@
+/* $FreeBSD$	*/
+/*	From: NetBSD: rtld_start.S,v 1.1 1996/12/16 20:38:09 cgd Exp 	*/
+
+/*
+ * Copyright 1996 Matt Thomas <matt@3am-software.com>
+ * Copyright 2000 John D. Polstra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+#include <sys/syscall.h>
+
+ENTRY(_rtld_start, 0)
+	alloc	r2=ar.pfs,3,0,3,0
+	;;
+1:	mov	r14=ip			// calculate gp
+	movl	r15=@gprel(1b)
+	;;
+	sub	gp=r14,r15
+	;;
+	.section .sdata
+2:	data4	@ltv(1b)		// unrelocated address of 1b
+	.align	8
+	.previous
+	add	r15=@gprel(2b),gp
+	;;
+	ld8	r15=[r15]
+	;;
+	sub	out0=r14,r15		// out0 is image base address
+	br.call.sptk.many rp=_rtld_reloc // fixup image
+
+	add	sp=-16,sp		// 16 bytes for us, 16 for _rtld
+	;;
+	mov	out0=in0
+	add	out1=16,sp		// address for exit proc
+	add	out2=24,sp		// address for obj_main
+
+	br.call.sptk.many rp=_rtld	// r8=_rtld(sp, &exit_proc, &obj_main)
+
+	add	r16=16,sp		// address for exit proc
+	;;
+	ld8	r15=[r16]		// read exit proc
+	add	sp=16,sp		// readjust stack
+	mov	b7=r8			// address of real _start
+	;;
+	alloc	r2=ar.pfs,0,0,3,0	// dump register frame
+	mov	out2=r15
+
+	br.call.sptk.many rp=b7		// transfer to main program
+	br.call.sptk.many rp=exit	// die
+END(_rtld_start)
+
+/*
+ * _rtld_bind_start:	lookup a lazy binding and transfer to real target
+ *
+ * Arguments:
+ *	r1	gp value for rtld
+ *	r15	Index in plt
+ *	r16	Obj_Entry of caller
+ *	in0-in7	Arguments for target procedure
+ *	rp	Return address back to caller
+ */
+ENTRY(_rtld_bind_start, 0)
+	alloc	loc0=ar.pfs,8,6,3,0	// space to save r8-r11
+	add	sp=-8*16,sp		// space to save f8-f15
+	mov	loc1=rp
+	;;
+	add	r17=16,sp		// leave 16 bytes for _rtld_bind
+	add	r18=32,sp
+	;;
+	mov	loc2=r8			// structure return address
+	mov	loc3=r9			// language specific
+	mov	loc4=r10		// language specific
+	mov	loc5=r11		// language specific
+	;;
+	stf.spill [r17]=f8,32		// save float arguments
+	stf.spill [r18]=f9,32
+	mov	out0=r16		// Obj_Entry for caller
+	;;
+	stf.spill [r17]=f10,32
+	stf.spill [r18]=f11,32
+	shl	out1=r15,4		// 16 * index
+	;;
+	stf.spill [r17]=f12,32
+	stf.spill [r18]=f13,32
+	shladd	out1=r15,3,out1		// rela offset = 24 * index
+	;;
+	stf.spill [r17]=f14,32
+	stf.spill [r18]=f15,32
+	;;
+	br.call.sptk.many rp=_rtld_bind
+	;;
+	add	r17=16,sp
+	add	r18=32,sp
+	ld8	r14=[r8],8		// target address
+	;;
+	ldf.fill f8=[r17],32
+	ldf.fill f9=[r18],32
+	ld8	r1=[r8]			// target gp
+	;;
+	ldf.fill f10=[r17],32		// restore float arguments
+	ldf.fill f11=[r18],32
+	mov	r8=loc2			// and structure pointer
+	;;
+	ldf.fill f12=[r17],32		// etc.
+	ldf.fill f13=[r18],32
+	mov	r9=loc3
+	;;
+	ldf.fill f14=[r17],32
+	ldf.fill f15=[r18],32
+	mov	r10=loc4
+	;;
+	mov	r11=loc5
+	mov	b7=r14
+	mov	ar.pfs=loc0		// clean up
+	mov	rp=loc1
+	add	sp=8*16,sp
+	;;
+	alloc	r14=ar.pfs,0,0,8,0	// drop our register frame
+	br.sptk.many b7			// jump to target
+END(_rtld_bind_start)
+
+/*
+ * int cmp0_and_store_int(volatile int *p, int newval);
+ *
+ * If an int holds 0, store newval into it; else do nothing.  Returns
+ * the previous value.
+ */
+ENTRY(cmp0_and_store_int, 2)
+	mov	ar.ccv=0
+	;;
+	cmpxchg4.acq r8=[in0],in1,ar.ccv
+	br.ret.sptk.many rp
+END(cmp0_and_store_int)
+
+ENTRY(atomic_add_int, 2)
+1:	ld4	r14=[in0]
+	;;
+	mov	ar.ccv=r14
+	add	r15=in1,r14
+	;;
+	cmpxchg4.acq r16=[in0],r15,ar.ccv
+	;;
+	cmp.ne	p6,p0=r14,r16
+(p6)	br.cond.spnt.few 1b
+	br.ret.sptk.many rp
+END(atomic_add_int)
+
+/* Atomically increment an int. */
+ENTRY(atomic_incr_int, 1)
+1:	ld4	r14=[in0]
+	;;
+	mov	ar.ccv=r14
+	add	r15=1,r14
+	;;
+	cmpxchg4.acq r16=[in0],r15,ar.ccv
+	;;
+	cmp.ne	p6,p0=r14,r16
+(p6)	br.cond.spnt.few 1b
+	br.ret.sptk.many rp
+END(atomic_incr_int)
+
+/* Atomically decrement an int. */
+ENTRY(atomic_decr_int, 1)
+1:	ld4	r14=[in0]
+	;;
+	mov	ar.ccv=r14
+	add	r15=-1,r14
+	;;
+	cmpxchg4.acq r16=[in0],r15,ar.ccv
+	;;
+	cmp.ne	p6,p0=r14,r16
+(p6)	br.cond.spnt.few 1b
+	br.ret.sptk.many rp
+END(atomic_decr_int)
+
+#define DT_NULL		0	/* Terminating entry. */
+#define DT_RELA		7	/* Address of ElfNN_Rela relocations. */
+#define DT_RELASZ	8	/* Total size of ElfNN_Rela relocations. */
+#define DT_RELAENT	9	/* Size of each ElfNN_Rela relocation entry. */
+
+#define R_IA64_NONE		0	/* None */
+#define R_IA64_DIR64LSB		0x27	/* word64 LSB	S + A */
+#define R_IA64_REL64LSB		0x6f	/* word64 LSB	BD + A */
+
+/*
+ * _rtld_reloc:	relocate the rtld image, apart from @fptrs.
+ *
+ * Assumes that rtld was linked at zero and that we only need to
+ * handle REL64LSB and DIR64LSB relocations.
+ *
+ * Arguments:
+ *	r1	gp value for rtld
+ *	in0	rtld base address
+ */
+STATIC_ENTRY(_rtld_reloc, 1)
+	alloc	loc0=ar.pfs,1,2,0,0
+	mov	loc1=rp
+	;;
+	movl	r15=@gprel(_DYNAMIC)	// find _DYNAMIC etc.
+	;;
+	add	r15=r15,gp		// relocate _DYNAMIC etc.
+	;;
+1:	ld8	r16=[r15],8		// read r15->d_tag
+	;;
+	ld8	r17=[r15],8		// and r15->d_val
+	;;
+	cmp.eq	p6,p0=DT_NULL,r16	// done?
+(p6)	br.cond.dpnt.few 2f
+	;;
+	cmp.eq	p6,p0=DT_RELA,r16
+	;;
+(p6)	add	r18=r17,in0		// found rela section
+	;;
+	cmp.eq	p6,p0=DT_RELASZ,r16
+	;;
+(p6)	mov	r19=r17			// found rela size
+	;;
+	cmp.eq	p6,p0=DT_RELAENT,r16
+	;;
+(p6)	mov	r22=r17			// found rela entry size
+	;;
+	br.sptk.few 1b
+
+2:
+	ld8	r15=[r18],8		// read r_offset
+	;;
+	ld8	r16=[r18],8		// read r_info
+	add	r15=r15,in0		// relocate r_offset
+	;;
+	ld8	r17=[r18],8		// read r_addend
+	sub	r19=r19,r22		// update relasz
+
+	extr.u	r23=r16,0,32		// ELF64_R_TYPE(r16)
+	;;
+	cmp.eq	p6,p0=R_IA64_NONE,r23
+(p6)	br.cond.dpnt.few 3f
+	;;
+	cmp.eq	p6,p0=R_IA64_DIR64LSB,r23
+	;;
+(p6)	br.cond.dptk.few 4f
+	;;
+	cmp.eq	p6,p0=R_IA64_REL64LSB,r23
+	;;
+(p6)	br.cond.dptk.few 4f
+	;;
+
+3:	cmp.ltu	p6,p0=0,r19		// more?
+(p6)	br.cond.dptk.few 2b		// loop
+
+	mov	r8=0			// success return value
+	;;
+	br.cond.sptk.few 9f		// done
+
+4:
+	ld8	r16=[r15]		// read value
+	;;
+	add	r16=r16,in0		// relocate it
+	;;
+	st8	[r15]=r16		// and store it back
+	br.cond.sptk.few 3b
+
+9:
+	mov	ar.pfs=loc0
+	mov	rp=loc1
+	;;
+	br.ret.sptk.few rp
+
+END(_rtld_reloc)

-- 
Doug Rabson				Mail:  dfr@nlsystems.com
					Phone: +44 20 8348 6160



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ia64" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20011010100824.Y549-100000>