GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/dlfcn/init.c Lines: 41 53 77.4 %
Date: 2017-11-13 Branches: 19 37 51.4 %

Line Branch Exec Source
1
/*	$OpenBSD: init.c,v 1.5 2016/09/06 18:49:34 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
/* XXX should be in an include file shared with csu */
38
char	***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void));
39
40
/* provide definition for this */
41
int	_pagesize = 0;
42
43
/*
44
 * In dynamicly linked binaries environ and __progname are overriden by
45
 * the definitions in ld.so.
46
 */
47
char	**environ __attribute__((weak)) = NULL;
48
char	*__progname __attribute__((weak)) = NULL;
49
50
51
#ifndef PIC
52
struct dl_phdr_info	_static_phdr_info = { .dlpi_name = "a.out" };
53
54
static inline void early_static_init(char **_argv, char **_envp);
55
static inline void setup_static_tib(Elf_Phdr *_phdr, int _phnum);
56
#endif /* PIC */
57
58
59
/*
60
 * extract useful bits from the auxiliary vector and either
61
 * a) register ld.so's cleanup in dynamic links, or
62
 * b) init __progname, environ, and the TIB in static links.
63
 */
64
char ***
65
_csu_finish(char **argv, char **envp, void (*cleanup)(void))
66
{
67
	AuxInfo	*aux;
68
#ifndef PIC
69
	Elf_Phdr *phdr = NULL;
70
	int phnum = 0;
71
72
	/* static libc in a static link? */
73
30
	if (cleanup == NULL)
74
15
		early_static_init(argv, envp);
75
#endif /* !PIC */
76
77
	/* Extract useful bits from the auxiliary vector */
78
750
	while (*envp++ != NULL)
79
		;
80
240
	for (aux = (void *)envp; aux->au_id != AUX_null; aux++) {
81

165
		switch (aux->au_id) {
82
		case AUX_pagesz:
83
15
			_pagesize = aux->au_v;
84
15
			break;
85
#ifndef PIC
86
		case AUX_base:
87
15
			_static_phdr_info.dlpi_addr = aux->au_v;
88
15
			break;
89
		case AUX_phdr:
90
15
			phdr = (void *)aux->au_v;
91
15
			_static_phdr_info.dlpi_phdr = phdr;
92
15
			break;
93
		case AUX_phnum:
94
15
			phnum = aux->au_v;
95
15
			_static_phdr_info.dlpi_phnum = phnum;
96
15
			break;
97
#endif /* !PIC */
98
		}
99
	}
100
101
#ifndef PIC
102
	/* static libc in a static link? */
103
15
	if (cleanup == NULL)
104
15
		setup_static_tib(phdr, phnum);
105
#endif /* !PIC */
106
107
15
	if (cleanup != NULL)
108
		atexit(cleanup);
109
110
15
	return &environ;
111
}
112
113
#ifndef PIC
114
/*
115
 * static libc in a static link?  Then disable kbind and set up
116
 * __progname and environ
117
 */
118
static inline void
119
early_static_init(char **argv, char **envp)
120
{
121
	static char progname_storage[NAME_MAX+1];
122
123
	/* disable kbind */
124
30
	syscall(SYS_kbind, (void *)NULL, (size_t)0, (long long)0);
125
126
15
	environ = envp;
127
128
	/* set up __progname */
129
15
	if (*argv != NULL) {		/* NULL ptr if argc = 0 */
130
15
		const char *p = strrchr(*argv, '/');
131
132
15
		if (p == NULL)
133
			p = *argv;
134
		else
135
15
			p++;
136
15
		strlcpy(progname_storage, p, sizeof(progname_storage));
137
15
	}
138
15
	__progname = progname_storage;
139
15
}
140
141
/*
142
 * static TLS handling
143
 */
144
#define ELF_ROUND(x,malign)	(((x) + (malign)-1) & ~((malign)-1))
145
146
/* for static binaries, the location and size of the TLS image */
147
static void		*static_tls;
148
static size_t		static_tls_fsize;
149
150
size_t			_static_tls_size = 0;
151
152
static inline void
153
setup_static_tib(Elf_Phdr *phdr, int phnum)
154
{
155
	struct tib *tib;
156
	char *base;
157
	int i;
158
159
30
	if (phdr != NULL) {
160
300
		for (i = 0; i < phnum; i++) {
161
135
			if (phdr[i].p_type != PT_TLS)
162
				continue;
163
			if (phdr[i].p_memsz == 0)
164
				break;
165
			if (phdr[i].p_memsz < phdr[i].p_filesz)
166
				break;		/* invalid */
167
#if TLS_VARIANT == 1
168
			_static_tls_size = phdr[i].p_memsz;
169
#elif TLS_VARIANT == 2
170
			/*
171
			 * variant 2 places the data before the TIB
172
			 * so we need to round up to the alignment
173
			 */
174
			_static_tls_size = ELF_ROUND(phdr[i].p_memsz,
175
			    phdr[i].p_align);
176
#endif
177
			if (phdr[i].p_vaddr != 0 && phdr[i].p_filesz != 0) {
178
				static_tls = (void *)phdr[i].p_vaddr;
179
				static_tls_fsize = phdr[i].p_filesz;
180
			}
181
			break;
182
		}
183
	}
184
185
	/*
186
	 * We call getpagesize() here instead of using _pagesize because
187
	 * there's no aux-vector in non-PIE static links, so _pagesize
188
	 * might not be set yet.  If so getpagesize() will get the value.
189
	 */
190
15
	base = mmap(NULL, ELF_ROUND(_static_tls_size + sizeof *tib,
191
	    getpagesize()), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
192
# if TLS_VARIANT == 1
193
	tib = (struct tib *)base;
194
# elif TLS_VARIANT == 2
195
15
	tib = (struct tib *)(base + _static_tls_size);
196
# endif
197
198
15
	_static_tls_init(base);
199
15
	TIB_INIT(tib, NULL, NULL);
200
15
	tib->tib_tid = getthrid();
201
15
	TCB_SET(TIB_TO_TCB(tib));
202
#if ! TCB_HAVE_MD_GET
203
	_libc_single_tcb = TIB_TO_TCB(tib);
204
#endif
205
15
}
206
207
void
208
_static_tls_init(char *base)
209
{
210
30
	if (_static_tls_size) {
211
#if TLS_VARIANT == 1
212
		base += sizeof(struct tib);
213
#endif
214
		if (static_tls != NULL)
215
			memcpy(base, static_tls, static_tls_fsize);
216
		memset(base + static_tls_fsize, 0,
217
		    _static_tls_size - static_tls_fsize);
218
	}
219
15
}
220
#endif /* !PIC */