xref: /openbsd-src/lib/libc/dlfcn/init.c (revision 9f11ffb7133c203312a01e4b986886bc88c7d74b)
1 /*	$OpenBSD: init.c,v 1.6 2017/12/01 23:30:05 guenther Exp $ */
2 /*
3  * Copyright (c) 2014,2015 Philip Guenther <guenther@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 
19 #define _DYN_LOADER
20 
21 #include <sys/types.h>
22 #include <sys/syscall.h>
23 
24 #ifndef PIC
25 #include <sys/mman.h>
26 #endif
27 
28 #include <tib.h>
29 #include <limits.h>		/* NAME_MAX */
30 #include <link.h>
31 #include <stdlib.h>		/* atexit */
32 #include <string.h>
33 #include <unistd.h>
34 
35 #include "init.h"
36 
37 #define MAX(a,b)	(((a)>(b))?(a):(b))
38 
39 #ifdef TIB_EXTRA_ALIGN
40 # define TIB_ALIGN	MAX(__alignof__(struct tib), TIB_EXTRA_ALIGN)
41 #else
42 # define TIB_ALIGN	__alignof__(struct tib)
43 #endif
44 
45 /* XXX should be in an include file shared with csu */
46 char	***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void));
47 
48 /* provide definition for this */
49 int	_pagesize = 0;
50 
51 /*
52  * In dynamicly linked binaries environ and __progname are overriden by
53  * the definitions in ld.so.
54  */
55 char	**environ __attribute__((weak)) = NULL;
56 char	*__progname __attribute__((weak)) = NULL;
57 
58 
59 #ifndef PIC
60 struct dl_phdr_info	_static_phdr_info = { .dlpi_name = "a.out" };
61 
62 static inline void early_static_init(char **_argv, char **_envp);
63 static inline void setup_static_tib(Elf_Phdr *_phdr, int _phnum);
64 
65 /* provided by the linker */
66 extern Elf_Ehdr __executable_start[] __attribute__((weak));
67 #endif /* PIC */
68 
69 /*
70  * extract useful bits from the auxiliary vector and either
71  * a) register ld.so's cleanup in dynamic links, or
72  * b) init __progname, environ, and the TIB in static links.
73  */
74 char ***
75 _csu_finish(char **argv, char **envp, void (*cleanup)(void))
76 {
77 	AuxInfo	*aux;
78 #ifndef PIC
79 	Elf_Phdr *phdr = NULL;
80 	int phnum = 0;
81 
82 	/* static libc in a static link? */
83 	if (cleanup == NULL)
84 		early_static_init(argv, envp);
85 #endif /* !PIC */
86 
87 	/* Extract useful bits from the auxiliary vector */
88 	while (*envp++ != NULL)
89 		;
90 	for (aux = (void *)envp; aux->au_id != AUX_null; aux++) {
91 		switch (aux->au_id) {
92 		case AUX_pagesz:
93 			_pagesize = aux->au_v;
94 			break;
95 #ifndef PIC
96 		case AUX_base:
97 			_static_phdr_info.dlpi_addr = aux->au_v;
98 			break;
99 		case AUX_phdr:
100 			phdr = (void *)aux->au_v;
101 			_static_phdr_info.dlpi_phdr = phdr;
102 			break;
103 		case AUX_phnum:
104 			phnum = aux->au_v;
105 			_static_phdr_info.dlpi_phnum = phnum;
106 			break;
107 #endif /* !PIC */
108 		}
109 	}
110 
111 #ifndef PIC
112 	if (cleanup == NULL && phdr == NULL && __executable_start != NULL) {
113 		/*
114 		 * Static non-PIE processes don't get an AUX vector,
115 		 * so find the phdrs through the ELF header
116 		 */
117 		phdr = (void *)((char *)__executable_start +
118 		    __executable_start->e_phoff);
119 		phnum = __executable_start->e_phnum;
120 	}
121 	/* static libc in a static link? */
122 	if (cleanup == NULL)
123 		setup_static_tib(phdr, phnum);
124 #endif /* !PIC */
125 
126 	if (cleanup != NULL)
127 		atexit(cleanup);
128 
129 	return &environ;
130 }
131 
132 #ifndef PIC
133 /*
134  * static libc in a static link?  Then disable kbind and set up
135  * __progname and environ
136  */
137 static inline void
138 early_static_init(char **argv, char **envp)
139 {
140 	static char progname_storage[NAME_MAX+1];
141 
142 	/* disable kbind */
143 	syscall(SYS_kbind, (void *)NULL, (size_t)0, (long long)0);
144 
145 	environ = envp;
146 
147 	/* set up __progname */
148 	if (*argv != NULL) {		/* NULL ptr if argc = 0 */
149 		const char *p = strrchr(*argv, '/');
150 
151 		if (p == NULL)
152 			p = *argv;
153 		else
154 			p++;
155 		strlcpy(progname_storage, p, sizeof(progname_storage));
156 	}
157 	__progname = progname_storage;
158 }
159 
160 /*
161  * static TLS handling
162  */
163 #define ELF_ROUND(x,malign)	(((x) + (malign)-1) & ~((malign)-1))
164 
165 /* for static binaries, the location and size of the TLS image */
166 static void		*static_tls;
167 static size_t		static_tls_fsize;
168 
169 size_t			_static_tls_size = 0;
170 int			_static_tls_align;
171 int			_static_tls_align_offset;
172 
173 static inline void
174 setup_static_tib(Elf_Phdr *phdr, int phnum)
175 {
176 	struct tib *tib;
177 	char *base;
178 	int i;
179 
180 	_static_tls_align = TIB_ALIGN;
181 	if (phdr != NULL) {
182 		for (i = 0; i < phnum; i++) {
183 			if (phdr[i].p_type != PT_TLS)
184 				continue;
185 			if (phdr[i].p_memsz == 0)
186 				break;
187 			if (phdr[i].p_memsz < phdr[i].p_filesz)
188 				break;		/* invalid */
189 			if (phdr[i].p_align > getpagesize())
190 				break;		/* nope */
191 			_static_tls_align = MAX(phdr[i].p_align, TIB_ALIGN);
192 #if TLS_VARIANT == 1
193 			/*
194 			 * Variant 1 places the data after the TIB.  If the
195 			 * TLS alignment is larger than the TIB alignment
196 			 * then we may need to pad in front of the TIB to
197 			 * place the TLS data on the proper alignment.
198 			 * Example: p_align=16 sizeof(TIB)=52 align(TIB)=4
199 			 * - need to offset the TIB 12 bytes from the start
200 			 * - to place ths TLS data at offset 64
201 			 */
202 			_static_tls_size = phdr[i].p_memsz;
203 			_static_tls_align_offset =
204 			    ELF_ROUND(sizeof(struct tib), _static_tls_align) -
205 			    sizeof(struct tib);
206 #elif TLS_VARIANT == 2
207 			/*
208 			 * Variant 2 places the data before the TIB
209 			 * so we need to round up the size to the
210 			 * TLS data alignment TIB's alignment.
211 			 * Example A: p_memsz=24 p_align=16 align(TIB)=8
212 			 * - need to allocate 32 bytes for TLS as compiler
213 			 * - will give the first TLS symbol an offset of -32
214 			 * Example B: p_memsz=4 p_align=4 align(TIB)=8
215 			 * - need to allocate 8 bytes so that the TIB is
216 			 * - properly aligned
217 			 */
218 			_static_tls_size = ELF_ROUND(phdr[i].p_memsz,
219 			    phdr[i].p_align);
220 			_static_tls_align_offset = ELF_ROUND(_static_tls_size,
221 			    _static_tls_align) - _static_tls_size;
222 #endif
223 			if (phdr[i].p_vaddr != 0 && phdr[i].p_filesz != 0) {
224 				static_tls = (void *)phdr[i].p_vaddr +
225 				    _static_phdr_info.dlpi_addr;
226 				static_tls_fsize = phdr[i].p_filesz;
227 			}
228 			break;
229 		}
230 	}
231 
232 	base = mmap(NULL, _static_tls_size + _static_tls_align_offset
233 	    + sizeof *tib, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
234 
235 	tib = _static_tls_init(base, NULL);
236 	tib->tib_tid = getthrid();
237 	TCB_SET(TIB_TO_TCB(tib));
238 #if ! TCB_HAVE_MD_GET
239 	_libc_single_tcb = TIB_TO_TCB(tib);
240 #endif
241 }
242 
243 struct tib *
244 _static_tls_init(char *base, void *thread)
245 {
246 	struct tib *tib;
247 
248 	base += _static_tls_align_offset;
249 # if TLS_VARIANT == 1
250 	tib = (struct tib *)base;
251 	base += sizeof(struct tib);
252 # elif TLS_VARIANT == 2
253 	tib = (struct tib *)(base + _static_tls_size);
254 # endif
255 
256 	if (_static_tls_size) {
257 		if (static_tls != NULL)
258 			memcpy(base, static_tls, static_tls_fsize);
259 		memset(base + static_tls_fsize, 0,
260 		    _static_tls_size - static_tls_fsize);
261 	}
262 
263 	TIB_INIT(tib, NULL, thread);
264 	return tib;
265 }
266 #endif /* !PIC */
267