Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Johnston <jjohnstn@redhat.com>2003-05-29 02:04:40 +0400
committerJeff Johnston <jjohnstn@redhat.com>2003-05-29 02:04:40 +0400
commitb359e82ceabbf42b1e3d8069627701fde5d7cb90 (patch)
tree38a5f38a753bd8420933e58d0da2dd6732afe406 /newlib/libc/sys/linux/dl
parent4218d888971213c57c903845e16a10bc8bde616b (diff)
2003-05-28 Jeff Johnston <jjohnstn@redhat.com>
Tom Fitzsimmons <fitzsim@redhat.com> * 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.
Diffstat (limited to 'newlib/libc/sys/linux/dl')
-rw-r--r--newlib/libc/sys/linux/dl/Makefile.am25
-rw-r--r--newlib/libc/sys/linux/dl/Makefile.in379
-rw-r--r--newlib/libc/sys/linux/dl/abi-tag.h4
-rw-r--r--newlib/libc/sys/linux/dl/atomicity.h56
-rw-r--r--newlib/libc/sys/linux/dl/dl-addr.c101
-rw-r--r--newlib/libc/sys/linux/dl/dl-cache.c271
-rw-r--r--newlib/libc/sys/linux/dl/dl-cache.h140
-rw-r--r--newlib/libc/sys/linux/dl/dl-close.c334
-rw-r--r--newlib/libc/sys/linux/dl/dl-debug.c57
-rw-r--r--newlib/libc/sys/linux/dl/dl-deps.c561
-rw-r--r--newlib/libc/sys/linux/dl/dl-dst.h45
-rw-r--r--newlib/libc/sys/linux/dl/dl-error.c189
-rw-r--r--newlib/libc/sys/linux/dl/dl-fini.c172
-rw-r--r--newlib/libc/sys/linux/dl/dl-init.c149
-rw-r--r--newlib/libc/sys/linux/dl/dl-iteratephdr.c65
-rw-r--r--newlib/libc/sys/linux/dl/dl-libc.c156
-rw-r--r--newlib/libc/sys/linux/dl/dl-librecon.h87
-rw-r--r--newlib/libc/sys/linux/dl/dl-load.c1830
-rw-r--r--newlib/libc/sys/linux/dl/dl-lookup.c654
-rw-r--r--newlib/libc/sys/linux/dl/dl-lookupcfg.h22
-rw-r--r--newlib/libc/sys/linux/dl/dl-minimal.c250
-rw-r--r--newlib/libc/sys/linux/dl/dl-misc.c277
-rw-r--r--newlib/libc/sys/linux/dl/dl-object.c163
-rw-r--r--newlib/libc/sys/linux/dl/dl-open.c487
-rw-r--r--newlib/libc/sys/linux/dl/dl-osinfo.h108
-rw-r--r--newlib/libc/sys/linux/dl/dl-profile.c539
-rw-r--r--newlib/libc/sys/linux/dl/dl-profstub.c43
-rw-r--r--newlib/libc/sys/linux/dl/dl-reloc.c213
-rw-r--r--newlib/libc/sys/linux/dl/dl-runtime.c231
-rw-r--r--newlib/libc/sys/linux/dl/dl-support.c184
-rw-r--r--newlib/libc/sys/linux/dl/dl-sym.c158
-rw-r--r--newlib/libc/sys/linux/dl/dl-version.c385
-rw-r--r--newlib/libc/sys/linux/dl/dlfcn.h84
-rw-r--r--newlib/libc/sys/linux/dl/do-lookup.h200
-rw-r--r--newlib/libc/sys/linux/dl/do-rel.h118
-rw-r--r--newlib/libc/sys/linux/dl/dynamic-link.h244
-rw-r--r--newlib/libc/sys/linux/dl/kernel-features.h193
-rw-r--r--newlib/libc/sys/linux/dl/ldsodefs.h535
-rw-r--r--newlib/libc/sys/linux/dl/libintl.h2
-rw-r--r--newlib/libc/sys/linux/dl/trusted-dirs.h7
-rw-r--r--newlib/libc/sys/linux/dl/unsecvars.h19
41 files changed, 9737 insertions, 0 deletions
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 <dlfcn.h>
+#include <stddef.h>
+#include <ldsodefs.h>
+
+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 <assert.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <sys/mman.h>
+#include <dl-cache.h>
+#include <machine/dl-procinfo.h>
+#include <machine/weakalias.h>
+
+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 <stdint.h>
+
+#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 <assert.h>
+#include <dlfcn.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <ldsodefs.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+
+/* 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 <ldsodefs.h>
+
+/* 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 <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <ldsodefs.h>
+
+#include <dl-dst.h>
+
+/* 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 <libintl.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <sys/libc-tsd.h>
+
+/* 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] ?: "<program name unknown>",
+ 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 <alloca.h>
+#include <assert.h>
+#include <string.h>
+#include <ldsodefs.h>
+
+
+/* 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 <stddef.h>
+#include <ldsodefs.h>
+
+
+/* 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 <jakub@redhat.com>, 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 <errno.h>
+#include <ldsodefs.h>
+#include <stddef.h>
+#include <bits/libc-lock.h>
+
+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 <zack@rabi.columbia.edu>, 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 <dlfcn.h>
+#include <stdlib.h>
+#include <ldsodefs.h>
+
+/* 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 <drepper@cygnus.com>, 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 <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "dynamic-link.h"
+#include <abi-tag.h>
+#include <dl-osinfo.h>
+
+#include <dl-dst.h>
+
+/* 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 <endian.h>
+#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 <alloca.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include "dl-hash.h"
+#include <machine/dl-machine.h>
+#include <bits/libc-lock.h>
+
+#include <assert.h>
+
+#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, &current_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] ?: "<main program>")),
+ 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] ?: "<main program>")),
+ 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, &current_value, *scope, i,
+ skip_map, 0))
+ while (*++scope)
+ if (_dl_do_lookup (undef_name, hash, *ref, &current_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] ?: "<main program>")),
+ 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, &current_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] ?: "<main program>")),
+ 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] ?: "<main program>")), 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] ?: "<main program>")),
+ 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, &current_value,
+ *scope, i, version, skip_map, 0))
+ while (*++scope)
+ if (_dl_do_lookup_versioned (undef_name, hash, *ref, &current_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] ?: "<main program>")),
+ 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] ?: "<main program>")),
+ 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 <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <ldsodefs.h>
+#include <machine/weakalias.h>
+
+#include <assert.h>
+
+/* 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 <assert.h>
+#include <fcntl.h>
+#include <ldsodefs.h>
+#include <limits.h>
+#include <link.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#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 <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+
+#include <assert.h>
+
+
+/* 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 <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h> /* Check whether MAP_COPY is defined. */
+#include <sys/param.h>
+#include <ldsodefs.h>
+#include <bp-sym.h>
+
+#include <dl-dst.h>
+#include <machine/weakalias.h>
+
+
+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 <unistd.h>
+
+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 (" <main>");
+
+ _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 <string.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+#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 <drepper@cygnus.com>, 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 <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <sys/gmon.h>
+#include <sys/gmon_out.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <atomicity.h>
+#include <config.h>
+
+/* 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
+ <external> 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 <drepper@cygnus.com>, 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 <dlfcn.h>
+#include <elf.h>
+#include <ldsodefs.h>
+#include <libc-symbols.h>
+
+/* 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 <errno.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#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] ?: "<program name unknown>",
+ 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 <alloca.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#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 <errno.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <ldsodefs.h>
+#include <machine/dl-machine.h>
+#include <dl-librecon.h>
+#include <unsecvars.h>
+#include <machine/hp-timing.h>
+
+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 <stddef.h>
+#include <setjmp.h>
+#include <libintl.h>
+
+#include <dlfcn.h>
+#include <ldsodefs.h>
+#include <dl-hash.h>
+
+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 <drepper@cygnus.com>, 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 <elf.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ldsodefs.h>
+
+#include <assert.h>
+
+
+#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 <features.h>
+
+/* Collect various system dependent definitions and declarations. */
+#include <sys/dlfcn.h>
+
+
+/* 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 <machine/weakalias.h>
+
+#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 <elf.h>
+#include <machine/dl-machine.h>
+#include <assert.h>
+
+#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 <features.h>
+
+#define __need_size_t
+#define __need_NULL
+#include <stddef.h>
+#include <string.h>
+
+#include <elf.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <dl-lookupcfg.h>
+#include <bits/libc-lock.h>
+
+__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 <dlfcn.h> 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_<CPU>_* 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"