1*aeee56d1Sriastradh /* $NetBSD: dlfcn_elf.c,v 1.17 2023/07/04 19:24:25 riastradh Exp $ */
278b10569Sminoura
378b10569Sminoura /*
478b10569Sminoura * Copyright (c) 2000 Takuya SHIOZAKI
578b10569Sminoura * All rights reserved.
678b10569Sminoura *
778b10569Sminoura * Redistribution and use in source and binary forms, with or without
878b10569Sminoura * modification, are permitted provided that the following conditions
978b10569Sminoura * are met:
1078b10569Sminoura * 1. Redistributions of source code must retain the above copyright
1178b10569Sminoura * notice, this list of conditions and the following disclaimer.
1278b10569Sminoura * 2. Redistributions in binary form must reproduce the above copyright
1378b10569Sminoura * notice, this list of conditions and the following disclaimer in the
1478b10569Sminoura * documentation and/or other materials provided with the distribution.
1578b10569Sminoura *
1678b10569Sminoura * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1778b10569Sminoura * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1878b10569Sminoura * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1978b10569Sminoura * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2078b10569Sminoura * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2178b10569Sminoura * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2278b10569Sminoura * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2378b10569Sminoura * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2478b10569Sminoura * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2578b10569Sminoura * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2678b10569Sminoura */
2778b10569Sminoura
2878b10569Sminoura #include <sys/cdefs.h>
2978b10569Sminoura #if defined(LIBC_SCCS) && !defined(lint)
30*aeee56d1Sriastradh __RCSID("$NetBSD: dlfcn_elf.c,v 1.17 2023/07/04 19:24:25 riastradh Exp $");
3178b10569Sminoura #endif /* LIBC_SCCS and not lint */
3278b10569Sminoura
3378b10569Sminoura #include "namespace.h"
34fecb3174Sjoerg #include <sys/atomic.h>
35c5e820caSchristos #include <assert.h>
365c3ccd6eSjoerg #include <elf.h>
375c3ccd6eSjoerg #include <errno.h>
385c3ccd6eSjoerg #include <string.h>
39fecb3174Sjoerg #include <stdbool.h>
4078b10569Sminoura
4117a7df3aSkamil #undef dl_iterate_phdr
422a63e040Sthorpej #undef dlopen
432a63e040Sthorpej #undef dlclose
442a63e040Sthorpej #undef dlsym
452a63e040Sthorpej #undef dlerror
462a63e040Sthorpej #undef dladdr
474c1e54d8Spooka #undef dfinfo
482a63e040Sthorpej
492a63e040Sthorpej #define dlopen ___dlopen
502a63e040Sthorpej #define dlclose ___dlclose
512a63e040Sthorpej #define dlsym ___dlsym
52c52f9a5dSnonaka #define dlvsym ___dlvsym
532a63e040Sthorpej #define dlerror ___dlerror
542a63e040Sthorpej #define dladdr ___dladdr
554c1e54d8Spooka #define dlinfo ___dlinfo
56e6cdac9cSskrll #define dl_iterate_phdr ___dl_iterate_phdr
572a63e040Sthorpej
5878b10569Sminoura #define ELFSIZE ARCH_ELFSIZE
5978b10569Sminoura #include "rtld.h"
6078b10569Sminoura
6178b10569Sminoura #ifdef __weak_alias
622a63e040Sthorpej __weak_alias(dlopen,___dlopen)
632a63e040Sthorpej __weak_alias(dlclose,___dlclose)
642a63e040Sthorpej __weak_alias(dlsym,___dlsym)
65c52f9a5dSnonaka __weak_alias(dlvsym,___dlvsym)
662a63e040Sthorpej __weak_alias(dlerror,___dlerror)
672a63e040Sthorpej __weak_alias(dladdr,___dladdr)
684c1e54d8Spooka __weak_alias(dlinfo,___dlinfo)
69e6cdac9cSskrll __weak_alias(dl_iterate_phdr,___dl_iterate_phdr)
702a63e040Sthorpej
712a63e040Sthorpej __weak_alias(__dlopen,___dlopen)
722a63e040Sthorpej __weak_alias(__dlclose,___dlclose)
732a63e040Sthorpej __weak_alias(__dlsym,___dlsym)
74c52f9a5dSnonaka __weak_alias(__dlvsym,___dlvsym)
752a63e040Sthorpej __weak_alias(__dlerror,___dlerror)
762a63e040Sthorpej __weak_alias(__dladdr,___dladdr)
774c1e54d8Spooka __weak_alias(__dlinfo,___dlinfo)
78e6cdac9cSskrll __weak_alias(__dl_iterate_phdr,___dl_iterate_phdr)
79e5678be8Sjoerg __weak_alias(__dl_cxa_refcount, ___dl_cxa_refcount)
8078b10569Sminoura #endif
8178b10569Sminoura
82d9007319Sskrll /*
83d9007319Sskrll * For ELF, the dynamic linker directly resolves references to its
84d9007319Sskrll * services to functions inside the dynamic linker itself. These
85d9007319Sskrll * weak-symbol stubs are necessary so that "ld" won't complain about
86d9007319Sskrll * undefined symbols. The stubs are executed only when the program is
87d9007319Sskrll * linked statically, or when a given service isn't implemented in the
88d9007319Sskrll * dynamic linker. They must return an error if called, and they must
89d9007319Sskrll * be weak symbols so that the dynamic linker can override them.
90d9007319Sskrll */
91d9007319Sskrll
92d9007319Sskrll static char dlfcn_error[] = "Service unavailable";
93d9007319Sskrll
94d9007319Sskrll /*ARGSUSED*/
95d9007319Sskrll void *
dlopen(const char * name,int mode)96d9007319Sskrll dlopen(const char *name, int mode)
97d9007319Sskrll {
98d9007319Sskrll
99d9007319Sskrll return NULL;
100d9007319Sskrll }
101d9007319Sskrll
102d9007319Sskrll /*ARGSUSED*/
103d9007319Sskrll int
dlclose(void * fd)104d9007319Sskrll dlclose(void *fd)
105d9007319Sskrll {
106d9007319Sskrll
107d9007319Sskrll return -1;
108d9007319Sskrll }
109d9007319Sskrll
110d9007319Sskrll /*ARGSUSED*/
111d9007319Sskrll void *
dlsym(void * handle,const char * name)112d9007319Sskrll dlsym(void *handle, const char *name)
113d9007319Sskrll {
114d9007319Sskrll
115d9007319Sskrll return NULL;
116d9007319Sskrll }
117d9007319Sskrll
118d9007319Sskrll /*ARGSUSED*/
119c52f9a5dSnonaka void *
dlvsym(void * handle,const char * name,const char * version)120c52f9a5dSnonaka dlvsym(void *handle, const char *name, const char *version)
121c52f9a5dSnonaka {
122c52f9a5dSnonaka
123c52f9a5dSnonaka return NULL;
124c52f9a5dSnonaka }
125c52f9a5dSnonaka
126c52f9a5dSnonaka /*ARGSUSED*/
127d9007319Sskrll __aconst char *
dlerror(void)1283d365e74Schristos dlerror(void)
129d9007319Sskrll {
130d9007319Sskrll
131d9007319Sskrll return dlfcn_error;
132d9007319Sskrll }
133d9007319Sskrll
134d9007319Sskrll /*ARGSUSED*/
135d9007319Sskrll int
dladdr(const void * addr,Dl_info * dli)136d9007319Sskrll dladdr(const void *addr, Dl_info *dli)
137d9007319Sskrll {
138d9007319Sskrll
139d9007319Sskrll return 0;
140d9007319Sskrll }
1414c1e54d8Spooka
1424c1e54d8Spooka /*ARGSUSED*/
1434c1e54d8Spooka int
dlinfo(void * handle,int req,void * v)1444c1e54d8Spooka dlinfo(void *handle, int req, void *v)
1454c1e54d8Spooka {
1464c1e54d8Spooka
1474c1e54d8Spooka return -1;
1484c1e54d8Spooka }
149e6cdac9cSskrll
1505c3ccd6eSjoerg static const char *dlpi_name;
1515c3ccd6eSjoerg static Elf_Addr dlpi_addr;
1525c3ccd6eSjoerg static const Elf_Phdr *dlpi_phdr;
1535c3ccd6eSjoerg static Elf_Half dlpi_phnum;
1545c3ccd6eSjoerg
1555c3ccd6eSjoerg static void
dl_iterate_phdr_setup(void)1565c3ccd6eSjoerg dl_iterate_phdr_setup(void)
1575c3ccd6eSjoerg {
1585c3ccd6eSjoerg const AuxInfo *aux;
1595c3ccd6eSjoerg
16052a4c27eSjoerg _DIAGASSERT(_dlauxinfo() != NULL);
1615c3ccd6eSjoerg
16252a4c27eSjoerg for (aux = _dlauxinfo(); aux->a_type != AT_NULL; ++aux) {
1635c3ccd6eSjoerg switch (aux->a_type) {
1645c3ccd6eSjoerg case AT_BASE:
1655c3ccd6eSjoerg dlpi_addr = aux->a_v;
1665c3ccd6eSjoerg break;
1675c3ccd6eSjoerg case AT_PHDR:
1685c3ccd6eSjoerg dlpi_phdr = (void *)aux->a_v;
1695c3ccd6eSjoerg break;
1705c3ccd6eSjoerg case AT_PHNUM:
171c5e820caSchristos _DIAGASSERT(__type_fit(Elf_Half, aux->a_v));
172c5e820caSchristos dlpi_phnum = (Elf_Half)aux->a_v;
1735c3ccd6eSjoerg break;
1745c3ccd6eSjoerg case AT_SUN_EXECNAME:
1755c3ccd6eSjoerg dlpi_name = (void *)aux->a_v;
1765c3ccd6eSjoerg break;
1775c3ccd6eSjoerg }
1785c3ccd6eSjoerg }
179bf395f73Sjoerg
180bf395f73Sjoerg if (!dlpi_phdr)
181bf395f73Sjoerg return;
182bf395f73Sjoerg
183bf395f73Sjoerg const Elf_Phdr *phdr = (const Elf_Phdr *)dlpi_phdr;
184bf395f73Sjoerg const Elf_Phdr *phlimit = phdr + dlpi_phnum;
185bf395f73Sjoerg
186bf395f73Sjoerg for (; phdr < phlimit; ++phdr) {
187bf395f73Sjoerg if (phdr->p_type == PT_PHDR)
188bf395f73Sjoerg dlpi_addr = (uintptr_t)phdr - phdr->p_vaddr;
189bf395f73Sjoerg }
1905c3ccd6eSjoerg }
1915c3ccd6eSjoerg
192e6cdac9cSskrll /*ARGSUSED*/
193e6cdac9cSskrll int
dl_iterate_phdr(int (* callback)(struct dl_phdr_info *,size_t,void *),void * data)194e6cdac9cSskrll dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *),
195e6cdac9cSskrll void *data)
196e6cdac9cSskrll {
197fecb3174Sjoerg static bool setup_done;
1985c3ccd6eSjoerg struct dl_phdr_info phdr_info;
199e6cdac9cSskrll
200fecb3174Sjoerg if (!setup_done) {
201fecb3174Sjoerg /*
202fecb3174Sjoerg * This can race on the first call to dl_iterate_phdr.
203fecb3174Sjoerg * dl_iterate_phdr_setup only touches field of pointer size
204fecb3174Sjoerg * and smaller and such stores are atomic.
205fecb3174Sjoerg */
206fecb3174Sjoerg dl_iterate_phdr_setup();
207fecb3174Sjoerg membar_producer();
208fecb3174Sjoerg setup_done = true;
209fecb3174Sjoerg }
210*aeee56d1Sriastradh membar_consumer();
2115c3ccd6eSjoerg
2125c3ccd6eSjoerg memset(&phdr_info, 0, sizeof(phdr_info));
2135c3ccd6eSjoerg phdr_info.dlpi_addr = dlpi_addr;
2145c3ccd6eSjoerg phdr_info.dlpi_phdr = dlpi_phdr;
2155c3ccd6eSjoerg phdr_info.dlpi_phnum = dlpi_phnum;
2165c3ccd6eSjoerg phdr_info.dlpi_name = dlpi_name;
2175c3ccd6eSjoerg
2185c3ccd6eSjoerg return callback(&phdr_info, sizeof(phdr_info), data);
219e6cdac9cSskrll }
220e5678be8Sjoerg
221e5678be8Sjoerg void ___dl_cxa_refcount(void *, ssize_t);
222e5678be8Sjoerg
223e5678be8Sjoerg /*ARGSUSED*/
224e5678be8Sjoerg void
___dl_cxa_refcount(void * dso_symbol,ssize_t delta)225e5678be8Sjoerg ___dl_cxa_refcount(void *dso_symbol, ssize_t delta)
226e5678be8Sjoerg {
227e5678be8Sjoerg }
228