Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/libexec/ld.elf_so Add support for dynamic linking on HP PA-R...
details: https://anonhg.NetBSD.org/src/rev/1158c6ce5911
branches: trunk
changeset: 533881:1158c6ce5911
user: fredette <fredette%NetBSD.org@localhost>
date: Wed Jul 10 15:12:33 2002 +0000
description:
Add support for dynamic linking on HP PA-RISC.
diffstat:
libexec/ld.elf_so/Makefile | 3 +-
libexec/ld.elf_so/README | 9 +-
libexec/ld.elf_so/arch/hppa/Makefile.inc | 17 +
libexec/ld.elf_so/arch/hppa/hppa_reloc.c | 337 +++++++++++++++++++++++++++++++
libexec/ld.elf_so/arch/hppa/ld.so.script | 190 +++++++++++++++++
libexec/ld.elf_so/arch/hppa/rtld_start.S | 269 ++++++++++++++++++++++++
libexec/ld.elf_so/headers.c | 25 +-
libexec/ld.elf_so/reloc.c | 120 ++++++++++-
libexec/ld.elf_so/rtld.c | 25 ++-
libexec/ld.elf_so/rtld.h | 18 +-
10 files changed, 991 insertions(+), 22 deletions(-)
diffs (truncated from 1214 to 300 lines):
diff -r 37186e76ee93 -r 1158c6ce5911 libexec/ld.elf_so/Makefile
--- a/libexec/ld.elf_so/Makefile Wed Jul 10 15:00:35 2002 +0000
+++ b/libexec/ld.elf_so/Makefile Wed Jul 10 15:12:33 2002 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.48 2002/03/01 20:15:16 tv Exp $
+# $NetBSD: Makefile,v 1.49 2002/07/10 15:12:33 fredette Exp $
.include <bsd.own.mk> # for OBJECT_FMT definition
@@ -7,6 +7,7 @@
.if ((${MACHINE_ARCH} == "alpha") || \
(${MACHINE_ARCH} == "arm") || \
+ (${MACHINE_ARCH} == "hppa") || \
(${MACHINE_ARCH} == "i386") || \
(${MACHINE_ARCH} == "m68k") || \
(${MACHINE_ARCH} == "mipsel") || (${MACHINE_ARCH} == "mipseb") || \
diff -r 37186e76ee93 -r 1158c6ce5911 libexec/ld.elf_so/README
--- a/libexec/ld.elf_so/README Wed Jul 10 15:00:35 2002 +0000
+++ b/libexec/ld.elf_so/README Wed Jul 10 15:12:33 2002 +0000
@@ -1,4 +1,4 @@
-$NetBSD: README,v 1.8 2001/12/20 06:49:03 thorpej Exp $
+$NetBSD: README,v 1.9 2002/07/10 15:12:34 fredette Exp $
BUGS/PROBLEMS:
@@ -15,13 +15,14 @@
* The method used to relocate ld.so is shoddy and fragile. Currently it's
something like:
- alpha, powerpc:
+ alpha, hppa, powerpc:
(1) assembly code relocates RELATIVE relocations in the GOT
(on some ports, all relative relocations; this will probably
have to be #ifdef'd in reloc.c), assuming that everything
- in the GOT is a RELATIVE relocation.
+ in the GOT is a RELATIVE relocation. On the hppa, this
+ is actually done in C code.
- (2) alpha only: C code relocates the rest of the loader,
+ (2) alpha, hppa only: C code relocates the rest of the loader,
excluding those RELATIVE relocations already done (via an ...
iffy heuristic).
diff -r 37186e76ee93 -r 1158c6ce5911 libexec/ld.elf_so/arch/hppa/Makefile.inc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libexec/ld.elf_so/arch/hppa/Makefile.inc Wed Jul 10 15:12:33 2002 +0000
@@ -0,0 +1,17 @@
+# $NetBSD: Makefile.inc,v 1.1 2002/07/10 15:12:37 fredette Exp $
+
+SRCS+= rtld_start.S hppa_reloc.c
+
+# XXX Should not be in CPPFLAGS!
+CPPFLAGS+= -fpic
+
+CPPFLAGS+= -DELFSIZE=32 #-DVARPSZ
+#CPPFLAGS+= -DRTLD_DEBUG
+#CPPFLAGS+= -DRTLD_DEBUG_RELOC
+#CPPFLAGS+= -DRTLD_DEBUG_HPPA
+
+LDFLAGS+= -Bshareable -Bsymbolic -e '$$rtld_start'
+LDFLAGS+= --script ${.CURDIR}/arch/hppa/ld.so.script
+
+# XXX fredette - the libgcc millicode is needed here:
+LDADD=`$(CC) -print-libgcc-file-name`
diff -r 37186e76ee93 -r 1158c6ce5911 libexec/ld.elf_so/arch/hppa/hppa_reloc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libexec/ld.elf_so/arch/hppa/hppa_reloc.c Wed Jul 10 15:12:33 2002 +0000
@@ -0,0 +1,337 @@
+/* $NetBSD: hppa_reloc.c,v 1.1 2002/07/10 15:12:38 fredette Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Fredette.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+
+#include "rtld.h"
+#include "debug.h"
+
+#ifdef RTLD_DEBUG_HPPA
+#define hdbg(x) if (dodebug) xprintf x
+#else
+#define hdbg(x) /* nothing */
+#endif
+
+/*
+ * In the runtime architecture (ABI), PLABEL function
+ * pointers are distinguished from normal function
+ * pointers by having the next-least-significant bit
+ * set. (This bit is referred to as the L field in
+ * HP documentation). The $$dyncall millicode is
+ * aware of this.
+ */
+#define RTLD_MAKE_PLABEL(plabel) (((Elf_Addr)(plabel)) | (1 << 1))
+#define RTLD_IS_PLABEL(addr) (((Elf_Addr)(addr)) & (1 << 1))
+#define RTLD_GET_PLABEL(addr) ((hppa_plabel *) (((Elf_Addr)addr) & ~3))
+
+/*
+ * This is the PLABEL structure. The function PC and
+ * shared linkage members must come first, as they are
+ * the actual PLABEL.
+ */
+typedef struct _hppa_plabel {
+ Elf_Addr hppa_plabel_pc;
+ Elf_Addr hppa_plabel_sl;
+ SLIST_ENTRY(_hppa_plabel) hppa_plabel_next;
+} hppa_plabel;
+
+/*
+ * For now allocated PLABEL structures are tracked on a
+ * singly linked list. This maybe should be revisited.
+ */
+static SLIST_HEAD(hppa_plabel_head, _hppa_plabel) hppa_plabel_list
+ = SLIST_HEAD_INITIALIZER(hppa_plabel_list);
+
+/*
+ * Because I'm hesitant to use NEW while relocating self,
+ * this is a small pool of preallocated PLABELs.
+ */
+#define HPPA_PLABEL_PRE (10)
+static hppa_plabel hppa_plabel_pre[HPPA_PLABEL_PRE];
+static int hppa_plabel_pre_next = 0;
+
+/*
+ * The DT_PLTGOT _DYNAMIC entry always gives the linkage table
+ * pointer for an object. This is often, but not always, the
+ * same as the object's value for _GLOBAL_OFFSET_TABLE_. We
+ * cache one object's GOT value, otherwise we look it up.
+ * XXX it would be nice to be able to keep this in the Obj_Entry.
+ */
+static const Obj_Entry *hppa_got_cache_obj = NULL;
+static Elf_Addr *hppa_got_cache_got;
+#define HPPA_OBJ_SL(obj) ((obj)->pltgot)
+#define HPPA_OBJ_GOT(obj) ((obj) == hppa_got_cache_obj ? \
+ hppa_got_cache_got : \
+ _rtld_fill_hppa_got_cache(obj))
+static Elf_Addr *_rtld_fill_hppa_got_cache __P((const Obj_Entry *));
+
+/*
+ * This bootstraps the dynamic linker by relocating its GOT.
+ * On the hppa, unlike on other architectures, static strings
+ * are found through the GOT. Static strings are essential
+ * for RTLD_DEBUG, and I suspect they're used early even when
+ * !defined(RTLD_DEBUG), making relocating the GOT essential.
+ *
+ * It gets worse. Relocating the GOT doesn't mean just walking
+ * it and adding the relocbase to all of the entries. You must
+ * find and use the GOT relocations, since those RELA relocations
+ * have the necessary addends - the GOT comes initialized as
+ * zeroes.
+ */
+void
+_rtld_bootstrap_hppa_got(Elf_Dyn *dynp, Elf_Addr relocbase,
+ Elf_Addr got_begin, Elf_Addr got_end)
+{
+ const Elf_Rela *relafirst, *rela, *relalim;
+ Elf_Addr relasz = 0;
+ Elf_Addr where;
+
+ /*
+ * Process the DYNAMIC section, looking for the non-PLT
+ * relocations.
+ */
+ relafirst = NULL;
+ for (; dynp->d_tag != DT_NULL; ++dynp) {
+ switch (dynp->d_tag) {
+
+ case DT_RELA:
+ relafirst = (const Elf_Rela *)
+ (relocbase + dynp->d_un.d_ptr);
+ break;
+
+ case DT_RELASZ:
+ relasz = dynp->d_un.d_val;
+ break;
+ }
+ }
+ relalim = (const Elf_Rela *)((caddr_t)relafirst + relasz);
+
+ /*
+ * Process all relocations that look like they're in
+ * the GOT.
+ */
+ for(rela = relafirst; rela < relalim; rela++) {
+ where = (Elf_Addr)(relocbase + rela->r_offset);
+ if (where >= got_begin && where < got_end)
+ *((Elf_Addr *)where) = relocbase + rela->r_addend;
+ }
+
+#if defined(RTLD_DEBUG_HPPA)
+ for(rela = relafirst; rela < relalim; rela++) {
+ where = (Elf_Addr)(relocbase + rela->r_offset);
+ if (where >= got_begin && where < got_end)
+ xprintf("GOT rela @%p(%p) -> %p(%p)\n",
+ (void *)rela->r_offset,
+ (void *)where,
+ (void *)rela->r_addend,
+ (void *)*((Elf_Addr *)where));
+ }
+#endif /* RTLD_DEBUG_HPPA */
+}
+
+/*
+ * This looks up the object's _GLOBAL_OFFSET_TABLE_
+ * and caches the result.
+ */
+static Elf_Addr *
+_rtld_fill_hppa_got_cache(const Obj_Entry *obj)
+{
+ const char *name = "_GLOBAL_OFFSET_TABLE_";
+ unsigned long hash;
+ const Elf_Sym *def;
+
+ hash = _rtld_elf_hash(name);
+ def = _rtld_symlook_obj(name, hash, obj, true);
+ assert(def != NULL);
+ hppa_got_cache_obj = obj;
+ return hppa_got_cache_got =
+ (Elf_Addr *)(obj->relocbase + def->st_value);
+}
+
+/* This sets up an object's GOT. */
+void
+_rtld_setup_hppa_pltgot(const Obj_Entry *obj)
+{
+ __rtld_setup_hppa_pltgot(obj, HPPA_OBJ_GOT(obj));
+}
+
+/*
+ * This allocates a PLABEL. If called with a non-NULL def, the
+ * plabel is for the function associated with that definition
+ * in the defining object defobj, plus the given addend. If
+ * called with a NULL def, the plabel is for the function at
+ * the (unrelocated) address in addend in the object defobj.
+ */
+Elf_Addr
+_rtld_function_descriptor_alloc(const Obj_Entry *defobj, const Elf_Sym *def,
+ Elf_Addr addend)
+{
+ Elf_Addr func_pc, func_sl;
+ hppa_plabel *plabel;
+
+ if (def != NULL) {
+
+ /*
+ * We assume that symbols of type STT_NOTYPE
+ * are undefined. Return NULL for these.
+ */
+ if (ELF_ST_TYPE(def->st_info) == STT_NOTYPE)
+ return (Elf_Addr)NULL;
+
+ /* Otherwise assert that this symbol must be a function. */
+ assert(ELF_ST_TYPE(def->st_info) == STT_FUNC);
+
+ func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
+ addend);
+ } else
+ func_pc = (Elf_Addr)(defobj->relocbase + addend);
+
+ /*
+ * Search the existing PLABELs for one matching
+ * this function. If there is one, return it.
+ */
+ func_sl = (Elf_Addr)HPPA_OBJ_SL(defobj);
Home |
Main Index |
Thread Index |
Old Index