From b359e82ceabbf42b1e3d8069627701fde5d7cb90 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Wed, 28 May 2003 22:04:40 +0000 Subject: 2003-05-28 Jeff Johnston Tom Fitzsimmons * configure.in: Add iconvdata support for x86 linux. * configure: Regenerated. * libc/sys/linux/Makefile.am: Add EL/IX level 3 network, dynamic library, iconv, and linuxthreads support. * libc/sys/linux/configure.in: Ditto. * libc/sys/linux/Makefile.in: Regenerated. * libc/sys/linux/configure: Ditto. * iconvdata/EUC-JP.irreversible: New file. * iconvdata/Makefile.am: Ditto. * iconvdata/Makefile.in: Ditto. * iconvdata/SJIS.irreversible: Ditto. * iconvdata/aclocal.m4: Ditto. * iconvdata/configure: Ditto. * iconvdata/configure.in: Ditto. * iconvdata/dummy.c: Ditto. * iconvdata/euc-jp.c: Ditto. * iconvdata/gconv-modules: Ditto. * iconvdata/jis0201.c: Ditto. * iconvdata/jis0201.h: Ditto. * iconvdata/jis0208.c: Ditto. * iconvdata/jis0208.h: Ditto. * iconvdata/jis0212.c: Ditto. * iconvdata/jis0212.h: Ditto. * iconvdata/sjis.c: Ditto. * libc/include/errno.h: Protect definition of error_t. * libc/sys/linux/gethostid.c: New file. * libc/sys/linux/sethostid.c: Ditto. * libc/sys/linux/dl/Makefile.am: Ditto. * libc/sys/linux/dl/Makefile.in: Ditto. * libc/sys/linux/dl/abi-tag.h: Ditto. * libc/sys/linux/dl/atomicity.h: Ditto. * libc/sys/linux/dl/dl-addr.c: Ditto. * libc/sys/linux/dl/dl-cache.c: Ditto. * libc/sys/linux/dl/dl-cache.h: Ditto. * libc/sys/linux/dl/dl-close.c: Ditto. * libc/sys/linux/dl/dl-debug.c: Ditto. * libc/sys/linux/dl/dl-deps.c: Ditto. * libc/sys/linux/dl/dl-dst.h: Ditto. * libc/sys/linux/dl/dl-error.c: Ditto. * libc/sys/linux/dl/dl-fini.c: Ditto. * libc/sys/linux/dl/dl-init.c: Ditto. * libc/sys/linux/dl/dl-iteratephdr.c: Ditto. * libc/sys/linux/dl/dl-libc.c: Ditto. * libc/sys/linux/dl/dl-librecon.h: Ditto. * libc/sys/linux/dl/dl-load.c: Ditto. * libc/sys/linux/dl/dl-lookup.c: Ditto. * libc/sys/linux/dl/dl-lookupcfg.h: Ditto. * libc/sys/linux/dl/dl-minimal.c: Ditto. * libc/sys/linux/dl/dl-misc.c: Ditto. * libc/sys/linux/dl/dl-object.c: Ditto. * libc/sys/linux/dl/dl-open.c: Ditto. * libc/sys/linux/dl/dl-osinfo.h: Ditto. * libc/sys/linux/dl/dl-profile.c: Ditto. * libc/sys/linux/dl/dl-profstub.c: Ditto. * libc/sys/linux/dl/dl-reloc.c: Ditto. * libc/sys/linux/dl/dl-runtime.c: Ditto. * libc/sys/linux/dl/dl-support.c: Ditto. * libc/sys/linux/dl/dl-sym.c: Ditto. * libc/sys/linux/dl/dl-version.c: Ditto. * libc/sys/linux/dl/dlfcn.h: Ditto. * libc/sys/linux/dl/do-lookup.h: Ditto. * libc/sys/linux/dl/do-rel.h: Ditto. * libc/sys/linux/dl/dynamic-link.h: Ditto. * libc/sys/linux/dl/kernel-features.h: Ditto. * libc/sys/linux/dl/ldsodefs.h: Ditto. * libc/sys/linux/dl/libintl.h: Ditto. * libc/sys/linux/dl/trusted-dirs.h: Ditto. * libc/sys/linux/dl/unsecvars.h: Ditto. * libc/sys/linux/iconv/Makefile.am: Ditto. * libc/sys/linux/iconv/Makefile.in: Ditto. * libc/sys/linux/iconv/categories.def: Ditto. * libc/sys/linux/iconv/dummy-repertoire.c: Ditto. * libc/sys/linux/iconv/gconv.c: Ditto. * libc/sys/linux/iconv/gconv_builtin.c: Ditto. * libc/sys/linux/iconv/gconv_builtin.h: Ditto. * libc/sys/linux/iconv/gconv_cache.c: Ditto. * libc/sys/linux/iconv/gconv_charset.h: Ditto. * libc/sys/linux/iconv/gconv_close.c: Ditto. * libc/sys/linux/iconv/gconv_conf.c: Ditto. * libc/sys/linux/iconv/gconv_db.c: Ditto. * libc/sys/linux/iconv/gconv_dl.c: Ditto. * libc/sys/linux/iconv/gconv_int.h: Ditto. * libc/sys/linux/iconv/gconv_open.c: Ditto. * libc/sys/linux/iconv/gconv_simple.c: Ditto. * libc/sys/linux/iconv/gconv_trans.c: Ditto. * libc/sys/linux/iconv/hash-string.h: Ditto. * libc/sys/linux/iconv/iconv.c: Ditto. * libc/sys/linux/iconv/iconv.h: Ditto. * libc/sys/linux/iconv/iconv_charmap.c: Ditto. * libc/sys/linux/iconv/iconv_close.c: Ditto. * libc/sys/linux/iconv/iconv_open.c: Ditto. * libc/sys/linux/iconv/iconvconfig.c: Ditto. * libc/sys/linux/iconv/iconvconfig.h: Ditto. * libc/sys/linux/iconv/loadinfo.h: Ditto. * libc/sys/linux/iconv/localeinfo.h: Ditto. * libc/sys/linux/iconv/loop.c: Ditto. * libc/sys/linux/iconv/skeleton.c: Ditto. * libc/sys/linux/iconv/strtab.c: Ditto. * libc/sys/linux/include/dl-hash.h: Ditto. * libc/sys/linux/include/dlfcn.h: Ditto. * libc/sys/linux/include/fnmatch.h: Ditto. * libc/sys/linux/include/gconv.h: Ditto. * libc/sys/linux/include/glob.h: Ditto. * libc/sys/linux/include/hesiod.h: Ditto. * libc/sys/linux/include/ifaddrs.h: Ditto. * libc/sys/linux/include/libc_private.h: Ditto. * libc/sys/linux/include/link.h: Ditto. * libc/sys/linux/include/namespace.h: Ditto. * libc/sys/linux/include/netconfig.h: Ditto. * libc/sys/linux/include/netdb.h: Ditto. * libc/sys/linux/include/nsswitch.h: Ditto. * libc/sys/linux/include/regex.h: Ditto. * libc/sys/linux/include/resolv.h: Ditto. * libc/sys/linux/include/rune.h: Ditto. * libc/sys/linux/include/runetype.h: Ditto. * libc/sys/linux/include/semaphore.h: Ditto. * libc/sys/linux/include/setlocale.h: Ditto. * libc/sys/linux/include/un-namespace.h: Ditto. * libc/sys/linux/include/wordexp.h: Ditto. * libc/sys/linux/include/arpa/ftp.h: Ditto. * libc/sys/linux/include/arpa/inet.h: Ditto. * libc/sys/linux/include/arpa/nameser.h: Ditto. * libc/sys/linux/include/arpa/nameser_compat.h: Ditto. * libc/sys/linux/include/arpa/telnet.h: Ditto. * libc/sys/linux/include/arpa/tftp.h: Ditto. * libc/sys/linux/include/net/bpf.h: Ditto. * libc/sys/linux/include/net/bpf_compat.h: Ditto. * libc/sys/linux/include/net/bpfdesc.h: Ditto. * libc/sys/linux/include/net/bridge.h: Ditto. * libc/sys/linux/include/net/ethernet.h: Ditto. * libc/sys/linux/include/net/fddi.h: Ditto. * libc/sys/linux/include/net/if.h: Ditto. * libc/sys/linux/include/net/if_arc.h: Ditto. * libc/sys/linux/include/net/if_arp.h: Ditto. * libc/sys/linux/include/net/if_atm.h: Ditto. * libc/sys/linux/include/net/if_dl.h: Ditto. * libc/sys/linux/include/net/if_gif.h: Ditto. * libc/sys/linux/include/net/if_ieee80211.h: Ditto. * libc/sys/linux/include/net/if_llc.h: Ditto. * libc/sys/linux/include/net/if_media.h: Ditto. * libc/sys/linux/include/net/if_mib.h: Ditto. * libc/sys/linux/include/net/if_ppp.h: Ditto. * libc/sys/linux/include/net/if_pppvar.h: Ditto. * libc/sys/linux/include/net/if_slvar.h: Ditto. * libc/sys/linux/include/net/if_sppp.h: Ditto. * libc/sys/linux/include/net/if_stf.h: Ditto. * libc/sys/linux/include/net/if_tap.h: Ditto. * libc/sys/linux/include/net/if_tapvar.h: Ditto. * libc/sys/linux/include/net/if_tun.h: Ditto. * libc/sys/linux/include/net/if_tunvar.h: Ditto. * libc/sys/linux/include/net/if_types.h: Ditto. * libc/sys/linux/include/net/if_var.h: Ditto. * libc/sys/linux/include/net/if_vlan_var.h: Ditto. * libc/sys/linux/include/net/intrq.h: Ditto. * libc/sys/linux/include/net/iso88025.h: Ditto. * libc/sys/linux/include/net/net_osdep.h: Ditto. * libc/sys/linux/include/net/netisr.h: Ditto. * libc/sys/linux/include/net/pfil.h: Ditto. * libc/sys/linux/include/net/pfkeyv2.h: Ditto. * libc/sys/linux/include/net/ppp_comp.h: Ditto. * libc/sys/linux/include/net/ppp_defs.h: Ditto. * libc/sys/linux/include/net/radix.h: Ditto. * libc/sys/linux/include/net/raw_cb.h: Ditto. * libc/sys/linux/include/net/route.h: Ditto. * libc/sys/linux/include/net/slcompress.h: Ditto. * libc/sys/linux/include/net/slip.h: Ditto. * libc/sys/linux/include/net/zlib.h: Ditto. * libc/sys/linux/include/netinet/icmp6.h: Ditto. * libc/sys/linux/include/netinet/icmp_var.h: Ditto. * libc/sys/linux/include/netinet/if_atm.h: Ditto. * libc/sys/linux/include/netinet/if_ether.h: Ditto. * libc/sys/linux/include/netinet/igmp.h: Ditto. * libc/sys/linux/include/netinet/igmp_var.h: Ditto. * libc/sys/linux/include/netinet/in.h: Ditto. * libc/sys/linux/include/netinet/in_gif.h: Ditto. * libc/sys/linux/include/netinet/in_pcb.h: Ditto. * libc/sys/linux/include/netinet/in_systm.h: Ditto. * libc/sys/linux/include/netinet/in_var.h: Ditto. * libc/sys/linux/include/netinet/ip.h: Ditto. * libc/sys/linux/include/netinet/ip6.h: Ditto. * libc/sys/linux/include/netinet/ip_dummynet.h: Ditto. * libc/sys/linux/include/netinet/ip_ecn.h: Ditto. * libc/sys/linux/include/netinet/ip_encap.h: Ditto. * libc/sys/linux/include/netinet/ip_flow.h: Ditto. * libc/sys/linux/include/netinet/ip_fw.h: Ditto. * libc/sys/linux/include/netinet/ip_icmp.h: Ditto. * libc/sys/linux/include/netinet/ip_mroute.h: Ditto. * libc/sys/linux/include/netinet/ip_var.h: Ditto. * libc/sys/linux/include/netinet/ipprotosw.h: Ditto. * libc/sys/linux/include/netinet/tcp.h: Ditto. * libc/sys/linux/include/netinet/tcp_debug.h: Ditto. * libc/sys/linux/include/netinet/tcp_fsm.h: Ditto. * libc/sys/linux/include/netinet/tcp_seq.h: Ditto. * libc/sys/linux/include/netinet/tcp_timer.h: Ditto. * libc/sys/linux/include/netinet/tcp_var.h: Ditto. * libc/sys/linux/include/netinet/tcpip.h: Ditto. * libc/sys/linux/include/netinet/udp.h: Ditto. * libc/sys/linux/include/netinet/udp_var.h: Ditto. * libc/sys/linux/include/netinet6/ah.h: Ditto. * libc/sys/linux/include/netinet6/ah6.h: Ditto. * libc/sys/linux/include/netinet6/esp.h: Ditto. * libc/sys/linux/include/netinet6/esp6.h: Ditto. * libc/sys/linux/include/netinet6/esp_rijndael.h: Ditto. * libc/sys/linux/include/netinet6/icmp6.h: Ditto. * libc/sys/linux/include/netinet6/in6.h: Ditto. * libc/sys/linux/include/netinet6/in6_gif.h: Ditto. * libc/sys/linux/include/netinet6/in6_ifattach.h: Ditto. * libc/sys/linux/include/netinet6/in6_pcb.h: Ditto. * libc/sys/linux/include/netinet6/in6_prefix.h: Ditto. * libc/sys/linux/include/netinet6/in6_var.h: Ditto. * libc/sys/linux/include/netinet6/ip6.h: Ditto. * libc/sys/linux/include/netinet6/ip6_ecn.h: Ditto. * libc/sys/linux/include/netinet6/ip6_fw.h: Ditto. * libc/sys/linux/include/netinet6/ip6_mroute.h: Ditto. * libc/sys/linux/include/netinet6/ip6_var.h: Ditto. * libc/sys/linux/include/netinet6/ip6protosw.h: Ditto. * libc/sys/linux/include/netinet6/ipcomp.h: Ditto. * libc/sys/linux/include/netinet6/ipcomp6.h: Ditto. * libc/sys/linux/include/netinet6/ipsec.h: Ditto. * libc/sys/linux/include/netinet6/ipsec6.h: Ditto. * libc/sys/linux/include/netinet6/mld6_var.h: Ditto. * libc/sys/linux/include/netinet6/nd6.h: Ditto. * libc/sys/linux/include/netinet6/pim6.h: Ditto. * libc/sys/linux/include/netinet6/pim6_var.h: Ditto. * libc/sys/linux/include/netinet6/raw_ip6.h: Ditto. * libc/sys/linux/include/netinet6/scope6_var.h: Ditto. * libc/sys/linux/include/netinet6/tcp6_var.h: Ditto. * libc/sys/linux/include/netinet6/udp6_var.h: Ditto. * libc/sys/linux/include/netns/idp.h: Ditto. * libc/sys/linux/include/netns/idp_var.h: Ditto. * libc/sys/linux/include/netns/ns.h: Ditto. * libc/sys/linux/include/netns/ns_error.h: Ditto. * libc/sys/linux/include/netns/ns_if.h: Ditto. * libc/sys/linux/include/netns/ns_pcb.h: Ditto. * libc/sys/linux/include/netns/sp.h: Ditto. * libc/sys/linux/include/netns/spidp.h: Ditto. * libc/sys/linux/include/netns/spp_debug.h: Ditto. * libc/sys/linux/include/netns/spp_timer.h: Ditto. * libc/sys/linux/include/netns/spp_var.h: Ditto. * libc/sys/linux/include/rpc/Makefile: Ditto. * libc/sys/linux/include/rpc/auth.h: Ditto. * libc/sys/linux/include/rpc/auth_des.h: Ditto. * libc/sys/linux/include/rpc/auth_kerb.h: Ditto. * libc/sys/linux/include/rpc/auth_unix.h: Ditto. * libc/sys/linux/include/rpc/clnt.h: Ditto. * libc/sys/linux/include/rpc/clnt_soc.h: Ditto. * libc/sys/linux/include/rpc/clnt_stat.h: Ditto. * libc/sys/linux/include/rpc/des.h: Ditto. * libc/sys/linux/include/rpc/des_crypt.h: Ditto. * libc/sys/linux/include/rpc/nettype.h: Ditto. * libc/sys/linux/include/rpc/pmap_clnt.h: Ditto. * libc/sys/linux/include/rpc/pmap_prot.h: Ditto. * libc/sys/linux/include/rpc/pmap_rmt.h: Ditto. * libc/sys/linux/include/rpc/raw.h: Ditto. * libc/sys/linux/include/rpc/rpc.h: Ditto. * libc/sys/linux/include/rpc/rpc_com.h: Ditto. * libc/sys/linux/include/rpc/rpc_msg.h: Ditto. * libc/sys/linux/include/rpc/rpcb_clnt.h: Ditto. * libc/sys/linux/include/rpc/rpcb_prot.h: Ditto. * libc/sys/linux/include/rpc/rpcb_prot.x: Ditto. * libc/sys/linux/include/rpc/rpcent.h: Ditto. * libc/sys/linux/include/rpc/svc.h: Ditto. * libc/sys/linux/include/rpc/svc_auth.h: Ditto. * libc/sys/linux/include/rpc/svc_dg.h: Ditto. * libc/sys/linux/include/rpc/svc_soc.h: Ditto. * libc/sys/linux/include/rpc/types.h: Ditto. * libc/sys/linux/include/rpc/xdr.h: Ditto. * libc/sys/linux/intl/Makefile.am: Ditto. * libc/sys/linux/intl/Makefile.in: Ditto. * libc/sys/linux/intl/bindtextdom.c: Ditto. * libc/sys/linux/intl/catgets.c: Ditto. * libc/sys/linux/intl/catgetsinfo.h: Ditto. * libc/sys/linux/intl/config.h: Ditto. * libc/sys/linux/intl/dcgettext.c: Ditto. * libc/sys/linux/intl/dcigettext.c: Ditto. * libc/sys/linux/intl/dcngettext.c: Ditto. * libc/sys/linux/intl/dgettext.c: Ditto. * libc/sys/linux/intl/dngettext.c: Ditto. * libc/sys/linux/intl/explodename.c: Ditto. * libc/sys/linux/intl/finddomain.c: Ditto. * libc/sys/linux/intl/gettext.c: Ditto. * libc/sys/linux/intl/gettext.h: Ditto. * libc/sys/linux/intl/gettextP.h: Ditto. * libc/sys/linux/intl/hash-string.h: Ditto. * libc/sys/linux/intl/l10nflist.c: Ditto. * libc/sys/linux/intl/loadinfo.h: Ditto. * libc/sys/linux/intl/loadmsgcat.c: Ditto. * libc/sys/linux/intl/locale.alias: Ditto. * libc/sys/linux/intl/localealias.c: Ditto. * libc/sys/linux/intl/ngettext.c: Ditto. * libc/sys/linux/intl/open_catalog.c: Ditto. * libc/sys/linux/intl/plural.c: Ditto. * libc/sys/linux/intl/plural.y: Ditto. * libc/sys/linux/intl/stpcpy.c: Ditto. * libc/sys/linux/intl/textdomain.c: Ditto. * libc/sys/linux/linuxthreads/LICENSE: Ditto. * libc/sys/linux/linuxthreads/Makefile.am: Ditto. * libc/sys/linux/linuxthreads/Makefile.in: Ditto. * libc/sys/linux/linuxthreads/aclocal.m4: Ditto. * libc/sys/linux/linuxthreads/attr.c: Ditto. * libc/sys/linux/linuxthreads/barrier.c: Ditto. * libc/sys/linux/linuxthreads/bp-sym.h: Ditto. * libc/sys/linux/linuxthreads/cancel.c: Ditto. * libc/sys/linux/linuxthreads/condvar.c: Ditto. * libc/sys/linux/linuxthreads/config.h: Ditto. * libc/sys/linux/linuxthreads/configure: Ditto. * libc/sys/linux/linuxthreads/configure.in: Ditto. * libc/sys/linux/linuxthreads/defs.awk: Ditto. * libc/sys/linux/linuxthreads/ecmutex.c: Ditto. * libc/sys/linux/linuxthreads/events.c: Ditto. * libc/sys/linux/linuxthreads/getcpuclockid.c: Ditto. * libc/sys/linux/linuxthreads/getreent.c: Ditto. * libc/sys/linux/linuxthreads/internals.h: Ditto. * libc/sys/linux/linuxthreads/join.c: Ditto. * libc/sys/linux/linuxthreads/joinrace.c: Ditto. * libc/sys/linux/linuxthreads/kernel-features.h: Ditto. * libc/sys/linux/linuxthreads/libc-internal.h: Ditto. * libc/sys/linux/linuxthreads/libc-symbols.h: Ditto. * libc/sys/linux/linuxthreads/linuxthreads.texi: Ditto. * libc/sys/linux/linuxthreads/lockfile.c: Ditto. * libc/sys/linux/linuxthreads/manager.c: Ditto. * libc/sys/linux/linuxthreads/mq_notify.c: Ditto. * libc/sys/linux/linuxthreads/mutex.c: Ditto. * libc/sys/linux/linuxthreads/no-tsd.c: Ditto. * libc/sys/linux/linuxthreads/oldsemaphore.c: Ditto. * libc/sys/linux/linuxthreads/posix-timer.h: Ditto. * libc/sys/linux/linuxthreads/prio.c: Ditto. * libc/sys/linux/linuxthreads/proc_service.h: Ditto. * libc/sys/linux/linuxthreads/pt-machine.c: Ditto. * libc/sys/linux/linuxthreads/ptclock_gettime.c: Ditto. * libc/sys/linux/linuxthreads/ptclock_settime.c: Ditto. * libc/sys/linux/linuxthreads/ptfork.c: Ditto. * libc/sys/linux/linuxthreads/pthread.c: Ditto. * libc/sys/linux/linuxthreads/ptlongjmp.c: Ditto. * libc/sys/linux/linuxthreads/queue.h: Ditto. * libc/sys/linux/linuxthreads/reent.c: Ditto. * libc/sys/linux/linuxthreads/reqsyscalls.c: Ditto. * libc/sys/linux/linuxthreads/restart.h: Ditto. * libc/sys/linux/linuxthreads/rwlock.c: Ditto. * libc/sys/linux/linuxthreads/semaphore.c: Ditto. * libc/sys/linux/linuxthreads/semaphore.h: Ditto. * libc/sys/linux/linuxthreads/shlib-compat.h: Ditto. * libc/sys/linux/linuxthreads/signals.c: Ditto. * libc/sys/linux/linuxthreads/specific.c: Ditto. * libc/sys/linux/linuxthreads/spinlock.c: Ditto. * libc/sys/linux/linuxthreads/spinlock.h: Ditto. * libc/sys/linux/linuxthreads/sysctl.c: Ditto. * libc/sys/linux/linuxthreads/td_init.c: Ditto. * libc/sys/linux/linuxthreads/td_log.c: Ditto. * libc/sys/linux/linuxthreads/td_symbol_list.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_clear_event.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_delete.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_enable_stats.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_event_addr.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_event_getmsg.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_get_nthreads.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_get_ph.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_get_stats.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_map_id2thr.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_map_lwp2thr.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_new.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_reset_stats.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_set_event.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_setconcurrency.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_thr_iter.c: Ditto. * libc/sys/linux/linuxthreads/td_ta_tsd_iter.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_clear_event.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_dbresume.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_dbsuspend.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_event_enable.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_event_getmsg.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_get_info.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_getfpregs.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_getgregs.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_getxregs.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_getxregsize.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_set_event.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_setfpregs.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_setgregs.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_setprio.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_setsigpending.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_setxregs.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_sigsetmask.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_tsd.c: Ditto. * libc/sys/linux/linuxthreads/td_thr_validate.c: Ditto. * libc/sys/linux/linuxthreads/testrtsig.h: Ditto. * libc/sys/linux/linuxthreads/thread_db.h: Ditto. * libc/sys/linux/linuxthreads/thread_dbP.h: Ditto. * libc/sys/linux/linuxthreads/timer_create.c: Ditto. * libc/sys/linux/linuxthreads/timer_delete.c: Ditto. * libc/sys/linux/linuxthreads/timer_getoverr.c: Ditto. * libc/sys/linux/linuxthreads/timer_gettime.c: Ditto. * libc/sys/linux/linuxthreads/timer_routines.c: Ditto. * libc/sys/linux/linuxthreads/timer_settime.c: Ditto. * libc/sys/linux/linuxthreads/tst-cancel.c: Ditto. * libc/sys/linux/linuxthreads/tst-context.c: Ditto. * libc/sys/linux/linuxthreads/tststack.c: Ditto. * libc/sys/linux/linuxthreads/unload.c: Ditto. * libc/sys/linux/linuxthreads/weaks.c: Ditto. * libc/sys/linux/linuxthreads/wrapsyscall.c: Ditto. * libc/sys/linux/linuxthreads/bits/initspin.h: Ditto. * libc/sys/linux/linuxthreads/bits/libc-lock.h: Ditto. * libc/sys/linux/linuxthreads/bits/libc-tsd.h: Ditto. * libc/sys/linux/linuxthreads/bits/local_lim.h: Ditto. * libc/sys/linux/linuxthreads/bits/posix_opt.h: Ditto. * libc/sys/linux/linuxthreads/bits/pthreadtypes.h: Ditto. * libc/sys/linux/linuxthreads/bits/sigthread.h: Ditto. * libc/sys/linux/linuxthreads/machine/Makefile.am: Ditto. * libc/sys/linux/linuxthreads/machine/Makefile.in: Ditto. * libc/sys/linux/linuxthreads/machine/aclocal.m4: Ditto. * libc/sys/linux/linuxthreads/machine/configure: Ditto. * libc/sys/linux/linuxthreads/machine/configure.in: Ditto. * libc/sys/linux/linuxthreads/machine/generic/generic-sysd: Ditto.ep.h * libc/sys/linux/linuxthreads/machine/i386/Makefile.am: Ditto. * libc/sys/linux/linuxthreads/machine/i386/Makefile.in: Ditto. * libc/sys/linux/linuxthreads/machine/i386/aclocal.m4: Ditto. * libc/sys/linux/linuxthreads/machine/i386/bp-asm.h: Ditto. * libc/sys/linux/linuxthreads/machine/i386/clone.S: Ditto. * libc/sys/linux/linuxthreads/machine/i386/configure: Ditto. * libc/sys/linux/linuxthreads/machine/i386/configure.in: Ditto. * libc/sys/linux/linuxthreads/machine/i386/i386-sysdep.S: Ditto. * libc/sys/linux/linuxthreads/machine/i386/i386-sysdep.h: Ditto. * libc/sys/linux/linuxthreads/machine/i386/pspinlock.c: Ditto. * libc/sys/linux/linuxthreads/machine/i386/pt-machine.h: Ditto. * libc/sys/linux/linuxthreads/machine/i386/sigcontextinfo.h: Ditto. * libc/sys/linux/linuxthreads/machine/i386/stackinfo.h: Ditto. * libc/sys/linux/linuxthreads/machine/i386/sysdep.S: Ditto. * libc/sys/linux/linuxthreads/machine/i386/sysdep.h: Ditto. * libc/sys/linux/linuxthreads/machine/i386/useldt.h: Ditto. * libc/sys/linux/machine/i386/dl-machine.h: Ditto. * libc/sys/linux/net/Makefile.am: Ditto. * libc/sys/linux/net/Makefile.in: Ditto. * libc/sys/linux/net/addr2ascii.3: Ditto. * libc/sys/linux/net/addr2ascii.c: Ditto. * libc/sys/linux/net/ascii2addr.c: Ditto. * libc/sys/linux/net/base64.c: Ditto. * libc/sys/linux/net/bindresvport.c: Ditto. * libc/sys/linux/net/byteorder.3: Ditto. * libc/sys/linux/net/ether_addr.c: Ditto. * libc/sys/linux/net/ethers.3: Ditto. * libc/sys/linux/net/getaddrinfo.3: Ditto. * libc/sys/linux/net/getaddrinfo.c: Ditto. * libc/sys/linux/net/gethostbydns.c: Ditto. * libc/sys/linux/net/gethostbyht.c: Ditto. * libc/sys/linux/net/gethostbyname.3: Ditto. * libc/sys/linux/net/gethostbynis.c: Ditto. * libc/sys/linux/net/gethostnamadr.c: Ditto. * libc/sys/linux/net/getifaddrs.3: Ditto. * libc/sys/linux/net/getifaddrs.c: Ditto. * libc/sys/linux/net/getipnodebyname.3: Ditto. * libc/sys/linux/net/getnameinfo.3: Ditto. * libc/sys/linux/net/getnameinfo.c: Ditto. * libc/sys/linux/net/getnetbydns.c: Ditto. * libc/sys/linux/net/getnetbyht.c: Ditto. * libc/sys/linux/net/getnetbynis.c: Ditto. * libc/sys/linux/net/getnetent.3: Ditto. * libc/sys/linux/net/getnetnamadr.c: Ditto. * libc/sys/linux/net/getproto.c: Ditto. * libc/sys/linux/net/getprotoent.3: Ditto. * libc/sys/linux/net/getprotoent.c: Ditto. * libc/sys/linux/net/getprotoname.c: Ditto. * libc/sys/linux/net/getservbyname.c: Ditto. * libc/sys/linux/net/getservbyport.c: Ditto. * libc/sys/linux/net/getservent.3: Ditto. * libc/sys/linux/net/getservent.c: Ditto. * libc/sys/linux/net/herror.c: Ditto. * libc/sys/linux/net/hesiod.3: Ditto. * libc/sys/linux/net/hesiod.c: Ditto. * libc/sys/linux/net/if_indextoname.3: Ditto. * libc/sys/linux/net/ifname.c: Ditto. * libc/sys/linux/net/inet.3: Ditto. * libc/sys/linux/net/inet6_option_s: Ditto.pace.3 * libc/sys/linux/net/inet6_rthdr_space.3: Ditto. * libc/sys/linux/net/inet_addr.c: Ditto. * libc/sys/linux/net/inet_lnaof.c: Ditto. * libc/sys/linux/net/inet_makeaddr.c: Ditto. * libc/sys/linux/net/inet_net.3: Ditto. * libc/sys/linux/net/inet_net_ntop.c: Ditto. * libc/sys/linux/net/inet_net_pton.c: Ditto. * libc/sys/linux/net/inet_neta.c: Ditto. * libc/sys/linux/net/inet_netof.c: Ditto. * libc/sys/linux/net/inet_network.c: Ditto. * libc/sys/linux/net/inet_ntoa.c: Ditto. * libc/sys/linux/net/inet_ntop.c: Ditto. * libc/sys/linux/net/inet_pton.c: Ditto. * libc/sys/linux/net/innetgr-stub.c: Ditto. * libc/sys/linux/net/ip6opt.c: Ditto. * libc/sys/linux/net/iso_addr.3: Ditto. * libc/sys/linux/net/iso_addr.c: Ditto. * libc/sys/linux/net/issetugid-stub.c: Ditto. * libc/sys/linux/net/linkaddr.3: Ditto. * libc/sys/linux/net/linkaddr.c: Ditto. * libc/sys/linux/net/map_v4v6.c: Ditto. * libc/sys/linux/net/name6.c: Ditto. * libc/sys/linux/net/namespace.h: Ditto. * libc/sys/linux/net/ns.3: Ditto. * libc/sys/linux/net/ns_addr.c: Ditto. * libc/sys/linux/net/ns_name.c: Ditto. * libc/sys/linux/net/ns_netint.c: Ditto. * libc/sys/linux/net/ns_ntoa.c: Ditto. * libc/sys/linux/net/ns_parse.c: Ditto. * libc/sys/linux/net/ns_print.c: Ditto. * libc/sys/linux/net/ns_ttl.c: Ditto. * libc/sys/linux/net/nsap_addr.c: Ditto. * libc/sys/linux/net/nsdispatch.3: Ditto. * libc/sys/linux/net/nsdispatch.c: Ditto. * libc/sys/linux/net/nslexer.c: Ditto. * libc/sys/linux/net/nslexer.l: Ditto. * libc/sys/linux/net/nsparser.c: Ditto. * libc/sys/linux/net/nsparser.h: Ditto. * libc/sys/linux/net/nsparser.y: Ditto. * libc/sys/linux/net/rcmd.3: Ditto. * libc/sys/linux/net/rcmd.c: Ditto. * libc/sys/linux/net/rcmdsh.3: Ditto. * libc/sys/linux/net/rcmdsh.c: Ditto. * libc/sys/linux/net/recv.c: Ditto. * libc/sys/linux/net/res_comp.c: Ditto. * libc/sys/linux/net/res_config.h: Ditto. * libc/sys/linux/net/res_data.c: Ditto. * libc/sys/linux/net/res_debug.c: Ditto. * libc/sys/linux/net/res_init.c: Ditto. * libc/sys/linux/net/res_mkquery.c: Ditto. * libc/sys/linux/net/res_mkupdate.c: Ditto. * libc/sys/linux/net/res_query.c: Ditto. * libc/sys/linux/net/res_send.c: Ditto. * libc/sys/linux/net/res_update.c: Ditto. * libc/sys/linux/net/resolver.3: Ditto. * libc/sys/linux/net/rthdr.c: Ditto. * libc/sys/linux/net/send.c: Ditto. * libc/sys/linux/net/un-namespace.h: Ditto. * libc/sys/linux/net/vars.c: Ditto. * libc/sys/linux/stdlib/COPYRIGHT: Ditto. * libc/sys/linux/stdlib/Makefile.am: Ditto. * libc/sys/linux/stdlib/Makefile.in: Ditto. * libc/sys/linux/stdlib/cclass.h: Ditto. * libc/sys/linux/stdlib/cname.h: Ditto. * libc/sys/linux/stdlib/collate.c: Ditto. * libc/sys/linux/stdlib/collate.h: Ditto. * libc/sys/linux/stdlib/collcmp.c: Ditto. * libc/sys/linux/stdlib/engine.c: Ditto. * libc/sys/linux/stdlib/fnmatch.3: Ditto. * libc/sys/linux/stdlib/fnmatch.c: Ditto. * libc/sys/linux/stdlib/glob.3: Ditto. * libc/sys/linux/stdlib/glob.c: Ditto. * libc/sys/linux/stdlib/reallocf.c: Ditto. * libc/sys/linux/stdlib/regcomp.c: Ditto. * libc/sys/linux/stdlib/regerror.c: Ditto. * libc/sys/linux/stdlib/regex.3: Ditto. * libc/sys/linux/stdlib/regex2.h: Ditto. * libc/sys/linux/stdlib/regexec.c: Ditto. * libc/sys/linux/stdlib/regfree.c: Ditto. * libc/sys/linux/stdlib/utils.h: Ditto. * libc/sys/linux/stdlib/wordexp.c: Ditto. * libc/sys/linux/stdlib/wordfree.c: Ditto. * libc/sys/linux/sys/dlfcn.h: Ditto. * libc/sys/linux/sys/elfclass.h: Ditto. * libc/sys/linux/sys/event.h: Ditto. * libc/sys/linux/sys/ioccom.h: Ditto. * libc/sys/linux/sys/libc-tsd.h: Ditto. * libc/sys/linux/sys/link.h: Ditto. * libc/sys/linux/sys/lock.h: Ditto. * libc/sys/linux/sys/param.h: Ditto. * libc/sys/linux/sys/socket.h: Ditto. * libc/sys/linux/sys/sockio.h: Ditto. --- newlib/libc/sys/linux/dl/Makefile.am | 25 + newlib/libc/sys/linux/dl/Makefile.in | 379 ++++++ newlib/libc/sys/linux/dl/abi-tag.h | 4 + newlib/libc/sys/linux/dl/atomicity.h | 56 + newlib/libc/sys/linux/dl/dl-addr.c | 101 ++ newlib/libc/sys/linux/dl/dl-cache.c | 271 ++++ newlib/libc/sys/linux/dl/dl-cache.h | 140 +++ newlib/libc/sys/linux/dl/dl-close.c | 334 +++++ newlib/libc/sys/linux/dl/dl-debug.c | 57 + newlib/libc/sys/linux/dl/dl-deps.c | 561 +++++++++ newlib/libc/sys/linux/dl/dl-dst.h | 45 + newlib/libc/sys/linux/dl/dl-error.c | 189 +++ newlib/libc/sys/linux/dl/dl-fini.c | 172 +++ newlib/libc/sys/linux/dl/dl-init.c | 149 +++ newlib/libc/sys/linux/dl/dl-iteratephdr.c | 65 + newlib/libc/sys/linux/dl/dl-libc.c | 156 +++ newlib/libc/sys/linux/dl/dl-librecon.h | 87 ++ newlib/libc/sys/linux/dl/dl-load.c | 1830 ++++++++++++++++++++++++++++ newlib/libc/sys/linux/dl/dl-lookup.c | 654 ++++++++++ newlib/libc/sys/linux/dl/dl-lookupcfg.h | 22 + newlib/libc/sys/linux/dl/dl-minimal.c | 250 ++++ newlib/libc/sys/linux/dl/dl-misc.c | 277 +++++ newlib/libc/sys/linux/dl/dl-object.c | 163 +++ newlib/libc/sys/linux/dl/dl-open.c | 487 ++++++++ newlib/libc/sys/linux/dl/dl-osinfo.h | 108 ++ newlib/libc/sys/linux/dl/dl-profile.c | 539 ++++++++ newlib/libc/sys/linux/dl/dl-profstub.c | 43 + newlib/libc/sys/linux/dl/dl-reloc.c | 213 ++++ newlib/libc/sys/linux/dl/dl-runtime.c | 231 ++++ newlib/libc/sys/linux/dl/dl-support.c | 184 +++ newlib/libc/sys/linux/dl/dl-sym.c | 158 +++ newlib/libc/sys/linux/dl/dl-version.c | 385 ++++++ newlib/libc/sys/linux/dl/dlfcn.h | 84 ++ newlib/libc/sys/linux/dl/do-lookup.h | 200 +++ newlib/libc/sys/linux/dl/do-rel.h | 118 ++ newlib/libc/sys/linux/dl/dynamic-link.h | 244 ++++ newlib/libc/sys/linux/dl/kernel-features.h | 193 +++ newlib/libc/sys/linux/dl/ldsodefs.h | 535 ++++++++ newlib/libc/sys/linux/dl/libintl.h | 2 + newlib/libc/sys/linux/dl/trusted-dirs.h | 7 + newlib/libc/sys/linux/dl/unsecvars.h | 19 + 41 files changed, 9737 insertions(+) create mode 100644 newlib/libc/sys/linux/dl/Makefile.am create mode 100644 newlib/libc/sys/linux/dl/Makefile.in create mode 100644 newlib/libc/sys/linux/dl/abi-tag.h create mode 100644 newlib/libc/sys/linux/dl/atomicity.h create mode 100644 newlib/libc/sys/linux/dl/dl-addr.c create mode 100644 newlib/libc/sys/linux/dl/dl-cache.c create mode 100644 newlib/libc/sys/linux/dl/dl-cache.h create mode 100644 newlib/libc/sys/linux/dl/dl-close.c create mode 100644 newlib/libc/sys/linux/dl/dl-debug.c create mode 100644 newlib/libc/sys/linux/dl/dl-deps.c create mode 100644 newlib/libc/sys/linux/dl/dl-dst.h create mode 100644 newlib/libc/sys/linux/dl/dl-error.c create mode 100644 newlib/libc/sys/linux/dl/dl-fini.c create mode 100644 newlib/libc/sys/linux/dl/dl-init.c create mode 100644 newlib/libc/sys/linux/dl/dl-iteratephdr.c create mode 100644 newlib/libc/sys/linux/dl/dl-libc.c create mode 100644 newlib/libc/sys/linux/dl/dl-librecon.h create mode 100644 newlib/libc/sys/linux/dl/dl-load.c create mode 100644 newlib/libc/sys/linux/dl/dl-lookup.c create mode 100644 newlib/libc/sys/linux/dl/dl-lookupcfg.h create mode 100644 newlib/libc/sys/linux/dl/dl-minimal.c create mode 100644 newlib/libc/sys/linux/dl/dl-misc.c create mode 100644 newlib/libc/sys/linux/dl/dl-object.c create mode 100644 newlib/libc/sys/linux/dl/dl-open.c create mode 100644 newlib/libc/sys/linux/dl/dl-osinfo.h create mode 100644 newlib/libc/sys/linux/dl/dl-profile.c create mode 100644 newlib/libc/sys/linux/dl/dl-profstub.c create mode 100644 newlib/libc/sys/linux/dl/dl-reloc.c create mode 100644 newlib/libc/sys/linux/dl/dl-runtime.c create mode 100644 newlib/libc/sys/linux/dl/dl-support.c create mode 100644 newlib/libc/sys/linux/dl/dl-sym.c create mode 100644 newlib/libc/sys/linux/dl/dl-version.c create mode 100644 newlib/libc/sys/linux/dl/dlfcn.h create mode 100644 newlib/libc/sys/linux/dl/do-lookup.h create mode 100644 newlib/libc/sys/linux/dl/do-rel.h create mode 100644 newlib/libc/sys/linux/dl/dynamic-link.h create mode 100644 newlib/libc/sys/linux/dl/kernel-features.h create mode 100644 newlib/libc/sys/linux/dl/ldsodefs.h create mode 100644 newlib/libc/sys/linux/dl/libintl.h create mode 100644 newlib/libc/sys/linux/dl/trusted-dirs.h create mode 100644 newlib/libc/sys/linux/dl/unsecvars.h (limited to 'newlib/libc/sys/linux/dl') diff --git a/newlib/libc/sys/linux/dl/Makefile.am b/newlib/libc/sys/linux/dl/Makefile.am new file mode 100644 index 000000000..9c73a1367 --- /dev/null +++ b/newlib/libc/sys/linux/dl/Makefile.am @@ -0,0 +1,25 @@ +## Process this file with automake to generate Makefile.in + +AUTOMAKE_OPTIONS = cygnus + +INCLUDES = -DSHARED -D_GNU_SOURCE $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) -I$(srcdir)/.. + +LIB_SOURCES = \ + dl-addr.c dl-deps.c dl-init.c dl-load.c dl-misc.c dl-profile.c dl-runtime.c dl-version.c \ + dl-close.c dl-error.c dl-iteratephdr.c dl-lookup.c dl-object.c dl-profstub.c dl-support.c \ + dl-debug.c dl-fini.c dl-libc.c dl-open.c dl-reloc.c dl-sym.c dl-cache.c + +AM_CFLAGS = -D_GNU_SOURCE -D__strerror_r=strerror_r +libdl_la_LDFLAGS = -Xcompiler -nostdlib + +if USE_LIBTOOL +noinst_LTLIBRARIES = libdl.la +libdl_la_SOURCES = $(LIB_SOURCES) +noinst_DATA = objectlist.awk.in +else +noinst_LIBRARIES = lib.a +lib_a_SOURCES = $(LIB_SOURCES) +noinst_DATA = +endif # USE_LIBTOOL + +include $(srcdir)/../../../../Makefile.shared diff --git a/newlib/libc/sys/linux/dl/Makefile.in b/newlib/libc/sys/linux/dl/Makefile.in new file mode 100644 index 000000000..56e88ae0a --- /dev/null +++ b/newlib/libc/sys/linux/dl/Makefile.in @@ -0,0 +1,379 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AR = @AR@ +AS = @AS@ +AWK = @AWK@ +CC = @CC@ +CPP = @CPP@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +DLLTOOL = @DLLTOOL@ +EXEEXT = @EXEEXT@ +GCJ = @GCJ@ +GCJFLAGS = @GCJFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBTOOL = @LIBTOOL@ +LINUX_MACH_LIB = @LINUX_MACH_LIB@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +NEWLIB_CFLAGS = @NEWLIB_CFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +aext = @aext@ +libm_machine_dir = @libm_machine_dir@ +machine_dir = @machine_dir@ +newlib_basedir = @newlib_basedir@ +oext = @oext@ +sys_dir = @sys_dir@ + +AUTOMAKE_OPTIONS = cygnus + +INCLUDES = -DSHARED -D_GNU_SOURCE $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) -I$(srcdir)/.. + +LIB_SOURCES = \ + dl-addr.c dl-deps.c dl-init.c dl-load.c dl-misc.c dl-profile.c dl-runtime.c dl-version.c \ + dl-close.c dl-error.c dl-iteratephdr.c dl-lookup.c dl-object.c dl-profstub.c dl-support.c \ + dl-debug.c dl-fini.c dl-libc.c dl-open.c dl-reloc.c dl-sym.c dl-cache.c + + +AM_CFLAGS = -D_GNU_SOURCE -D__strerror_r=strerror_r +libdl_la_LDFLAGS = -Xcompiler -nostdlib + +@USE_LIBTOOL_TRUE@noinst_LTLIBRARIES = @USE_LIBTOOL_TRUE@libdl.la +@USE_LIBTOOL_TRUE@libdl_la_SOURCES = @USE_LIBTOOL_TRUE@$(LIB_SOURCES) +@USE_LIBTOOL_TRUE@noinst_DATA = @USE_LIBTOOL_TRUE@objectlist.awk.in +@USE_LIBTOOL_FALSE@noinst_DATA = +@USE_LIBTOOL_FALSE@noinst_LIBRARIES = @USE_LIBTOOL_FALSE@lib.a +@USE_LIBTOOL_FALSE@lib_a_SOURCES = @USE_LIBTOOL_FALSE@$(LIB_SOURCES) +mkinstalldirs = $(SHELL) $(top_srcdir)/../../../../mkinstalldirs +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +lib_a_LIBADD = +@USE_LIBTOOL_FALSE@lib_a_OBJECTS = dl-addr.$(OBJEXT) dl-deps.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@dl-init.$(OBJEXT) dl-load.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@dl-misc.$(OBJEXT) dl-profile.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@dl-runtime.$(OBJEXT) dl-version.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@dl-close.$(OBJEXT) dl-error.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@dl-iteratephdr.$(OBJEXT) dl-lookup.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@dl-object.$(OBJEXT) dl-profstub.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@dl-support.$(OBJEXT) dl-debug.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@dl-fini.$(OBJEXT) dl-libc.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@dl-open.$(OBJEXT) dl-reloc.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@dl-sym.$(OBJEXT) dl-cache.$(OBJEXT) +LTLIBRARIES = $(noinst_LTLIBRARIES) + +libdl_la_LIBADD = +@USE_LIBTOOL_TRUE@libdl_la_OBJECTS = dl-addr.lo dl-deps.lo dl-init.lo \ +@USE_LIBTOOL_TRUE@dl-load.lo dl-misc.lo dl-profile.lo dl-runtime.lo \ +@USE_LIBTOOL_TRUE@dl-version.lo dl-close.lo dl-error.lo \ +@USE_LIBTOOL_TRUE@dl-iteratephdr.lo dl-lookup.lo dl-object.lo \ +@USE_LIBTOOL_TRUE@dl-profstub.lo dl-support.lo dl-debug.lo dl-fini.lo \ +@USE_LIBTOOL_TRUE@dl-libc.lo dl-open.lo dl-reloc.lo dl-sym.lo \ +@USE_LIBTOOL_TRUE@dl-cache.lo +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DATA = $(noinst_DATA) + +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +SOURCES = $(lib_a_SOURCES) $(libdl_la_SOURCES) +OBJECTS = $(lib_a_OBJECTS) $(libdl_la_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .lo .o .obj .s +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) $(srcdir)/../../../../Makefile.shared + cd $(top_srcdir) && $(AUTOMAKE) --cygnus dl/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +# FIXME: We should only use cygpath when building on Windows, +# and only if it is available. +.c.obj: + $(COMPILE) -c `cygpath -w $<` + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + -rm -f *.$(OBJEXT) + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.c.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +lib.a: $(lib_a_OBJECTS) $(lib_a_DEPENDENCIES) + -rm -f lib.a + $(AR) cru lib.a $(lib_a_OBJECTS) $(lib_a_LIBADD) + $(RANLIB) lib.a + +mostlyclean-noinstLTLIBRARIES: + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + +distclean-noinstLTLIBRARIES: + +maintainer-clean-noinstLTLIBRARIES: + +libdl.la: $(libdl_la_OBJECTS) $(libdl_la_DEPENDENCIES) + $(LINK) $(libdl_la_LDFLAGS) $(libdl_la_OBJECTS) $(libdl_la_LIBADD) $(LIBS) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = dl + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + if test -f $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: +check: check-am +installcheck-am: +installcheck: installcheck-am +install-info-am: +install-info: install-info-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(DATA) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-libtool mostlyclean-noinstLTLIBRARIES \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-libtool \ + clean-noinstLTLIBRARIES clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-libtool distclean-noinstLTLIBRARIES \ + distclean-tags distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-noinstLTLIBRARIES \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-libtool distclean-libtool \ +clean-libtool maintainer-clean-libtool mostlyclean-noinstLTLIBRARIES \ +distclean-noinstLTLIBRARIES clean-noinstLTLIBRARIES \ +maintainer-clean-noinstLTLIBRARIES tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-info-am install-info \ +install-exec-am install-exec install-data-am install-data install-am \ +install uninstall-am uninstall all-redirect all-am all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +objectlist.awk.in: $(noinst_LTLIBRARIES) + -rm -f objectlist.awk.in + for i in `ls *.lo` ; \ + do \ + echo $$i `pwd`/$$i >> objectlist.awk.in ; \ + done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/newlib/libc/sys/linux/dl/abi-tag.h b/newlib/libc/sys/linux/dl/abi-tag.h new file mode 100644 index 000000000..85db374c6 --- /dev/null +++ b/newlib/libc/sys/linux/dl/abi-tag.h @@ -0,0 +1,4 @@ +#define __ABI_TAG_OS 0 +#ifndef __ABI_TAG_VERSION +# define __ABI_TAG_VERSION 2,0,0 +#endif diff --git a/newlib/libc/sys/linux/dl/atomicity.h b/newlib/libc/sys/linux/dl/atomicity.h new file mode 100644 index 000000000..8b52ab407 --- /dev/null +++ b/newlib/libc/sys/linux/dl/atomicity.h @@ -0,0 +1,56 @@ +/* Low-level functions for atomic operations. ix86 version, x >= 4. + Copyright (C) 1997, 2000, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _ATOMICITY_H +#define _ATOMICITY_H 1 + + + +static inline uint32_t +__attribute__ ((unused)) +exchange_and_add (volatile uint32_t *mem, uint32_t val) +{ + register uint32_t result; + __asm__ __volatile__ ("lock; xaddl %0,%1" + : "=r" (result), "=m" (*mem) : "0" (val), "1" (*mem)); + return result; +} + +static inline void +__attribute__ ((unused)) +atomic_add (volatile uint32_t *mem, int val) +{ + __asm__ __volatile__ ("lock; addl %1,%0" + : "=m" (*mem) : "ir" (val), "0" (*mem)); +} + +static inline char +__attribute__ ((unused)) +compare_and_swap (volatile long int *p, long int oldval, long int newval) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (newval), "1" (*p), "a" (oldval)); + return ret; +} + +#endif /* atomicity.h */ diff --git a/newlib/libc/sys/linux/dl/dl-addr.c b/newlib/libc/sys/linux/dl/dl-addr.c new file mode 100644 index 000000000..23867491f --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-addr.c @@ -0,0 +1,101 @@ +/* Locate the shared object symbol nearest a given address. + Copyright (C) 1996-2000, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +int +internal_function +_dl_addr (const void *address, Dl_info *info) +{ + const ElfW(Addr) addr = DL_LOOKUP_ADDRESS (address); + struct link_map *l, *match; + const ElfW(Sym) *symtab, *matchsym; + const char *strtab; + ElfW(Word) strtabsize; + + /* Find the highest-addressed object that ADDRESS is not below. */ + match = NULL; + for (l = _dl_loaded; l; l = l->l_next) + if (addr >= l->l_map_start && addr < l->l_map_end) + { + /* We know ADDRESS lies within L if in any shared object. + Make sure it isn't past the end of L's segments. */ + size_t n = l->l_phnum; + if (n > 0) + { + do + --n; + while (l->l_phdr[n].p_type != PT_LOAD); + if (addr >= (l->l_addr + + l->l_phdr[n].p_vaddr + l->l_phdr[n].p_memsz)) + /* Off the end of the highest-addressed shared object. */ + continue; + } + + match = l; + break; + } + + if (match == NULL) + return 0; + + /* Now we know what object the address lies in. */ + info->dli_fname = match->l_name; + info->dli_fbase = (void *) match->l_addr; + + /* If this is the main program the information is incomplete. */ + if (__builtin_expect (info->dli_fbase == NULL, 0)) + { + info->dli_fname = _dl_argv[0]; + info->dli_fbase = (void *) match->l_map_start; + } + + symtab = (const void *) D_PTR (match, l_info[DT_SYMTAB]); + strtab = (const void *) D_PTR (match, l_info[DT_STRTAB]); + strtabsize = match->l_info[DT_STRSZ]->d_un.d_val; + + /* We assume that the string table follows the symbol table, because + there is no way in ELF to know the size of the dynamic symbol table!! */ + for (matchsym = NULL; (void *) symtab < (void *) strtab; ++symtab) + if (addr >= match->l_addr + symtab->st_value + && ((symtab->st_size == 0 && addr == match->l_addr + symtab->st_value) + || addr < match->l_addr + symtab->st_value + symtab->st_size) + && symtab->st_name < strtabsize + && (matchsym == NULL || matchsym->st_value < symtab->st_value) + && (ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL + || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)) + matchsym = symtab; + + if (matchsym) + { + /* We found a symbol close by. Fill in its name and exact address. */ + info->dli_sname = strtab + matchsym->st_name; + info->dli_saddr = (void *) (match->l_addr + matchsym->st_value); + } + else + { + /* No symbol matches. We return only the containing object. */ + info->dli_sname = NULL; + info->dli_saddr = NULL; + } + + return 1; +} diff --git a/newlib/libc/sys/linux/dl/dl-cache.c b/newlib/libc/sys/linux/dl/dl-cache.c new file mode 100644 index 000000000..a71e5e876 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-cache.c @@ -0,0 +1,271 @@ +/* Support for reading /etc/ld.so.cache files written by Linux ldconfig. + Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include + +extern const char *_dl_platform; + +#ifndef _DL_PLATFORMS_COUNT +# define _DL_PLATFORMS_COUNT 0 +#endif + +/* This is the starting address and the size of the mmap()ed file. */ +static struct cache_file *cache; +static struct cache_file_new *cache_new; +static size_t cachesize; + +/* 1 if cache_data + PTR points into the cache. */ +#define _dl_cache_verify_ptr(ptr) (ptr < cache_data_size) + +/* This is the cache ID we expect. Normally it is 3 for glibc linked + binaries. */ +int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID; + +#define SEARCH_CACHE(cache) \ +/* We use binary search since the table is sorted in the cache file. \ + The first matching entry in the table is returned. \ + It is important to use the same algorithm as used while generating \ + the cache file. */ \ +do \ + { \ + left = 0; \ + right = cache->nlibs - 1; \ + \ + while (left <= right) \ + { \ + __typeof__ (cache->libs[0].key) key; \ + \ + middle = (left + right) / 2; \ + \ + key = cache->libs[middle].key; \ + \ + /* Make sure string table indices are not bogus before using \ + them. */ \ + if (! _dl_cache_verify_ptr (key)) \ + { \ + cmpres = 1; \ + break; \ + } \ + \ + /* Actually compare the entry with the key. */ \ + cmpres = _dl_cache_libcmp (name, cache_data + key); \ + if (__builtin_expect (cmpres == 0, 0)) \ + { \ + /* Found it. LEFT now marks the last entry for which we \ + know the name is correct. */ \ + left = middle; \ + \ + /* There might be entries with this name before the one we \ + found. So we have to find the beginning. */ \ + while (middle > 0) \ + { \ + __typeof__ (cache->libs[0].key) key; \ + \ + key = cache->libs[middle - 1].key; \ + /* Make sure string table indices are not bogus before \ + using them. */ \ + if (! _dl_cache_verify_ptr (key) \ + /* Actually compare the entry. */ \ + || _dl_cache_libcmp (name, cache_data + key) != 0) \ + break; \ + --middle; \ + } \ + \ + do \ + { \ + int flags; \ + __typeof__ (cache->libs[0]) *lib = &cache->libs[middle]; \ + \ + /* Only perform the name test if necessary. */ \ + if (middle > left \ + /* We haven't seen this string so far. Test whether the \ + index is ok and whether the name matches. Otherwise \ + we are done. */ \ + && (! _dl_cache_verify_ptr (lib->key) \ + || (_dl_cache_libcmp (name, cache_data + lib->key) \ + != 0))) \ + break; \ + \ + flags = lib->flags; \ + if (_dl_cache_check_flags (flags) \ + && _dl_cache_verify_ptr (lib->value)) \ + { \ + if (best == NULL || flags == _dl_correct_cache_id) \ + { \ + HWCAP_CHECK; \ + best = cache_data + lib->value; \ + \ + if (flags == _dl_correct_cache_id) \ + /* We've found an exact match for the shared \ + object and no general `ELF' release. Stop \ + searching. */ \ + break; \ + } \ + } \ + } \ + while (++middle <= right); \ + break; \ + } \ + \ + if (cmpres < 0) \ + left = middle + 1; \ + else \ + right = middle - 1; \ + } \ + } \ +while (0) + + + +/* Look up NAME in ld.so.cache and return the file name stored there, + or null if none is found. */ + +const char * +internal_function +_dl_load_cache_lookup (const char *name) +{ + int left, right, middle; + int cmpres; + const char *cache_data; + uint32_t cache_data_size; + const char *best; + + if (cache == NULL) + { + /* Read the contents of the file. */ + void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize, + PROT_READ); + + /* We can handle three different cache file formats here: + - the old libc5/glibc2.0/2.1 format + - the old format with the new format in it + - only the new format + The following checks if the cache contains any of these formats. */ + if (file != MAP_FAILED && cachesize > sizeof *cache + && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0) + { + size_t offset; + /* Looks ok. */ + cache = file; + + /* Check for new version. */ + offset = ALIGN_CACHE (sizeof (struct cache_file) + + cache->nlibs * sizeof (struct file_entry)); + + cache_new = (struct cache_file_new *) ((void *) cache + offset); + if (cachesize < (offset + sizeof (struct cache_file_new)) + || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW, + sizeof CACHEMAGIC_VERSION_NEW - 1) != 0) + cache_new = (void *) -1; + } + else if (file != MAP_FAILED && cachesize > sizeof *cache_new + && memcmp (file, CACHEMAGIC_VERSION_NEW, + sizeof CACHEMAGIC_VERSION_NEW - 1) == 0) + { + cache_new = file; + cache = file; + } + else + { + if (file != MAP_FAILED) + munmap (file, cachesize); + cache = (void *) -1; + } + + assert (cache != NULL); + } + + if (cache == (void *) -1) + /* Previously looked for the cache file and didn't find it. */ + return NULL; + + best = NULL; + + if (cache_new != (void *) -1) + { + /* This file ends in static libraries where we don't have a hwcap. */ + unsigned long int *hwcap; + uint64_t platform; + weak_extern (_dl_hwcap); + + /* This is where the strings start. */ + cache_data = (const char *) cache_new; + + /* Now we can compute how large the string table is. */ + cache_data_size = (const char *) cache + cachesize - cache_data; + + hwcap = &_dl_hwcap; + platform = _dl_string_platform (_dl_platform); + if (platform != -1) + platform = 1ULL << platform; + + /* Only accept hwcap if it's for the right platform. */ +#define HWCAP_CHECK \ + if (_dl_osversion && cache_new->libs[middle].osversion > _dl_osversion) \ + continue; \ + if (_DL_PLATFORMS_COUNT && platform != -1 \ + && (lib->hwcap & _DL_HWCAP_PLATFORM) != 0 \ + && (lib->hwcap & _DL_HWCAP_PLATFORM) != platform) \ + continue; \ + if (hwcap \ + && ((lib->hwcap & *hwcap & ~_DL_HWCAP_PLATFORM) > *hwcap)) \ + continue + SEARCH_CACHE (cache_new); + } + else + { + /* This is where the strings start. */ + cache_data = (const char *) &cache->libs[cache->nlibs]; + + /* Now we can compute how large the string table is. */ + cache_data_size = (const char *) cache + cachesize - cache_data; + +#undef HWCAP_CHECK +#define HWCAP_CHECK do {} while (0) + SEARCH_CACHE (cache); + } + + /* Print our result if wanted. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0) && best != NULL) + _dl_debug_printf (" trying file=%s\n", best); + + return best; +} + +#ifndef MAP_COPY +/* If the system does not support MAP_COPY we cannot leave the file open + all the time since this would create problems when the file is replaced. + Therefore we provide this function to close the file and open it again + once needed. */ +void +_dl_unload_cache (void) +{ + if (cache != NULL && cache != (struct cache_file *) -1) + { + munmap (cache, cachesize); + cache = NULL; + } +} +#endif diff --git a/newlib/libc/sys/linux/dl/dl-cache.h b/newlib/libc/sys/linux/dl/dl-cache.h new file mode 100644 index 000000000..0699853e7 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-cache.h @@ -0,0 +1,140 @@ +/* Support for reading /etc/ld.so.cache files written by Linux ldconfig. + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +#ifndef _DL_CACHE_DEFAULT_ID +# define _DL_CACHE_DEFAULT_ID 3 +#endif + +#ifndef _dl_cache_check_flags +# define _dl_cache_check_flags(flags) \ + ((flags) == 1 || (flags) == _DL_CACHE_DEFAULT_ID) +#endif + +#ifndef SYSCONFDIR +# define SYSCONFDIR "/etc" +#endif + +#ifndef LD_SO_CACHE +# define LD_SO_CACHE SYSCONFDIR "/ld.so.cache" +#endif + +#define CACHEMAGIC "ld.so-1.7.0" + +/* libc5 and glibc 2.0/2.1 use the same format. For glibc 2.2 another + format has been added in a compatible way: + The beginning of the string table is used for the new table: + old_magic + nlibs + libs[0] + ... + libs[nlibs-1] + pad, new magic needs to be aligned + - this is string[0] for the old format + new magic - this is string[0] for the new format + newnlibs + ... + newlibs[0] + ... + newlibs[newnlibs-1] + string 1 + string 2 + ... +*/ +struct file_entry +{ + int flags; /* This is 1 for an ELF library. */ + unsigned int key, value; /* String table indices. */ +}; + +struct cache_file +{ + char magic[sizeof CACHEMAGIC - 1]; + unsigned int nlibs; + struct file_entry libs[0]; +}; + +#define CACHEMAGIC_NEW "glibc-ld.so.cache" +#define CACHE_VERSION "1.1" +#define CACHEMAGIC_VERSION_NEW CACHEMAGIC_NEW CACHE_VERSION + + +struct file_entry_new +{ + int32_t flags; /* This is 1 for an ELF library. */ + uint32_t key, value; /* String table indices. */ + uint32_t osversion; /* Required OS version. */ + uint64_t hwcap; /* Hwcap entry. */ +}; + +struct cache_file_new +{ + char magic[sizeof CACHEMAGIC_NEW - 1]; + char version[sizeof CACHE_VERSION - 1]; + uint32_t nlibs; /* Number of entries. */ + uint32_t len_strings; /* Size of string table. */ + uint32_t unused[5]; /* Leave space for future extensions + and align to 8 byte boundary. */ + struct file_entry_new libs[0]; /* Entries describing libraries. */ + /* After this the string table of size len_strings is found. */ +}; + +/* Used to align cache_file_new. */ +#define ALIGN_CACHE(addr) \ +(((addr) + __alignof__ (struct cache_file_new) -1) \ + & (~(__alignof__ (struct cache_file_new) - 1))) + +static int +_dl_cache_libcmp (const char *p1, const char *p2) +{ + while (*p1 != '\0') + { + if (*p1 >= '0' && *p1 <= '9') + { + if (*p2 >= '0' && *p2 <= '9') + { + /* Must compare this numerically. */ + int val1; + int val2; + + val1 = *p1++ - '0'; + val2 = *p2++ - '0'; + while (*p1 >= '0' && *p1 <= '9') + val1 = val1 * 10 + *p1++ - '0'; + while (*p2 >= '0' && *p2 <= '9') + val2 = val2 * 10 + *p2++ - '0'; + if (val1 != val2) + return val1 - val2; + } + else + return 1; + } + else if (*p2 >= '0' && *p2 <= '9') + return -1; + else if (*p1 != *p2) + return *p1 - *p2; + else + { + ++p1; + ++p2; + } + } + return *p1 - *p2; +} diff --git a/newlib/libc/sys/linux/dl/dl-close.c b/newlib/libc/sys/linux/dl/dl-close.c new file mode 100644 index 000000000..ef53868d9 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-close.c @@ -0,0 +1,334 @@ +/* Close a shared object opened by `_dl_open'. + Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Type of the constructor functions. */ +typedef void (*fini_t) (void); + + +void +internal_function +_dl_close (void *_map) +{ + struct reldep_list + { + struct link_map **rellist; + unsigned int nrellist; + struct reldep_list *next; + } *reldeps = NULL; + struct link_map **list; + struct link_map *map = _map; + unsigned int i; + unsigned int *new_opencount; + + /* First see whether we can remove the object at all. */ + if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0) + && map->l_init_called) + /* Nope. Do nothing. */ + return; + + if (__builtin_expect (map->l_opencount, 1) == 0) + _dl_signal_error (0, map->l_name, NULL, N_("shared object not open")); + + /* Acquire the lock. */ +#ifdef HAVE_DD_LOCK + __lock_acquire(_dl_load_lock); +#endif + + + /* Decrement the reference count. */ + if (map->l_opencount > 1 || map->l_type != lt_loaded) + { + /* There are still references to this object. Do nothing more. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) + _dl_debug_printf ("\nclosing file=%s; opencount == %u\n", + map->l_name, map->l_opencount); + + /* One decrement the object itself, not the dependencies. */ + --map->l_opencount; + +#ifdef HAVE_DD_LOCK + __lock_release(_dl_load_lock); +#endif + + return; + } + + list = map->l_initfini; + + /* Compute the new l_opencount values. */ + i = map->l_searchlist.r_nlist; + if (__builtin_expect (i == 0, 0)) + /* This can happen if we handle relocation dependencies for an + object which wasn't loaded directly. */ + for (i = 1; list[i] != NULL; ++i) + ; + + new_opencount = (unsigned int *) alloca (i * sizeof (unsigned int)); + + for (i = 0; list[i] != NULL; ++i) + { + list[i]->l_idx = i; + new_opencount[i] = list[i]->l_opencount; + } + --new_opencount[0]; + for (i = 1; list[i] != NULL; ++i) + if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called) + /* Decrement counter. */ + && --new_opencount[i] == 0 + /* Test whether this object was also loaded directly. */ + && list[i]->l_searchlist.r_list != NULL) + { + /* In this case we have the decrement all the dependencies of + this object. They are all in MAP's dependency list. */ + unsigned int j; + struct link_map **dep_list = list[i]->l_searchlist.r_list; + + for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j) + if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE) + || ! dep_list[j]->l_init_called) + { + assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist); + --new_opencount[dep_list[j]->l_idx]; + } + } + assert (new_opencount[0] == 0); + + /* Call all termination functions at once. */ + for (i = 0; list[i] != NULL; ++i) + { + struct link_map *imap = list[i]; + if (new_opencount[i] == 0 && imap->l_type == lt_loaded + && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY]) + && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called) + /* Skip any half-cooked objects that were never initialized. */ + && imap->l_init_called) + { + /* When debugging print a message first. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0)) + _dl_debug_printf ("\ncalling fini: %s\n\n", imap->l_name); + + /* Call its termination function. */ + if (imap->l_info[DT_FINI_ARRAY] != NULL) + { + ElfW(Addr) *array = + (ElfW(Addr) *) (imap->l_addr + + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr); + unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val + / sizeof (ElfW(Addr))); + unsigned int cnt; + + for (cnt = 0; cnt < sz; ++cnt) + ((fini_t) (imap->l_addr + array[cnt])) (); + } + + /* Next try the old-style destructor. */ + if (imap->l_info[DT_FINI] != NULL) + (*(void (*) (void)) DL_DT_FINI_ADDRESS + (imap, (void *) imap->l_addr + + imap->l_info[DT_FINI]->d_un.d_ptr)) (); + } + else if (new_opencount[i] != 0 && imap->l_type == lt_loaded) + { + /* The object is still used. But the object we are unloading + right now is responsible for loading it and therefore we + have the search list of the current object in its scope. + Remove it. */ + struct r_scope_elem **runp = imap->l_scope; + + while (*runp != NULL) + if (*runp == &map->l_searchlist) + { + /* Copy all later elements. */ + while ((runp[0] = runp[1]) != NULL) + ++runp; + break; + } + else + ++runp; + } + + /* Store the new l_opencount value. */ + imap->l_opencount = new_opencount[i]; + /* Just a sanity check. */ + assert (imap->l_type == lt_loaded || imap->l_opencount > 0); + } + + /* Notify the debugger we are about to remove some loaded objects. */ + _r_debug.r_state = RT_DELETE; + _dl_debug_state (); + + /* Check each element of the search list to see if all references to + it are gone. */ + for (i = 0; list[i] != NULL; ++i) + { + struct link_map *imap = list[i]; + if (imap->l_opencount == 0 && imap->l_type == lt_loaded) + { + struct libname_list *lnp; + + /* That was the last reference, and this was a dlopen-loaded + object. We can unmap it. */ + if (__builtin_expect (imap->l_global, 0)) + { + /* This object is in the global scope list. Remove it. */ + unsigned int cnt = _dl_main_searchlist->r_nlist; + + do + --cnt; + while (_dl_main_searchlist->r_list[cnt] != imap); + + /* The object was already correctly registered. */ + while (++cnt < _dl_main_searchlist->r_nlist) + _dl_main_searchlist->r_list[cnt - 1] + = _dl_main_searchlist->r_list[cnt]; + + --_dl_main_searchlist->r_nlist; + } + + /* We can unmap all the maps at once. We determined the + start address and length when we loaded the object and + the `munmap' call does the rest. */ + DL_UNMAP (imap); + + /* Finally, unlink the data structure and free it. */ +#ifdef SHARED + /* We will unlink the first object only if this is a statically + linked program. */ + assert (imap->l_prev != NULL); + imap->l_prev->l_next = imap->l_next; +#else + if (imap->l_prev != NULL) + imap->l_prev->l_next = imap->l_next; + else + _dl_loaded = imap->l_next; +#endif + --_dl_nloaded; + if (imap->l_next) + imap->l_next->l_prev = imap->l_prev; + + if (imap->l_versions != NULL) + free (imap->l_versions); + if (imap->l_origin != NULL && imap->l_origin != (char *) -1) + free ((char *) imap->l_origin); + + /* If the object has relocation dependencies save this + information for latter. */ + if (__builtin_expect (imap->l_reldeps != NULL, 0)) + { + struct reldep_list *newrel; + + newrel = (struct reldep_list *) alloca (sizeof (*reldeps)); + newrel->rellist = imap->l_reldeps; + newrel->nrellist = imap->l_reldepsact; + newrel->next = reldeps; + + reldeps = newrel; + } + + /* This name always is allocated. */ + free (imap->l_name); + /* Remove the list with all the names of the shared object. */ + lnp = imap->l_libname; + do + { + struct libname_list *this = lnp; + lnp = lnp->next; + if (!this->dont_free) + free (this); + } + while (lnp != NULL); + + /* Remove the searchlists. */ + if (imap != map) + free (imap->l_initfini); + + /* Remove the scope array if we allocated it. */ + if (imap->l_scope != imap->l_scope_mem) + free (imap->l_scope); + + if (imap->l_phdr_allocated) + free ((void *) imap->l_phdr); + + if (imap->l_rpath_dirs.dirs != (void *) -1) + free (imap->l_rpath_dirs.dirs); + if (imap->l_runpath_dirs.dirs != (void *) -1) + free (imap->l_runpath_dirs.dirs); + + free (imap); + } + } + + /* Notify the debugger those objects are finalized and gone. */ + _r_debug.r_state = RT_CONSISTENT; + _dl_debug_state (); + + /* Now we can perhaps also remove the modules for which we had + dependencies because of symbol lookup. */ + while (__builtin_expect (reldeps != NULL, 0)) + { + while (reldeps->nrellist-- > 0) + _dl_close (reldeps->rellist[reldeps->nrellist]); + + free (reldeps->rellist); + + reldeps = reldeps->next; + } + + free (list); + + /* Release the lock. */ +#ifdef HAVE_DD_LOCK + __lock_release(_dl_load_lock); +#endif + + +} + + +static void +free_mem (void) +{ + if (__builtin_expect (_dl_global_scope_alloc, 0) != 0 + && _dl_main_searchlist->r_nlist == _dl_initial_searchlist.r_nlist) + { + /* All object dynamically loaded by the program are unloaded. Free + the memory allocated for the global scope variable. */ + struct link_map **old = _dl_main_searchlist->r_list; + + /* Put the old map in. */ + _dl_main_searchlist->r_list = _dl_initial_searchlist.r_list; + /* Signal that the original map is used. */ + _dl_global_scope_alloc = 0; + + /* Now free the old map. */ + free (old); + } +} +text_set_element (__libc_subfreeres, free_mem); diff --git a/newlib/libc/sys/linux/dl/dl-debug.c b/newlib/libc/sys/linux/dl/dl-debug.c new file mode 100644 index 000000000..5a51b5335 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-debug.c @@ -0,0 +1,57 @@ +/* Communicate dynamic linker state to the debugger at runtime. + Copyright (C) 1996, 1998, 2000 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +/* This structure communicates dl state to the debugger. The debugger + normally finds it via the DT_DEBUG entry in the dynamic section, but in + a statically-linked program there is no dynamic section for the debugger + to examine and it looks for this particular symbol name. */ +struct r_debug _r_debug; + + +/* Initialize _r_debug if it has not already been done. The argument is + the run-time load address of the dynamic linker, to be put in + _r_debug.r_ldbase. Returns the address of _r_debug. */ + +struct r_debug * +internal_function +_dl_debug_initialize (ElfW(Addr) ldbase) +{ + if (_r_debug.r_brk == 0) + { + /* Tell the debugger where to find the map of loaded objects. */ + _r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */; + _r_debug.r_ldbase = ldbase; + _r_debug.r_map = _dl_loaded; + _r_debug.r_brk = (ElfW(Addr)) &_dl_debug_state; + } + + return &_r_debug; +} + + +/* This function exists solely to have a breakpoint set on it by the + debugger. The debugger is supposed to find this function's address by + examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks + for this particular symbol name in the PT_INTERP file. */ +void +_dl_debug_state (void) +{ +} diff --git a/newlib/libc/sys/linux/dl/dl-deps.c b/newlib/libc/sys/linux/dl/dl-deps.c new file mode 100644 index 000000000..4596a85d7 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-deps.c @@ -0,0 +1,561 @@ +/* Load the dependencies of a mapped object. + Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Whether an shared object references one or more auxiliary objects + is signaled by the AUXTAG entry in l_info. */ +#define AUXTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + + DT_EXTRATAGIDX (DT_AUXILIARY)) +/* Whether an shared object references one or more auxiliary objects + is signaled by the AUXTAG entry in l_info. */ +#define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ + + DT_EXTRATAGIDX (DT_FILTER)) + +/* This is zero at program start to signal that the global scope map is + allocated by rtld. Later it keeps the size of the map. It might be + reset if in _dl_close if the last global object is removed. */ +size_t _dl_global_scope_alloc; + +extern size_t _dl_platformlen; + +/* When loading auxiliary objects we must ignore errors. It's ok if + an object is missing. */ +struct openaux_args + { + /* The arguments to openaux. */ + struct link_map *map; + int trace_mode; + const char *strtab; + const char *name; + + /* The return value of openaux. */ + struct link_map *aux; + }; + +static void +openaux (void *a) +{ + struct openaux_args *args = (struct openaux_args *) a; + + args->aux = _dl_map_object (args->map, args->name, 0, + (args->map->l_type == lt_executable + ? lt_library : args->map->l_type), + args->trace_mode, 0); +} + + + +/* We use a very special kind of list to track the path + through the list of loaded shared objects. We have to + produce a flat list with unique members of all involved objects. +*/ +struct list + { + int done; /* Nonzero if this map was processed. */ + struct link_map *map; /* The data. */ + struct list *next; /* Elements for normal list. */ + }; + + +/* Macro to expand DST. It is an macro since we use `alloca'. */ +#define expand_dst(l, str, fatal) \ + ({ \ + const char *__str = (str); \ + const char *__result = __str; \ + size_t __cnt = DL_DST_COUNT(__str, 0); \ + \ + if (__cnt != 0) \ + { \ + char *__newp; \ + \ + __newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str), \ + __cnt)); \ + \ + __result = DL_DST_SUBSTITUTE (l, __str, __newp, 0); \ + \ + if (*__result == '\0') \ + { \ + /* The replacement for the DST is not known. We can't \ + processed. */ \ + if (fatal) \ + _dl_signal_error (0, __str, NULL, N_("\ +empty dynamics string token substitution")); \ + else \ + { \ + /* This is for DT_AUXILIARY. */ \ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) \ + _dl_debug_printf ("cannot load auxiliary `%s' because of" \ + "empty dynamic string token " \ + "substitution\n", __str); \ + continue; \ + } \ + } \ + } \ + \ + __result; }) + + +void +internal_function +_dl_map_object_deps (struct link_map *map, + struct link_map **preloads, unsigned int npreloads, + int trace_mode) +{ + struct list known[1 + npreloads + 1]; + struct list *runp, *tail; + unsigned int nlist, i; + /* Object name. */ + const char *name; + int errno_saved; + int errno_reason; + const char *errstring; + const char *objname; + + auto inline void preload (struct link_map *map); + + inline void preload (struct link_map *map) + { + known[nlist].done = 0; + known[nlist].map = map; + known[nlist].next = &known[nlist + 1]; + + ++nlist; + /* We use `l_reserved' as a mark bit to detect objects we have + already put in the search list and avoid adding duplicate + elements later in the list. */ + map->l_reserved = 1; + } + + /* No loaded object so far. */ + nlist = 0; + + /* First load MAP itself. */ + preload (map); + + /* Add the preloaded items after MAP but before any of its dependencies. */ + for (i = 0; i < npreloads; ++i) + preload (preloads[i]); + + /* Terminate the lists. */ + known[nlist - 1].next = NULL; + + /* Pointer to last unique object. */ + tail = &known[nlist - 1]; + + /* Process each element of the search list, loading each of its + auxiliary objects and immediate dependencies. Auxiliary objects + will be added in the list before the object itself and + dependencies will be appended to the list as we step through it. + This produces a flat, ordered list that represents a + breadth-first search of the dependency tree. + + The whole process is complicated by the fact that we better + should use alloca for the temporary list elements. But using + alloca means we cannot use recursive function calls. */ + errno_saved = errno; + errno_reason = 0; + errstring = NULL; + errno = 0; + name = NULL; + for (runp = known; runp; ) + { + struct link_map *l = runp->map; + struct link_map **needed = NULL; + unsigned int nneeded = 0; + + /* Unless otherwise stated, this object is handled. */ + runp->done = 1; + + /* Allocate a temporary record to contain the references to the + dependencies of this object. */ + if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL + && l != map && l->l_ldnum > 0) + needed = (struct link_map **) alloca (l->l_ldnum + * sizeof (struct link_map *)); + + if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG]) + { + const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); + struct openaux_args args; + struct list *orig; + const ElfW(Dyn) *d; + + args.strtab = strtab; + args.map = l; + args.trace_mode = trace_mode; + orig = runp; + + for (d = l->l_ld; d->d_tag != DT_NULL; ++d) + if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED) + { + /* Map in the needed object. */ + struct link_map *dep; + int err; + + /* Recognize DSTs. */ + name = expand_dst (l, strtab + d->d_un.d_val, 0); + /* Store the tag in the argument structure. */ + args.name = name; + + err = _dl_catch_error (&objname, &errstring, openaux, &args); + if (__builtin_expect (errstring != NULL, 0)) + { + if (err) + errno_reason = err; + else + errno_reason = -1; + goto out; + } + else + dep = args.aux; + + if (! dep->l_reserved) + { + /* Allocate new entry. */ + struct list *newp; + + newp = alloca (sizeof (struct list)); + + /* Append DEP to the list. */ + newp->map = dep; + newp->done = 0; + newp->next = NULL; + tail->next = newp; + tail = newp; + ++nlist; + /* Set the mark bit that says it's already in the list. */ + dep->l_reserved = 1; + } + + /* Remember this dependency. */ + if (needed != NULL) + needed[nneeded++] = dep; + } + else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER) + { + struct list *newp; + + /* Recognize DSTs. */ + name = expand_dst (l, strtab + d->d_un.d_val, + d->d_tag == DT_AUXILIARY); + /* Store the tag in the argument structure. */ + args.name = name; + + if (d->d_tag == DT_AUXILIARY) + { + int err; + + /* Say that we are about to load an auxiliary library. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_debug_printf ("load auxiliary object=%s" + " requested by file=%s\n", name, + l->l_name[0] + ? l->l_name : _dl_argv[0]); + + /* We must be prepared that the addressed shared + object is not available. */ + err = _dl_catch_error (&objname, &errstring, openaux, + &args); + if (__builtin_expect (errstring != NULL, 0)) + { + /* We are not interested in the error message. */ + assert (errstring != NULL); + if (errstring != _dl_out_of_memory) + free ((char *) errstring); + + /* Simply ignore this error and continue the work. */ + continue; + } + } + else + { + int err; + + /* Say that we are about to load an auxiliary library. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_debug_printf ("load filtered object=%s" + " requested by file=%s\n", name, + l->l_name[0] + ? l->l_name : _dl_argv[0]); + + /* For filter objects the dependency must be available. */ + err = _dl_catch_error (&objname, &errstring, openaux, + &args); + if (__builtin_expect (errstring != NULL, 0)) + { + if (err) + errno_reason = err; + else + errno_reason = -1; + goto out; + } + } + + /* The auxiliary object is actually available. + Incorporate the map in all the lists. */ + + /* Allocate new entry. This always has to be done. */ + newp = alloca (sizeof (struct list)); + + /* We want to insert the new map before the current one, + but we have no back links. So we copy the contents of + the current entry over. Note that ORIG and NEWP now + have switched their meanings. */ + memcpy (newp, orig, sizeof (*newp)); + + /* Initialize new entry. */ + orig->done = 0; + orig->map = args.aux; + + /* Remember this dependency. */ + if (needed != NULL) + needed[nneeded++] = args.aux; + + /* We must handle two situations here: the map is new, + so we must add it in all three lists. If the map + is already known, we have two further possibilities: + - if the object is before the current map in the + search list, we do nothing. It is already found + early + - if the object is after the current one, we must + move it just before the current map to make sure + the symbols are found early enough + */ + if (args.aux->l_reserved) + { + /* The object is already somewhere in the list. + Locate it first. */ + struct list *late; + + /* This object is already in the search list we + are building. Don't add a duplicate pointer. + Just added by _dl_map_object. */ + for (late = newp; late->next != NULL; late = late->next) + if (late->next->map == args.aux) + break; + + if (late->next != NULL) + { + /* The object is somewhere behind the current + position in the search path. We have to + move it to this earlier position. */ + orig->next = newp; + + /* Now remove the later entry from the list + and adjust the tail pointer. */ + if (tail == late->next) + tail = late; + late->next = late->next->next; + + /* We must move the object earlier in the chain. */ + if (args.aux->l_prev != NULL) + args.aux->l_prev->l_next = args.aux->l_next; + if (args.aux->l_next != NULL) + args.aux->l_next->l_prev = args.aux->l_prev; + + args.aux->l_prev = newp->map->l_prev; + newp->map->l_prev = args.aux; + if (args.aux->l_prev != NULL) + args.aux->l_prev->l_next = args.aux; + args.aux->l_next = newp->map; + } + else + { + /* The object must be somewhere earlier in the + list. Undo to the current list element what + we did above. */ + memcpy (orig, newp, sizeof (*newp)); + continue; + } + } + else + { + /* This is easy. We just add the symbol right here. */ + orig->next = newp; + ++nlist; + /* Set the mark bit that says it's already in the list. */ + args.aux->l_reserved = 1; + + /* The only problem is that in the double linked + list of all objects we don't have this new + object at the correct place. Correct this here. */ + if (args.aux->l_prev) + args.aux->l_prev->l_next = args.aux->l_next; + if (args.aux->l_next) + args.aux->l_next->l_prev = args.aux->l_prev; + + args.aux->l_prev = newp->map->l_prev; + newp->map->l_prev = args.aux; + if (args.aux->l_prev != NULL) + args.aux->l_prev->l_next = args.aux; + args.aux->l_next = newp->map; + } + + /* Move the tail pointer if necessary. */ + if (orig == tail) + tail = newp; + + /* Move on the insert point. */ + orig = newp; + } + } + + /* Terminate the list of dependencies and store the array address. */ + if (needed != NULL) + { + needed[nneeded++] = NULL; + + l->l_initfini = (struct link_map **) + malloc ((nneeded + 1) * sizeof needed[0]); + if (l->l_initfini == NULL) + _dl_signal_error (ENOMEM, map->l_name, NULL, + N_("cannot allocate dependency list")); + l->l_initfini[0] = l; + memcpy (&l->l_initfini[1], needed, nneeded * sizeof needed[0]); + } + + /* If we have no auxiliary objects just go on to the next map. */ + if (runp->done) + do + runp = runp->next; + while (runp != NULL && runp->done); + } + + out: + if (errno == 0 && errno_saved != 0) + __set_errno (errno_saved); + + if (map->l_initfini != NULL && map->l_type == lt_loaded) + { + /* This object was previously loaded as a dependency and we have + a separate l_initfini list. We don't need it anymore. */ + assert (map->l_searchlist.r_list == NULL); + free (map->l_initfini); + } + + /* Store the search list we built in the object. It will be used for + searches in the scope of this object. */ + map->l_initfini = + (struct link_map **) malloc ((2 * nlist + 1) + * sizeof (struct link_map *)); + if (map->l_initfini == NULL) + _dl_signal_error (ENOMEM, map->l_name, NULL, + N_("cannot allocate symbol search list")); + + + map->l_searchlist.r_list = &map->l_initfini[nlist + 1]; + map->l_searchlist.r_nlist = nlist; + + for (nlist = 0, runp = known; runp; runp = runp->next) + { + if (__builtin_expect (trace_mode, 0) && runp->map->l_faked) + /* This can happen when we trace the loading. */ + --map->l_searchlist.r_nlist; + else + map->l_searchlist.r_list[nlist++] = runp->map; + + /* Now clear all the mark bits we set in the objects on the search list + to avoid duplicates, so the next call starts fresh. */ + runp->map->l_reserved = 0; + } + + /* Maybe we can remove some relocation dependencies now. */ + assert (map->l_searchlist.r_list[0] == map); + for (i = 0; i < map->l_reldepsact; ++i) + { + unsigned int j; + + for (j = 1; j < nlist; ++j) + if (map->l_searchlist.r_list[j] == map->l_reldeps[i]) + { + /* A direct or transitive dependency is also on the list + of relocation dependencies. Remove the latter. */ + --map->l_reldeps[i]->l_opencount; + + for (j = i + 1; j < map->l_reldepsact; ++j) + map->l_reldeps[j - 1] = map->l_reldeps[j]; + + --map->l_reldepsact; + + /* Account for the '++i' performed by the 'for'. */ + --i; + break; + } + } + + /* Now determine the order in which the initialization has to happen. */ + memcpy (map->l_initfini, map->l_searchlist.r_list, + nlist * sizeof (struct link_map *)); + /* We can skip looking for the binary itself which is at the front + of the search list. Look through the list backward so that circular + dependencies are not changing the order. */ + for (i = 1; i < nlist; ++i) + { + struct link_map *l = map->l_searchlist.r_list[i]; + unsigned int j; + unsigned int k; + + /* Find the place in the initfini list where the map is currently + located. */ + for (j = 1; map->l_initfini[j] != l; ++j) + ; + + /* Find all object for which the current one is a dependency and + move the found object (if necessary) in front. */ + for (k = j + 1; k < nlist; ++k) + { + struct link_map **runp; + + runp = map->l_initfini[k]->l_initfini; + if (runp != NULL) + { + while (*runp != NULL) + if (__builtin_expect (*runp++ == l, 0)) + { + struct link_map *here = map->l_initfini[k]; + + /* Move it now. */ + memmove (&map->l_initfini[j] + 1, + &map->l_initfini[j], + (k - j) * sizeof (struct link_map *)); + map->l_initfini[j] = here; + + break; + } + } + } + } + /* Terminate the list of dependencies. */ + map->l_initfini[nlist] = NULL; + + if (errno_reason) + _dl_signal_error (errno_reason == -1 ? 0 : errno_reason, + objname, NULL, errstring); +} diff --git a/newlib/libc/sys/linux/dl/dl-dst.h b/newlib/libc/sys/linux/dl/dl-dst.h new file mode 100644 index 000000000..ccebf9259 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-dst.h @@ -0,0 +1,45 @@ +/* Handling of dynamic sring tokens. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Determine the number of DST elements in the name. Only if IS_PATH is + nonzero paths are recognized (i.e., multiple, ':' separated filenames). */ +#define DL_DST_COUNT(name, is_path) \ + ({ \ + size_t __cnt = 0; \ + const char *__sf = strchr (name, '$'); \ + \ + if (__builtin_expect (__sf != NULL, 0)) \ + __cnt = _dl_dst_count (__sf, is_path); \ + \ + __cnt; }) + +/* Prototype for used function. */ +extern size_t _dl_dst_count (const char *name, int is_path); + + +/* Guess from the number of DSTs the length of the result string. */ +#define DL_DST_REQUIRED(l, name, len, cnt) 1024 + +/* Perform the DST substitution. */ +#define DL_DST_SUBSTITUTE(l, name, res, is_path) \ + _dl_dst_substitute (l, name, res, is_path) + +/* Prototype for used function. */ +extern char *_dl_dst_substitute (struct link_map *l, const char *name, + char *result, int is_path); diff --git a/newlib/libc/sys/linux/dl/dl-error.c b/newlib/libc/sys/linux/dl/dl-error.c new file mode 100644 index 000000000..9c0f55f7f --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-error.c @@ -0,0 +1,189 @@ +/* Error handling for runtime dynamic linker. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include + +/* This structure communicates state between _dl_catch_error and + _dl_signal_error. */ +struct catch + { + const char *objname; /* Object/File name. */ + const char *errstring; /* Error detail filled in here. */ + jmp_buf env; /* longjmp here on error. */ + }; + +/* Multiple threads at once can use the `_dl_catch_error' function. The + calls can come from `_dl_map_object_deps', `_dlerror_run', or from + any of the libc functionality which loads dynamic objects (NSS, iconv). + Therefore we have to be prepared to save the state in thread-local + memory. */ + +__libc_tsd_define (static, DL_ERROR) +#define tsd_getspecific() __libc_tsd_get (DL_ERROR) +#define tsd_setspecific(data) __libc_tsd_set (DL_ERROR, (data)) + + +/* This message we return as a last resort. We define the string in a + variable since we have to avoid freeing it and so have to enable + a pointer comparison. See below and in dlfcn/dlerror.c. */ +const char _dl_out_of_memory[] = "out of memory"; + + +/* This points to a function which is called when an continuable error is + received. Unlike the handling of `catch' this function may return. + The arguments will be the `errstring' and `objname'. + + Since this functionality is not used in normal programs (only in ld.so) + we do not care about multi-threaded programs here. We keep this as a + global variable. */ +static receiver_fct receiver; + + +void +internal_function +_dl_signal_error (int errcode, const char *objname, const char *occation, + const char *errstring) +{ + struct catch *lcatch; + + if (! errstring) + errstring = N_("DYNAMIC LINKER BUG!!!"); + + lcatch = tsd_getspecific (); + if (objname == NULL) + objname = ""; + if (lcatch != NULL) + { + /* We are inside _dl_catch_error. Return to it. We have to + duplicate the error string since it might be allocated on the + stack. The object name is always a string constant. */ + size_t len_objname = strlen (objname) + 1; + size_t len_errstring = strlen (errstring) + 1; + + lcatch->errstring = (char *) malloc (len_objname + len_errstring); + if (lcatch->errstring != NULL) + { + char *tmp; + /* Make a copy of the object file name and the error string. */ + tmp = memcpy ((char *) lcatch->errstring, + errstring, len_errstring); + tmp += len_errstring; + lcatch->objname = memcpy (tmp, + objname, len_objname); + } + else + { + /* This is better than nothing. */ + lcatch->objname = ""; + lcatch->errstring = _dl_out_of_memory; + } + longjmp (lcatch->env, errcode ?: -1); + } + else + { + /* Lossage while resolving the program's own symbols is always fatal. */ + char buffer[1024]; + _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n", + _dl_argv[0] ?: "", + occation ?: N_("error while loading shared libraries"), + objname, *objname ? ": " : "", + errstring, errcode ? ": " : "", + (errcode + ? __strerror_r (errcode, buffer, sizeof buffer) + : "")); + } +} + + +void +internal_function +_dl_signal_cerror (int errcode, const char *objname, const char *occation, + const char *errstring) +{ + if (receiver) + { + /* We are inside _dl_receive_error. Call the user supplied + handler and resume the work. The receiver will still be + installed. */ + (*receiver) (errcode, objname, errstring); + } + else + _dl_signal_error (errcode, objname, occation, errstring); +} + + +int +internal_function +_dl_catch_error (const char **objname, const char **errstring, + void (*operate) (void *), void *args) +{ + int errcode; + struct catch *volatile old; + struct catch c; + /* We need not handle `receiver' since setting a `catch' is handled + before it. */ + + /* Some systems (e.g., SPARC) handle constructors to local variables + inefficient. So we initialize `c' by hand. */ + c.errstring = NULL; + + old = tsd_getspecific (); + errcode = setjmp (c.env); + if (__builtin_expect (errcode, 0) == 0) + { + tsd_setspecific (&c); + (*operate) (args); + tsd_setspecific (old); + *objname = NULL; + *errstring = NULL; + return 0; + } + + /* We get here only if we longjmp'd out of OPERATE. */ + tsd_setspecific (old); + *objname = c.objname; + *errstring = c.errstring; + return errcode == -1 ? 0 : errcode; +} + +void +internal_function +_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) +{ + struct catch *old_catch; + receiver_fct old_receiver; + + old_catch = tsd_getspecific (); + old_receiver = receiver; + + /* Set the new values. */ + tsd_setspecific (NULL); + receiver = fct; + + (*operate) (args); + + tsd_setspecific (old_catch); + receiver = old_receiver; +} diff --git a/newlib/libc/sys/linux/dl/dl-fini.c b/newlib/libc/sys/linux/dl/dl-fini.c new file mode 100644 index 000000000..fc4f4b68a --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-fini.c @@ -0,0 +1,172 @@ +/* Call the termination functions of loaded shared objects. + Copyright (C) 1995,96,98,99,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include + + +/* Type of the constructor functions. */ +typedef void (*fini_t) (void); + + +void +internal_function +_dl_fini (void) +{ + /* Lots of fun ahead. We have to call the destructors for all still + loaded objects. The problem is that the ELF specification now + demands that dependencies between the modules are taken into account. + I.e., the destructor for a module is called before the ones for any + of its dependencies. + + To make things more complicated, we cannot simply use the reverse + order of the constructors. Since the user might have loaded objects + using `dlopen' there are possibly several other modules with its + dependencies to be taken into account. Therefore we have to start + determining the order of the modules once again from the beginning. */ + unsigned int i; + struct link_map *l; + struct link_map **maps; + + /* XXX Could it be (in static binaries) that there is no object loaded? */ + assert (_dl_nloaded > 0); + + /* Now we can allocate an array to hold all the pointers and copy + the pointers in. */ + maps = (struct link_map **) alloca (_dl_nloaded + * sizeof (struct link_map *)); + for (l = _dl_loaded, i = 0; l != NULL; l = l->l_next) + { + assert (i < _dl_nloaded); + + maps[i++] = l; + + /* Bump l_opencount of all objects so that they are not dlclose()ed + from underneath us. */ + ++l->l_opencount; + } + assert (i == _dl_nloaded); + + /* Now we have to do the sorting. */ + for (l = _dl_loaded->l_next; l != NULL; l = l->l_next) + { + unsigned int j; + unsigned int k; + + /* Find the place in the `maps' array. */ + for (j = 1; maps[j] != l; ++j) + ; + + /* Find all object for which the current one is a dependency and + move the found object (if necessary) in front. */ + for (k = j + 1; k < _dl_nloaded; ++k) + { + struct link_map **runp; + + runp = maps[k]->l_initfini; + if (runp != NULL) + { + while (*runp != NULL) + if (*runp == l) + { + struct link_map *here = maps[k]; + + /* Move it now. */ + memmove (&maps[j] + 1, + &maps[j], + (k - j) * sizeof (struct link_map *)); + maps[j++] = here; + + break; + } + else + ++runp; + } + + if (__builtin_expect (maps[k]->l_reldeps != NULL, 0)) + { + unsigned int m = maps[k]->l_reldepsact; + struct link_map **relmaps = maps[k]->l_reldeps; + + while (m-- > 0) + { + if (relmaps[m] == l) + { + struct link_map *here = maps[k]; + + /* Move it now. */ + memmove (&maps[j] + 1, + &maps[j], + (k - j) * sizeof (struct link_map *)); + maps[j] = here; + + break; + } + + } + } + } + } + + /* `maps' now contains the objects in the right order. Now call the + destructors. We have to process this array from the front. */ + for (i = 0; i < _dl_nloaded; ++i) + { + l = maps[i]; + + if (l->l_init_called) + { + /* Make sure nothing happens if we are called twice. */ + l->l_init_called = 0; + + /* Don't call the destructors for objects we are not supposed to. */ + if (l->l_name[0] == '\0' && l->l_type == lt_executable) + continue; + + /* Is there a destructor function? */ + if (l->l_info[DT_FINI_ARRAY] == NULL && l->l_info[DT_FINI] == NULL) + continue; + + /* When debugging print a message first. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0)) + _dl_debug_printf ("\ncalling fini: %s\n\n", + l->l_name[0] ? l->l_name : _dl_argv[0]); + + /* First see whether an array is given. */ + if (l->l_info[DT_FINI_ARRAY] != NULL) + { + ElfW(Addr) *array = + (ElfW(Addr) *) (l->l_addr + + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); + unsigned int sz = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val + / sizeof (ElfW(Addr))); + unsigned int cnt; + + for (cnt = 0; cnt < sz; ++cnt) + ((fini_t) (l->l_addr + array[cnt])) (); + } + + /* Next try the old-style destructor. */ + if (l->l_info[DT_FINI] != NULL) + ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); + } + } +} diff --git a/newlib/libc/sys/linux/dl/dl-init.c b/newlib/libc/sys/linux/dl/dl-init.c new file mode 100644 index 000000000..5448b03c3 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-init.c @@ -0,0 +1,149 @@ +/* Return the next shared object initializer function not yet run. + Copyright (C) 1995,1996,1998,1999,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + + +/* Type of the initializer. */ +typedef void (*init_t) (int, char **, char **); + +/* Flag, nonzero during startup phase. */ +extern int _dl_starting_up; + +/* The object to be initialized first. */ +extern struct link_map *_dl_initfirst; + + +static void +call_init (struct link_map *l, int argc, char **argv, char **env) +{ + if (l->l_init_called) + /* This object is all done. */ + return; + + /* Avoid handling this constructor again in case we have a circular + dependency. */ + l->l_init_called = 1; + + /* Check for object which constructors we do not run here. */ + if (__builtin_expect (l->l_name[0], 'a') == '\0' + && l->l_type == lt_executable) + return; + + /* Are there any constructors? */ + if (l->l_info[DT_INIT] == NULL + && __builtin_expect (l->l_info[DT_INIT_ARRAY] == NULL, 1)) + return; + + /* Print a debug message if wanted. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0)) + _dl_debug_printf ("\ncalling init: %s\n\n", + l->l_name[0] ? l->l_name : _dl_argv[0]); + + /* Now run the local constructors. There are two forms of them: + - the one named by DT_INIT + - the others in the DT_INIT_ARRAY. + */ + if (l->l_info[DT_INIT] != NULL) + { + init_t init = (init_t) DL_DT_INIT_ADDRESS + (l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr); + + /* Call the function. */ + init (argc, argv, env); + } + + /* Next see whether there is an array with initialization functions. */ + if (l->l_info[DT_INIT_ARRAY] != NULL) + { + unsigned int j; + unsigned int jm; + ElfW(Addr) *addrs; + + jm = l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)); + + addrs = (ElfW(Addr) *) (l->l_info[DT_INIT_ARRAY]->d_un.d_ptr + + l->l_addr); + for (j = 0; j < jm; ++j) + ((init_t) addrs[j]) (argc, argv, env); + } +} + + +void +internal_function +_dl_init (struct link_map *main_map, int argc, char **argv, char **env) +{ + ElfW(Dyn) *preinit_array = main_map->l_info[DT_PREINIT_ARRAY]; + struct r_debug *r; + unsigned int i; + + if (__builtin_expect (_dl_initfirst != NULL, 0)) + { + call_init (_dl_initfirst, argc, argv, env); + _dl_initfirst = NULL; + } + + /* Don't do anything if there is no preinit array. */ + if (__builtin_expect (preinit_array != NULL, 0) + && (i = preinit_array->d_un.d_val / sizeof (ElfW(Addr))) > 0) + { + ElfW(Addr) *addrs; + unsigned int cnt; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_IMPCALLS, 0)) + _dl_debug_printf ("\ncalling preinit: %s\n\n", + main_map->l_name[0] + ? main_map->l_name : _dl_argv[0]); + + addrs = (ElfW(Addr) *) (main_map->l_info[DT_PREINIT_ARRAY]->d_un.d_ptr + + main_map->l_addr); + for (cnt = 0; cnt < i; ++cnt) + ((init_t) addrs[cnt]) (argc, argv, env); + } + + /* Notify the debugger we have added some objects. We need to call + _dl_debug_initialize in a static program in case dynamic linking has + not been used before. */ + r = _dl_debug_initialize (0); + r->r_state = RT_ADD; + _dl_debug_state (); + + /* Stupid users forced the ELF specification to be changed. It now + says that the dynamic loader is responsible for determining the + order in which the constructors have to run. The constructors + for all dependencies of an object must run before the constructor + for the object itself. Circular dependencies are left unspecified. + + This is highly questionable since it puts the burden on the dynamic + loader which has to find the dependencies at runtime instead of + letting the user do it right. Stupidity rules! */ + + i = main_map->l_searchlist.r_nlist; + while (i-- > 0) + call_init (main_map->l_initfini[i], argc, argv, env); + + /* Notify the debugger all new objects are now ready to go. */ + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + + /* Finished starting up. */ + _dl_starting_up = 0; +} diff --git a/newlib/libc/sys/linux/dl/dl-iteratephdr.c b/newlib/libc/sys/linux/dl/dl-iteratephdr.c new file mode 100644 index 000000000..a39a4934e --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-iteratephdr.c @@ -0,0 +1,65 @@ +/* Get loaded objects program headers. + Copyright (C) 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2001. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include + +int +__dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info, + size_t size, void *data), void *data) +{ + struct link_map *l; + struct dl_phdr_info info; + int ret = 0; + + /* Make sure we are alone. */ +#ifdef HAVE_DD_LOCK + __lock_acquire(_dl_load_lock); +#endif + + + for (l = _dl_loaded; l != NULL; l = l->l_next) + { + /* Skip the dynamic linker. */ + if (l->l_phdr == NULL) + continue; + info.dlpi_addr = l->l_addr; + info.dlpi_name = l->l_name; + info.dlpi_phdr = l->l_phdr; + info.dlpi_phnum = l->l_phnum; + ret = callback (&info, sizeof (struct dl_phdr_info), data); + if (ret) + break; + } + + /* Release the lock. */ +#ifdef HAVE_DD_LOCK + __lock_release(_dl_load_lock); +#endif + + + return ret; +} + +#ifdef SHARED +weak_alias (__dl_iterate_phdr, dl_iterate_phdr); +#endif diff --git a/newlib/libc/sys/linux/dl/dl-libc.c b/newlib/libc/sys/linux/dl/dl-libc.c new file mode 100644 index 000000000..c83448df7 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-libc.c @@ -0,0 +1,156 @@ +/* Handle loading and unloading shared objects for internal libc purposes. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Zack Weinberg , 1999. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +/* The purpose of this file is to provide wrappers around the dynamic + linker error mechanism (similar to dlopen() et al in libdl) which + are usable from within libc. Generally we want to throw away the + string that dlerror() would return and just pass back a null pointer + for errors. This also lets the rest of libc not know about the error + handling mechanism. + + Much of this code came from gconv_dl.c with slight modifications. */ + +static int +internal_function +dlerror_run (void (*operate) (void *), void *args) +{ + const char *objname; + const char *last_errstring = NULL; + int result; + + (void) _dl_catch_error (&objname, &last_errstring, operate, args); + + result = last_errstring != NULL; + if (result && last_errstring != _dl_out_of_memory) + free ((char *) last_errstring); + + return result; +} + +/* These functions are called by dlerror_run... */ + +struct do_dlopen_args +{ + /* Argument to do_dlopen. */ + const char *name; + + /* Return from do_dlopen. */ + struct link_map *map; +}; + +struct do_dlsym_args +{ + /* Arguments to do_dlsym. */ + struct link_map *map; + const char *name; + + /* Return values of do_dlsym. */ + lookup_t loadbase; + const ElfW(Sym) *ref; +}; + +static void +do_dlopen (void *ptr) +{ + struct do_dlopen_args *args = (struct do_dlopen_args *) ptr; + /* Open and relocate the shared object. */ + args->map = _dl_open (args->name, RTLD_LAZY, NULL); +} + +static void +do_dlsym (void *ptr) +{ + struct do_dlsym_args *args = (struct do_dlsym_args *) ptr; + args->ref = NULL; + args->loadbase = _dl_lookup_symbol (args->name, args->map, &args->ref, + args->map->l_local_scope, 0, 1); +} + +static void +do_dlclose (void *ptr) +{ + _dl_close ((struct link_map *) ptr); +} + +/* ... and these functions call dlerror_run. */ + +void * +__libc_dlopen (const char *__name) +{ + struct do_dlopen_args args; + args.name = __name; + + return (dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map); +} + +void * +__libc_dlsym (void *__map, const char *__name) +{ + struct do_dlsym_args args; + args.map = __map; + args.name = __name; + + return (dlerror_run (do_dlsym, &args) ? NULL + : (void *) (DL_SYMBOL_ADDRESS (args.loadbase, args.ref))); +} + +int +__libc_dlclose (void *__map) +{ + return dlerror_run (do_dlclose, __map); +} + + +static void +free_mem (void) +{ + struct link_map *l; + struct r_search_path_elem *d; + + /* Remove all search directories. */ + d = _dl_all_dirs; + while (d != _dl_init_all_dirs) + { + struct r_search_path_elem *old = d; + d = d->next; + free (old); + } + + /* Remove all additional names added to the objects. */ + for (l = _dl_loaded; l != NULL; l = l->l_next) + { + struct libname_list *lnp = l->l_libname->next; + + l->l_libname->next = NULL; + + while (lnp != NULL) + { + struct libname_list *old = lnp; + lnp = lnp->next; + if (! old->dont_free) + free (old); + } + } +} +text_set_element (__libc_subfreeres, free_mem); diff --git a/newlib/libc/sys/linux/dl/dl-librecon.h b/newlib/libc/sys/linux/dl/dl-librecon.h new file mode 100644 index 000000000..3e39a32e6 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-librecon.h @@ -0,0 +1,87 @@ +/* Optional code to distinguish library flavours. + Copyright (C) 1998, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1998. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _DL_LIBRECON_H +#define _DL_LIBRECON_H 1 + +#define DISTINGUISH_LIB_VERSIONS \ + do \ + { \ + /* We have to find out whether the binary is linked against \ + libc 5 or glibc. We do this by looking at all the DT_NEEDED \ + entries. If one is libc.so.5 this is a libc 5 linked binary. */ \ + if (_dl_loaded->l_info[DT_NEEDED]) \ + { \ + /* We have dependencies. */ \ + const ElfW(Dyn) *d; \ + const char *strtab; \ + \ + strtab = (const char *) D_PTR (_dl_loaded, l_info[DT_STRTAB]); \ + \ + for (d = _dl_loaded->l_ld; d->d_tag != DT_NULL; ++d) \ + if (d->d_tag == DT_NEEDED \ + && strcmp (strtab + d->d_un.d_val, "libc.so.5") == 0) \ + break; \ + \ + /* We print a `5' or `6' depending on the outcome. */ \ + _dl_printf (d->d_tag != DT_NULL ? "5\n" : "6\n"); \ + } \ + } \ + while (0) + +/* Recognizing extra environment variables. */ +#define EXTRA_LD_ENVVARS \ + case 13: \ + if (memcmp (envline, "ASSUME_KERNEL", 13) == 0) \ + { \ + unsigned long int i, j, osversion = 0; \ + char *p = &envline[14], *q; \ + \ + for (i = 0; i < 3; i++, p = q + 1) \ + { \ + j = __strtoul_internal (p, &q, 0, 0); \ + if (j >= 255 || p == q || (i < 2 && *q && *q != '.')) \ + { \ + osversion = 0; \ + break; \ + } \ + osversion |= j << (16 - 8 * i); \ + if (!*q) \ + break; \ + } \ + if (osversion) \ + _dl_osversion = osversion; \ + break; \ + } \ + \ + case 15: \ + if (memcmp (envline, "LIBRARY_VERSION", 15) == 0) \ + { \ + _dl_correct_cache_id = envline[16] == '5' ? 2 : 3; \ + break; \ + } + +/* Extra unsecure variables. The names are all stuffed in a single + string which means they have to be terminated with a '\0' explicitly. */ +#define EXTRA_UNSECURE_ENVVARS \ + "LD_AOUT_LIBRARY_PATH\0" \ + "LD_AOUT_PRELOAD\0" + +#endif /* dl-librecon.h */ diff --git a/newlib/libc/sys/linux/dl/dl-load.c b/newlib/libc/sys/linux/dl/dl-load.c new file mode 100644 index 000000000..65b72c729 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-load.c @@ -0,0 +1,1830 @@ +/* Map in a shared object's segments from the file. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dynamic-link.h" +#include +#include + +#include + +/* 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. */ +#ifndef MAP_COPY +# define MAP_COPY MAP_PRIVATE +#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 + + +#include +#if BYTE_ORDER == BIG_ENDIAN +# define byteorder ELFDATA2MSB +#elif BYTE_ORDER == LITTLE_ENDIAN +# define byteorder ELFDATA2LSB +#else +# error "Unknown BYTE_ORDER " BYTE_ORDER +# define byteorder ELFDATANONE +#endif + +#define STRING(x) __STRING (x) + +#ifdef MAP_ANON +/* The fd is not examined when using MAP_ANON. */ +# define ANONFD -1 +#else +int _dl_zerofd = -1; +# define ANONFD _dl_zerofd +#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 + +/* Type for the buffer we put the ELF header and hopefully the program + header. This buffer does not really have to be too large. In most + cases the program header follows the ELF header directly. If this + is not the case all bets are off and we can make the header arbitrarily + large and still won't get it read. This means the only question is + how large are the ELF and program header combined. The ELF header + in 64-bit files is 56 bytes long. Each program header entry is again + 56 bytes long. I.e., even with a file which has 17 program header + entries we only have to read 1kB. And 17 program header entries is + plenty, normal files have < 10. If this heuristic should really fail + for some file the code in `_dl_map_object_from_fd' knows how to + recover. */ +struct filebuf +{ + ssize_t len; + char buf[1024]; +}; + +size_t _dl_pagesize; + +unsigned int _dl_osversion; + +int _dl_clktck; + +extern const char *_dl_platform; +extern size_t _dl_platformlen; + +/* The object to be initialized first. */ +struct link_map *_dl_initfirst; + +/* This is the decomposed LD_LIBRARY_PATH search path. */ +static struct r_search_path_struct env_path_list; + +/* List of the hardware capabilities we might end up using. */ +static const struct r_strlenpair *capstr; +static size_t ncapstr; +static size_t max_capstrlen; + + +/* Get the generated information about the trusted directories. */ +#include "trusted-dirs.h" + +static const char system_dirs[] = SYSTEM_DIRS; +static const size_t system_dirs_len[] = +{ + SYSTEM_DIRS_LEN +}; +#define nsystem_dirs_len \ + (sizeof (system_dirs_len) / sizeof (system_dirs_len[0])) + + +/* Local version of `strdup' function. */ +static inline char * +local_strdup (const char *s) +{ + size_t len = strlen (s) + 1; + void *new = malloc (len); + + if (new == NULL) + return NULL; + + return (char *) memcpy (new, s, len); +} + + +static size_t +is_dst (const char *start, const char *name, const char *str, size_t cmplen, + int is_path, int secure) +{ + size_t len; + + if (strncmp (name, str, cmplen) == 0) + len = cmplen + 1; + else if (strncmp (name, str + 1, cmplen - 2) == 0 + && (name[cmplen - 2] == '\0' || name[cmplen - 2] == '/' + || (is_path && name[cmplen - 2] == ':'))) + len = cmplen - 1; + else + return 0; + + if (__builtin_expect (secure, 0) + && ((name[len - 1] != '\0' && (!is_path || name[len - 1] != ':')) + || (name != start + 1 && (!is_path || name[-2] != ':')))) + return 0; + + return len; +} + + +size_t +_dl_dst_count (const char *name, int is_path) +{ + const char *const start = name; + size_t cnt = 0; + + do + { + size_t len = 1; + + /* $ORIGIN is not expanded for SUID/GUID programs (except if it + is $ORIGIN alone) and it must always appear first in path. + + Note that it is no bug that the string in the second and + fourth `strncmp' call is longer than the sequence which is + actually tested. */ + if ((len = is_dst (start, name + 1, "{ORIGIN}", 8, is_path, + 0)) != 0 + || ((len = is_dst (start, name + 1, "{PLATFORM}", 10, is_path, 0)) + != 0)) + ++cnt; + + name = strchr (name + len, '$'); + } + while (name != NULL); + + return cnt; +} + + +char * +_dl_dst_substitute (struct link_map *l, const char *name, char *result, + int is_path) +{ + const char *const start = name; + char *last_elem, *wp; + + /* Now fill the result path. While copying over the string we keep + track of the start of the last path element. When we come accross + a DST we copy over the value or (if the value is not available) + leave the entire path element out. */ + last_elem = wp = result; + + do + { + if (__builtin_expect (*name == '$', 0)) + { + const char *repl = NULL; + size_t len = 1; + + /* Note that it is no bug that the string in the second and + fourth `strncmp' call is longer than the sequence which + is actually tested. */ + if ((len = is_dst (start, name + 1, "{ORIGIN}", 8, is_path, + 0)) != 0) + repl = l->l_origin; + else if ((len = is_dst (start, name + 1, "{PLATFORM}", 10, is_path, + 0)) != 0) + repl = _dl_platform; + + if (repl != NULL && repl != (const char *) -1) + { + wp = strcpy (wp, repl); + wp += strlen (repl); + name += len; + } + else if (len > 1) + { + /* We cannot use this path element, the value of the + replacement is unknown. */ + wp = last_elem; + name += len; + while (*name != '\0' && (!is_path || *name != ':')) + ++name; + } + else + /* No DST we recognize. */ + *wp++ = *name++; + } + else + { + *wp++ = *name++; + if (is_path && *name == ':') + last_elem = wp; + } + } + while (*name != '\0'); + + *wp = '\0'; + + return result; +} + + +/* Return copy of argument with all recognized dynamic string tokens + ($ORIGIN and $PLATFORM for now) replaced. On some platforms it + might not be possible to determine the path from which the object + belonging to the map is loaded. In this case the path element + containing $ORIGIN is left out. */ +static char * +expand_dynamic_string_token (struct link_map *l, const char *s) +{ + /* We make two runs over the string. First we determine how large the + resulting string is and then we copy it over. Since this is now + frequently executed operation we are looking here not for performance + but rather for code size. */ + size_t cnt; + size_t total; + char *result; + + /* Determine the number of DST elements. */ + cnt = DL_DST_COUNT (s, 1); + + /* If we do not have to replace anything simply copy the string. */ + if (__builtin_expect (cnt, 0) == 0) + return local_strdup (s); + + /* Determine the length of the substituted string. */ + total = DL_DST_REQUIRED (l, s, strlen (s), cnt); + + /* Allocate the necessary memory. */ + result = (char *) malloc (total + 1); + if (result == NULL) + return NULL; + + return DL_DST_SUBSTITUTE (l, s, result, 1); +} + + +/* Add `name' to the list of names for a particular shared object. + `name' is expected to have been allocated with malloc and will + be freed if the shared object already has this name. + Returns false if the object already had this name. */ +static void +internal_function +add_name_to_object (struct link_map *l, const char *name) +{ + struct libname_list *lnp, *lastp; + struct libname_list *newname; + size_t name_len; + + lastp = NULL; + for (lnp = l->l_libname; lnp != NULL; lastp = lnp, lnp = lnp->next) + if (strcmp (name, lnp->name) == 0) + return; + + name_len = strlen (name) + 1; + newname = (struct libname_list *) malloc (sizeof *newname + name_len); + if (newname == NULL) + { + /* No more memory. */ + _dl_signal_error (ENOMEM, name, NULL, N_("cannot allocate name record")); + return; + } + /* The object should have a libname set from _dl_new_object. */ + assert (lastp != NULL); + + newname->name = memcpy (newname + 1, name, name_len); + newname->next = NULL; + newname->dont_free = 0; + lastp->next = newname; +} + +/* All known directories in sorted order. */ +struct r_search_path_elem *_dl_all_dirs; + +/* All directories after startup. */ +struct r_search_path_elem *_dl_init_all_dirs; + +/* Standard search directories. */ +static struct r_search_path_struct rtld_search_dirs; + +static size_t max_dirnamelen; + +static inline struct r_search_path_elem ** +fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, + int check_trusted, const char *what, const char *where) +{ + char *cp; + size_t nelems = 0; + + printf("In fillin_rpath\n"); + while ((cp = strsep (&rpath, sep)) != NULL) + { + struct r_search_path_elem *dirp; + size_t len = strlen (cp); + + /* `strsep' can pass an empty string. This has to be + interpreted as `use the current directory'. */ + if (len == 0) + { + static const char curwd[] = "./"; + cp = (char *) curwd; + } + + /* Remove trailing slashes (except for "/"). */ + while (len > 1 && cp[len - 1] == '/') + --len; + + /* Now add one if there is none so far. */ + if (len > 0 && cp[len - 1] != '/') + cp[len++] = '/'; + + /* Make sure we don't use untrusted directories if we run SUID. */ + if (__builtin_expect (check_trusted, 0)) + { + const char *trun = system_dirs; + size_t idx; + int unsecure = 1; + + /* All trusted directories must be complete names. */ + if (cp[0] == '/') + { + for (idx = 0; idx < nsystem_dirs_len; ++idx) + { + if (len == system_dirs_len[idx] + && memcmp (trun, cp, len) == 0) + { + /* Found it. */ + unsecure = 0; + break; + } + + trun += system_dirs_len[idx] + 1; + } + } + + if (unsecure) + /* Simply drop this directory. */ + continue; + } + + /* See if this directory is already known. */ + for (dirp = _dl_all_dirs; dirp != NULL; dirp = dirp->next) + if (dirp->dirnamelen == len && memcmp (cp, dirp->dirname, len) == 0) + break; + + if (dirp != NULL) + { + /* It is available, see whether it's on our own list. */ + size_t cnt; + for (cnt = 0; cnt < nelems; ++cnt) + if (result[cnt] == dirp) + break; + + if (cnt == nelems) + result[nelems++] = dirp; + } + else + { + size_t cnt; + enum r_dir_status init_val; + size_t where_len = where ? strlen (where) + 1 : 0; + + /* It's a new directory. Create an entry and add it. */ + dirp = (struct r_search_path_elem *) + malloc (sizeof (*dirp) + ncapstr * sizeof (enum r_dir_status) + + where_len + len + 1); + if (dirp == NULL) + _dl_signal_error (ENOMEM, NULL, NULL, + N_("cannot create cache for search path")); + + dirp->dirname = ((char *) dirp + sizeof (*dirp) + + ncapstr * sizeof (enum r_dir_status)); + *((char *) (memcpy ((char *) dirp->dirname, cp, len) + len)) = '\0'; + dirp->dirnamelen = len; + + if (len > max_dirnamelen) + max_dirnamelen = len; + + /* We have to make sure all the relative directories are + never ignored. The current directory might change and + all our saved information would be void. */ + init_val = cp[0] != '/' ? existing : unknown; + for (cnt = 0; cnt < ncapstr; ++cnt) + dirp->status[cnt] = init_val; + + dirp->what = what; + if (__builtin_expect (where != NULL, 1)) + dirp->where = memcpy ((char *) dirp + sizeof (*dirp) + len + 1 + + ncapstr * sizeof (enum r_dir_status), + where, where_len); + else + dirp->where = NULL; + + dirp->next = _dl_all_dirs; + _dl_all_dirs = dirp; + + /* Put it in the result array. */ + result[nelems++] = dirp; + } + } + + /* Terminate the array. */ + result[nelems] = NULL; + + return result; +} + + +static void +internal_function +decompose_rpath (struct r_search_path_struct *sps, + const char *rpath, struct link_map *l, const char *what) +{ + /* Make a copy we can work with. */ + const char *where = l->l_name; + char *copy; + char *cp; + struct r_search_path_elem **result; + size_t nelems; + /* Initialize to please the compiler. */ + const char *errstring = NULL; + + /* First see whether we must forget the RUNPATH and RPATH from this + object. */ + if (__builtin_expect (_dl_inhibit_rpath != NULL, 0)) + { + const char *found = strstr (_dl_inhibit_rpath, where); + if (found != NULL) + { + size_t len = strlen (where); + if ((found == _dl_inhibit_rpath || found[-1] == ':') + && (found[len] == '\0' || found[len] == ':')) + { + /* This object is on the list of objects for which the + RUNPATH and RPATH must not be used. */ + result = (struct r_search_path_elem **) + malloc (sizeof (*result)); + if (result == NULL) + { + signal_error_cache: + errstring = N_("cannot create cache for search path"); + signal_error: + _dl_signal_error (ENOMEM, NULL, NULL, errstring); + } + + result[0] = NULL; + + sps->dirs = result; + sps->malloced = 1; + + return; + } + } + } + + /* Make a writable copy. At the same time expand possible dynamic + string tokens. */ + copy = expand_dynamic_string_token (l, rpath); + if (copy == NULL) + { + errstring = N_("cannot create RUNPATH/RPATH copy"); + goto signal_error; + } + + /* Count the number of necessary elements in the result array. */ + nelems = 0; + for (cp = copy; *cp != '\0'; ++cp) + if (*cp == ':') + ++nelems; + + /* Allocate room for the result. NELEMS + 1 is an upper limit for the + number of necessary entries. */ + result = (struct r_search_path_elem **) malloc ((nelems + 1 + 1) + * sizeof (*result)); + if (result == NULL) + goto signal_error_cache; + + fillin_rpath (copy, result, ":", 0, what, where); + + /* Free the copied RPATH string. `fillin_rpath' make own copies if + necessary. */ + free (copy); + + sps->dirs = result; + /* The caller will change this value if we haven't used a real malloc. */ + sps->malloced = 1; +} + + +void +internal_function +_dl_init_paths (const char *llp) +{ + size_t idx; + const char *strp; + struct r_search_path_elem *pelem, **aelem; + size_t round_size; +#ifdef SHARED + struct link_map *l; +#endif + /* Initialize to please the compiler. */ + const char *errstring = NULL; + + /* Fill in the information about the application's RPATH and the + directories addressed by the LD_LIBRARY_PATH environment variable. */ + + /* Get the capabilities. */ + capstr = _dl_important_hwcaps (_dl_platform, _dl_platformlen, + &ncapstr, &max_capstrlen); + + /* First set up the rest of the default search directory entries. */ + aelem = rtld_search_dirs.dirs = (struct r_search_path_elem **) + malloc ((nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *)); + if (rtld_search_dirs.dirs == NULL) + { + errstring = N_("cannot create search path array"); + signal_error: + _dl_signal_error (ENOMEM, NULL, NULL, errstring); + } + + round_size = ((2 * sizeof (struct r_search_path_elem) - 1 + + ncapstr * sizeof (enum r_dir_status)) + / sizeof (struct r_search_path_elem)); + + rtld_search_dirs.dirs[0] = (struct r_search_path_elem *) + malloc ((sizeof (system_dirs) / sizeof (system_dirs[0])) + * round_size * sizeof (struct r_search_path_elem)); + if (rtld_search_dirs.dirs[0] == NULL) + { + errstring = N_("cannot create cache for search path"); + goto signal_error; + } + + rtld_search_dirs.malloced = 0; + pelem = _dl_all_dirs = rtld_search_dirs.dirs[0]; + strp = system_dirs; + idx = 0; + + do + { + size_t cnt; + + *aelem++ = pelem; + + pelem->what = "system search path"; + pelem->where = NULL; + + pelem->dirname = strp; + pelem->dirnamelen = system_dirs_len[idx]; + strp += system_dirs_len[idx] + 1; + + /* System paths must be absolute. */ + assert (pelem->dirname[0] == '/'); + for (cnt = 0; cnt < ncapstr; ++cnt) + pelem->status[cnt] = unknown; + + pelem->next = (++idx == nsystem_dirs_len ? NULL : (pelem + round_size)); + + pelem += round_size; + } + while (idx < nsystem_dirs_len); + + max_dirnamelen = SYSTEM_DIRS_MAX_LEN; + *aelem = NULL; + +#ifdef SHARED + /* This points to the map of the main object. */ + l = _dl_loaded; + if (l != NULL) + { + assert (l->l_type != lt_loaded); + + if (l->l_info[DT_RUNPATH]) + { + /* Allocate room for the search path and fill in information + from RUNPATH. */ + decompose_rpath (&l->l_runpath_dirs, + (const void *) (D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_RUNPATH]->d_un.d_val), + l, "RUNPATH"); + + /* The RPATH is ignored. */ + l->l_rpath_dirs.dirs = (void *) -1; + } + else + { + l->l_runpath_dirs.dirs = (void *) -1; + + if (l->l_info[DT_RPATH]) + { + /* Allocate room for the search path and fill in information + from RPATH. */ + decompose_rpath (&l->l_rpath_dirs, + (const void *) (D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_RPATH]->d_un.d_val), + l, "RPATH"); + l->l_rpath_dirs.malloced = 0; + } + else + l->l_rpath_dirs.dirs = (void *) -1; + } + } +#endif /* SHARED */ + + if (llp != NULL && *llp != '\0') + { + size_t nllp; + const char *cp = llp; + const char *old = llp; + size_t len = strlen (old) + 1; + char *new = alloca(len); + char *llp_tmp; + + llp_tmp = memcpy (new, old, len); + + /* Decompose the LD_LIBRARY_PATH contents. First determine how many + elements it has. */ + nllp = 1; + while (*cp) + { + if (*cp == ':' || *cp == ';') + ++nllp; + ++cp; + } + + env_path_list.dirs = (struct r_search_path_elem **) + malloc ((nllp + 1) * sizeof (struct r_search_path_elem *)); + if (env_path_list.dirs == NULL) + { + errstring = N_("cannot create cache for search path"); + goto signal_error; + } + + (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;", + 0, "LD_LIBRARY_PATH", NULL); + + if (env_path_list.dirs[0] == NULL) + { + free (env_path_list.dirs); + env_path_list.dirs = (void *) -1; + } + + env_path_list.malloced = 0; + } + else + env_path_list.dirs = (void *) -1; + + /* Remember the last search directory added at startup. */ + _dl_init_all_dirs = _dl_all_dirs; +} + + +/* Think twice before changing anything in this function. It is placed + here and prepared using the `alloca' magic to prevent it from being + inlined. The function is only called in case of an error. But then + performance does not count. The function used to be "inlinable" and + the compiled did so all the time. This increased the code size for + absolutely no good reason. */ +static void +__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 = (int *) alloca (sizeof (int)); + a[0] = fd; + /* The file might already be closed. */ + if (a[0] != -1) + (void) close (a[0]); + if (l != NULL) + { + /* Remove the stillborn object from the list and free it. */ + assert (l->l_next == NULL); +#ifndef SHARED + if (l->l_prev == NULL) + /* No other module loaded. */ + _dl_loaded = NULL; + else +#endif + l->l_prev->l_next = NULL; + --_dl_nloaded; + free (l); + } + free (realname); + _dl_signal_error (code, name, NULL, msg); +} + + +/* Map in the shared object NAME, actually located in REALNAME, and already + opened on FD. */ + +#ifndef EXTERNAL_MAP_FROM_FD +static +#endif +struct link_map * +_dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp, + char *realname, struct link_map *loader, int l_type, + int mode) +{ + struct link_map *l = NULL; + const ElfW(Ehdr) *header; + const ElfW(Phdr) *phdr; + const ElfW(Phdr) *ph; + size_t maplength; + int type; + struct stat64 st; + /* Initialize to keep the compiler happy. */ + const char *errstring = NULL; + int errval = 0; + + /* Get file information. */ + if (__builtin_expect (fstat64 (fd, &st) < 0, 0)) + { + errstring = N_("cannot stat shared object"); + call_lose_errno: + errval = errno; + call_lose: + fprintf (stderr, "%s\n", errstring); + lose (errval, fd, name, realname, l, errstring); + } + + /* Look again to see if the real name matched another already loaded. */ + for (l = _dl_loaded; l; l = l->l_next) + if (l->l_ino == st.st_ino && l->l_dev == st.st_dev) + { + /* The object is already loaded. + Just bump its reference count and return it. */ + close (fd); + + /* If the name is not in the list of names for this object add + it. */ + free (realname); + add_name_to_object (l, name); + + return l; + } + + if (mode & RTLD_NOLOAD) + /* We are not supposed to load the object unless it is already + loaded. So return now. */ + return NULL; + + /* Print debugging message. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) + _dl_debug_printf ("file=%s; generating link map\n", name); + + /* This is the ELF header. We read it in `open_verify'. */ + header = (void *) fbp->buf; + +#ifndef MAP_ANON +# define MAP_ANON 0 + if (_dl_zerofd == -1) + { + _dl_zerofd = _dl_sysdep_open_zero_fill (); + if (_dl_zerofd == -1) + { + close (fd); + _dl_signal_error (errno, NULL, NULL, + N_("cannot open zero fill device")); + } + } +#endif + + /* Enter the new object in the list of loaded objects. */ + l = _dl_new_object (realname, name, l_type, loader); + if (__builtin_expect (! l, 0)) + { + errstring = N_("cannot create shared object descriptor"); + goto call_lose_errno; + } + + /* Extract the remaining details we need from the ELF header + and then read in the program header table. */ + l->l_entry = header->e_entry; + type = header->e_type; + l->l_phnum = header->e_phnum; + + maplength = header->e_phnum * sizeof (ElfW(Phdr)); + if (header->e_phoff + maplength <= fbp->len) + phdr = (void *) (fbp->buf + header->e_phoff); + else + { + phdr = alloca (maplength); + lseek (fd, SEEK_SET, header->e_phoff); + if (__libc_read (fd, (void *) phdr, maplength) != maplength) + { + errstring = N_("cannot read file data"); + goto call_lose_errno; + } + } + + { + /* Scan the program header table, collecting its load commands. */ + struct loadcmd + { + ElfW(Addr) mapstart, mapend, dataend, allocend; + off_t mapoff; + int prot; + } loadcmds[l->l_phnum], *c; + size_t nloadcmds = 0; + + /* The struct is initialized to zero so this is not necessary: + 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) + { + /* These entries tell us where to find things once the file's + segments are mapped in. We record the addresses it says + verbatim, and later correct for the run-time load address. */ + case PT_DYNAMIC: + l->l_ld = (void *) ph->p_vaddr; + l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); + break; + + case PT_PHDR: + l->l_phdr = (void *) ph->p_vaddr; + break; + + case PT_LOAD: + /* 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 & (_dl_pagesize - 1)) != 0) + { + errstring = N_("ELF load command alignment not page-aligned"); + goto call_lose; + } + if (((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1)) != 0) + { + errstring + = N_("ELF load command address/offset not properly aligned"); + goto call_lose; + } + + { + struct loadcmd *c = &loadcmds[nloadcmds++]; + c->mapstart = ph->p_vaddr & ~(ph->p_align - 1); + c->mapend = ((ph->p_vaddr + ph->p_filesz + _dl_pagesize - 1) + & ~(_dl_pagesize - 1)); + 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); + + /* Optimize a common case. */ +#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7 + c->prot = (PF_TO_PROT + >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf; +#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; +#endif + } + break; + } + + /* Now process the load commands and map segments into memory. */ + c = loadcmds; + + /* Length of the sections to be loaded. */ + maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart; + + if (__builtin_expect (type, ET_DYN) == ET_DYN) + { + /* 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 remove + access from excess portion, and there is known sufficient space + there to remap from the later segments. + + As a refinement, sometimes we have an address that we would + prefer to map such objects at; but this is only a preference, + the OS can do whatever it likes. */ + ElfW(Addr) mappref; + mappref = (ELF_PREFERRED_ADDRESS (loader, maplength, c->mapstart) + - MAP_BASE_ADDR (l)); + + /* Remember which part of the address space this object uses. */ + l->l_map_start = (ElfW(Addr)) mmap ((void *) mappref, maplength, + c->prot, MAP_COPY | MAP_FILE, + fd, c->mapoff); + if ((void *) l->l_map_start == MAP_FAILED) + { + map_error: + errstring = N_("failed to map segment from shared object"); + goto call_lose_errno; + } + + l->l_map_end = l->l_map_start + maplength; + l->l_addr = l->l_map_start - c->mapstart; + + /* Change protection on the excess portion to disallow all access; + the portions we do not remap later will be inaccessible as if + unallocated. Then jump into the normal segment-mapping loop to + handle the portion of the segment past the end of the file + mapping. */ + mprotect ((caddr_t) (l->l_addr + c->mapend), + loadcmds[nloadcmds - 1].allocend - c->mapend, + PROT_NONE); + + goto postmap; + } + else + { + /* This object is loaded at a fixed address. This must never + happen for objects loaded with dlopen(). */ + if (__builtin_expect (mode & __RTLD_DLOPEN, 0)) + { + errstring = N_("cannot dynamically load executable"); + goto call_lose; + } + + /* Notify ELF_PREFERRED_ADDRESS that we have to load this one + fixed. */ + ELF_FIXED_ADDRESS (loader, c->mapstart); + } + + /* Remember which part of the address space this object uses. */ + l->l_map_start = c->mapstart + l->l_addr; + l->l_map_end = l->l_map_start + maplength; + + while (c < &loadcmds[nloadcmds]) + { + if (c->mapend > c->mapstart + /* Map the segment contents from the file. */ + && (mmap ((void *) (l->l_addr + c->mapstart), + c->mapend - c->mapstart, c->prot, + MAP_FIXED | MAP_COPY | MAP_FILE, fd, c->mapoff) + == MAP_FAILED)) + goto map_error; + + postmap: + if (l->l_phdr == 0 + && c->mapoff <= header->e_phoff + && (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 *) (c->mapstart + header->e_phoff - c->mapoff); + + if (c->allocend > c->dataend) + { + /* Extra zero pages should appear at the end of this segment, + after the data mapped from the file. */ + ElfW(Addr) zero, zeroend, zeropage; + + zero = l->l_addr + c->dataend; + zeroend = l->l_addr + c->allocend; + zeropage = (zero + _dl_pagesize - 1) & ~(_dl_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 ((c->prot & PROT_WRITE) == 0) + { + /* Dag nab it. */ + if (mprotect ((caddr_t) (zero & ~(_dl_pagesize - 1)), + _dl_pagesize, c->prot|PROT_WRITE) < 0) + { + errstring = N_("cannot change memory protections"); + goto call_lose_errno; + } + } + memset ((void *) zero, '\0', zeropage - zero); + if ((c->prot & PROT_WRITE) == 0) + mprotect ((caddr_t) (zero & ~(_dl_pagesize - 1)), + _dl_pagesize, c->prot); + } + + if (zeroend > zeropage) + { + /* Map the remaining zero pages in from the zero fill FD. */ + caddr_t mapat; + mapat = mmap ((caddr_t) zeropage, zeroend - zeropage, + c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED, + ANONFD, 0); + if (mapat == MAP_FAILED) + { + errstring = N_("cannot map zero-fill pages"); + goto call_lose_errno; + } + } + } + + ++c; + } + + if (l->l_phdr == NULL) + { + /* The program header is not contained in any of the segments. + We have to allocate memory ourself and copy it over from + out temporary place. */ + ElfW(Phdr) *newp = (ElfW(Phdr) *) malloc (header->e_phnum + * sizeof (ElfW(Phdr))); + if (newp == NULL) + { + errstring = N_("cannot allocate memory for program header"); + goto call_lose_errno; + } + + l->l_phdr = memcpy (newp, phdr, + (header->e_phnum * sizeof (ElfW(Phdr)))); + l->l_phdr_allocated = 1; + } + else + /* Adjust the PT_PHDR value by the runtime load address. */ + (ElfW(Addr)) l->l_phdr += l->l_addr; + } + + /* We are done mapping in the file. We no longer need the descriptor. */ + close (fd); + /* Signal that we closed the file. */ + fd = -1; + + if (l->l_type == lt_library && type == ET_EXEC) + l->l_type = lt_executable; + + if (l->l_ld == 0) + { + if (type == ET_DYN) + { + errstring = N_("object file has no dynamic section"); + goto call_lose; + } + } + else + (ElfW(Addr)) l->l_ld += l->l_addr; + + l->l_entry += l->l_addr; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) + _dl_debug_printf (" dynamic: 0x%0*lx base: 0x%0*lx size: 0x%0*Zx\n" + " entry: 0x%0*lx phdr: 0x%0*lx phnum: %*u\n\n", + (int) sizeof (void *) * 2, (unsigned long int) l->l_ld, + (int) sizeof (void *) * 2, (unsigned long int) l->l_addr, + (int) sizeof (void *) * 2, maplength, + (int) sizeof (void *) * 2, (unsigned long int) l->l_entry, + (int) sizeof (void *) * 2, (unsigned long int) l->l_phdr, + (int) sizeof (void *) * 2, l->l_phnum); + + elf_get_dynamic_info (l); + + /* Make sure we are dlopen()ing an object which has the DF_1_NOOPEN + flag set. */ + if (__builtin_expect (l->l_flags_1 & DF_1_NOOPEN, 0) + && (mode & __RTLD_DLOPEN)) + { + /* We are not supposed to load this object. Free all resources. */ + munmap ((void *) l->l_map_start, l->l_map_end - l->l_map_start); + + if (!l->l_libname->dont_free) + free (l->l_libname); + + if (l->l_phdr_allocated) + free ((void *) l->l_phdr); + + errstring = N_("shared object cannot be dlopen()ed"); + goto call_lose; + } + + if (l->l_info[DT_HASH]) + _dl_setup_hash (l); + + /* If this object has DT_SYMBOLIC set modify now its scope. We don't + have to do this for the main map. */ + if (__builtin_expect (l->l_info[DT_SYMBOLIC] != NULL, 0) + && &l->l_searchlist != l->l_scope[0]) + { + /* Create an appropriate searchlist. It contains only this map. + + XXX This is the definition of DT_SYMBOLIC in SysVr4. The old + GNU ld.so implementation had a different interpretation which + is more reasonable. We are prepared to add this possibility + back as part of a GNU extension of the ELF format. */ + l->l_symbolic_searchlist.r_list = + (struct link_map **) malloc (sizeof (struct link_map *)); + + if (l->l_symbolic_searchlist.r_list == NULL) + { + errstring = N_("cannot create searchlist"); + goto call_lose_errno; + } + + l->l_symbolic_searchlist.r_list[0] = l; + l->l_symbolic_searchlist.r_nlist = 1; + + /* Now move the existing entries one back. */ + memmove (&l->l_scope[1], &l->l_scope[0], + (l->l_scope_max - 1) * sizeof (l->l_scope[0])); + + /* Now add the new entry. */ + l->l_scope[0] = &l->l_symbolic_searchlist; + } + + /* Remember whether this object must be initialized first. */ + if (l->l_flags_1 & DF_1_INITFIRST) + _dl_initfirst = l; + + /* Finally the file information. */ + l->l_dev = st.st_dev; + l->l_ino = st.st_ino; + + return l; +} + +/* Print search path. */ +static void +print_search_path (struct r_search_path_elem **list, + const char *what, const char *name) +{ + char buf[max_dirnamelen + max_capstrlen]; + int first = 1; + + _dl_debug_printf (" search path="); + + while (*list != NULL && (*list)->what == what) /* Yes, ==. */ + { + char *endp = memcpy (buf, (*list)->dirname, (*list)->dirnamelen); + size_t cnt; + endp += (*list)->dirnamelen; + + + for (cnt = 0; cnt < ncapstr; ++cnt) + if ((*list)->status[cnt] != nonexisting) + { + char *cp = memcpy (endp, capstr[cnt].str, capstr[cnt].len); + cp += capstr[cnt].len; + + if (cp == buf || (cp == buf + 1 && buf[0] == '/')) + cp[0] = '\0'; + else + cp[-1] = '\0'; + + _dl_debug_printf_c (first ? "%s" : ":%s", buf); + first = 0; + } + + ++list; + } + + if (name != NULL) + _dl_debug_printf_c ("\t\t(%s from file %s)\n", what, + name[0] ? name : _dl_argv[0]); + else + _dl_debug_printf_c ("\t\t(%s)\n", what); +} + +/* Open a file and verify it is an ELF file for this architecture. We + ignore only ELF files for other architectures. Non-ELF files and + ELF files with different header information cause fatal errors since + this could mean there is something wrong in the installation and the + user might want to know about this. */ +static int +open_verify (const char *name, struct filebuf *fbp) +{ + /* This is the expected ELF header. */ +#define ELF32_CLASS ELFCLASS32 +#define ELF64_CLASS ELFCLASS64 +#ifndef VALID_ELF_HEADER +# define VALID_ELF_HEADER(hdr,exp,size) (memcmp (hdr, exp, size) == 0) +# define VALID_ELF_OSABI(osabi) (osabi == ELFOSABI_SYSV) +# define VALID_ELF_ABIVERSION(ver) (ver == 0) +#endif + 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 + }; + static const struct + { + ElfW(Word) vendorlen; + ElfW(Word) datalen; + ElfW(Word) type; + char vendor[4]; + } expected_note = { 4, 16, 1, "GNU" }; + int fd; + /* Initialize it to make the compiler happy. */ + const char *errstring = NULL; + int errval = 0; + + /* Open the file. We always open files read-only. */ + fd = open (name, O_RDONLY); + if (fd != -1) + { + ElfW(Ehdr) *ehdr; + ElfW(Phdr) *phdr, *ph; + ElfW(Word) *abi_note, abi_note_buf[8]; + unsigned int osversion; + size_t maplength; + + /* We successfully openened the file. Now verify it is a file + we can use. */ + __set_errno (0); + fbp->len = __libc_read (fd, fbp->buf, sizeof (fbp->buf)); + + /* This is where the ELF header is loaded. */ + assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr))); + ehdr = (ElfW(Ehdr) *) fbp->buf; + + /* Now run the tests. */ + if (__builtin_expect (fbp->len < (ssize_t) sizeof (ElfW(Ehdr)), 0)) + { + errval = errno; + errstring = (errval == 0 + ? N_("file too short") : N_("cannot read file data")); + call_lose: + lose (errval, fd, name, NULL, NULL, errstring); + } + + /* See whether the ELF header is what we expect. */ + if (__builtin_expect (! VALID_ELF_HEADER (ehdr->e_ident, expected, + EI_PAD), 0)) + { + /* Something is wrong. */ + if (*(Elf32_Word *) &ehdr->e_ident != +#if BYTE_ORDER == LITTLE_ENDIAN + ((ELFMAG0 << (EI_MAG0 * 8)) | + (ELFMAG1 << (EI_MAG1 * 8)) | + (ELFMAG2 << (EI_MAG2 * 8)) | + (ELFMAG3 << (EI_MAG3 * 8))) +#else + ((ELFMAG0 << (EI_MAG3 * 8)) | + (ELFMAG1 << (EI_MAG2 * 8)) | + (ELFMAG2 << (EI_MAG1 * 8)) | + (ELFMAG3 << (EI_MAG0 * 8))) +#endif + ) + errstring = N_("invalid ELF header"); + else if (ehdr->e_ident[EI_CLASS] != ELFW(CLASS)) + /* This is not a fatal error. On architectures where + 32-bit and 64-bit binaries can be run this might + happen. */ + goto close_and_out; + else if (ehdr->e_ident[EI_DATA] != byteorder) + { + if (BYTE_ORDER == BIG_ENDIAN) + errstring = N_("ELF file data encoding not big-endian"); + else + errstring = N_("ELF file data encoding not little-endian"); + } + else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) + errstring + = N_("ELF file version ident does not match current one"); + /* XXX We should be able so set system specific versions which are + allowed here. */ + else if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI])) + errstring = N_("ELF file OS ABI invalid"); + else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_ABIVERSION])) + errstring = N_("ELF file ABI version invalid"); + else + /* Otherwise we don't know what went wrong. */ + errstring = N_("internal error"); + + goto call_lose; + } + + if (__builtin_expect (ehdr->e_version, EV_CURRENT) != EV_CURRENT) + { + errstring = N_("ELF file version does not match current one"); + goto call_lose; + } + if (! __builtin_expect (elf_machine_matches_host (ehdr), 1)) + goto close_and_out; + else if (__builtin_expect (ehdr->e_phentsize, sizeof (ElfW(Phdr))) + != sizeof (ElfW(Phdr))) + { + errstring = N_("ELF file's phentsize not the expected size"); + goto call_lose; + } + else if (__builtin_expect (ehdr->e_type, ET_DYN) != ET_DYN + && __builtin_expect (ehdr->e_type, ET_EXEC) != ET_EXEC) + { + errstring = N_("only ET_DYN and ET_EXEC can be loaded"); + goto call_lose; + } + + maplength = ehdr->e_phnum * sizeof (ElfW(Phdr)); + if (ehdr->e_phoff + maplength <= fbp->len) + phdr = (void *) (fbp->buf + ehdr->e_phoff); + else + { + phdr = alloca (maplength); + lseek (fd, SEEK_SET, ehdr->e_phoff); + if (__libc_read (fd, (void *) phdr, maplength) != maplength) + { + read_error: + errval = errno; + errstring = N_("cannot read file data"); + goto call_lose; + } + } + + /* Check .note.ABI-tag if present. */ + for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph) + if (ph->p_type == PT_NOTE && ph->p_filesz == 32 && ph->p_align >= 4) + { + if (ph->p_offset + 32 <= fbp->len) + abi_note = (void *) (fbp->buf + ph->p_offset); + else + { + lseek (fd, SEEK_SET, ph->p_offset); + if (__libc_read (fd, (void *) abi_note_buf, 32) != 32) + goto read_error; + + abi_note = abi_note_buf; + } + + if (memcmp (abi_note, &expected_note, sizeof (expected_note))) + continue; + + osversion = (abi_note[5] & 0xff) * 65536 + + (abi_note[6] & 0xff) * 256 + + (abi_note[7] & 0xff); + if (abi_note[4] != __ABI_TAG_OS + || (_dl_osversion && _dl_osversion < osversion)) + { + close_and_out: + close (fd); + __set_errno (ENOENT); + fd = -1; + } + + break; + } + } + + return fd; +} + +/* Try to open NAME in one of the directories in *DIRSP. + Return the fd, or -1. If successful, fill in *REALNAME + with the malloc'd full directory name. If it turns out + that none of the directories in *DIRSP exists, *DIRSP is + replaced with (void *) -1, and the old value is free()d + if MAY_FREE_DIRS is true. */ + +static int +open_path (const char *name, size_t namelen, int preloaded, + struct r_search_path_struct *sps, char **realname, + struct filebuf *fbp) +{ + struct r_search_path_elem **dirs = sps->dirs; + char *buf; + int fd = -1; + const char *current_what = NULL; + int any = 0; + + buf = alloca (max_dirnamelen + max_capstrlen + namelen); + do + { + struct r_search_path_elem *this_dir = *dirs; + size_t buflen = 0; + size_t cnt; + char *edp; + int here_any = 0; + int err; + + /* If we are debugging the search for libraries print the path + now if it hasn't happened now. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0) + && current_what != this_dir->what) + { + current_what = this_dir->what; + print_search_path (dirs, current_what, this_dir->where); + } + + edp = (char *) (memcpy (buf, this_dir->dirname, this_dir->dirnamelen) + this_dir->dirnamelen); + for (cnt = 0; fd == -1 && cnt < ncapstr; ++cnt) + { + char *tmp; + /* Skip this directory if we know it does not exist. */ + if (this_dir->status[cnt] == nonexisting) + continue; + + tmp = memcpy (edp, capstr[cnt].str, capstr[cnt].len); + tmp += capstr[cnt].len; + + tmp = memcpy (tmp, name, namelen); + tmp += namelen; + buflen = ((char *) (tmp - buf)); + + /* Print name we try if this is wanted. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_debug_printf (" trying file=%s\n", buf); + + fd = open_verify (buf, fbp); + if (this_dir->status[cnt] == unknown) + { + if (fd != -1) + this_dir->status[cnt] = existing; + else + { + /* We failed to open machine dependent library. Let's + test whether there is any directory at all. */ + struct stat64 st; + + buf[buflen - namelen - 1] = '\0'; + + if (stat64 (buf, &st) != 0 + || ! S_ISDIR (st.st_mode)) + /* The directory does not exist or it is no directory. */ + this_dir->status[cnt] = nonexisting; + else + this_dir->status[cnt] = existing; + } + } + + /* Remember whether we found any existing directory. */ + here_any |= this_dir->status[cnt] == existing; + + if (fd != -1 && __builtin_expect (preloaded, 0) + && 0) + { + /* This is an extra security effort to make sure nobody can + preload broken shared objects which are in the trusted + directories and so exploit the bugs. */ + struct stat64 st; + + if (fstat64 (fd, &st) != 0 + || (st.st_mode & S_ISUID) == 0) + { + /* The shared object cannot be tested for being SUID + or this bit is not set. In this case we must not + use this object. */ + close (fd); + fd = -1; + /* We simply ignore the file, signal this by setting + the error value which would have been set by `open'. */ + errno = ENOENT; + } + } + } + + if (fd != -1) + { + *realname = (char *) malloc (buflen); + if (*realname != NULL) + { + memcpy (*realname, buf, buflen); + return fd; + } + else + { + /* No memory for the name, we certainly won't be able + to load and link it. */ + close (fd); + return -1; + } + } + if (here_any && (err = errno) != ENOENT && err != EACCES) + /* The file exists and is readable, but something went wrong. */ + return -1; + + /* Remember whether we found anything. */ + any |= here_any; + } + while (*++dirs != NULL); + + /* Remove the whole path if none of the directories exists. */ + if (__builtin_expect (! any, 0)) + { + /* Paths which were allocated using the minimal malloc() in ld.so + must not be freed using the general free() in libc. */ + if (sps->malloced) + free (sps->dirs); + sps->dirs = (void *) -1; + } + + return -1; +} + +/* Map in the shared object file NAME. */ + +struct link_map * +internal_function +_dl_map_object (struct link_map *loader, const char *name, int preloaded, + int type, int trace_mode, int mode) +{ + int fd; + char *realname; + char *name_copy; + struct link_map *l; + struct filebuf fb; + + /* Look for this name among those already loaded. */ + for (l = _dl_loaded; l; l = l->l_next) + { + /* If the requested name matches the soname of a loaded object, + use that object. Elide this check for names that have not + yet been opened. */ + if (__builtin_expect (l->l_faked, 0) != 0) + continue; + if (!_dl_name_match_p (name, l)) + { + const char *soname; + + if (__builtin_expect (l->l_soname_added, 1) + || l->l_info[DT_SONAME] == NULL) + continue; + + soname = ((const char *) D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_SONAME]->d_un.d_val); + if (strcmp (name, soname) != 0) + continue; + + /* We have a match on a new name -- cache it. */ + add_name_to_object (l, soname); + l->l_soname_added = 1; + } + + /* We have a match. */ + return l; + } + + /* Display information if we are debugging. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0) && loader != NULL) + _dl_debug_printf ("\nfile=%s; needed by %s\n", name, + loader->l_name[0] ? loader->l_name : _dl_argv[0]); + + if (strchr (name, '/') == NULL) + { + /* Search for NAME in several places. */ + + size_t namelen = strlen (name) + 1; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_debug_printf ("find library=%s; searching\n", name); + + fd = -1; + + /* When the object has the RUNPATH information we don't use any + RPATHs. */ + if (loader == NULL || loader->l_info[DT_RUNPATH] == NULL) + { + /* First try the DT_RPATH of the dependent object that caused NAME + to be loaded. Then that object's dependent, and on up. */ + for (l = loader; fd == -1 && l; l = l->l_loader) + { + if (l->l_rpath_dirs.dirs == NULL) + { + if (l->l_info[DT_RPATH] == NULL) + { + /* There is no path. */ + l->l_rpath_dirs.dirs = (void *) -1; + continue; + } + else + { + /* Make sure the cache information is available. */ + size_t ptrval = (D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_RPATH]->d_un.d_val); + decompose_rpath (&l->l_rpath_dirs, + (const char *) ptrval, l, "RPATH"); + } + } + + if (l->l_rpath_dirs.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs, + &realname, &fb); + } + + /* If dynamically linked, try the DT_RPATH of the executable + itself. */ + l = _dl_loaded; + if (fd == -1 && l && l->l_type != lt_loaded && l != loader + && l->l_rpath_dirs.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs, + &realname, &fb); + } + + /* Try the LD_LIBRARY_PATH environment variable. */ + if (fd == -1 && env_path_list.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, &env_path_list, + &realname, &fb); + + /* Look at the RUNPATH information for this binary. + + Note that this is no real loop. 'while' is used only to enable + us to use 'break' instead of a 'goto' to jump to the end. The + loop is always left after the first round. */ + while (fd == -1 && loader != NULL + && loader->l_runpath_dirs.dirs != (void *) -1) + { + if (loader->l_runpath_dirs.dirs == NULL) + { + if (loader->l_info[DT_RUNPATH] == NULL) + { + /* No RUNPATH. */ + loader->l_runpath_dirs.dirs = (void *) -1; + break; + } + else + { + /* Make sure the cache information is available. */ + size_t ptrval = (D_PTR (loader, l_info[DT_STRTAB]) + + loader->l_info[DT_RUNPATH]->d_un.d_val); + decompose_rpath (&loader->l_runpath_dirs, + (const char *) ptrval, loader, "RUNPATH"); + } + } + + if (loader->l_runpath_dirs.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, + &loader->l_runpath_dirs, &realname, &fb); + break; + } + + if (fd == -1 + && (__builtin_expect (! preloaded, 1) || ! 0)) + { + /* Check the list of libraries in the file /etc/ld.so.cache, + for compatibility with Linux's ldconfig program. */ + const char *cached = _dl_load_cache_lookup (name); + + if (cached != NULL) + { +#ifdef SHARED + l = loader ?: _dl_loaded; +#else + l = loader; +#endif + + /* If the loader has the DF_1_NODEFLIB flag set we must not + use a cache entry from any of these directories. */ + if ( +#ifndef SHARED + /* 'l' is always != NULL for dynamically linked objects. */ + l != NULL && +#endif + __builtin_expect (l->l_flags_1 & DF_1_NODEFLIB, 0)) + { + const char *dirp = system_dirs; + unsigned int cnt = 0; + + do + { + if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0) + { + /* The prefix matches. Don't use the entry. */ + cached = NULL; + break; + } + + dirp += system_dirs_len[cnt] + 1; + ++cnt; + } + while (cnt < nsystem_dirs_len); + } + + if (cached != NULL) + { + fd = open_verify (cached, &fb); + if (__builtin_expect (fd != -1, 1)) + { + realname = local_strdup (cached); + if (realname == NULL) + { + close (fd); + fd = -1; + } + } + } + } + } + + /* Finally, try the default path. */ + if (fd == -1 + && ((l = loader ?: _dl_loaded) + /* 'l' is always != NULL for dynamically linked objects. */ +#ifdef SHARED + , +#else + == NULL || +#endif + __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1)) + && rtld_search_dirs.dirs != (void *) -1) + fd = open_path (name, namelen, preloaded, &rtld_search_dirs, + &realname, &fb); + + /* Add another newline when we a tracing the library loading. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_LIBS, 0)) + _dl_debug_printf ("\n"); + } + else + { + /* The path may contain dynamic string tokens. */ + realname = (loader + ? expand_dynamic_string_token (loader, name) + : local_strdup (name)); + if (realname == NULL) + fd = -1; + else + { + fd = open_verify (realname, &fb); + if (__builtin_expect (fd, 0) == -1) + free (realname); + } + } + + if (__builtin_expect (fd, 0) == -1) + { + if (trace_mode) + { + /* We haven't found an appropriate library. But since we + are only interested in the list of libraries this isn't + so severe. Fake an entry with all the information we + have. */ + static const Elf_Symndx dummy_bucket = STN_UNDEF; + + /* Enter the new object in the list of loaded objects. */ + if ((name_copy = local_strdup (name)) == NULL + || (l = _dl_new_object (name_copy, name, type, loader)) == NULL) + _dl_signal_error (ENOMEM, name, NULL, + N_("cannot create shared object descriptor")); + /* Signal that this is a faked entry. */ + l->l_faked = 1; + /* Since the descriptor is initialized with zero we do not + have do this here. + l->l_reserved = 0; */ + l->l_buckets = &dummy_bucket; + l->l_nbuckets = 1; + l->l_relocated = 1; + + return l; + } + else + _dl_signal_error (errno, name, NULL, + N_("cannot open shared object file")); + } + + return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode); +} diff --git a/newlib/libc/sys/linux/dl/dl-lookup.c b/newlib/libc/sys/linux/dl/dl-lookup.c new file mode 100644 index 000000000..9fc296cf1 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-lookup.c @@ -0,0 +1,654 @@ +/* Look up a symbol in the loaded objects. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include "dl-hash.h" +#include +#include + +#include + +#define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) + +/* We need this string more than once. */ +static const char undefined_msg[] = "undefined symbol: "; + + +struct sym_val + { + const ElfW(Sym) *s; + struct link_map *m; + }; + + +#define make_string(string, rest...) \ + ({ \ + const char *all[] = { string, ## rest }; \ + size_t len, cnt; \ + char *result, *cp; \ + \ + len = 1; \ + for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ + len += strlen (all[cnt]); \ + \ + cp = result = alloca (len); \ + for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ + { \ + cp = strcpy (cp, all[cnt]); \ + cp += strlen(all[cnt]); \ + } \ + \ + result; \ + }) + +/* Statistics function. */ +unsigned long int _dl_num_relocations; + + +/* We have two different situations when looking up a simple: with or + without versioning. gcc is not able to optimize a single function + definition serving for both purposes so we define two functions. */ +#define VERSIONED 0 +#include "do-lookup.h" + +#define VERSIONED 1 +#include "do-lookup.h" + + +/* Add extra dependency on MAP to UNDEF_MAP. */ +static int +internal_function +add_dependency (struct link_map *undef_map, struct link_map *map) +{ + struct link_map **list; + struct link_map *runp; + unsigned int act; + unsigned int i; + int result = 0; + + /* Avoid self-references. */ + if (undef_map == map) + return 0; + + /* Make sure nobody can unload the object while we are at it. */ +#ifdef HAVE_DD_LOCK + __lock_acquire(_dl_load_lock); +#endif + + + /* Determine whether UNDEF_MAP already has a reference to MAP. First + look in the normal dependencies. */ + if (undef_map->l_searchlist.r_list != NULL) + { + list = undef_map->l_initfini; + + for (i = 0; list[i] != NULL; ++i) + if (list[i] == map) + goto out; + } + + /* No normal dependency. See whether we already had to add it + to the special list of dynamic dependencies. */ + list = undef_map->l_reldeps; + act = undef_map->l_reldepsact; + + for (i = 0; i < act; ++i) + if (list[i] == map) + goto out; + + /* The object is not yet in the dependency list. Before we add + it make sure just one more time the object we are about to + reference is still available. There is a brief period in + which the object could have been removed since we found the + definition. */ + runp = _dl_loaded; + while (runp != NULL && runp != map) + runp = runp->l_next; + + if (runp != NULL) + { + /* The object is still available. Add the reference now. */ + if (__builtin_expect (act >= undef_map->l_reldepsmax, 0)) + { + /* Allocate more memory for the dependency list. Since this + can never happen during the startup phase we can use + `realloc'. */ + void *newp; + + undef_map->l_reldepsmax += 5; + newp = realloc (undef_map->l_reldeps, + undef_map->l_reldepsmax + * sizeof (struct link_map *)); + + if (__builtin_expect (newp != NULL, 1)) + undef_map->l_reldeps = (struct link_map **) newp; + else + /* Correct the addition. */ + undef_map->l_reldepsmax -= 5; + } + + /* If we didn't manage to allocate memory for the list this is + no fatal mistake. We simply increment the use counter of the + referenced object and don't record the dependencies. This + means this increment can never be reverted and the object + will never be unloaded. This is semantically the correct + behaviour. */ + if (__builtin_expect (act < undef_map->l_reldepsmax, 1)) + undef_map->l_reldeps[undef_map->l_reldepsact++] = map; + + if (map->l_searchlist.r_list != NULL) + /* And increment the counter in the referenced object. */ + ++map->l_opencount; + else + /* We have to bump the counts for all dependencies since so far + this object was only a normal or transitive dependency. + Now it might be closed with _dl_close() directly. */ + for (list = map->l_initfini; *list != NULL; ++list) + ++(*list)->l_opencount; + + /* Display information if we are debugging. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) + _dl_debug_printf ("\ +\nfile=%s; needed by %s (relocation dependency)\n\n", + map->l_name[0] ? map->l_name : _dl_argv[0], + undef_map->l_name[0] + ? undef_map->l_name : _dl_argv[0]); + } + else + /* Whoa, that was bad luck. We have to search again. */ + result = -1; + + out: + /* Release the lock. */ +#ifdef HAVE_DD_LOCK + __lock_release(_dl_load_lock); +#endif + + + return result; +} + +static int +internal_function +_dl_do_lookup (const char *undef_name, unsigned long int hash, + const ElfW(Sym) *ref, struct sym_val *result, + struct r_scope_elem *scope, size_t i, + struct link_map *skip, int type_class); +static int +internal_function +_dl_do_lookup_versioned (const char *undef_name, unsigned long int hash, + const ElfW(Sym) *ref, struct sym_val *result, + struct r_scope_elem *scope, size_t i, + const struct r_found_version *const version, + struct link_map *skip, int type_class); + + +/* Search loaded objects' symbol tables for a definition of the symbol + UNDEF_NAME. */ + +lookup_t +internal_function +_dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, + const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[], + int type_class, int explicit) +{ + unsigned long int hash = _dl_elf_hash (undef_name); + struct sym_val current_value = { NULL, NULL }; + struct r_scope_elem **scope; + int protected; + + ++_dl_num_relocations; + + /* Search the relevant loaded objects for a definition. */ + for (scope = symbol_scope; *scope; ++scope) + if (do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, NULL, + type_class)) + { + /* We have to check whether this would bind UNDEF_MAP to an object + in the global scope which was dynamically loaded. In this case + we have to prevent the latter from being unloaded unless the + UNDEF_MAP object is also unloaded. */ + if (__builtin_expect (current_value.m->l_type == lt_loaded, 0) + /* Don't do this for explicit lookups as opposed to implicit + runtime lookups. */ + && ! explicit + /* Add UNDEF_MAP to the dependencies. */ + && add_dependency (undef_map, current_value.m) < 0) + /* Something went wrong. Perhaps the object we tried to reference + was just removed. Try finding another definition. */ + return _dl_lookup_symbol (undef_name, undef_map, ref, symbol_scope, + type_class, 0); + + break; + } + + if (__builtin_expect (current_value.s == NULL, 0)) + { + const char *reference_name = undef_map ? undef_map->l_name : NULL; + + if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) + /* We could find no value for a strong reference. */ + /* XXX We cannot translate the messages. */ + _dl_signal_cerror (0, (reference_name && reference_name[0] + ? reference_name + : (_dl_argv[0] ?: "
")), + N_("relocation error"), + make_string (undefined_msg, undef_name)); + *ref = NULL; + return 0; + } + + protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) + { + const char *reference_name = undef_map ? undef_map->l_name : NULL; + + _dl_debug_printf ("binding file %s to %s: %s symbol `%s'\n", + (reference_name && reference_name[0] + ? reference_name : (_dl_argv[0] ?: "
")), + current_value.m->l_name[0] + ? current_value.m->l_name : _dl_argv[0], + protected ? "protected" : "normal", undef_name); + } + + if (__builtin_expect (protected == 0, 1)) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + else + { + /* It is very tricky. We need to figure out what value to + return for the protected symbol */ + struct sym_val protected_value = { NULL, NULL }; + + for (scope = symbol_scope; *scope; ++scope) + if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, + 0, NULL, ELF_RTYPE_CLASS_PLT)) + break; + + if (protected_value.s == NULL || protected_value.m == undef_map) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + + return LOOKUP_VALUE (undef_map); + } +} + + +/* This function is nearly the same as `_dl_lookup_symbol' but it + skips in the first list all objects until SKIP_MAP is found. I.e., + it only considers objects which were loaded after the described + object. If there are more search lists the object described by + SKIP_MAP is only skipped. */ +lookup_t +internal_function +_dl_lookup_symbol_skip (const char *undef_name, + struct link_map *undef_map, const ElfW(Sym) **ref, + struct r_scope_elem *symbol_scope[], + struct link_map *skip_map) +{ + const char *reference_name = undef_map ? undef_map->l_name : NULL; + const unsigned long int hash = _dl_elf_hash (undef_name); + struct sym_val current_value = { NULL, NULL }; + struct r_scope_elem **scope; + size_t i; + int protected; + + ++_dl_num_relocations; + + /* Search the relevant loaded objects for a definition. */ + scope = symbol_scope; + for (i = 0; (*scope)->r_list[i] != skip_map; ++i) + assert (i < (*scope)->r_nlist); + + if (! _dl_do_lookup (undef_name, hash, *ref, ¤t_value, *scope, i, + skip_map, 0)) + while (*++scope) + if (_dl_do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, + skip_map, 0)) + break; + + if (__builtin_expect (current_value.s == NULL, 0)) + { + *ref = NULL; + return 0; + } + + protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) + _dl_debug_printf ("binding file %s to %s: %s symbol `%s'\n", + (reference_name && reference_name[0] + ? reference_name : (_dl_argv[0] ?: "
")), + current_value.m->l_name[0] + ? current_value.m->l_name : _dl_argv[0], + protected ? "protected" : "normal", undef_name); + + if (__builtin_expect (protected == 0, 1)) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + else + { + /* It is very tricky. We need to figure out what value to + return for the protected symbol. */ + struct sym_val protected_value = { NULL, NULL }; + + if (i >= (*scope)->r_nlist + || !_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, + i, skip_map, ELF_RTYPE_CLASS_PLT)) + while (*++scope) + if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, + 0, skip_map, ELF_RTYPE_CLASS_PLT)) + break; + + if (protected_value.s == NULL || protected_value.m == undef_map) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + + return LOOKUP_VALUE (undef_map); + } +} + + +/* This function works like _dl_lookup_symbol but it takes an + additional arguement with the version number of the requested + symbol. + + XXX We'll see whether we need this separate function. */ +lookup_t +internal_function +_dl_lookup_versioned_symbol (const char *undef_name, + struct link_map *undef_map, const ElfW(Sym) **ref, + struct r_scope_elem *symbol_scope[], + const struct r_found_version *version, + int type_class, int explicit) +{ + unsigned long int hash = _dl_elf_hash (undef_name); + struct sym_val current_value = { NULL, NULL }; + struct r_scope_elem **scope; + int protected; + + ++_dl_num_relocations; + + /* Search the relevant loaded objects for a definition. */ + for (scope = symbol_scope; *scope; ++scope) + { + int res = do_lookup_versioned (undef_name, hash, *ref, ¤t_value, + *scope, 0, version, NULL, type_class); + if (res > 0) + { + /* We have to check whether this would bind UNDEF_MAP to an object + in the global scope which was dynamically loaded. In this case + we have to prevent the latter from being unloaded unless the + UNDEF_MAP object is also unloaded. */ + if (__builtin_expect (current_value.m->l_type == lt_loaded, 0) + /* Don't do this for explicit lookups as opposed to implicit + runtime lookups. */ + && ! explicit + /* Add UNDEF_MAP to the dependencies. */ + && add_dependency (undef_map, current_value.m) < 0) + /* Something went wrong. Perhaps the object we tried to reference + was just removed. Try finding another definition. */ + return _dl_lookup_versioned_symbol (undef_name, undef_map, ref, + symbol_scope, version, + type_class, 0); + + break; + } + + if (__builtin_expect (res, 0) < 0) + { + /* Oh, oh. The file named in the relocation entry does not + contain the needed symbol. */ + const char *reference_name = undef_map ? undef_map->l_name : NULL; + + /* XXX We cannot translate the message. */ + _dl_signal_cerror (0, (reference_name && reference_name[0] + ? reference_name + : (_dl_argv[0] ?: "
")), + N_("relocation error"), + make_string ("symbol ", undef_name, ", version ", + version->name, + " not defined in file ", + version->filename, + " with link time reference", + res == -2 + ? " (no version symbols)" : "")); + *ref = NULL; + return 0; + } + } + + if (__builtin_expect (current_value.s == NULL, 0)) + { + if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) + { + /* We could find no value for a strong reference. */ + const char *reference_name = undef_map ? undef_map->l_name : NULL; + + /* XXX We cannot translate the message. */ + _dl_signal_cerror (0, (reference_name && reference_name[0] + ? reference_name + : (_dl_argv[0] ?: "
")), NULL, + make_string (undefined_msg, undef_name, + ", version ", + version->name ?: NULL)); + } + *ref = NULL; + return 0; + } + + protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) + { + const char *reference_name = undef_map ? undef_map->l_name : NULL; + + _dl_debug_printf ("binding file %s to %s: %s symbol `%s' [%s]\n", + (reference_name && reference_name[0] + ? reference_name : (_dl_argv[0] ?: "
")), + current_value.m->l_name[0] + ? current_value.m->l_name : _dl_argv[0], + protected ? "protected" : "normal", + undef_name, version->name); + } + + if (__builtin_expect (protected == 0, 1)) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + else + { + /* It is very tricky. We need to figure out what value to + return for the protected symbol */ + struct sym_val protected_value = { NULL, NULL }; + + for (scope = symbol_scope; *scope; ++scope) + if (_dl_do_lookup_versioned (undef_name, hash, *ref, &protected_value, + *scope, 0, version, NULL, + ELF_RTYPE_CLASS_PLT)) + break; + + if (protected_value.s == NULL || protected_value.m == undef_map) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + + return LOOKUP_VALUE (undef_map); + } +} + + +/* Similar to _dl_lookup_symbol_skip but takes an additional argument + with the version we are looking for. */ +lookup_t +internal_function +_dl_lookup_versioned_symbol_skip (const char *undef_name, + struct link_map *undef_map, + const ElfW(Sym) **ref, + struct r_scope_elem *symbol_scope[], + const struct r_found_version *version, + struct link_map *skip_map) +{ + const char *reference_name = undef_map ? undef_map->l_name : NULL; + const unsigned long int hash = _dl_elf_hash (undef_name); + struct sym_val current_value = { NULL, NULL }; + struct r_scope_elem **scope; + size_t i; + int protected; + + ++_dl_num_relocations; + + /* Search the relevant loaded objects for a definition. */ + scope = symbol_scope; + for (i = 0; (*scope)->r_list[i] != skip_map; ++i) + assert (i < (*scope)->r_nlist); + + if (! _dl_do_lookup_versioned (undef_name, hash, *ref, ¤t_value, + *scope, i, version, skip_map, 0)) + while (*++scope) + if (_dl_do_lookup_versioned (undef_name, hash, *ref, ¤t_value, + *scope, 0, version, skip_map, 0)) + break; + + if (__builtin_expect (current_value.s == NULL, 0)) + { + if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) + { + /* We could find no value for a strong reference. */ + const size_t len = strlen (undef_name); + char buf[sizeof undefined_msg + len]; + char *tmp; + tmp = memcpy (buf, undefined_msg, sizeof undefined_msg - 1); + tmp += (sizeof undefined_msg - 1); + + memcpy (tmp, undef_name, len + 1); + + /* XXX We cannot translate the messages. */ + _dl_signal_cerror (0, (reference_name && reference_name[0] + ? reference_name + : (_dl_argv[0] ?: "
")), + NULL, buf); + } + *ref = NULL; + return 0; + } + + protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) + _dl_debug_printf ("binding file %s to %s: %s symbol `%s' [%s]\n", + (reference_name && reference_name[0] + ? reference_name : (_dl_argv[0] ?: "
")), + current_value.m->l_name[0] + ? current_value.m->l_name : _dl_argv[0], + protected ? "protected" : "normal", + undef_name, version->name); + + if (__builtin_expect (protected == 0, 1)) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + else + { + /* It is very tricky. We need to figure out what value to + return for the protected symbol */ + struct sym_val protected_value = { NULL, NULL }; + + if (i >= (*scope)->r_nlist + || !_dl_do_lookup_versioned (undef_name, hash, *ref, + &protected_value, *scope, i, version, + skip_map, ELF_RTYPE_CLASS_PLT)) + while (*++scope) + if (_dl_do_lookup_versioned (undef_name, hash, *ref, + &protected_value, *scope, 0, version, + skip_map, ELF_RTYPE_CLASS_PLT)) + break; + + if (protected_value.s == NULL || protected_value.m == undef_map) + { + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } + + return LOOKUP_VALUE (undef_map); + } +} + + +/* Cache the location of MAP's hash table. */ + +void +internal_function +_dl_setup_hash (struct link_map *map) +{ + Elf_Symndx *hash; + Elf_Symndx nchain; + + if (!map->l_info[DT_HASH]) + return; + hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr); + + map->l_nbuckets = *hash++; + nchain = *hash++; + map->l_buckets = hash; + hash += map->l_nbuckets; + map->l_chain = hash; +} + +/* These are here so that we only inline do_lookup{,_versioned} in the common + case, not everywhere. */ +static int +internal_function +_dl_do_lookup (const char *undef_name, unsigned long int hash, + const ElfW(Sym) *ref, struct sym_val *result, + struct r_scope_elem *scope, size_t i, + struct link_map *skip, int type_class) +{ + return do_lookup (undef_name, hash, ref, result, scope, i, skip, + type_class); +} + +static int +internal_function +_dl_do_lookup_versioned (const char *undef_name, unsigned long int hash, + const ElfW(Sym) *ref, struct sym_val *result, + struct r_scope_elem *scope, size_t i, + const struct r_found_version *const version, + struct link_map *skip, int type_class) +{ + return do_lookup_versioned (undef_name, hash, ref, result, scope, i, + version, skip, type_class); +} diff --git a/newlib/libc/sys/linux/dl/dl-lookupcfg.h b/newlib/libc/sys/linux/dl/dl-lookupcfg.h new file mode 100644 index 000000000..810e8c7c6 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-lookupcfg.h @@ -0,0 +1,22 @@ +/* Configuration of lookup functions. + Copyright (C) 2000 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Some platforms need more information from the symbol lookup function + than just the address. But this is not generally the case. */ +#undef DL_LOOKUP_RETURNS_MAP diff --git a/newlib/libc/sys/linux/dl/dl-minimal.c b/newlib/libc/sys/linux/dl/dl-minimal.c new file mode 100644 index 000000000..807bfad63 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-minimal.c @@ -0,0 +1,250 @@ +/* Minimal replacements for basic facilities used in the dynamic linker. + Copyright (C) 1995,96,97,98,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Minimal `malloc' allocator for use while loading shared libraries. + No block is ever freed. */ + +static void *alloc_ptr, *alloc_end, *alloc_last_block; + +/* Declarations of global functions. */ +extern void weak_function free (void *ptr); +extern void * weak_function realloc (void *ptr, size_t n); +extern unsigned long int weak_function __strtoul_internal +(const char *nptr, char **endptr, int base, int group); +extern unsigned long int weak_function strtoul (const char *nptr, + char **endptr, int base); + + +void * weak_function +malloc (size_t n) +{ +#ifdef MAP_ANON +#define _dl_zerofd (-1) +#else + extern int _dl_zerofd; + + if (_dl_zerofd == -1) + _dl_zerofd = _dl_sysdep_open_zero_fill (); +#define MAP_ANON 0 +#endif + + if (alloc_end == 0) + { + /* Consume any unused space in the last page of our data segment. */ + extern int _end; + alloc_ptr = &_end; + alloc_end = (void *) 0 + (((alloc_ptr - (void *) 0) + _dl_pagesize - 1) + & ~(_dl_pagesize - 1)); + } + + /* Make sure the allocation pointer is ideally aligned. */ + alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + sizeof (double) - 1) + & ~(sizeof (double) - 1)); + + if (alloc_ptr + n >= alloc_end) + { + /* Insufficient space left; allocate another page. */ + caddr_t page; + size_t nup = (n + _dl_pagesize - 1) & ~(_dl_pagesize - 1); + page = __mmap (0, nup, PROT_READ|PROT_WRITE, + MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0); + assert (page != MAP_FAILED); + if (page != alloc_end) + alloc_ptr = page; + alloc_end = page + nup; + } + + alloc_last_block = (void *) alloc_ptr; + alloc_ptr += n; + return alloc_last_block; +} + +/* We use this function occasionally since the real implementation may + be optimized when it can assume the memory it returns already is + set to NUL. */ +void * weak_function +calloc (size_t nmemb, size_t size) +{ + size_t total = nmemb * size; + void *result = malloc (total); + return memset (result, '\0', total); +} + +/* This will rarely be called. */ +void weak_function +free (void *ptr) +{ + /* We can free only the last block allocated. */ + if (ptr == alloc_last_block) + alloc_ptr = alloc_last_block; +} + +/* This is only called with the most recent block returned by malloc. */ +void * weak_function +realloc (void *ptr, size_t n) +{ + void *new; + if (ptr == NULL) + return malloc (n); + assert (ptr == alloc_last_block); + alloc_ptr = alloc_last_block; + new = malloc (n); + assert (new == ptr); + return new; +} + + +/* Define our own version of the internal function used by strerror. We + only provide the messages for some common errors. This avoids pulling + in the whole error list. */ + +char * weak_function +__strerror_r (int errnum, char *buf, size_t buflen) +{ + char *msg; + + switch (errnum) + { + case ENOMEM: + msg = (char *) "Cannot allocate memory"; + break; + case EINVAL: + msg = (char *) "Invalid argument"; + break; + case ENOENT: + msg = (char *) "No such file or directory"; + break; + case EPERM: + msg = (char *) "Operation not permitted"; + break; + case EIO: + msg = (char *) "Input/output error"; + break; + case EACCES: + msg = (char *) "Permission denied"; + break; + default: + /* No need to check buffer size, all calls in the dynamic linker + provide enough space. */ + msg = (char *) "Error"; + break; + } + + return msg; +} + +#ifndef NDEBUG + +/* Define (weakly) our own assert failure function which doesn't use stdio. + If we are linked into the user program (-ldl), the normal __assert_fail + defn can override this one. */ + +void weak_function +__assert_fail (const char *assertion, + const char *file, unsigned int line, const char *function) +{ + _dl_fatal_printf ("\ +Inconsistency detected by ld.so: %s: %u: %s%sAssertion `%s' failed!\n", + file, line, function ?: "", function ? ": " : "", + assertion); + +} + +void weak_function +__assert_perror_fail (int errnum, + const char *file, unsigned int line, + const char *function) +{ + char errbuf[64]; + _dl_fatal_printf ("\ +Inconsistency detected by ld.so: %s: %u: %s%sUnexpected error: %s\n", + file, line, function ?: "", function ? ": " : "", + __strerror_r (errnum, errbuf, sizeof (errbuf))); +} + +#endif + +unsigned long int weak_function +__strtoul_internal (const char *nptr, char **endptr, int base, int group) +{ + unsigned long int result = 0; + long int sign = 1; + + while (*nptr == ' ' || *nptr == '\t') + ++nptr; + + if (*nptr == '-') + { + sign = -1; + ++nptr; + } + else if (*nptr == '+') + ++nptr; + + if (*nptr < '0' || *nptr > '9') + { + if (endptr != NULL) + *endptr = (char *) nptr; + return 0UL; + } + + assert (base == 0); + base = 10; + if (*nptr == '0') + { + if (nptr[1] == 'x' || nptr[1] == 'X') + { + base = 16; + nptr += 2; + } + else + base = 8; + } + + while (*nptr >= '0' && *nptr <= '9') + { + unsigned long int digval = *nptr - '0'; + if (result > LONG_MAX / 10 + || (result == ULONG_MAX / 10 && digval > ULONG_MAX % 10)) + { + errno = ERANGE; + if (endptr != NULL) + *endptr = (char *) nptr; + return ULONG_MAX; + } + result *= base; + result += digval; + ++nptr; + } + + if (endptr != NULL) + *endptr = (char *) nptr; + return result * sign; +} diff --git a/newlib/libc/sys/linux/dl/dl-misc.c b/newlib/libc/sys/linux/dl/dl-misc.c new file mode 100644 index 000000000..1a4c297d5 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-misc.c @@ -0,0 +1,277 @@ +/* Miscellaneous support functions for dynamic linker + Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MAP_ANON +/* This is the only dl-sysdep.c function that is actually needed at run-time + by _dl_map_object. */ + +int +_dl_sysdep_open_zero_fill (void) +{ + return __open ("/dev/zero", O_RDONLY); +} +#endif + +/* Read the whole contents of FILE into new mmap'd space with given + protections. *SIZEP gets the size of the file. On error MAP_FAILED + is returned. */ + +void * +internal_function +_dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot) +{ + void *result = MAP_FAILED; + struct stat64 st; + int fd = __open (file, O_RDONLY); + if (fd >= 0) + { + if (fstat64 (fd, &st) >= 0) + { + *sizep = st.st_size; + + /* No need to map the file if it is empty. */ + if (*sizep != 0) + /* Map a copy of the file contents. */ + result = mmap (NULL, *sizep, prot, +#ifdef MAP_COPY + MAP_COPY +#else + MAP_PRIVATE +#endif +#ifdef MAP_FILE + | MAP_FILE +#endif + , fd, 0); + } + close (fd); + } + return result; +} + + +/* Descriptor to write debug messages to. */ +int _dl_debug_fd = 2; + + +/* Bare-bone printf implementation. This function only knows about + the formats and flags needed and can handle only up to 64 stripes in + the output. */ +static void +_dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) +{ + const int niovmax = 64; + struct iovec iov[niovmax]; + int niov = 0; + pid_t pid = 0; + char pidbuf[7]; + + while (*fmt != '\0') + { + const char *startp = fmt; + + if (tag_p > 0) + { + /* Generate the tag line once. It consists of the PID and a + colon followed by a tab. */ + if (pid == 0) + { + char *p = "0"; + pid = __getpid (); + assert (pid >= 0 && pid < 100000); + while (p > pidbuf) + *--p = '0'; + pidbuf[5] = ':'; + pidbuf[6] = '\t'; + } + + /* Append to the output. */ + assert (niov < niovmax); + iov[niov].iov_len = 7; + iov[niov++].iov_base = pidbuf; + + /* No more tags until we see the next newline. */ + tag_p = -1; + } + + /* Skip everything except % and \n (if tags are needed). */ + while (*fmt != '\0' && *fmt != '%' && (! tag_p || *fmt != '\n')) + ++fmt; + + /* Append constant string. */ + assert (niov < niovmax); + if ((iov[niov].iov_len = fmt - startp) != 0) + iov[niov++].iov_base = (char *) startp; + + if (*fmt == '%') + { + /* It is a format specifier. */ + char fill = ' '; + int width = -1; +#if LONG_MAX != INT_MAX + int long_mod = 0; +#endif + + /* Recognize zero-digit fill flag. */ + if (*++fmt == '0') + { + fill = '0'; + ++fmt; + } + + /* See whether with comes from a parameter. Note that no other + way to specify the width is implemented. */ + if (*fmt == '*') + { + width = va_arg (arg, int); + ++fmt; + } + + /* Recognize the l modifier. It is only important on some + platforms where long and int have a different size. We + can use the same code for size_t. */ + if (*fmt == 'l' || *fmt == 'Z') + { +#if LONG_MAX != INT_MAX + long_mod = 1; +#endif + ++fmt; + } + + switch (*fmt) + { + /* Integer formatting. */ + case 'u': + case 'x': + { + /* We have to make a difference if long and int have a + different size. */ +#if LONG_MAX != INT_MAX + unsigned long int num = (long_mod + ? va_arg (arg, unsigned long int) + : va_arg (arg, unsigned int)); +#else + unsigned long int num = va_arg (arg, unsigned int); +#endif + /* We use alloca() to allocate the buffer with the most + pessimistic guess for the size. Using alloca() allows + having more than one integer formatting in a call. */ + char *buf = (char *) alloca (3 * sizeof (unsigned long int)); + char *endp = &buf[3 * sizeof (unsigned long int)]; + char *cp = "0"; + + /* Pad to the width the user specified. */ + if (width != -1) + while (endp - cp < width) + *--cp = fill; + + iov[niov].iov_base = cp; + iov[niov].iov_len = endp - cp; + ++niov; + } + break; + + case 's': + /* Get the string argument. */ + iov[niov].iov_base = va_arg (arg, char *); + iov[niov].iov_len = strlen (iov[niov].iov_base); + ++niov; + break; + + case '%': + iov[niov].iov_base = (void *) fmt; + iov[niov].iov_len = 1; + ++niov; + break; + + default: + assert (! "invalid format specifier"); + } + ++fmt; + } + else if (*fmt == '\n') + { + /* See whether we have to print a single newline character. */ + if (fmt == startp) + { + iov[niov].iov_base = (char *) startp; + iov[niov++].iov_len = 1; + } + else + /* No, just add it to the rest of the string. */ + ++iov[niov - 1].iov_len; + + /* Next line, print a tag again. */ + tag_p = 1; + ++fmt; + } + } + + /* Finally write the result. */ + writev (fd, iov, niov); +} + + +/* Write to debug file. */ +void +_dl_debug_printf (const char *fmt, ...) +{ + va_list arg; + + va_start (arg, fmt); + _dl_debug_vdprintf (_dl_debug_fd, 1, fmt, arg); + va_end (arg); +} + + +/* Write to debug file but don't start with a tag. */ +void +_dl_debug_printf_c (const char *fmt, ...) +{ + va_list arg; + + va_start (arg, fmt); + _dl_debug_vdprintf (_dl_debug_fd, -1, fmt, arg); + va_end (arg); +} + + +/* Write the given file descriptor. */ +void +_dl_dprintf (int fd, const char *fmt, ...) +{ + va_list arg; + + va_start (arg, fmt); + _dl_debug_vdprintf (fd, 0, fmt, arg); + va_end (arg); +} diff --git a/newlib/libc/sys/linux/dl/dl-object.c b/newlib/libc/sys/linux/dl/dl-object.c new file mode 100644 index 000000000..1e2049e25 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-object.c @@ -0,0 +1,163 @@ +/* Storage management for the chain of loaded shared objects. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include + +#include + + +/* Allocate a `struct link_map' for a new object being loaded, + and enter it into the _dl_loaded list. */ + +struct link_map * +internal_function +_dl_new_object (char *realname, const char *libname, int type, + struct link_map *loader) +{ + struct link_map *l; + int idx; + size_t libname_len = strlen (libname) + 1; + struct link_map *new; + struct libname_list *newname; + + new = (struct link_map *) calloc (sizeof (*new) + sizeof (*newname) + + libname_len, 1); + if (new == NULL) + return NULL; + + new->l_libname = newname = (struct libname_list *) (new + 1); + newname->name = (char *) memcpy (newname + 1, libname, libname_len); + /* newname->next = NULL; We use calloc therefore not necessary. */ + newname->dont_free = 1; + + new->l_name = realname; + new->l_type = type; + new->l_loader = loader; + /* new->l_global = 0; We use calloc therefore not necessary. */ + + /* Use the 'l_scope_mem' array by default for the the 'l_scope' + information. If we need more entries we will allocate a large + array dynamically. */ + new->l_scope = new->l_scope_mem; + new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]); + + /* Counter for the scopes we have to handle. */ + idx = 0; + + if (_dl_loaded != NULL) + { + l = _dl_loaded; + while (l->l_next != NULL) + l = l->l_next; + new->l_prev = l; + /* new->l_next = NULL; Would be necessary but we use calloc. */ + l->l_next = new; + + /* Add the global scope. */ + new->l_scope[idx++] = &_dl_loaded->l_searchlist; + } + else + _dl_loaded = new; + ++_dl_nloaded; + + /* If we have no loader the new object acts as it. */ + if (loader == NULL) + loader = new; + else + /* Determine the local scope. */ + while (loader->l_loader != NULL) + loader = loader->l_loader; + + /* Insert the scope if it isn't the global scope we already added. */ + if (idx == 0 || &loader->l_searchlist != new->l_scope[0]) + new->l_scope[idx] = &loader->l_searchlist; + + new->l_local_scope[0] = &new->l_searchlist; + + /* Don't try to find the origin for the main map which has the name "". */ + if (realname[0] != '\0') + { + size_t realname_len = strlen (realname) + 1; + char *origin; + char *cp; + + if (realname[0] == '/') + { + /* It is an absolute path. Use it. But we have to make a + copy since we strip out the trailing slash. */ + cp = origin = (char *) malloc (realname_len); + if (origin == NULL) + { + origin = (char *) -1; + goto out; + } + } + else + { + size_t len = realname_len; + char *result = NULL; + + /* Get the current directory name. */ + origin = NULL; + do + { + len += 128; + origin = (char *) realloc (origin, len); + } + while (origin != NULL + && (result = getcwd (origin, len - realname_len)) == NULL + && errno == ERANGE); + + if (result == NULL) + { + /* We were not able to determine the current directory. + Note that free(origin) is OK if origin == NULL. */ + free (origin); + origin = (char *) -1; + goto out; + } + + /* Find the end of the path and see whether we have to add + a slash. */ + cp = memchr (origin, '\0', strlen(origin)); + if (cp[-1] != '/') + *cp++ = '/'; + } + + /* Add the real file name. */ + memcpy (cp, realname, realname_len); + + /* Now remove the filename and the slash. Leave the slash if it + the name is something like "/foo". */ + cp = strrchr (origin, '/'); + if (cp == origin) + origin[1] = '\0'; + else + *cp = '\0'; + + out: + new->l_origin = origin; + } + + return new; +} diff --git a/newlib/libc/sys/linux/dl/dl-open.c b/newlib/libc/sys/linux/dl/dl-open.c new file mode 100644 index 000000000..195361427 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-open.c @@ -0,0 +1,487 @@ +/* Load a shared object at runtime, relocate it, and run its initializer. + Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include /* Check whether MAP_COPY is defined. */ +#include +#include +#include + +#include +#include + + +extern ElfW(Addr) _dl_sysdep_start (void **start_argptr, + void (*dl_main) (const ElfW(Phdr) *phdr, + ElfW(Word) phnum, + ElfW(Addr) *user_entry)); +weak_extern (BP_SYM (_dl_sysdep_start)) + +/* This function is used to unload the cache file if necessary. */ +extern void _dl_unload_cache (void); + +int __libc_argc = 0; +char **__libc_argv = NULL; + +extern char **environ; + +extern int _dl_lazy; /* Do we do lazy relocations? */ + +/* Undefine the following for debugging. */ +/* #define SCOPE_DEBUG 1 */ +#ifdef SCOPE_DEBUG +static void show_scope (struct link_map *new); +#endif + +extern size_t _dl_platformlen; + +/* We must be carefull not to leave us in an inconsistent state. Thus we + catch any error and re-raise it after cleaning up. */ + +struct dl_open_args +{ + const char *file; + int mode; + const void *caller; + struct link_map *map; +}; + + +static int +add_to_global (struct link_map *new) +{ + struct link_map **new_global; + unsigned int to_add = 0; + unsigned int cnt; + + /* Count the objects we have to put in the global scope. */ + for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) + if (new->l_searchlist.r_list[cnt]->l_global == 0) + ++to_add; + + /* The symbols of the new objects and its dependencies are to be + introduced into the global scope that will be used to resolve + references from other dynamically-loaded objects. + + The global scope is the searchlist in the main link map. We + extend this list if necessary. There is one problem though: + since this structure was allocated very early (before the libc + is loaded) the memory it uses is allocated by the malloc()-stub + in the ld.so. When we come here these functions are not used + anymore. Instead the malloc() implementation of the libc is + used. But this means the block from the main map cannot be used + in an realloc() call. Therefore we allocate a completely new + array the first time we have to add something to the locale scope. */ + + if (_dl_global_scope_alloc == 0) + { + /* This is the first dynamic object given global scope. */ + _dl_global_scope_alloc = _dl_main_searchlist->r_nlist + to_add + 8; + new_global = (struct link_map **) + malloc (_dl_global_scope_alloc * sizeof (struct link_map *)); + if (new_global == NULL) + { + _dl_global_scope_alloc = 0; + nomem: + _dl_signal_error (ENOMEM, new->l_libname->name, NULL, + N_("cannot extend global scope")); + return 1; + } + + /* Copy over the old entries. */ + memcpy (new_global, _dl_main_searchlist->r_list, + (_dl_main_searchlist->r_nlist * sizeof (struct link_map *))); + + _dl_main_searchlist->r_list = new_global; + } + else if (_dl_main_searchlist->r_nlist + to_add > _dl_global_scope_alloc) + { + /* We have to extend the existing array of link maps in the + main map. */ + new_global = (struct link_map **) + realloc (_dl_main_searchlist->r_list, + ((_dl_global_scope_alloc + to_add + 8) + * sizeof (struct link_map *))); + if (new_global == NULL) + goto nomem; + + _dl_global_scope_alloc += to_add + 8; + _dl_main_searchlist->r_list = new_global; + } + + /* Now add the new entries. */ + for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) + { + struct link_map *map = new->l_searchlist.r_list[cnt]; + + if (map->l_global == 0) + { + map->l_global = 1; + _dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist] = map; + ++_dl_main_searchlist->r_nlist; + } + } + + return 0; +} + + +static void +dl_open_worker (void *a) +{ + struct dl_open_args *args = a; + const char *file = args->file; + int mode = args->mode; + struct link_map *new, *l; + const char *dst; + int lazy; + unsigned int i; + + /* Maybe we have to expand a DST. */ + dst = strchr (file, '$'); + if (dst != NULL) + { + const void *caller = args->caller; + size_t len = strlen (file); + size_t required; + struct link_map *call_map; + char *new_file; + + /* We have to find out from which object the caller is calling. */ + call_map = NULL; + for (l = _dl_loaded; l; l = l->l_next) + if (caller >= (const void *) l->l_map_start + && caller < (const void *) l->l_map_end) + { + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ + call_map = l; + break; + } + + if (call_map == NULL) + /* In this case we assume this is the main application. */ + call_map = _dl_loaded; + + /* Determine how much space we need. We have to allocate the + memory locally. */ + required = DL_DST_REQUIRED (call_map, file, len, _dl_dst_count (dst, 0)); + + /* Get space for the new file name. */ + new_file = (char *) alloca (required + 1); + + /* Generate the new file name. */ + DL_DST_SUBSTITUTE (call_map, file, new_file, 0); + + /* If the substitution failed don't try to load. */ + if (*new_file == '\0') + _dl_signal_error (0, "dlopen", NULL, + N_("empty dynamic string token substitution")); + + /* Now we have a new file name. */ + file = new_file; + } + + /* Load the named object. */ + args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0, + mode); + + /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is + set and the object is not already loaded. */ + if (new == NULL) + { + assert (mode & RTLD_NOLOAD); + return; + } + + /* It was already open. */ + if (new->l_searchlist.r_list != NULL) + { + /* Let the user know about the opencount. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) + _dl_debug_printf ("opening file=%s; opencount == %u\n\n", + new->l_name, new->l_opencount); + + /* If the user requested the object to be in the global namespace + but it is not so far, add it now. */ + if ((mode & RTLD_GLOBAL) && new->l_global == 0) + (void) add_to_global (new); + + /* Increment just the reference counter of the object. */ + ++new->l_opencount; + + return; + } + + /* Load that object's dependencies. */ + _dl_map_object_deps (new, NULL, 0, 0); + + /* So far, so good. Now check the versions. */ + for (i = 0; i < new->l_searchlist.r_nlist; ++i) + if (new->l_searchlist.r_list[i]->l_versions == NULL) + (void) _dl_check_map_versions (new->l_searchlist.r_list[i], 0, 0); + +#ifdef SCOPE_DEBUG + show_scope (new); +#endif + + /* Only do lazy relocation if `LD_BIND_NOW' is not set. */ + lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && _dl_lazy; + + /* Relocate the objects loaded. We do this in reverse order so that copy + relocs of earlier objects overwrite the data written by later objects. */ + + l = new; + while (l->l_next) + l = l->l_next; + while (1) + { + if (! l->l_relocated) + { +#if 0 +#ifdef SHARED + if (_dl_profile != NULL) + { + /* If this here is the shared object which we want to profile + make sure the profile is started. We can find out whether + this is necessary or not by observing the `_dl_profile_map' + variable. If was NULL but is not NULL afterwars we must + start the profiling. */ + struct link_map *old_profile_map = _dl_profile_map; + + _dl_relocate_object (l, l->l_scope, 1, 1); + + if (old_profile_map == NULL && _dl_profile_map != NULL) + /* We must prepare the profiling. */ + _dl_start_profile (_dl_profile_map, _dl_profile_output); + } + else +#endif +#endif + _dl_relocate_object (l, l->l_scope, lazy, 0); + } + + if (l == new) + break; + l = l->l_prev; + } + + /* Increment the open count for all dependencies. If the file is + not loaded as a dependency here add the search list of the newly + loaded object to the scope. */ + for (i = 0; i < new->l_searchlist.r_nlist; ++i) + if (++new->l_searchlist.r_list[i]->l_opencount > 1 + && new->l_searchlist.r_list[i]->l_type == lt_loaded) + { + struct link_map *imap = new->l_searchlist.r_list[i]; + struct r_scope_elem **runp = imap->l_scope; + size_t cnt = 0; + + while (*runp != NULL) + { + /* This can happen if imap was just loaded, but during + relocation had l_opencount bumped because of relocation + dependency. Avoid duplicates in l_scope. */ + if (__builtin_expect (*runp == &new->l_searchlist, 0)) + break; + + ++cnt; + ++runp; + } + + if (*runp != NULL) + /* Avoid duplicates. */ + continue; + + if (__builtin_expect (cnt + 1 >= imap->l_scope_max, 0)) + { + /* The 'r_scope' array is too small. Allocate a new one + dynamically. */ + struct r_scope_elem **newp; + size_t new_size = imap->l_scope_max * 2; + + if (imap->l_scope == imap->l_scope_mem) + { + newp = (struct r_scope_elem **) + malloc (new_size * sizeof (struct r_scope_elem *)); + if (newp == NULL) + _dl_signal_error (ENOMEM, "dlopen", NULL, + N_("cannot create scope list")); + imap->l_scope = memcpy (newp, imap->l_scope, + cnt * sizeof (imap->l_scope[0])); + } + else + { + newp = (struct r_scope_elem **) + realloc (imap->l_scope, + new_size * sizeof (struct r_scope_elem *)); + if (newp == NULL) + _dl_signal_error (ENOMEM, "dlopen", NULL, + N_("cannot create scope list")); + imap->l_scope = newp; + } + + imap->l_scope_max = new_size; + } + + imap->l_scope[cnt++] = &new->l_searchlist; + imap->l_scope[cnt] = NULL; + } + + /* Run the initializer functions of new objects. */ + _dl_init (new, __libc_argc, __libc_argv, environ); + + /* Now we can make the new map available in the global scope. */ + if (mode & RTLD_GLOBAL) + /* Move the object in the global namespace. */ + if (add_to_global (new) != 0) + /* It failed. */ + return; + + /* Mark the object as not deletable if the RTLD_NODELETE flags was + passed. */ + if (__builtin_expect (mode & RTLD_NODELETE, 0)) + new->l_flags_1 |= DF_1_NODELETE; + + /* Let the user know about the opencount. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) + _dl_debug_printf ("opening file=%s; opencount == %u\n\n", + new->l_name, new->l_opencount); +} + + +void * +internal_function +_dl_open (const char *file, int mode, const void *caller) +{ + struct dl_open_args args; + const char *objname; + const char *errstring; + int errcode; + + if ((mode & RTLD_BINDING_MASK) == 0) + /* One of the flags must be set. */ + _dl_signal_error (EINVAL, file, NULL, N_("invalid mode for dlopen()")); + + /* Make sure we are alone. */ +#ifdef HAVE_DD_LOCK + __lock_acquire_recursive(_dl_load_lock); +#endif + + args.file = file; + args.mode = mode; + args.caller = caller; + args.map = NULL; + errcode = _dl_catch_error (&objname, &errstring, dl_open_worker, &args); + +#ifndef MAP_COPY + /* We must munmap() the cache file. */ + _dl_unload_cache (); +#endif + + /* Release the lock. */ +#ifdef HAVE_DD_LOCK + __lock_release_recursive(_dl_load_lock); +#endif + + + if (errstring) + { + /* Some error occurred during loading. */ + char *local_errstring; + size_t len_errstring; + + /* Remove the object from memory. It may be in an inconsistent + state if relocation failed, for example. */ + if (args.map) + { + unsigned int i; + + /* Increment open counters for all objects since this has + not happened yet. */ + for (i = 0; i < args.map->l_searchlist.r_nlist; ++i) + ++args.map->l_searchlist.r_list[i]->l_opencount; + + _dl_close (args.map); + } + + /* Make a local copy of the error string so that we can release the + memory allocated for it. */ + len_errstring = strlen (errstring) + 1; + if (objname == errstring + len_errstring) + { + size_t total_len = len_errstring + strlen (objname) + 1; + local_errstring = alloca (total_len); + memcpy (local_errstring, errstring, total_len); + objname = local_errstring + len_errstring; + } + else + { + local_errstring = alloca (len_errstring); + memcpy (local_errstring, errstring, len_errstring); + } + + if (errstring != _dl_out_of_memory) + free ((char *) errstring); + + /* Reraise the error. */ + _dl_signal_error (errcode, objname, NULL, local_errstring); + } + +#ifndef SHARED + DL_STATIC_INIT (args.map); +#endif + + return args.map; +} + + +#ifdef SCOPE_DEBUG +#include + +static void +show_scope (struct link_map *new) +{ + int scope_cnt; + + for (scope_cnt = 0; new->l_scope[scope_cnt] != NULL; ++scope_cnt) + { + char numbuf[2]; + unsigned int cnt; + + numbuf[0] = '0' + scope_cnt; + numbuf[1] = '\0'; + _dl_printf ("scope %s:", numbuf); + + for (cnt = 0; cnt < new->l_scope[scope_cnt]->r_nlist; ++cnt) + if (*new->l_scope[scope_cnt]->r_list[cnt]->l_name) + _dl_printf (" %s", new->l_scope[scope_cnt]->r_list[cnt]->l_name); + else + _dl_printf ("
"); + + _dl_printf ("\n"); + } +} +#endif diff --git a/newlib/libc/sys/linux/dl/dl-osinfo.h b/newlib/libc/sys/linux/dl/dl-osinfo.h new file mode 100644 index 000000000..4976b3126 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-osinfo.h @@ -0,0 +1,108 @@ +/* Operating system specific code for generic dynamic loader functions. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include "kernel-features.h" + +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifdef SHARED +/* This is the function used in the dynamic linker to print the fatal error + message. */ +static inline void +__attribute__ ((__noreturn__)) +dl_fatal (const char *str) +{ + _dl_dprintf (2, str); + _exit (1); +} +#endif + + +#define DL_SYSDEP_OSCHECK(FATAL) \ + do { \ + /* Test whether the kernel is new enough. This test is only \ + performed if the library is not compiled to run on all \ + kernels. */ \ + if (__LINUX_KERNEL_VERSION > 0) \ + { \ + char bufmem[64]; \ + char *buf = bufmem; \ + unsigned int version; \ + int parts; \ + char *cp; \ + struct utsname uts; \ + \ + /* Try the uname syscall */ \ + if (__uname (&uts)) \ + { \ + /* This was not successful. Now try reading the /proc \ + filesystem. */ \ + ssize_t reslen; \ + int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY); \ + if (fd == -1 \ + || (reslen = __read (fd, bufmem, sizeof (bufmem))) <= 0) \ + /* This also didn't work. We give up since we cannot \ + make sure the library can actually work. */ \ + FATAL ("FATAL: cannot determine library version\n"); \ + __close (fd); \ + buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0'; \ + } \ + else \ + buf = uts.release; \ + \ + /* Now convert it into a number. The string consists of at most \ + three parts. */ \ + version = 0; \ + parts = 0; \ + cp = buf; \ + while ((*cp >= '0') && (*cp <= '9')) \ + { \ + unsigned int here = *cp++ - '0'; \ + \ + while ((*cp >= '0') && (*cp <= '9')) \ + { \ + here *= 10; \ + here += *cp++ - '0'; \ + } \ + \ + ++parts; \ + version <<= 8; \ + version |= here; \ + \ + if (*cp++ != '.') \ + /* Another part following? */ \ + break; \ + } \ + \ + if (parts < 3) \ + version <<= 8 * (3 - parts); \ + \ + /* Now we can test with the required version. */ \ + if (version < __LINUX_KERNEL_VERSION) \ + /* Not sufficent. */ \ + FATAL ("FATAL: kernel too old\n"); \ + \ + _dl_osversion = version; \ + } \ + } while (0) diff --git a/newlib/libc/sys/linux/dl/dl-profile.c b/newlib/libc/sys/linux/dl/dl-profile.c new file mode 100644 index 000000000..52c533f5f --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-profile.c @@ -0,0 +1,539 @@ +/* Profiling of shared libraries. + Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1997. + Based on the BSD mcount implementation. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The LD_PROFILE feature has to be implemented different to the + normal profiling using the gmon/ functions. The problem is that an + arbitrary amount of processes simulataneously can be run using + profiling and all write the results in the same file. To provide + this mechanism one could implement a complicated mechanism to merge + the content of two profiling runs or one could extend the file + format to allow more than one data set. For the second solution we + would have the problem that the file can grow in size beyond any + limit and both solutions have the problem that the concurrency of + writing the results is a big problem. + + Another much simpler method is to use mmap to map the same file in + all using programs and modify the data in the mmap'ed area and so + also automatically on the disk. Using the MAP_SHARED option of + mmap(2) this can be done without big problems in more than one + file. + + This approach is very different from the normal profiling. We have + to use the profiling data in exactly the way they are expected to + be written to disk. But the normal format used by gprof is not usable + to do this. It is optimized for size. It writes the tags as single + bytes but this means that the following 32/64 bit values are + unaligned. + + Therefore we use a new format. This will look like this + + 0 1 2 3 <- byte is 32 bit word + 0000 g m o n + 0004 *version* <- GMON_SHOBJ_VERSION + 0008 00 00 00 00 + 000c 00 00 00 00 + 0010 00 00 00 00 + + 0014 *tag* <- GMON_TAG_TIME_HIST + 0018 ?? ?? ?? ?? + ?? ?? ?? ?? <- 32/64 bit LowPC + 0018+A ?? ?? ?? ?? + ?? ?? ?? ?? <- 32/64 bit HighPC + 0018+2*A *histsize* + 001c+2*A *profrate* + 0020+2*A s e c o + 0024+2*A n d s \0 + 0028+2*A \0 \0 \0 \0 + 002c+2*A \0 \0 \0 + 002f+2*A s + + 0030+2*A ?? ?? ?? ?? <- Count data + ... ... + 0030+2*A+K ?? ?? ?? ?? + + 0030+2*A+K *tag* <- GMON_TAG_CG_ARC + 0034+2*A+K *lastused* + 0038+2*A+K ?? ?? ?? ?? + ?? ?? ?? ?? <- FromPC#1 + 0038+3*A+K ?? ?? ?? ?? + ?? ?? ?? ?? <- ToPC#1 + 0038+4*A+K ?? ?? ?? ?? <- Count#1 + ... ... ... + 0038+(2*(CN-1)+2)*A+(CN-1)*4+K ?? ?? ?? ?? + ?? ?? ?? ?? <- FromPC#CGN + 0038+(2*(CN-1)+3)*A+(CN-1)*4+K ?? ?? ?? ?? + ?? ?? ?? ?? <- ToPC#CGN + 0038+(2*CN+2)*A+(CN-1)*4+K ?? ?? ?? ?? <- Count#CGN + + We put (for now?) no basic block information in the file since this would + introduce rase conditions among all the processes who want to write them. + + `K' is the number of count entries which is computed as + + textsize / HISTFRACTION + + `CG' in the above table is the number of call graph arcs. Normally, + the table is sparse and the profiling code writes out only the those + entries which are really used in the program run. But since we must + not extend this table (the profiling file) we'll keep them all here. + So CN can be executed in advance as + + MINARCS <= textsize*(ARCDENSITY/100) <= MAXARCS + + Now the remaining question is: how to build the data structures we can + work with from this data. We need the from set and must associate the + froms with all the associated tos. We will do this by constructing this + data structures at the program start. To do this we'll simply visit all + entries in the call graph table and add it to the appropriate list. */ + +extern int __profile_frequency (void); + +/* We define a special type to address the elements of the arc table. + This is basically the `gmon_cg_arc_record' format but it includes + the room for the tag and it uses real types. */ +struct here_cg_arc_record + { + uintptr_t from_pc; + uintptr_t self_pc; + uint32_t count; + } __attribute__ ((packed)); + +static struct here_cg_arc_record *data; + +/* Nonzero if profiling is under way. */ +static int running; + +/* This is the number of entry which have been incorporated in the toset. */ +static uint32_t narcs; +/* This is a pointer to the object representing the number of entries + currently in the mmaped file. At no point of time this has to be the + same as NARCS. If it is equal all entries from the file are in our + lists. */ +static volatile uint32_t *narcsp; + +static volatile uint16_t *kcount; +static size_t kcountsize; + +struct here_fromstruct + { + struct here_cg_arc_record volatile *here; + uint16_t link; + }; + +static volatile uint16_t *tos; + +static struct here_fromstruct *froms; +static uint32_t fromlimit; +static volatile uint32_t fromidx; + +static uintptr_t lowpc; +static size_t textsize; +static unsigned int hashfraction; +static unsigned int log_hashfraction; + + + +/* Set up profiling data to profile object desribed by MAP. The output + file is found (or created) in OUTPUT_DIR. */ +void +internal_function +_dl_start_profile (struct link_map *map, const char *output_dir) +{ + char *filename; + int fd; + struct stat64 st; + const ElfW(Phdr) *ph; + ElfW(Addr) mapstart = ~((ElfW(Addr)) 0); + ElfW(Addr) mapend = 0; + struct gmon_hdr gmon_hdr; + struct gmon_hist_hdr hist_hdr; + char *hist, *cp, *tmp; + size_t idx; + size_t tossize; + size_t fromssize; + uintptr_t highpc; + struct gmon_hdr *addr = NULL; + off_t expected_size; + /* See profil(2) where this is described. */ + int s_scale; +#define SCALE_1_TO_1 0x10000L + + /* Compute the size of the sections which contain program code. */ + for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph) + if (ph->p_type == PT_LOAD && (ph->p_flags & PF_X)) + { + ElfW(Addr) start = (ph->p_vaddr & ~(_dl_pagesize - 1)); + ElfW(Addr) end = ((ph->p_vaddr + ph->p_memsz + _dl_pagesize - 1) + & ~(_dl_pagesize - 1)); + + if (start < mapstart) + mapstart = start; + if (end > mapend) + mapend = end; + } + + /* Now we can compute the size of the profiling data. This is done + with the same formulars as in `monstartup' (see gmon.c). */ + running = 0; + lowpc = ROUNDDOWN (mapstart + map->l_addr, + HISTFRACTION * sizeof (HISTCOUNTER)); + highpc = ROUNDUP (mapend + map->l_addr, + HISTFRACTION * sizeof (HISTCOUNTER)); + textsize = highpc - lowpc; + kcountsize = textsize / HISTFRACTION; + hashfraction = HASHFRACTION; + if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) + /* If HASHFRACTION is a power of two, mcount can use shifting + instead of integer division. Precompute shift amount. */ + log_hashfraction = ffs (hashfraction * sizeof (*froms)) - 1; + else + log_hashfraction = -1; + tossize = textsize / HASHFRACTION; + fromlimit = textsize * ARCDENSITY / 100; + if (fromlimit < MINARCS) + fromlimit = MINARCS; + if (fromlimit > MAXARCS) + fromlimit = MAXARCS; + fromssize = fromlimit * sizeof (struct here_fromstruct); + + expected_size = (sizeof (struct gmon_hdr) + + 4 + sizeof (struct gmon_hist_hdr) + kcountsize + + 4 + 4 + fromssize * sizeof (struct here_cg_arc_record)); + + /* Create the gmon_hdr we expect or write. */ + memset (&gmon_hdr, '\0', sizeof (struct gmon_hdr)); + memcpy (&gmon_hdr.cookie[0], GMON_MAGIC, sizeof (gmon_hdr.cookie)); + *(int32_t *) gmon_hdr.version = GMON_SHOBJ_VERSION; + + /* Create the hist_hdr we expect or write. */ + *(char **) hist_hdr.low_pc = (char *) mapstart; + *(char **) hist_hdr.high_pc = (char *) mapend; + *(int32_t *) hist_hdr.hist_size = kcountsize / sizeof (HISTCOUNTER); + *(int32_t *) hist_hdr.prof_rate = __profile_frequency (); + strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen)); + hist_hdr.dimen_abbrev = 's'; + + /* First determine the output name. We write in the directory + OUTPUT_DIR and the name is composed from the shared objects + soname (or the file name) and the ending ".profile". */ + filename = (char *) alloca (strlen (output_dir) + 1 + strlen (_dl_profile) + + sizeof ".profile"); + cp = strcpy (filename, output_dir); + cp += strlen (output_dir); + *cp++ = '/'; + tmp = strcpy (cp, _dl_profile); + tmp += strlen (_dl_profile); + strcpy (tmp, ".profile"); + +#ifdef O_NOFOLLOW +# define EXTRA_FLAGS | O_NOFOLLOW +#else +# define EXTRA_FLAGS +#endif + fd = __open (filename, O_RDWR | O_CREAT EXTRA_FLAGS); + if (fd == -1) + { + /* We cannot write the profiling data so don't do anything. */ + char buf[400]; + _dl_error_printf ("%s: cannot open file: %s\n", filename, + __strerror_r (errno, buf, sizeof buf)); + return; + } + + if (fstat64 (fd, &st) < 0 || !S_ISREG (st.st_mode)) + { + /* Not stat'able or not a regular file => don't use it. */ + char buf[400]; + int errnum = errno; + __close (fd); + _dl_error_printf ("%s: cannot stat file: %s\n", filename, + __strerror_r (errnum, buf, sizeof buf)); + return; + } + + /* Test the size. If it does not match what we expect from the size + values in the map MAP we don't use it and warn the user. */ + if (st.st_size == 0) + { + /* We have to create the file. */ + char buf[_dl_pagesize]; + + memset (buf, '\0', _dl_pagesize); + + if (__lseek (fd, expected_size & ~(_dl_pagesize - 1), SEEK_SET) == -1) + { + char buf[400]; + int errnum; + cannot_create: + errnum = errno; + __close (fd); + _dl_error_printf ("%s: cannot create file: %s\n", filename, + __strerror_r (errnum, buf, sizeof buf)); + return; + } + + if (TEMP_FAILURE_RETRY (__libc_write (fd, buf, (expected_size + & (_dl_pagesize - 1)))) + < 0) + goto cannot_create; + } + else if (st.st_size != expected_size) + { + __close (fd); + wrong_format: + + if (addr != NULL) + __munmap ((void *) addr, expected_size); + + _dl_error_printf ("%s: file is no correct profile data file for `%s'\n", + filename, _dl_profile); + return; + } + + addr = (struct gmon_hdr *) __mmap (NULL, expected_size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_FILE, fd, 0); + if (addr == (struct gmon_hdr *) MAP_FAILED) + { + char buf[400]; + int errnum = errno; + __close (fd); + _dl_error_printf ("%s: cannot map file: %s\n", filename, + __strerror_r (errnum, buf, sizeof buf)); + return; + } + + /* We don't need the file desriptor anymore. */ + __close (fd); + + /* Pointer to data after the header. */ + hist = (char *) (addr + 1); + kcount = (uint16_t *) ((char *) hist + sizeof (uint32_t) + + sizeof (struct gmon_hist_hdr)); + + /* Compute pointer to array of the arc information. */ + narcsp = (uint32_t *) ((char *) kcount + kcountsize + sizeof (uint32_t)); + data = (struct here_cg_arc_record *) ((char *) narcsp + sizeof (uint32_t)); + + if (st.st_size == 0) + { + /* Create the signature. */ + memcpy (addr, &gmon_hdr, sizeof (struct gmon_hdr)); + + *(uint32_t *) hist = GMON_TAG_TIME_HIST; + memcpy (hist + sizeof (uint32_t), &hist_hdr, + sizeof (struct gmon_hist_hdr)); + + narcsp[-1] = GMON_TAG_CG_ARC; + } + else + { + /* Test the signature in the file. */ + if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0 + || *(uint32_t *) hist != GMON_TAG_TIME_HIST + || memcmp (hist + sizeof (uint32_t), &hist_hdr, + sizeof (struct gmon_hist_hdr)) != 0 + || narcsp[-1] != GMON_TAG_CG_ARC) + goto wrong_format; + } + + /* Allocate memory for the froms data and the pointer to the tos records. */ + tos = (uint16_t *) calloc (tossize + fromssize, 1); + if (tos == NULL) + { + __munmap ((void *) addr, expected_size); + _dl_fatal_printf ("Out of memory while initializing profiler\n"); + /* NOTREACHED */ + } + + froms = (struct here_fromstruct *) ((char *) tos + tossize); + fromidx = 0; + + /* Now we have to process all the arc count entries. BTW: it is + not critical whether the *NARCSP value changes meanwhile. Before + we enter a new entry in to toset we will check that everything is + available in TOS. This happens in _dl_mcount. + + Loading the entries in reverse order should help to get the most + frequently used entries at the front of the list. */ + for (idx = narcs = MIN (*narcsp, fromlimit); idx > 0; ) + { + size_t to_index; + size_t newfromidx; + --idx; + to_index = (data[idx].self_pc / (hashfraction * sizeof (*tos))); + newfromidx = fromidx++; + froms[newfromidx].here = &data[idx]; + froms[newfromidx].link = tos[to_index]; + tos[to_index] = newfromidx; + } + + /* Setup counting data. */ + if (kcountsize < highpc - lowpc) + { +#if 0 + s_scale = ((double) kcountsize / (highpc - lowpc)) * SCALE_1_TO_1; +#else + size_t range = highpc - lowpc; + size_t quot = range / kcountsize; + + if (quot >= SCALE_1_TO_1) + s_scale = 1; + else if (quot >= SCALE_1_TO_1 / 256) + s_scale = SCALE_1_TO_1 / quot; + else if (range > ULONG_MAX / 256) + s_scale = (SCALE_1_TO_1 * 256) / (range / (kcountsize / 256)); + else + s_scale = (SCALE_1_TO_1 * 256) / ((range * 256) / kcountsize); +#endif + } + else + s_scale = SCALE_1_TO_1; + + /* Start the profiler. */ + profil ((void *) kcount, kcountsize, lowpc, s_scale); + + /* Turn on profiling. */ + running = 1; +} + + +void +_dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc) +{ + volatile uint16_t *topcindex; + size_t i, fromindex; + struct here_fromstruct *fromp; + + if (! running) + return; + + /* Compute relative addresses. The shared object can be loaded at + any address. The value of frompc could be anything. We cannot + restrict it in any way, just set to a fixed value (0) in case it + is outside the allowed range. These calls show up as calls from + in the gprof output. */ + frompc -= lowpc; + if (frompc >= textsize) + frompc = 0; + selfpc -= lowpc; + if (selfpc >= textsize) + goto done; + + /* Getting here we now have to find out whether the location was + already used. If yes we are lucky and only have to increment a + counter (this also has to be atomic). If the entry is new things + are getting complicated... */ + + /* Avoid integer divide if possible. */ + if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) + i = selfpc >> log_hashfraction; + else + i = selfpc / (hashfraction * sizeof (*tos)); + + topcindex = &tos[i]; + fromindex = *topcindex; + + if (fromindex == 0) + goto check_new_or_add; + + fromp = &froms[fromindex]; + + /* We have to look through the chain of arcs whether there is already + an entry for our arc. */ + while (fromp->here->from_pc != frompc) + { + if (fromp->link != 0) + do + fromp = &froms[fromp->link]; + while (fromp->link != 0 && fromp->here->from_pc != frompc); + + if (fromp->here->from_pc != frompc) + { + topcindex = &fromp->link; + + check_new_or_add: + /* Our entry is not among the entries we read so far from the + data file. Now see whether we have to update the list. */ + while (narcs != *narcsp && narcs < fromlimit) + { + size_t to_index; + size_t newfromidx; + to_index = (data[narcs].self_pc + / (hashfraction * sizeof (*tos))); + newfromidx = exchange_and_add (&fromidx, 1) + 1; + froms[newfromidx].here = &data[narcs]; + froms[newfromidx].link = tos[to_index]; + tos[to_index] = newfromidx; + atomic_add (&narcs, 1); + } + + /* If we still have no entry stop searching and insert. */ + if (*topcindex == 0) + { + uint32_t newarc = exchange_and_add (narcsp, 1); + + /* In rare cases it could happen that all entries in FROMS are + occupied. So we cannot count this anymore. */ + if (newarc >= fromlimit) + goto done; + + *topcindex = exchange_and_add (&fromidx, 1) + 1; + fromp = &froms[*topcindex]; + + fromp->here = &data[newarc]; + data[newarc].from_pc = frompc; + data[newarc].self_pc = selfpc; + data[newarc].count = 0; + fromp->link = 0; + atomic_add (&narcs, 1); + + break; + } + + fromp = &froms[*topcindex]; + } + else + /* Found in. */ + break; + } + + /* Increment the counter. */ + atomic_add (&fromp->here->count, 1); + + done: + ; +} diff --git a/newlib/libc/sys/linux/dl/dl-profstub.c b/newlib/libc/sys/linux/dl/dl-profstub.c new file mode 100644 index 000000000..41758864b --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-profstub.c @@ -0,0 +1,43 @@ +/* Helper definitions for profiling of shared libraries. + Copyright (C) 1998, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1997. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include + +/* This is the map for the shared object we profile. It is defined here + only because we test for this value being NULL or not. */ +extern struct link_map *_dl_profile_map; + + +void +_dl_mcount_wrapper (void *selfpc) +{ + _dl_mcount ((ElfW(Addr)) RETURN_ADDRESS (0), (ElfW(Addr)) selfpc); +} + + +void +_dl_mcount_wrapper_check (void *selfpc) +{ + if (_dl_profile_map != NULL) + _dl_mcount ((ElfW(Addr)) RETURN_ADDRESS (0), (ElfW(Addr)) selfpc); +} diff --git a/newlib/libc/sys/linux/dl/dl-reloc.c b/newlib/libc/sys/linux/dl/dl-reloc.c new file mode 100644 index 000000000..94163143e --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-reloc.c @@ -0,0 +1,213 @@ +/* Relocate a shared object and resolve its references to other loaded objects. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "dynamic-link.h" + +/* Statistics function. */ +unsigned long int _dl_num_cache_relocations; + + +void +_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + int lazy, int consider_profiling) +{ + struct textrels + { + caddr_t start; + size_t len; + int prot; + struct textrels *next; + } *textrels = NULL; + /* Initialize it to make the compiler happy. */ + const char *errstring = NULL; + + if (l->l_relocated) + return; + + /* If DT_BIND_NOW is set relocate all references in this object. We + do not do this if we are profiling, of course. */ + if (!consider_profiling + && __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0)) + lazy = 0; + + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_RELOC, 0)) + _dl_printf ("\nrelocation processing: %s%s\n", + l->l_name[0] ? l->l_name : _dl_argv[0], lazy ? " (lazy)" : ""); + + /* DT_TEXTREL is now in level 2 and might phase out at some time. + But we rewrite the DT_FLAGS entry to a DT_TEXTREL entry to make + testing easier and therefore it will be available at all time. */ + if (__builtin_expect (l->l_info[DT_TEXTREL] != NULL, 0)) + { + /* Bletch. We must make read-only segments writable + long enough to relocate them. */ + const ElfW(Phdr) *ph; + for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph) + if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0) + { + struct textrels *newp; + + newp = (struct textrels *) alloca (sizeof (*newp)); + newp->len = (((ph->p_vaddr + ph->p_memsz + _dl_pagesize - 1) + & ~(_dl_pagesize - 1)) + - (ph->p_vaddr & ~(_dl_pagesize - 1))); + newp->start = ((ph->p_vaddr & ~(_dl_pagesize - 1)) + + (caddr_t) l->l_addr); + + if (mprotect (newp->start, newp->len, PROT_READ|PROT_WRITE) < 0) + { + errstring = N_("cannot make segment writable for relocation"); + call_error: + _dl_signal_error (errno, l->l_name, NULL, errstring); + } + +#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7 + newp->prot = (PF_TO_PROT + >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf; +#else + newp->prot = 0; + if (ph->p_flags & PF_R) + newp->prot |= PROT_READ; + if (ph->p_flags & PF_W) + newp->prot |= PROT_WRITE; + if (ph->p_flags & PF_X) + newp->prot |= PROT_EXEC; +#endif + newp->next = textrels; + textrels = newp; + } + } + + { + /* Do the actual relocation of the object's GOT and other data. */ + + /* String table object symbols. */ + const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); + + /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */ +#define RESOLVE_MAP(ref, version, r_type) \ + (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \ + ? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0) \ + && elf_machine_type_class (r_type) == l->l_lookup_cache.type_class) \ + ? (++_dl_num_cache_relocations, \ + (*ref) = l->l_lookup_cache.ret, \ + l->l_lookup_cache.value) \ + : ({ lookup_t _lr; \ + int _tc = elf_machine_type_class (r_type); \ + l->l_lookup_cache.type_class = _tc; \ + l->l_lookup_cache.sym = (*ref); \ + _lr = ((version) != NULL && (version)->hash != 0 \ + ? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, \ + l, (ref), scope, \ + (version), _tc, 0) \ + : _dl_lookup_symbol (strtab + (*ref)->st_name, l, (ref), \ + scope, _tc, 0)); \ + l->l_lookup_cache.ret = (*ref); \ + l->l_lookup_cache.value = _lr; })) \ + : l) +#define RESOLVE(ref, version, r_type) \ + (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \ + ? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0) \ + && elf_machine_type_class (r_type) == l->l_lookup_cache.type_class) \ + ? (++_dl_num_cache_relocations, \ + (*ref) = l->l_lookup_cache.ret, \ + l->l_lookup_cache.value) \ + : ({ lookup_t _lr; \ + int _tc = elf_machine_type_class (r_type); \ + l->l_lookup_cache.type_class = _tc; \ + l->l_lookup_cache.sym = (*ref); \ + _lr = ((version) != NULL && (version)->hash != 0 \ + ? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, \ + l, (ref), scope, \ + (version), _tc, 0) \ + : _dl_lookup_symbol (strtab + (*ref)->st_name, l, (ref), \ + scope, _tc, 0)); \ + l->l_lookup_cache.ret = (*ref); \ + l->l_lookup_cache.value = _lr; })) \ + : l->l_addr) + +#include "dynamic-link.h" + + ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling); + + if (__builtin_expect (consider_profiling, 0)) + { + /* Allocate the array which will contain the already found + relocations. If the shared object lacks a PLT (for example + if it only contains lead function) the l_info[DT_PLTRELSZ] + will be NULL. */ + if (l->l_info[DT_PLTRELSZ] == NULL) + { + errstring = N_("%s: profiler found no PLTREL in object %s\n"); + fatal: + _dl_fatal_printf (errstring, + _dl_argv[0] ?: "", + l->l_name); + } + + l->l_reloc_result = + (ElfW(Addr) *) calloc (sizeof (ElfW(Addr)), + l->l_info[DT_PLTRELSZ]->d_un.d_val); + if (l->l_reloc_result == NULL) + { + errstring = N_("\ +%s: profiler out of memory shadowing PLTREL of %s\n"); + goto fatal; + } + } + } + + /* Mark the object so we know this work has been done. */ + l->l_relocated = 1; + + /* Undo the segment protection changes. */ + while (__builtin_expect (textrels != NULL, 0)) + { + if (mprotect (textrels->start, textrels->len, textrels->prot) < 0) + { + errstring = N_("cannot restore segment prot after reloc"); + goto call_error; + } + + textrels = textrels->next; + } +} + + +void +internal_function +_dl_reloc_bad_type (struct link_map *map, unsigned int type, int plt) +{ + /* XXX We cannot translate these messages. */ + static const char msg[2][32] = { "unexpected reloc type", + "unexpected PLT reloc type" }; + char msgbuf[sizeof (msg[0])]; + + strcpy (msgbuf, msg[plt]); + + _dl_signal_error (0, map->l_name, NULL, msgbuf); +} diff --git a/newlib/libc/sys/linux/dl/dl-runtime.c b/newlib/libc/sys/linux/dl/dl-runtime.c new file mode 100644 index 000000000..111acfb71 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-runtime.c @@ -0,0 +1,231 @@ +/* On-demand PLT fixup for shared objects. + Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include "dynamic-link.h" + +#define __attribute_used__ + +#if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL +# define PLTREL ElfW(Rela) +#else +# define PLTREL ElfW(Rel) +#endif + +#ifndef VERSYMIDX +# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym)) +#endif + + +/* This function is called through a special trampoline from the PLT the + first time each PLT entry is called. We must perform the relocation + specified in the PLT of the given shared object, and return the resolved + function address to the trampoline, which will restart the original call + to that address. Future calls will bounce directly from the PLT to the + function. */ + +#ifndef ELF_MACHINE_NO_PLT +static ElfW(Addr) __attribute_used__ +fixup ( +# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS + ELF_MACHINE_RUNTIME_FIXUP_ARGS, +# endif + /* GKM FIXME: Fix trampoline to pass bounds so we can do + without the `__unbounded' qualifier. */ + struct link_map *__unbounded l, ElfW(Word) reloc_offset) +{ + const ElfW(Sym) *const symtab + = (const void *) D_PTR (l, l_info[DT_SYMTAB]); + const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); + + const PLTREL *const reloc + = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset); + const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; + void *const rel_addr = (void *)(l->l_addr + reloc->r_offset); + lookup_t result; + ElfW(Addr) value; + + /* The use of `alloca' here looks ridiculous but it helps. The goal is + to prevent the function from being inlined and thus optimized out. + There is no official way to do this so we use this trick. gcc never + inlines functions which use `alloca'. */ + alloca (sizeof (int)); + + /* Sanity check that we're really looking at a PLT relocation. */ + assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); + + /* Look up the target symbol. If the normal lookup rules are not + used don't look in the global scope. */ + if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) + { + switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) + { + default: + { + const ElfW(Half) *vernum = + (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]); + ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)]; + const struct r_found_version *version = &l->l_versions[ndx]; + + if (version->hash != 0) + { + result = _dl_lookup_versioned_symbol (strtab + sym->st_name, + l, &sym, l->l_scope, + version, + ELF_RTYPE_CLASS_PLT, 0); + break; + } + } + case 0: + result = _dl_lookup_symbol (strtab + sym->st_name, l, &sym, + l->l_scope, ELF_RTYPE_CLASS_PLT, 0); + } + + /* Currently result contains the base load address (or link map) + of the object that defines sym. Now add in the symbol + offset. */ + value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0); + } + else + { + /* We already found the symbol. The module (and therefore its load + address) is also known. */ + value = l->l_addr + sym->st_value; +#ifdef DL_LOOKUP_RETURNS_MAP + result = l; +#endif + } + + /* And now perhaps the relocation addend. */ + value = elf_machine_plt_value (l, reloc, value); + + /* Finally, fix up the plt itself. */ + if (__builtin_expect (_dl_bind_not, 0)) + return value; + + return elf_machine_fixup_plt (l, result, reloc, rel_addr, value); +} +#endif + +#if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__ + +static ElfW(Addr) __attribute_used__ +profile_fixup ( +#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS + ELF_MACHINE_RUNTIME_FIXUP_ARGS, +#endif + struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr) +{ + void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = _dl_mcount; + ElfW(Addr) *resultp; + lookup_t result; + ElfW(Addr) value; + + /* The use of `alloca' here looks ridiculous but it helps. The goal is + to prevent the function from being inlined, and thus optimized out. + There is no official way to do this so we use this trick. gcc never + inlines functions which use `alloca'. */ + alloca (sizeof (int)); + + /* This is the address in the array where we store the result of previous + relocations. */ + resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)]; + + value = *resultp; + if (value == 0) + { + /* This is the first time we have to relocate this object. */ + const ElfW(Sym) *const symtab + = (const void *) D_PTR (l, l_info[DT_SYMTAB]); + const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); + + const PLTREL *const reloc + = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset); + const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; + + /* Sanity check that we're really looking at a PLT relocation. */ + assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); + + /* Look up the target symbol. If the symbol is marked STV_PROTECTED + don't look in the global scope. */ + if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) + { + switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) + { + default: + { + const ElfW(Half) *vernum = + (const void *) D_PTR (l,l_info[VERSYMIDX (DT_VERSYM)]); + ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)]; + const struct r_found_version *version = &l->l_versions[ndx]; + + if (version->hash != 0) + { + result = _dl_lookup_versioned_symbol(strtab + sym->st_name, + l, &sym, l->l_scope, + version, + ELF_RTYPE_CLASS_PLT, + 0); + break; + } + } + case 0: + result = _dl_lookup_symbol (strtab + sym->st_name, l, &sym, + l->l_scope, ELF_RTYPE_CLASS_PLT, 0); + } + + /* Currently result contains the base load address (or link map) + of the object that defines sym. Now add in the symbol + offset. */ + value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0); + } + else + { + /* We already found the symbol. The module (and therefore its load + address) is also known. */ + value = l->l_addr + sym->st_value; +#ifdef DL_LOOKUP_RETURNS_MAP + result = l; +#endif + } + /* And now perhaps the relocation addend. */ + value = elf_machine_plt_value (l, reloc, value); + + /* Store the result for later runs. */ + if (__builtin_expect (! _dl_bind_not, 1)) + *resultp = value; + } + + (*mcount_fct) (retaddr, value); + + return value; +} + +#endif /* PROF && ELF_MACHINE_NO_PLT */ + + +/* This macro is defined in dl-machine.h to define the entry point called + by the PLT. The `fixup' function above does the real work, but a little + more twiddling is needed to get the stack right and jump to the address + finally resolved. */ + +ELF_MACHINE_RUNTIME_TRAMPOLINE diff --git a/newlib/libc/sys/linux/dl/dl-support.c b/newlib/libc/sys/linux/dl/dl-support.c new file mode 100644 index 000000000..b7cb560a6 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-support.c @@ -0,0 +1,184 @@ +/* Support for dynamic linking code in static libc. + Copyright (C) 1996, 97, 98, 99, 2000, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This file defines some things that for the dynamic linker are defined in + rtld.c and dl-sysdep.c in ways appropriate to bootstrap dynamic linking. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *__progname = "newlib"; +char **_dl_argv = &__progname; /* This is checked for some error messages. */ + +/* Name of the architecture. */ +const char *_dl_platform; +size_t _dl_platformlen; + +int _dl_debug_mask; +int _dl_lazy; +/* XXX I know about at least one case where we depend on the old weak + behavior (it has to do with librt). Until we get DSO groups implemented + we have to make this the default. Bummer. --drepper */ +#if 0 +int _dl_dynamic_weak; +#else +int _dl_dynamic_weak = 1; +#endif + +/* If nonzero print warnings about problematic situations. */ +int _dl_verbose; + +/* Structure to store information about search paths. */ +struct r_search_path *_dl_search_paths; + +/* We never do profiling. */ +const char *_dl_profile; + +/* Names of shared object for which the RUNPATHs and RPATHs should be + ignored. */ +const char *_dl_inhibit_rpath; + +/* The map for the object we will profile. */ +struct link_map *_dl_profile_map; + +/* This is the address of the last stack address ever used. */ +void *__libc_stack_end; + +/* Path where the binary is found. */ +const char *_dl_origin_path; + +/* Nonzero if runtime lookup should not update the .got/.plt. */ +int _dl_bind_not; + +/* Initially empty list of loaded objects. */ +struct link_map *_dl_loaded; +/* Number of object in the _dl_loaded list. */ +unsigned int _dl_nloaded; + +/* Fake scope. In dynamically linked binaries this is the scope of the + main application but here we don't have something like this. So + create a fake scope containing nothing. */ +struct r_scope_elem _dl_initial_searchlist; +/* Variable which can be used in lookup to process the global scope. */ +struct r_scope_elem *_dl_global_scope[2] = { &_dl_initial_searchlist, NULL }; +/* This is a global pointer to this structure which is public. It is + used by dlopen/dlclose to add and remove objects from what is regarded + to be the global scope. */ +struct r_scope_elem *_dl_main_searchlist = &_dl_initial_searchlist; + +/* Nonzero during startup. */ +int _dl_starting_up = 1; + +/* We expect less than a second for relocation. */ +#ifdef HP_SMALL_TIMING_AVAIL +# undef HP_TIMING_AVAIL +# define HP_TIMING_AVAIL HP_SMALL_TIMING_AVAIL +#endif + +/* Initial value of the CPU clock. */ +#ifndef HP_TIMING_NONAVAIL +hp_timing_t _dl_cpuclock_offset; +#endif + +/* During the program run we must not modify the global data of + loaded shared object simultanously in two threads. Therefore we + protect `_dl_open' and `_dl_close' in dl-close.c. + + This must be a recursive lock since the initializer function of + the loaded object might as well require a call to this function. + At this time it is not anymore a problem to modify the tables. */ +__LOCK_RECURSIVE_INIT (, _dl_load_lock) + + +#ifdef HAVE_AUX_VECTOR +extern int _dl_clktck; + +void +internal_function +_dl_aux_init (ElfW(auxv_t) *av) +{ + for (; av->a_type != AT_NULL; ++av) + switch (av->a_type) + { + case AT_PAGESZ: + _dl_pagesize = av->a_un.a_val; + break; + case AT_CLKTCK: + _dl_clktck = av->a_un.a_val; + break; + } +} +#endif + +void non_dynamic_init (void) __attribute__ ((unused)); + +void +non_dynamic_init (void) +{ + if (HP_TIMING_AVAIL) + HP_TIMING_NOW (_dl_cpuclock_offset); + + if (!_dl_pagesize) + _dl_pagesize = __getpagesize (); + + _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; + + /* Initialize the data structures for the search paths for shared + objects. */ + _dl_init_paths (getenv ("LD_LIBRARY_PATH")); + + _dl_lazy = *(getenv ("LD_BIND_NOW") ?: "") == '\0'; + + _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0'; + + _dl_dynamic_weak = *(getenv ("LD_DYNAMIC_WEAK") ?: "") == '\0'; + +#ifdef DL_PLATFORM_INIT + DL_PLATFORM_INIT; +#endif + + /* Now determine the length of the platform string. */ + if (_dl_platform != NULL) + _dl_platformlen = strlen (_dl_platform); +} +text_set_element (__libc_subinit, non_dynamic_init); + +const struct r_strlenpair * +internal_function +_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + size_t *max_capstrlen) +{ + static struct r_strlenpair result; + static char buf[1]; + + result.str = buf; /* Does not really matter. */ + result.len = 0; + + *sz = 1; + return &result; +} diff --git a/newlib/libc/sys/linux/dl/dl-sym.c b/newlib/libc/sys/linux/dl/dl-sym.c new file mode 100644 index 000000000..85d084f7f --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-sym.c @@ -0,0 +1,158 @@ +/* Look up a symbol in a shared object loaded by `dlopen'. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +#include +#include +#include + +void * +internal_function +_dl_sym (void *handle, const char *name, void *who) +{ + const ElfW(Sym) *ref = NULL; + lookup_t result; + ElfW(Addr) caller = (ElfW(Addr)) who; + struct link_map *match; + struct link_map *l; + + /* If the address is not recognized the call comes from the main + program (we hope). */ + match = _dl_loaded; + + /* Find the highest-addressed object that CALLER is not below. */ + for (l = _dl_loaded; l != NULL; l = l->l_next) + if (caller >= l->l_map_start && caller < l->l_map_end) + { + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ + match = l; + break; + } + + if (handle == RTLD_DEFAULT) + /* Search the global scope as seen in the caller object. */ + result = _dl_lookup_symbol (name, match, &ref, match->l_scope, 0, 0); + else + { + if (handle != RTLD_NEXT) + { + /* Search the scope of the given object. */ + struct link_map *map = handle; + + result = _dl_lookup_symbol (name, match, &ref, map->l_local_scope, + 0, 1); + } + else + { + if (__builtin_expect (match == _dl_loaded, 0)) + { + if (! _dl_loaded + || caller < _dl_loaded->l_map_start + || caller >= _dl_loaded->l_map_end) + _dl_signal_error (0, NULL, NULL, N_("\ +RTLD_NEXT used in code not dynamically loaded")); + } + + l = match; + while (l->l_loader != NULL) + l = l->l_loader; + + result = _dl_lookup_symbol_skip (name, l, &ref, l->l_local_scope, + match); + } + } + + if (ref != NULL) + return DL_SYMBOL_ADDRESS (result, ref); + + return NULL; +} + +void * +internal_function +_dl_vsym (void *handle, const char *name, const char *version, void *who) +{ + const ElfW(Sym) *ref = NULL; + struct r_found_version vers; + lookup_t result; + ElfW(Addr) caller = (ElfW(Addr)) who; + struct link_map *match; + struct link_map *l; + + /* Compute hash value to the version string. */ + vers.name = version; + vers.hidden = 1; + vers.hash = _dl_elf_hash (version); + /* We don't have a specific file where the symbol can be found. */ + vers.filename = NULL; + + /* If the address is not recognized the call comes from the main + program (we hope). */ + match = _dl_loaded; + + /* Find the highest-addressed object that CALLER is not below. */ + for (l = _dl_loaded; l != NULL; l = l->l_next) + if (caller >= l->l_map_start && caller < l->l_map_end) + { + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ + match = l; + break; + } + + if (handle == RTLD_DEFAULT) + /* Search the global scope. */ + result = _dl_lookup_versioned_symbol (name, match, &ref, match->l_scope, + &vers, 0, 0); + else if (handle == RTLD_NEXT) + { + if (__builtin_expect (match == _dl_loaded, 0)) + { + if (! _dl_loaded + || caller < _dl_loaded->l_map_start + || caller >= _dl_loaded->l_map_end) + _dl_signal_error (0, NULL, NULL, N_("\ +RTLD_NEXT used in code not dynamically loaded")); + } + + l = match; + while (l->l_loader != NULL) + l = l->l_loader; + + result = _dl_lookup_versioned_symbol_skip (name, l, &ref, + l->l_local_scope, + &vers, match); + } + else + { + /* Search the scope of the given object. */ + struct link_map *map = handle; + result = _dl_lookup_versioned_symbol (name, map, &ref, + map->l_local_scope, &vers, 0, 1); + } + + if (ref != NULL) + return DL_SYMBOL_ADDRESS (result, ref); + + return NULL; +} diff --git a/newlib/libc/sys/linux/dl/dl-version.c b/newlib/libc/sys/linux/dl/dl-version.c new file mode 100644 index 000000000..eefbea7ec --- /dev/null +++ b/newlib/libc/sys/linux/dl/dl-version.c @@ -0,0 +1,385 @@ +/* Handle symbol and library versioning. + Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1997. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include + +#include + + +#ifndef VERSYMIDX +# define VERSYMIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) +#endif + + +#define make_string(string, rest...) \ + ({ \ + const char *all[] = { string, ## rest }; \ + size_t len, cnt; \ + char *result, *cp; \ + \ + len = 1; \ + for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ + len += strlen (all[cnt]); \ + \ + cp = result = alloca (len); \ + for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ + { \ + cp = strcpy (cp, all[cnt]); \ + cp += strlen (all[cnt]); \ + } \ + \ + result; \ + }) + + +static inline struct link_map * +find_needed (const char *name, struct link_map *map) +{ + struct link_map *tmap; + unsigned int n; + + for (tmap = _dl_loaded; tmap != NULL; tmap = tmap->l_next) + if (_dl_name_match_p (name, tmap)) + return tmap; + + /* The required object is not in the global scope, look to see if it is + a dependency of the current object. */ + for (n = 0; n < map->l_searchlist.r_nlist; n++) + if (_dl_name_match_p (name, map->l_searchlist.r_list[n])) + return map->l_searchlist.r_list[n]; + + /* Should never happen. */ + return NULL; +} + + +static int +internal_function +match_symbol (const char *name, ElfW(Word) hash, const char *string, + struct link_map *map, int verbose, int weak) +{ + const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); + ElfW(Addr) def_offset; + ElfW(Verdef) *def; + /* Initialize to make the compiler happy. */ + const char *errstring = NULL; + int result = 0; + + /* Display information about what we are doing while debugging. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_VERSIONS, 0)) + _dl_debug_printf ("\ +checking for version `%s' in file %s required by file %s\n", + string, map->l_name[0] ? map->l_name : _dl_argv[0], + name); + + if (__builtin_expect (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL, 0)) + { + /* The file has no symbol versioning. I.e., the dependent + object was linked against another version of this file. We + only print a message if verbose output is requested. */ + if (verbose) + { + /* XXX We cannot translate the messages. */ + errstring = make_string ("\ +no version information available (required by ", name, ")"); + goto call_cerror; + } + return 0; + } + + def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr; + assert (def_offset != 0); + + def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset); + while (1) + { + /* Currently the version number of the definition entry is 1. + Make sure all we see is this version. */ + if (__builtin_expect (def->vd_version, 1) != 1) + { + char buf[20]; + buf[sizeof (buf) - 1] = '\0'; + /* XXX We cannot translate the message. */ + errstring = make_string ("unsupported version of Verdef record"); + result = 1; + goto call_cerror; + } + + /* Compare the hash values. */ + if (hash == def->vd_hash) + { + ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux); + + /* To be safe, compare the string as well. */ + if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0) + == 0) + /* Bingo! */ + return 0; + } + + /* If no more definitions we failed to find what we want. */ + if (def->vd_next == 0) + break; + + /* Next definition. */ + def = (ElfW(Verdef) *) ((char *) def + def->vd_next); + } + + /* Symbol not found. If it was a weak reference it is not fatal. */ + if (__builtin_expect (weak, 1)) + { + if (verbose) + { + /* XXX We cannot translate the message. */ + errstring = make_string ("weak version `", string, + "' not found (required by ", name, ")"); + goto call_cerror; + } + return 0; + } + + /* XXX We cannot translate the message. */ + errstring = make_string ("version `", string, "' not found (required by ", + name, ")"); + result = 1; + call_cerror: + _dl_signal_cerror (0, map->l_name[0] ? map->l_name : _dl_argv[0], NULL, + errstring); + return result; +} + + +int +internal_function +_dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) +{ + int result = 0; + const char *strtab; + /* Pointer to section with needed versions. */ + ElfW(Dyn) *dyn; + /* Pointer to dynamic section with definitions. */ + ElfW(Dyn) *def; + /* We need to find out which is the highest version index used + in a dependecy. */ + unsigned int ndx_high = 0; + /* Initialize to make the compiler happy. */ + const char *errstring = NULL; + int errval = 0; + + /* If we don't have a string table, we must be ok. */ + if (map->l_info[DT_STRTAB] == NULL) + return 0; + strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); + + dyn = map->l_info[VERSYMIDX (DT_VERNEED)]; + def = map->l_info[VERSYMIDX (DT_VERDEF)]; + + if (dyn != NULL) + { + /* This file requires special versions from its dependencies. */ + ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr); + + /* Currently the version number of the needed entry is 1. + Make sure all we see is this version. */ + if (__builtin_expect (ent->vn_version, 1) != 1) + { + char buf[20]; + buf[sizeof (buf) - 1] = '\0'; + /* XXX We cannot translate the message. */ + errstring = make_string ("unsupported version of Verneed record\n"); + call_error: + _dl_signal_error (errval, (*map->l_name ? map->l_name : _dl_argv[0]), + NULL, errstring); + } + + while (1) + { + ElfW(Vernaux) *aux; + struct link_map *needed = find_needed (strtab + ent->vn_file, map); + + /* If NEEDED is NULL this means a dependency was not found + and no stub entry was created. This should never happen. */ + assert (needed != NULL); + + /* Make sure this is no stub we created because of a missing + dependency. */ + if (__builtin_expect (! trace_mode, 1) + || ! __builtin_expect (needed->l_faked, 0)) + { + /* NEEDED is the map for the file we need. Now look for the + dependency symbols. */ + aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux); + while (1) + { + /* Match the symbol. */ + result |= match_symbol ((*map->l_name + ? map->l_name : _dl_argv[0]), + aux->vna_hash, + strtab + aux->vna_name, + needed, verbose, + aux->vna_flags & VER_FLG_WEAK); + + /* Compare the version index. */ + if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high) + ndx_high = aux->vna_other & 0x7fff; + + if (aux->vna_next == 0) + /* No more symbols. */ + break; + + /* Next symbol. */ + aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next); + } + } + + if (ent->vn_next == 0) + /* No more dependencies. */ + break; + + /* Next dependency. */ + ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next); + } + } + + /* We also must store the names of the defined versions. Determine + the maximum index here as well. + + XXX We could avoid the loop by just taking the number of definitions + as an upper bound of new indeces. */ + if (def != NULL) + { + ElfW(Verdef) *ent; + ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr); + while (1) + { + if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high) + ndx_high = ent->vd_ndx & 0x7fff; + + if (ent->vd_next == 0) + /* No more definitions. */ + break; + + ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next); + } + } + + if (ndx_high > 0) + { + /* Now we are ready to build the array with the version names + which can be indexed by the version index in the VERSYM + section. */ + map->l_versions = (struct r_found_version *) + calloc (ndx_high + 1, sizeof (*map->l_versions)); + if (__builtin_expect (map->l_versions == NULL, 0)) + { + errstring = N_("cannot allocate version reference table"); + errval = ENOMEM; + goto call_error; + } + + /* Store the number of available symbols. */ + map->l_nversions = ndx_high + 1; + + /* Compute the pointer to the version symbols. */ + map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); + + if (dyn != NULL) + { + ElfW(Verneed) *ent; + ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr); + while (1) + { + ElfW(Vernaux) *aux; + aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux); + while (1) + { + ElfW(Half) ndx = aux->vna_other & 0x7fff; + map->l_versions[ndx].hash = aux->vna_hash; + map->l_versions[ndx].hidden = aux->vna_other & 0x8000; + map->l_versions[ndx].name = &strtab[aux->vna_name]; + map->l_versions[ndx].filename = &strtab[ent->vn_file]; + + if (aux->vna_next == 0) + /* No more symbols. */ + break; + + /* Advance to next symbol. */ + aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next); + } + + if (ent->vn_next == 0) + /* No more dependencies. */ + break; + + /* Advance to next dependency. */ + ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next); + } + } + + /* And insert the defined versions. */ + if (def != NULL) + { + ElfW(Verdef) *ent; + ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr); + while (1) + { + ElfW(Verdaux) *aux; + aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux); + + if ((ent->vd_flags & VER_FLG_BASE) == 0) + { + /* The name of the base version should not be + available for matching a versioned symbol. */ + ElfW(Half) ndx = ent->vd_ndx & 0x7fff; + map->l_versions[ndx].hash = ent->vd_hash; + map->l_versions[ndx].name = &strtab[aux->vda_name]; + map->l_versions[ndx].filename = NULL; + } + + if (ent->vd_next == 0) + /* No more definitions. */ + break; + + ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next); + } + } + } + + return result; +} + + +int +internal_function +_dl_check_all_versions (struct link_map *map, int verbose, int trace_mode) +{ + struct link_map *l; + int result = 0; + + for (l = map; l != NULL; l = l->l_next) + result |= ! l->l_faked && _dl_check_map_versions (l, verbose, trace_mode); + + return result; +} diff --git a/newlib/libc/sys/linux/dl/dlfcn.h b/newlib/libc/sys/linux/dl/dlfcn.h new file mode 100644 index 000000000..67ba73d5d --- /dev/null +++ b/newlib/libc/sys/linux/dl/dlfcn.h @@ -0,0 +1,84 @@ +/* User functions for run-time dynamic loading. + Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _DLFCN_H +#define _DLFCN_H 1 + +#include + +/* Collect various system dependent definitions and declarations. */ +#include + + +/* If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT + the run-time address of the symbol called NAME in the next shared + object is returned. The "next" relation is defined by the order + the shared objects were loaded. */ +# define RTLD_NEXT ((void *) -1l) + +/* If the first argument to `dlsym' or `dlvsym' is set to RTLD_DEFAULT + the run-time address of the symbol called NAME in the global scope + is returned. */ +# define RTLD_DEFAULT ((void *) 0) + + +__BEGIN_DECLS + +/* Open the shared object FILE and map it in; return a handle that can be + passed to `dlsym' to get symbol values from it. */ +extern void *dlopen (__const char *__file, int __mode) __THROW; + +/* Unmap and close a shared object opened by `dlopen'. + The handle cannot be used again after calling `dlclose'. */ +extern int dlclose (void *__handle) __THROW; + +/* Find the run-time address in the shared object HANDLE refers to + of the symbol called NAME. */ +extern void *dlsym (void *__restrict __handle, + __const char *__restrict __name) __THROW; + +/* Find the run-time address in the shared object HANDLE refers to + of the symbol called NAME with VERSION. */ +extern void *dlvsym (void *__restrict __handle, + __const char *__restrict __name, + __const char *__restrict __version) __THROW; + +/* When any of the above functions fails, call this function + to return a string describing the error. Each call resets + the error string so that a following call returns null. */ +extern char *dlerror (void) __THROW; + + +/* Structure containing information about object searched using + `dladdr'. */ +typedef struct +{ + __const char *dli_fname; /* File name of defining object. */ + void *dli_fbase; /* Load address of that object. */ + __const char *dli_sname; /* Name of nearest symbol. */ + void *dli_saddr; /* Exact value of nearest symbol. */ +} Dl_info; + +/* Fill in *INFO with the following information about ADDRESS. + Returns 0 iff no shared object's segments contain that address. */ +extern int dladdr (__const void *__address, Dl_info *__info) __THROW; + +__END_DECLS + +#endif /* dlfcn.h */ diff --git a/newlib/libc/sys/linux/dl/do-lookup.h b/newlib/libc/sys/linux/dl/do-lookup.h new file mode 100644 index 000000000..b9364b95d --- /dev/null +++ b/newlib/libc/sys/linux/dl/do-lookup.h @@ -0,0 +1,200 @@ +/* Look up a symbol in the loaded objects. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#if VERSIONED +# define FCT do_lookup_versioned +# define ARG const struct r_found_version *const version, +#else +# define FCT do_lookup +# define ARG +#endif + +/* Inner part of the lookup functions. We return a value > 0 if we + found the symbol, the value 0 if nothing is found and < 0 if + something bad happened. */ +static inline int +FCT (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref, + struct sym_val *result, struct r_scope_elem *scope, size_t i, ARG + struct link_map *skip, int type_class) +{ + struct link_map **list = scope->r_list; + size_t n = scope->r_nlist; + struct link_map *map; + + do + { + const ElfW(Sym) *symtab; + const char *strtab; + const ElfW(Half) *verstab; + Elf_Symndx symidx; + const ElfW(Sym) *sym; +#if ! VERSIONED + int num_versions = 0; + const ElfW(Sym) *versioned_sym = NULL; +#endif + + map = list[i]; + + /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */ + if (skip != NULL && map == skip) + continue; + + /* Don't search the executable when resolving a copy reloc. */ + if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable) + continue; + + /* Print some debugging info if wanted. */ + if (__builtin_expect (_dl_debug_mask & DL_DEBUG_SYMBOLS, 0)) + _dl_debug_printf ("symbol=%s; lookup in file=%s\n", undef_name, + map->l_name[0] ? map->l_name : _dl_argv[0]); + + symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); + strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); + verstab = map->l_versyms; + + /* Search the appropriate hash bucket in this object's symbol table + for a definition for the same symbol name. */ + for (symidx = map->l_buckets[hash % map->l_nbuckets]; + symidx != STN_UNDEF; + symidx = map->l_chain[symidx]) + { + sym = &symtab[symidx]; + + assert (ELF_RTYPE_CLASS_PLT == 1); + if (sym->st_value == 0 || /* No value. */ + /* ((type_class & ELF_RTYPE_CLASS_PLT) + && (sym->st_shndx == SHN_UNDEF)) */ + (type_class & (sym->st_shndx == SHN_UNDEF))) + continue; + + if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC) + /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC entries + since these are no code/data definitions. */ + continue; + + if (sym != ref && strcmp (strtab + sym->st_name, undef_name)) + /* Not the symbol we are looking for. */ + continue; + +#if VERSIONED + if (__builtin_expect (verstab == NULL, 0)) + { + /* We need a versioned symbol but haven't found any. If + this is the object which is referenced in the verneed + entry it is a bug in the library since a symbol must + not simply disappear. + + It would also be a bug in the object since it means that + the list of required versions is incomplete and so the + tests in dl-version.c haven't found a problem.*/ + assert (version->filename == NULL + || ! _dl_name_match_p (version->filename, map)); + + /* Otherwise we accept the symbol. */ + } + else + { + /* We can match the version information or use the + default one if it is not hidden. */ + ElfW(Half) ndx = verstab[symidx] & 0x7fff; + if ((map->l_versions[ndx].hash != version->hash + || strcmp (map->l_versions[ndx].name, version->name)) + && (version->hidden || map->l_versions[ndx].hash + || (verstab[symidx] & 0x8000))) + /* It's not the version we want. */ + continue; + } +#else + /* No specific version is selected. When the object file + also does not define a version we have a match. + Otherwise we accept the default version, or in case there + is only one version defined, this one version. */ + if (verstab != NULL) + { + ElfW(Half) ndx = verstab[symidx] & 0x7fff; + if (ndx > 2) /* map->l_versions[ndx].hash != 0) */ + { + /* Don't accept hidden symbols. */ + if ((verstab[symidx] & 0x8000) == 0 && num_versions++ == 0) + /* No version so far. */ + versioned_sym = sym; + continue; + } + } +#endif + + /* There cannot be another entry for this symbol so stop here. */ + goto found_it; + } + + /* If we have seen exactly one versioned symbol while we are + looking for an unversioned symbol and the version is not the + default version we still accept this symbol since there are + no possible ambiguities. */ +#if VERSIONED + sym = NULL; +#else + sym = num_versions == 1 ? versioned_sym : NULL; +#endif + + if (sym != NULL) + { + found_it: + switch (ELFW(ST_BIND) (sym->st_info)) + { + case STB_WEAK: + /* Weak definition. Use this value if we don't find another. */ + if (__builtin_expect (_dl_dynamic_weak, 0)) + { + if (! result->s) + { + result->s = sym; + result->m = map; + } + break; + } + /* FALLTHROUGH */ + case STB_GLOBAL: + /* Global definition. Just what we need. */ + result->s = sym; + result->m = map; + return 1; + default: + /* Local symbols are ignored. */ + break; + } + } + +#if VERSIONED + /* If this current map is the one mentioned in the verneed entry + and we have not found a weak entry, it is a bug. */ + if (symidx == STN_UNDEF && version->filename != NULL + && __builtin_expect (_dl_name_match_p (version->filename, map), 0)) + return -1; +#endif + } + while (++i < n); + + /* We have not found anything until now. */ + return 0; +} + +#undef FCT +#undef ARG +#undef VERSIONED diff --git a/newlib/libc/sys/linux/dl/do-rel.h b/newlib/libc/sys/linux/dl/do-rel.h new file mode 100644 index 000000000..46202d704 --- /dev/null +++ b/newlib/libc/sys/linux/dl/do-rel.h @@ -0,0 +1,118 @@ +/* Do relocations for ELF dynamic linking. + Copyright (C) 1995,96,97,98,99,2000,2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This file may be included twice, to define both + `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. */ + +#include + +#ifdef DO_RELA +# define elf_dynamic_do_rel elf_dynamic_do_rela +# define RELCOUNT_IDX VERSYMIDX (DT_RELACOUNT) +# define Rel Rela +# define elf_machine_rel elf_machine_rela +# define elf_machine_rel_relative elf_machine_rela_relative +#else +# define RELCOUNT_IDX VERSYMIDX (DT_RELCOUNT) +#endif + +#ifndef VERSYMIDX +# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym)) +#endif + +/* Perform the relocations in MAP on the running program image as specified + by RELTAG, SZTAG. If LAZY is nonzero, this is the first pass on PLT + relocations; they should be set up to call _dl_runtime_resolve, rather + than fully resolved now. */ + +static inline void +elf_dynamic_do_rel (struct link_map *map, + ElfW(Addr) reladdr, ElfW(Addr) relsize, + int lazy) +{ + const ElfW(Rel) *r = (const void *) reladdr; + const ElfW(Rel) *end = (const void *) (reladdr + relsize); + ElfW(Addr) l_addr = map->l_addr; + +#ifndef RTLD_BOOTSTRAP + /* We never bind lazily during ld.so bootstrap. Unfortunately gcc is + not clever enough to see through all the function calls to realize + that. */ + if (lazy) + { + /* Doing lazy PLT relocations; they need very little info. */ + for (; r < end; ++r) + elf_machine_lazy_rel (map, l_addr, r); + } + else +#endif + { + const ElfW(Sym) *const symtab = + (const void *) D_PTR (map, l_info[DT_SYMTAB]); + ElfW(Word) nrelative = (map->l_info[RELCOUNT_IDX] == NULL + ? 0 : map->l_info[RELCOUNT_IDX]->d_un.d_val); + const ElfW(Rel) *relative = r; + r = MIN (r + nrelative, end); + +#ifndef RTLD_BOOTSTRAP + /* This is defined in rtld.c, but nowhere in the static libc.a; make + the reference weak so static programs can still link. This + declaration cannot be done when compiling rtld.c (i.e. #ifdef + RTLD_BOOTSTRAP) because rtld.c contains the common defn for + _dl_rtld_map, which is incompatible with a weak decl in the same + file. */ + weak_extern (_dl_rtld_map); + if (map != &_dl_rtld_map) /* Already done in rtld itself. */ +# ifndef DO_RELA + /* Rela platforms get the offset from r_addend and this must + be copied in the relocation address. Therefore we can skip + the relative relocations only if this is for rel + relocations. */ + if (l_addr != 0) +# endif +#endif + for (; relative < r; ++relative) + elf_machine_rel_relative (l_addr, relative, + (void *) (l_addr + relative->r_offset)); + + if (map->l_info[VERSYMIDX (DT_VERSYM)]) + { + const ElfW(Half) *const version = + (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); + + for (; r < end; ++r) + { + ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)]; + elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], + &map->l_versions[ndx], + (void *) (l_addr + r->r_offset)); + } + } + else + for (; r < end; ++r) + elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL, + (void *) (l_addr + r->r_offset)); + } +} + +#undef elf_dynamic_do_rel +#undef Rel +#undef elf_machine_rel +#undef elf_machine_rel_relative +#undef RELCOUNT_IDX diff --git a/newlib/libc/sys/linux/dl/dynamic-link.h b/newlib/libc/sys/linux/dl/dynamic-link.h new file mode 100644 index 000000000..a63fded89 --- /dev/null +++ b/newlib/libc/sys/linux/dl/dynamic-link.h @@ -0,0 +1,244 @@ +/* Inline functions for dynamic linking. + Copyright (C) 1995,96,97,98,99,2000 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +#ifndef VERSYMIDX +# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym)) +#endif + + +/* Global read-only variable defined in rtld.c which is nonzero if we + shall give more warning messages. */ +extern int _dl_verbose __attribute__ ((unused)); + + +/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */ + +static inline void __attribute__ ((unused)) +elf_get_dynamic_info (struct link_map *l) +{ + ElfW(Dyn) *dyn = l->l_ld; + ElfW(Addr) l_addr; + ElfW(Dyn) **info; + + if (! dyn) + return; + + l_addr = l->l_addr; + info = l->l_info; + + while (dyn->d_tag != DT_NULL) + { + if (dyn->d_tag < DT_NUM) + info[dyn->d_tag] = dyn; + else if (dyn->d_tag >= DT_LOPROC && + dyn->d_tag < DT_LOPROC + DT_THISPROCNUM) + info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn; + else if ((Elf32_Word) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM) + info[VERSYMIDX (dyn->d_tag)] = dyn; + else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM) + info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM] = dyn; + else + assert (! "bad dynamic tag"); + ++dyn; + } +#ifndef DL_RO_DYN_SECTION + if (info[DT_PLTGOT] != NULL) + info[DT_PLTGOT]->d_un.d_ptr += l_addr; + if (info[DT_STRTAB] != NULL) + info[DT_STRTAB]->d_un.d_ptr += l_addr; + if (info[DT_SYMTAB] != NULL) + info[DT_SYMTAB]->d_un.d_ptr += l_addr; +# if ! ELF_MACHINE_NO_RELA + if (info[DT_RELA] != NULL) + { + assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela))); + info[DT_RELA]->d_un.d_ptr += l_addr; + } +# endif +# if ! ELF_MACHINE_NO_REL + if (info[DT_REL] != NULL) + { + assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel))); + info[DT_REL]->d_un.d_ptr += l_addr; + } +# endif +#endif + if (info[DT_PLTREL] != NULL) + { +# if ELF_MACHINE_NO_RELA + assert (info[DT_PLTREL]->d_un.d_val == DT_REL); +# elif ELF_MACHINE_NO_REL + assert (info[DT_PLTREL]->d_un.d_val == DT_RELA); +# else + assert (info[DT_PLTREL]->d_un.d_val == DT_REL + || info[DT_PLTREL]->d_un.d_val == DT_RELA); +# endif + } +#ifndef DL_RO_DYN_SECTION + if (info[DT_JMPREL] != NULL) + info[DT_JMPREL]->d_un.d_ptr += l_addr; + if (info[VERSYMIDX (DT_VERSYM)] != NULL) + info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr; +#endif + if (info[DT_FLAGS] != NULL) + { + /* Flags are used. Translate to the old form where available. + Since these l_info entries are only tested for NULL pointers it + is ok if they point to the DT_FLAGS entry. */ + ElfW(Word) flags = info[DT_FLAGS]->d_un.d_val; + if (flags & DF_SYMBOLIC) + info[DT_SYMBOLIC] = info[DT_FLAGS]; + if (flags & DF_TEXTREL) + info[DT_TEXTREL] = info[DT_FLAGS]; + if (flags & DF_BIND_NOW) + info[DT_BIND_NOW] = info[DT_FLAGS]; + } + if (info[VERSYMIDX (DT_FLAGS_1)] != NULL) + l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val; + if (info[DT_RUNPATH] != NULL) + /* If both RUNPATH and RPATH are given, the latter is ignored. */ + info[DT_RPATH] = NULL; +} + +#ifdef RESOLVE + +/* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. + These functions are almost identical, so we use cpp magic to avoid + duplicating their code. It cannot be done in a more general function + because we must be able to completely inline. */ + +/* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its + range. Note that according to the ELF spec, this is completely legal! + But conditionally define things so that on machines we know this will + not happen we do something more optimal. */ + +# ifdef ELF_MACHINE_PLTREL_OVERLAP +# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \ + do { \ + struct { ElfW(Addr) start, size; int lazy; } ranges[3]; \ + int ranges_index; \ + \ + ranges[0].lazy = ranges[2].lazy = 0; \ + ranges[1].lazy = 1; \ + ranges[0].size = ranges[1].size = ranges[2].size = 0; \ + \ + if ((map)->l_info[DT_##RELOC]) \ + { \ + ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \ + ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \ + } \ + \ + if ((do_lazy) \ + && (map)->l_info[DT_PLTREL] \ + && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \ + { \ + ranges[1].start = D_PTR ((map), l_info[DT_JMPREL]); \ + ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \ + ranges[2].start = ranges[1].start + ranges[1].size; \ + ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start; \ + ranges[0].size = ranges[1].start - ranges[0].start; \ + } \ + \ + for (ranges_index = 0; ranges_index < 3; ++ranges_index) \ + elf_dynamic_do_##reloc ((map), \ + ranges[ranges_index].start, \ + ranges[ranges_index].size, \ + ranges[ranges_index].lazy); \ + } while (0) +# else +# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \ + do { \ + struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \ + int ranges_index; \ + ranges[0].lazy = 0; \ + ranges[0].size = ranges[1].size = 0; \ + ranges[0].start = 0; \ + \ + if ((map)->l_info[DT_##RELOC]) \ + { \ + ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \ + ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \ + } \ + if ((map)->l_info[DT_PLTREL] \ + && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \ + { \ + ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \ + \ + if ((do_lazy) \ + /* This test does not only detect whether the relocation \ + sections are in the right order, it also checks whether \ + there is a DT_REL/DT_RELA section. */ \ + || ranges[0].start + ranges[0].size != start) \ + { \ + ranges[1].start = start; \ + ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \ + ranges[1].lazy = (do_lazy); \ + } \ + else \ + /* Combine processing the sections. */ \ + ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \ + } \ + \ + for (ranges_index = 0; ranges_index < 2; ++ranges_index) \ + elf_dynamic_do_##reloc ((map), \ + ranges[ranges_index].start, \ + ranges[ranges_index].size, \ + ranges[ranges_index].lazy); \ + } while (0) +# endif + +# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA +# define _ELF_CHECK_REL 0 +# else +# define _ELF_CHECK_REL 1 +# endif + +# if ! ELF_MACHINE_NO_REL +# include "do-rel.h" +# define ELF_DYNAMIC_DO_REL(map, lazy) \ + _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL) +# else +# define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do. */ +# endif + +# if ! ELF_MACHINE_NO_RELA +# define DO_RELA +# include "do-rel.h" +# define ELF_DYNAMIC_DO_RELA(map, lazy) \ + _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL) +# else +# define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do. */ +# endif + +/* This can't just be an inline function because GCC is too dumb + to inline functions containing inlines themselves. */ +# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \ + do { \ + int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \ + (consider_profile)); \ + ELF_DYNAMIC_DO_REL ((map), edr_lazy); \ + ELF_DYNAMIC_DO_RELA ((map), edr_lazy); \ + } while (0) + +#endif diff --git a/newlib/libc/sys/linux/dl/kernel-features.h b/newlib/libc/sys/linux/dl/kernel-features.h new file mode 100644 index 000000000..562a6c765 --- /dev/null +++ b/newlib/libc/sys/linux/dl/kernel-features.h @@ -0,0 +1,193 @@ +/* Set flags signalling availability of kernel features based on given + kernel version number. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This file must not contain any C code. At least it must be protected + to allow using the file also in assembler files. */ + +#ifndef __LINUX_KERNEL_VERSION +/* We assume the worst; all kernels should be supported. */ +# define __LINUX_KERNEL_VERSION 0 +#endif + +/* We assume for __LINUX_KERNEL_VERSION the same encoding used in + linux/version.h. I.e., the major, minor, and subminor all get a + byte with the major number being in the highest byte. This means + we can do numeric comparisons. + + In the following we will define certain symbols depending on + whether the describes kernel feature is available in the kernel + version given by __LINUX_KERNEL_VERSION. We are not always exactly + recording the correct versions in which the features were + introduced. If somebody cares these values can afterwards be + corrected. Most of the numbers here are set corresponding to + 2.2.0. */ + +/* `getcwd' system call. */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_GETCWD_SYSCALL 1 +#endif + +/* Real-time signal became usable in 2.1.70. */ +#if __LINUX_KERNEL_VERSION >= 131398 +# define __ASSUME_REALTIME_SIGNALS 1 +#endif + +/* When were the `pread'/`pwrite' syscalls introduced? */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_PREAD_SYSCALL 1 +# define __ASSUME_PWRITE_SYSCALL 1 +#endif + +/* When was `poll' introduced? */ +#if __LINUX_KERNEL_VERSION >= 131584 +# define __ASSUME_POLL_SYSCALL 1 +#endif + +/* The `lchown' syscall was introduced in 2.1.80. */ +#if __LINUX_KERNEL_VERSION >= 131408 +# define __ASSUME_LCHOWN_SYSCALL 1 +#endif + +/* When did the `setresuid' sysall became available? */ +#if __LINUX_KERNEL_VERSION >= 131584 && !defined __sparc__ +# define __ASSUME_SETRESUID_SYSCALL 1 +#endif + +/* The SIOCGIFNAME ioctl is available starting with 2.1.50. */ +#if __LINUX_KERNEL_VERSION >= 131408 +# define __ASSUME_SIOCGIFNAME 1 +#endif + +/* On x86 another `getrlimit' syscall was added in 2.3.25. */ +#if __LINUX_KERNEL_VERSION >= 131865 && defined __i386__ +# define __ASSUME_NEW_GETRLIMIT_SYSCALL 1 +#endif + +/* On x86 the truncate64/ftruncate64 syscalls were introduced in 2.3.31. */ +#if __LINUX_KERNEL_VERSION >= 131871 && defined __i386__ +# define __ASSUME_TRUNCATE64_SYSCALL 1 +#endif + +/* On x86 the mmap2 syscall was introduced in 2.3.31. */ +#if __LINUX_KERNEL_VERSION >= 131871 && defined __i386__ +# define __ASSUME_MMAP2_SYSCALL 1 +#endif + +/* On x86 the stat64/lstat64/fstat64 syscalls were introduced in 2.3.34. */ +#if __LINUX_KERNEL_VERSION >= 131874 && defined __i386__ +# define __ASSUME_STAT64_SYSCALL 1 +#endif + +/* On sparc and ARM the truncate64/ftruncate64/mmap2/stat64/lstat64/fstat64 + syscalls were introduced in 2.3.35. */ +#if __LINUX_KERNEL_VERSION >= 131875 && (defined __sparc__ || defined __arm__) +# define __ASSUME_TRUNCATE64_SYSCALL 1 +# define __ASSUME_MMAP2_SYSCALL 1 +# define __ASSUME_STAT64_SYSCALL 1 +#endif + +/* I know for sure that these are in 2.3.35 on powerpc. */ +#if __LINUX_KERNEL_VERSION >= 131875 && defined __powerpc__ +# define __ASSUME_TRUNCATE64_SYSCALL 1 +# define __ASSUME_STAT64_SYSCALL 1 +# define __ASSUME_NEW_GETRLIMIT_SYSCALL 1 +#endif + +/* Linux 2.3.39 introduced 32bit UID/GIDs and IPC64. Some platforms had 32 + bit type all along. */ +#if __LINUX_KERNEL_VERSION >= 131879 || defined __powerpc__ || defined __mips__ +# define __ASSUME_32BITUIDS 1 +# ifndef __powerpc__ +# define __ASSUME_IPC64 1 +# endif +# ifdef __sparc__ +# define __ASSUME_SETRESUID_SYSCALL 1 +# endif +#endif + +/* Linux 2.4.0 on PPC introduced a correct IPC64. */ +#if __LINUX_KERNEL_VERSION >= 132096 && defined __powerpc__ +# define __ASSUME_IPC64 1 +#endif + +/* We can use the LDTs for threading with Linux 2.3.99 and newer. */ +#if __LINUX_KERNEL_VERSION >= 131939 +# define __ASSUME_LDT_WORKS 1 +#endif + +/* The changed st_ino field appeared in 2.4.0-test6. But we cannot + distinguish this version from other 2.4.0 releases. Therefore play + save and assume it available is for 2.4.1 and up. */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_ST_INO_64_BIT 1 +#endif + +/* To support locking of large files a new fcntl() syscall was introduced + in 2.4.0-test7. We test for 2.4.1 for the earliest version we know + the syscall is available. */ +#if __LINUX_KERNEL_VERSION >= 132097 && (defined __i386__ || defined __sparc__) +# define __ASSUME_FCNTL64 1 +#endif + +/* Arm got fcntl64 in 2.4.4, PowerPC and SH have it also in 2.4.4 (I + don't know when it got introduced). */ +#if __LINUX_KERNEL_VERSION >= 132100 \ + && (defined __arm__ || defined __powerpc__ || defined __sh__) +# define __ASSUME_FCNTL64 1 +#endif + +/* The getdents64 syscall was introduced in 2.4.0-test7. We test for + 2.4.1 for the earliest version we know the syscall is available. */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_GETDENTS64_SYSCALL 1 +#endif + +/* When did O_DIRECTORY became available? Early in 2.3 but when? + Be safe, use 2.3.99. */ +#if __LINUX_KERNEL_VERSION >= 131939 +# define __ASSUME_O_DIRECTORY 1 +#endif + +/* Starting with one of the 2.4.0 pre-releases the Linux kernel passes + up the page size information. */ +#if __LINUX_KERNEL_VERSION >= 132097 +# define __ASSUME_AT_PAGESIZE 1 +#endif + +/* Starting with 2.4.5 kernels PPC passes the AUXV in the standard way + and the mmap2 syscall made it into the official kernel. */ +#if __LINUX_KERNEL_VERSION >= (132096+5) && defined __powerpc__ +# define __ASSUME_STD_AUXV 1 +# define __ASSUME_MMAP2_SYSCALL 1 +#endif + +/* There are an infinite number of PA-RISC kernel versions numbered + 2.4.0. But they've not really been released as such. We require + and expect the final version here. */ +#ifdef __hppa__ +# define __ASSUME_32BITUIDS 1 +# define __ASSUME_TRUNCATE64_SYSCALL 1 +# define __ASSUME_MMAP2_SYSCALL 1 +# define __ASSUME_STAT64_SYSCALL 1 +# define __ASSUME_IPC64 1 +# define __ASSUME_ST_INO_64_BIT 1 +# define __ASSUME_FCNTL64 1 +# define __ASSUME_GETDENTS64_SYSCALL 1 +#endif diff --git a/newlib/libc/sys/linux/dl/ldsodefs.h b/newlib/libc/sys/linux/dl/ldsodefs.h new file mode 100644 index 000000000..f24e1136b --- /dev/null +++ b/newlib/libc/sys/linux/dl/ldsodefs.h @@ -0,0 +1,535 @@ +/* Run-time dynamic linker data structures for loaded ELF shared objects. + Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LDSODEFS_H +#define _LDSODEFS_H 1 + +#include + +#define __need_size_t +#define __need_NULL +#include +#include + +#include +#include +#include +#include +#include + +__BEGIN_DECLS + +/* We use this macro to refer to ELF types independent of the native wordsize. + `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */ +#define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type) + +#define internal_function +/* All references to the value of l_info[DT_PLTGOT], + l_info[DT_STRTAB], l_info[DT_SYMTAB], l_info[DT_RELA], + l_info[DT_REL], l_info[DT_JMPREL], and l_info[VERSYMIDX (DT_VERSYM)] + have to be accessed via the D_PTR macro. The macro is needed since for + most architectures the entry is already relocated - but for some not + and we need to relocate at access time. */ +#ifdef DL_RO_DYN_SECTION +# define D_PTR(map,i) (map->i->d_un.d_ptr + map->l_addr) +#else +# define D_PTR(map,i) map->i->d_un.d_ptr +#endif + +/* On some platforms more information than just the address of the symbol + is needed from the lookup functions. In this case we return the whole + link map. */ +#ifdef DL_LOOKUP_RETURNS_MAP +typedef struct link_map *lookup_t; +# define LOOKUP_VALUE(map) map +# define LOOKUP_VALUE_ADDRESS(map) (map ? map->l_addr : 0) +#else +typedef ElfW(Addr) lookup_t; +# define LOOKUP_VALUE(map) map->l_addr +# define LOOKUP_VALUE_ADDRESS(address) address +#endif + +/* on some architectures a pointer to a function is not just a pointer + to the actual code of the function but rather an architecture + specific descriptor. */ +#ifndef ELF_FUNCTION_PTR_IS_SPECIAL +# define DL_SYMBOL_ADDRESS(map, ref) \ + (void *) (LOOKUP_VALUE_ADDRESS (map) + ref->st_value) +# define DL_LOOKUP_ADDRESS(addr) ((ElfW(Addr)) (addr)) +# define DL_DT_INIT_ADDRESS(map, start) (start) +# define DL_DT_FINI_ADDRESS(map, start) (start) +#endif + +/* Unmap a loaded object, called by _dl_close (). */ +#ifndef DL_UNMAP_IS_SPECIAL +# define DL_UNMAP(map) \ + __munmap ((void *) (map)->l_map_start, \ + (map)->l_map_end - (map)->l_map_start) +#endif + +/* By default we do not need special support to initialize DSOs loaded + by statically linked binaries. */ +#ifndef DL_STATIC_INIT +# define DL_STATIC_INIT(map) +#endif + +/* Reloc type classes as returned by elf_machine_type_class(). + ELF_RTYPE_CLASS_PLT means this reloc should not be satisfied by + some PLT symbol, ELF_RTYPE_CLASS_COPY means this reloc should not be + satisfied by any symbol in the executable. */ +#define ELF_RTYPE_CLASS_PLT 1 +#define ELF_RTYPE_CLASS_COPY 2 + +/* ELF uses the PF_x macros to specify the segment permissions, mmap + uses PROT_xxx. In most cases the three macros have the values 1, 2, + and 3 but not in a matching order. The following macros allows + converting from the PF_x values to PROT_xxx values. */ +#define PF_TO_PROT \ + ((PROT_READ << (PF_R * 4)) \ + | (PROT_WRITE << (PF_W * 4)) \ + | (PROT_EXEC << (PF_X * 4)) \ + | ((PROT_READ | PROT_WRITE) << ((PF_R | PF_W) * 4)) \ + | ((PROT_READ | PROT_EXEC) << ((PF_R | PF_X) * 4)) \ + | ((PROT_WRITE | PROT_EXEC) << (PF_W | PF_X) * 4) \ + | ((PROT_READ | PROT_WRITE | PROT_EXEC) << ((PF_R | PF_W | PF_X) * 4))) + + +/* For the version handling we need an array with only names and their + hash values. */ +struct r_found_version + { + const char *name; + ElfW(Word) hash; + + int hidden; + const char *filename; + }; + +/* We want to cache information about the searches for shared objects. */ + +enum r_dir_status { unknown, nonexisting, existing }; + +struct r_search_path_elem + { + /* This link is only used in the `all_dirs' member of `r_search_path'. */ + struct r_search_path_elem *next; + + /* Strings saying where the definition came from. */ + const char *what; + const char *where; + + /* Basename for this search path element. The string must end with + a slash character. */ + const char *dirname; + size_t dirnamelen; + + enum r_dir_status status[0]; + }; + +struct r_strlenpair + { + const char *str; + size_t len; + }; + + +/* A data structure for a simple single linked list of strings. */ +struct libname_list + { + const char *name; /* Name requested (before search). */ + struct libname_list *next; /* Link to next name for this object. */ + int dont_free; /* Flag whether this element should be freed + if the object is not entirely unloaded. */ + }; + + +/* Test whether given NAME matches any of the names of the given object. */ +static __inline int +__attribute__ ((unused)) +_dl_name_match_p (const char *__name, struct link_map *__map) +{ + int __found = strcmp (__name, __map->l_name) == 0; + struct libname_list *__runp = __map->l_libname; + + while (! __found && __runp != NULL) + if (strcmp (__name, __runp->name) == 0) + __found = 1; + else + __runp = __runp->next; + + return __found; +} + +/* Function used as argument for `_dl_receive_error' function. The + arguments are the error code, error string, and the objname the + error occurred in. */ +typedef void (*receiver_fct) (int, const char *, const char *); + +/* Internal functions of the run-time dynamic linker. + These can be accessed if you link again the dynamic linker + as a shared library, as in `-lld' or `/lib/ld.so' explicitly; + but are not normally of interest to user programs. + + The `-ldl' library functions in provide a simple + user interface to run-time dynamic linking. */ + + +/* Parameters passed to the dynamic linker. */ +extern char **_dl_argv; + +/* Cached value of `getpagesize ()'. */ +extern size_t _dl_pagesize; + +/* OS version. */ +extern unsigned int _dl_osversion; + +/* File descriptor referring to the zero-fill device. */ +extern int _dl_zerofd; + +/* Name of the shared object to be profiled (if any). */ +extern const char *_dl_profile; +/* Map of shared object to be profiled. */ +extern struct link_map *_dl_profile_map; +/* Filename of the output file. */ +extern const char *_dl_profile_output; + +/* If nonzero the appropriate debug information is printed. */ +extern int _dl_debug_mask; +#define DL_DEBUG_LIBS (1 << 0) +#define DL_DEBUG_IMPCALLS (1 << 1) +#define DL_DEBUG_BINDINGS (1 << 2) +#define DL_DEBUG_SYMBOLS (1 << 3) +#define DL_DEBUG_VERSIONS (1 << 4) +#define DL_DEBUG_RELOC (1 << 5) +#define DL_DEBUG_FILES (1 << 6) +#define DL_DEBUG_STATISTICS (1 << 7) +/* This one is used only internally. */ +#define DL_DEBUG_HELP (1 << 8) + +/* Expect cache ID. */ +extern int _dl_correct_cache_id; + +/* Mask for hardware capabilities that are available. */ +extern unsigned long int _dl_hwcap; + +/* Mask for important hardware capabilities we honour. */ +extern unsigned long int _dl_hwcap_mask; + +/* File descriptor to write debug messages to. */ +extern int _dl_debug_fd; + +/* Names of shared object for which the RPATH should be ignored. */ +extern const char *_dl_inhibit_rpath; + +/* Nonzero if references should be treated as weak during runtime linking. */ +extern int _dl_dynamic_weak; + +/* The array with message we print as a last resort. */ +extern const char _dl_out_of_memory[]; + +/* Nonzero if runtime lookups should not update the .got/.plt. */ +extern int _dl_bind_not; + +/* List of search directories. */ +extern struct r_search_path_elem *_dl_all_dirs; +extern struct r_search_path_elem *_dl_init_all_dirs; + +/* OS-dependent function to open the zero-fill device. */ +extern int _dl_sysdep_open_zero_fill (void); /* dl-sysdep.c */ + + +/* During the program run we must not modify the global data of + loaded shared object simultanously in two threads. Therefore we + protect `_dl_open' and `_dl_close' in dl-close.c. + + This must be a recursive lock since the initializer function of + the loaded object might as well require a call to this function. + At this time it is not anymore a problem to modify the tables. */ +__libc_lock_define_recursive (extern, _dl_load_lock) + + +/* Write message on the debug file descriptor. The parameters are + interpreted as for a `printf' call. All the lines start with a + tag showing the PID. */ +extern void _dl_debug_printf (const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); + +/* Write message on the debug file descriptor. The parameters are + interpreted as for a `printf' call. All the lines buf the first + start with a tag showing the PID. */ +extern void _dl_debug_printf_c (const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); + + +/* Write a message on the specified descriptor FD. The parameters are + interpreted as for a `printf' call. */ +extern void _dl_dprintf (int fd, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); + +/* Write a message on the specified descriptor standard output. The + parameters are interpreted as for a `printf' call. */ +#define _dl_printf(fmt, args...) \ + _dl_dprintf (STDOUT_FILENO, fmt, ##args) + +/* Write a message on the specified descriptor standard error. The + parameters are interpreted as for a `printf' call. */ +#define _dl_error_printf(fmt, args...) \ + _dl_dprintf (STDERR_FILENO, fmt, ##args) + +/* Write a message on the specified descriptor standard error and exit + the program. The parameters are interpreted as for a `printf' call. */ +#define _dl_fatal_printf(fmt, args...) \ + do \ + { \ + _dl_dprintf (STDERR_FILENO, fmt, ##args); \ + _exit (127); \ + } \ + while (1) + + +/* This function is called by all the internal dynamic linker functions + when they encounter an error. ERRCODE is either an `errno' code or + zero; OBJECT is the name of the problematical shared object, or null if + it is a general problem; ERRSTRING is a string describing the specific + problem. */ +extern void _dl_signal_error (int errcode, const char *object, + const char *occurred, const char *errstring) + internal_function + __attribute__ ((__noreturn__)); + +/* Like _dl_signal_error, but may return when called in the context of + _dl_receive_error. */ +extern void _dl_signal_cerror (int errcode, const char *object, + const char *occation, const char *errstring) + internal_function; + +/* Call OPERATE, receiving errors from `dl_signal_cerror'. Unlike + `_dl_catch_error' the operation is resumed after the OPERATE + function returns. + ARGS is passed as argument to OPERATE. */ +extern void _dl_receive_error (receiver_fct fct, void (*operate) (void *), + void *args) + internal_function; + + +/* Open the shared object NAME and map in its segments. + LOADER's DT_RPATH is used in searching for NAME. + If the object is already opened, returns its existing map. + For preloaded shared objects PRELOADED is set to a non-zero + value to allow additional security checks. */ +extern struct link_map *_dl_map_object (struct link_map *loader, + const char *name, int preloaded, + int type, int trace_mode, int mode) + internal_function; + +/* Call _dl_map_object on the dependencies of MAP, and set up + MAP->l_searchlist. PRELOADS points to a vector of NPRELOADS previously + loaded objects that will be inserted into MAP->l_searchlist after MAP + but before its dependencies. */ +extern void _dl_map_object_deps (struct link_map *map, + struct link_map **preloads, + unsigned int npreloads, int trace_mode) + internal_function; + +/* Cache the locations of MAP's hash table. */ +extern void _dl_setup_hash (struct link_map *map) internal_function; + + +/* Search loaded objects' symbol tables for a definition of the symbol + referred to by UNDEF. *SYM is the symbol table entry containing the + reference; it is replaced with the defining symbol, and the base load + address of the defining object is returned. SYMBOL_SCOPE is a + null-terminated list of object scopes to search; each object's + l_searchlist (i.e. the segment of the dependency tree starting at that + object) is searched in turn. REFERENCE_NAME should name the object + containing the reference; it is used in error messages. + TYPE_CLASS describes the type of symbol we are looking for. */ +extern lookup_t _dl_lookup_symbol (const char *undef, + struct link_map *undef_map, + const ElfW(Sym) **sym, + struct r_scope_elem *symbol_scope[], + int type_class, int explicit) + internal_function; + +/* Lookup versioned symbol. */ +extern lookup_t _dl_lookup_versioned_symbol (const char *undef, + struct link_map *undef_map, + const ElfW(Sym) **sym, + struct r_scope_elem *symbol_scope[], + const struct r_found_version *version, + int type_class, int explicit) + internal_function; + +/* For handling RTLD_NEXT we must be able to skip shared objects. */ +extern lookup_t _dl_lookup_symbol_skip (const char *undef, + struct link_map *undef_map, + const ElfW(Sym) **sym, + struct r_scope_elem *symbol_scope[], + struct link_map *skip_this) + internal_function; + +/* For handling RTLD_NEXT with versioned symbols we must be able to + skip shared objects. */ +extern lookup_t _dl_lookup_versioned_symbol_skip (const char *undef, + struct link_map *undef_map, + const ElfW(Sym) **sym, + struct r_scope_elem *symbol_scope[], + const struct r_found_version *version, + struct link_map *skip_this) + internal_function; + +/* Look up symbol NAME in MAP's scope and return its run-time address. */ +extern ElfW(Addr) _dl_symbol_value (struct link_map *map, const char *name) + internal_function; + + +/* Structure describing the dynamic linker itself. */ +extern struct link_map _dl_rtld_map; +/* And a pointer to the map for the main map. */ +extern struct link_map *_dl_loaded; +/* Number of object in the _dl_loaded list. */ +extern unsigned int _dl_nloaded; +/* Array representing global scope. */ +extern struct r_scope_elem *_dl_global_scope[2]; +/* Direct pointer to the searchlist of the main object. */ +extern struct r_scope_elem *_dl_main_searchlist; +/* Copy of the content of `_dl_main_searchlist'. */ +extern struct r_scope_elem _dl_initial_searchlist; +/* This is zero at program start to signal that the global scope map is + allocated by rtld. Later it keeps the size of the map. It might be + reset if in _dl_close if the last global object is removed. */ +extern size_t _dl_global_scope_alloc; + +/* Allocate a `struct link_map' for a new object being loaded, + and enter it into the _dl_main_map list. */ +extern struct link_map *_dl_new_object (char *realname, const char *libname, + int type, struct link_map *loader) + internal_function; + +/* Relocate the given object (if it hasn't already been). + SCOPE is passed to _dl_lookup_symbol in symbol lookups. + If LAZY is nonzero, don't relocate its PLT. */ +extern void _dl_relocate_object (struct link_map *map, + struct r_scope_elem *scope[], + int lazy, int consider_profiling); + +/* Call _dl_signal_error with a message about an unhandled reloc type. + TYPE is the result of ELFW(R_TYPE) (r_info), i.e. an R__* value. + PLT is nonzero if this was a PLT reloc; it just affects the message. */ +extern void _dl_reloc_bad_type (struct link_map *map, + unsigned int type, int plt) + internal_function __attribute__ ((__noreturn__)); + +/* Check the version dependencies of all objects available through + MAP. If VERBOSE print some more diagnostics. */ +extern int _dl_check_all_versions (struct link_map *map, int verbose, + int trace_mode) + internal_function; + +/* Check the version dependencies for MAP. If VERBOSE print some more + diagnostics. */ +extern int _dl_check_map_versions (struct link_map *map, int verbose, + int trace_mode) + internal_function; + +/* Initialize the object in SCOPE by calling the constructors with + ARGC, ARGV, and ENV as the parameters. */ +extern void _dl_init (struct link_map *main_map, int argc, char **argv, + char **env) internal_function; + +/* Call the finalizer functions of all shared objects whose + initializer functions have completed. */ +extern void _dl_fini (void) internal_function; + +/* The dynamic linker calls this function before and having changing + any shared object mappings. The `r_state' member of `struct r_debug' + says what change is taking place. This function's address is + the value of the `r_brk' member. */ +extern void _dl_debug_state (void); + +/* Initialize `struct r_debug' if it has not already been done. The + argument is the run-time load address of the dynamic linker, to be put + in the `r_ldbase' member. Returns the address of the structure. */ +extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase) + internal_function; + +/* Initialize the basic data structure for the search paths. */ +extern void _dl_init_paths (const char *library_path) internal_function; + +/* Gather the information needed to install the profiling tables and start + the timers. */ +extern void _dl_start_profile (struct link_map *map, const char *output_dir) + internal_function; + +/* The actual functions used to keep book on the calls. */ +extern void _dl_mcount (ElfW(Addr) frompc, ElfW(Addr) selfpc); + +/* This function is simply a wrapper around the _dl_mcount function + which does not require a FROMPC parameter since this is the + calling function. */ +extern void _dl_mcount_wrapper (void *selfpc); + +/* Show the members of the auxiliary array passed up from the kernel. */ +extern void _dl_show_auxv (void) internal_function; + +/* Return all environment variables starting with `LD_', one after the + other. */ +extern char *_dl_next_ld_env_entry (char ***position) internal_function; + +/* Return an array with the names of the important hardware capabilities. */ +extern const struct r_strlenpair *_dl_important_hwcaps (const char *platform, + size_t paltform_len, + size_t *sz, + size_t *max_capstrlen) + internal_function; + +/* Look up NAME in ld.so.cache and return the file name stored there, + or null if none is found. */ +extern const char *_dl_load_cache_lookup (const char *name) + internal_function; + +/* If the system does not support MAP_COPY we cannot leave the file open + all the time since this would create problems when the file is replaced. + Therefore we provide this function to close the file and open it again + once needed. */ +extern void _dl_unload_cache (void); + +/* System-dependent function to read a file's whole contents in the + most convenient manner available. *SIZEP gets the size of the + file. On error MAP_FAILED is returned. */ +extern void *_dl_sysdep_read_whole_file (const char *file, size_t *sizep, + int prot) + internal_function; + +/* System-specific function to do initial startup for the dynamic linker. + After this, file access calls and getenv must work. This is responsible + for setting __libc_enable_secure if we need to be secure (e.g. setuid), + and for setting _dl_argc and _dl_argv, and then calling _dl_main. */ +extern ElfW(Addr) _dl_sysdep_start (void **start_argptr, + void (*dl_main) (const ElfW(Phdr) *phdr, + ElfW(Word) phnum, + ElfW(Addr) *user_entry)); + +extern void _dl_sysdep_start_cleanup (void) + internal_function; + + +__END_DECLS + +#endif /* ldsodefs.h */ diff --git a/newlib/libc/sys/linux/dl/libintl.h b/newlib/libc/sys/linux/dl/libintl.h new file mode 100644 index 000000000..839210dea --- /dev/null +++ b/newlib/libc/sys/linux/dl/libintl.h @@ -0,0 +1,2 @@ +#define N_(x) x + diff --git a/newlib/libc/sys/linux/dl/trusted-dirs.h b/newlib/libc/sys/linux/dl/trusted-dirs.h new file mode 100644 index 000000000..103d6e6bb --- /dev/null +++ b/newlib/libc/sys/linux/dl/trusted-dirs.h @@ -0,0 +1,7 @@ +#define SYSTEM_DIRS \ + "/usr/local/lib/" + +#define SYSTEM_DIRS_LEN \ + 15 + +#define SYSTEM_DIRS_MAX_LEN 15 diff --git a/newlib/libc/sys/linux/dl/unsecvars.h b/newlib/libc/sys/linux/dl/unsecvars.h new file mode 100644 index 000000000..efb951595 --- /dev/null +++ b/newlib/libc/sys/linux/dl/unsecvars.h @@ -0,0 +1,19 @@ +/* Environment variable to be removed for SUID programs. The names are + all stuffed in a single string which means they have to be terminated + with a '\0' explicitly. */ +#define UNSECURE_ENVVARS \ + "LD_PRELOAD\0" \ + "LD_LIBRARY_PATH\0" \ + "LD_ORIGIN_PATH\0" \ + "LD_DEBUG_OUTPUT\0" \ + "LD_PROFILE\0" \ + "GCONV_PATH\0" \ + "HOSTALIASES\0" \ + "LOCALDOMAIN\0" \ + "LOCPATH\0" \ + "MALLOC_TRACE\0" \ + "NLSPATH\0" \ + "RESOLV_HOST_CONF\0" \ + "RES_OPTIONS\0" \ + "TMPDIR\0" \ + "TZDIR\0" -- cgit v1.2.3