xref: /netbsd-src/lib/libc/dlfcn/dlfcn_elf.c (revision aeee56d1a9118f5f0022974abaa82728888ab741)
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