]>
Commit | Line | Data |
---|---|---|
b2ec3c8a MT |
1 | When building glibc PIE (which is not something upstream support), |
2 | several modifications are necessary to the glibc build process. | |
3 | ||
4 | First, any syscalls in PIEs must be of the PIC variant, otherwise | |
5 | textrels ensue. Then, any syscalls made before the initialisation | |
6 | of the TLS will fail on i386, as the sysenter variant on i386 uses | |
7 | the TLS, giving rise to a chicken-and-egg situation. This patch | |
8 | defines a PIC syscall variant that doesn't use sysenter, even when the sysenter | |
9 | version is normally used, and uses the non-sysenter version for the brk | |
10 | syscall that is performed by the TLS initialisation. Further, the TLS | |
11 | initialisation is moved in this case prior to the initialisation of | |
12 | dl_osversion, as that requires further syscalls. | |
13 | ||
14 | csu/libc-start.c: Move initial TLS initialization to before the | |
15 | initialisation of dl_osversion, when INTERNAL_SYSCALL_NOSYSENTER is defined | |
16 | ||
17 | csu/libc-tls.c: Use the no-sysenter version of sbrk when | |
18 | INTERNAL_SYSCALL_NOSYSENTER is defined. | |
19 | ||
20 | misc/sbrk.c: Define a no-sysenter version of sbrk, using the no-sysenter | |
21 | version of brk - if INTERNAL_SYSCALL_NOSYSENTER is defined. | |
22 | ||
23 | misc/brk.c: Define a no-sysenter version of brk if | |
24 | INTERNAL_SYSCALL_NOSYSENTER is defined. | |
25 | ||
26 | sysdeps/unix/sysv/linux/i386/sysdep.h: Define INTERNAL_SYSCALL_NOSYSENTER | |
27 | Make INTERNAL_SYSCALL always use the PIC variant, even if not SHARED. | |
28 | ||
29 | Patch by Kevin F. Quinn <kevquinn@gentoo.org> | |
30 | ||
31 | --- glibc-2.10.1/csu/libc-start.c | |
32 | +++ glibc-2.10.1/csu/libc-start.c | |
33 | @@ -28,6 +28,7 @@ | |
34 | extern int __libc_multiple_libcs; | |
35 | ||
36 | #include <tls.h> | |
37 | +#include <sysdep.h> | |
38 | #ifndef SHARED | |
39 | # include <dl-osinfo.h> | |
40 | extern void __pthread_initialize_minimal (void); | |
41 | @@ -129,6 +130,11 @@ | |
42 | # endif | |
43 | _dl_aux_init (auxvec); | |
44 | # endif | |
45 | +# ifdef INTERNAL_SYSCALL_NOSYSENTER | |
46 | + /* Do the initial TLS initialization before _dl_osversion, | |
47 | + since the latter uses the uname syscall. */ | |
48 | + __pthread_initialize_minimal (); | |
49 | +# endif | |
50 | # ifdef DL_SYSDEP_OSCHECK | |
51 | if (!__libc_multiple_libcs) | |
52 | { | |
53 | @@ -138,10 +144,12 @@ | |
54 | } | |
55 | # endif | |
56 | ||
57 | +# ifndef INTERNAL_SYSCALL_NOSYSENTER | |
58 | /* Initialize the thread library at least a bit since the libgcc | |
59 | functions are using thread functions if these are available and | |
60 | we need to setup errno. */ | |
61 | __pthread_initialize_minimal (); | |
62 | +# endif | |
63 | ||
64 | /* Set up the stack checker's canary. */ | |
65 | uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (); | |
66 | --- glibc-2.10.1/csu/libc-tls.c | |
67 | +++ glibc-2.10.1/csu/libc-tls.c | |
68 | @@ -23,6 +23,7 @@ | |
69 | #include <unistd.h> | |
70 | #include <stdio.h> | |
71 | #include <sys/param.h> | |
72 | +#include <sysdep.h> | |
73 | ||
74 | ||
75 | #ifdef SHARED | |
76 | @@ -29,6 +30,9 @@ | |
77 | #error makefile bug, this file is for static only | |
78 | #endif | |
79 | ||
80 | +#ifdef INTERNAL_SYSCALL_NOSYSENTER | |
81 | +extern void *__sbrk_nosysenter (intptr_t __delta); | |
82 | +#endif | |
83 | extern ElfW(Phdr) *_dl_phdr; | |
84 | extern size_t _dl_phnum; | |
85 | ||
86 | @@ -141,14 +145,26 @@ | |
87 | ||
88 | The initialized value of _dl_tls_static_size is provided by dl-open.c | |
89 | to request some surplus that permits dynamic loading of modules with | |
90 | - IE-model TLS. */ | |
91 | + IE-model TLS. | |
92 | + | |
93 | + Where the normal sbrk would use a syscall that needs the TLS (i386) | |
94 | + use the special non-sysenter version instead. */ | |
95 | #if TLS_TCB_AT_TP | |
96 | tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign); | |
97 | +# ifdef INTERNAL_SYSCALL_NOSYSENTER | |
98 | + tlsblock = __sbrk_nosysenter (tcb_offset + tcbsize + max_align); | |
99 | +# else | |
100 | tlsblock = __sbrk (tcb_offset + tcbsize + max_align); | |
101 | +# endif | |
102 | #elif TLS_DTV_AT_TP | |
103 | tcb_offset = roundup (tcbsize, align ?: 1); | |
104 | +# ifdef INTERNAL_SYSCALL_NOSYSENTER | |
105 | + tlsblock = __sbrk_nosysenter (tcb_offset + memsz + max_align | |
106 | + + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size)); | |
107 | +# else | |
108 | tlsblock = __sbrk (tcb_offset + memsz + max_align | |
109 | + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size)); | |
110 | +# endif | |
111 | tlsblock += TLS_PRE_TCB_SIZE; | |
112 | #else | |
113 | /* In case a model with a different layout for the TCB and DTV | |
114 | --- glibc-2.10.1/misc/sbrk.c | |
115 | +++ glibc-2.10.1/misc/sbrk.c | |
116 | @@ -18,6 +18,7 @@ | |
117 | ||
118 | #include <stdint.h> | |
119 | #include <unistd.h> | |
120 | +#include <sysdep.h> | |
121 | ||
122 | /* Defined in brk.c. */ | |
123 | extern void *__curbrk; | |
124 | @@ -29,6 +30,35 @@ | |
125 | /* Extend the process's data space by INCREMENT. | |
126 | If INCREMENT is negative, shrink data space by - INCREMENT. | |
127 | Return start of new space allocated, or -1 for errors. */ | |
128 | +#ifdef INTERNAL_SYSCALL_NOSYSENTER | |
129 | +/* This version is used by csu/libc-tls.c whem initialising the TLS | |
130 | + if the SYSENTER version requires the TLS (which it does on i386). | |
131 | + Obviously using the TLS before it is initialised is broken. */ | |
132 | +extern int __brk_nosysenter (void *addr); | |
133 | +void * | |
134 | +__sbrk_nosysenter (intptr_t increment) | |
135 | +{ | |
136 | + void *oldbrk; | |
137 | + | |
138 | + /* If this is not part of the dynamic library or the library is used | |
139 | + via dynamic loading in a statically linked program update | |
140 | + __curbrk from the kernel's brk value. That way two separate | |
141 | + instances of __brk and __sbrk can share the heap, returning | |
142 | + interleaved pieces of it. */ | |
143 | + if (__curbrk == NULL || __libc_multiple_libcs) | |
144 | + if (__brk_nosysenter (0) < 0) /* Initialize the break. */ | |
145 | + return (void *) -1; | |
146 | + | |
147 | + if (increment == 0) | |
148 | + return __curbrk; | |
149 | + | |
150 | + oldbrk = __curbrk; | |
151 | + if (__brk_nosysenter (oldbrk + increment) < 0) | |
152 | + return (void *) -1; | |
153 | + | |
154 | + return oldbrk; | |
155 | +} | |
156 | +#endif | |
157 | void * | |
158 | __sbrk (intptr_t increment) | |
159 | { | |
160 | --- glibc-2.10.1/sysdeps/unix/sysv/linux/i386/brk.c | |
161 | +++ glibc-2.10.1/sysdeps/unix/sysv/linux/i386/brk.c | |
162 | @@ -31,6 +31,30 @@ | |
163 | linker. */ | |
164 | weak_alias (__curbrk, ___brk_addr) | |
165 | ||
166 | +#ifdef INTERNAL_SYSCALL_NOSYSENTER | |
167 | +/* This version is used by csu/libc-tls.c whem initialising the TLS | |
168 | + * if the SYSENTER version requires the TLS (which it does on i386). | |
169 | + * Obviously using the TLS before it is initialised is broken. */ | |
170 | +int | |
171 | +__brk_nosysenter (void *addr) | |
172 | +{ | |
173 | + void *__unbounded newbrk; | |
174 | + | |
175 | + INTERNAL_SYSCALL_DECL (err); | |
176 | + newbrk = (void *__unbounded) INTERNAL_SYSCALL_NOSYSENTER (brk, err, 1, | |
177 | + __ptrvalue (addr)); | |
178 | + | |
179 | + __curbrk = newbrk; | |
180 | + | |
181 | + if (newbrk < addr) | |
182 | + { | |
183 | + __set_errno (ENOMEM); | |
184 | + return -1; | |
185 | + } | |
186 | + | |
187 | + return 0; | |
188 | +} | |
189 | +#endif | |
190 | int | |
191 | __brk (void *addr) | |
192 | { | |
193 | --- glibc-2.10.1/sysdeps/unix/sysv/linux/i386/sysdep.h | |
194 | +++ glibc-2.10.1/sysdeps/unix/sysv/linux/i386/sysdep.h | |
195 | @@ -187,7 +187,7 @@ | |
196 | /* The original calling convention for system calls on Linux/i386 is | |
197 | to use int $0x80. */ | |
198 | #ifdef I386_USE_SYSENTER | |
199 | -# ifdef SHARED | |
200 | +# if defined SHARED || defined __PIC__ | |
201 | # define ENTER_KERNEL call *%gs:SYSINFO_OFFSET | |
202 | # else | |
203 | # define ENTER_KERNEL call *_dl_sysinfo | |
204 | @@ -358,7 +358,7 @@ | |
205 | possible to use more than four parameters. */ | |
206 | #undef INTERNAL_SYSCALL | |
207 | #ifdef I386_USE_SYSENTER | |
208 | -# ifdef SHARED | |
209 | +# if defined SHARED || defined __PIC__ | |
210 | # define INTERNAL_SYSCALL(name, err, nr, args...) \ | |
211 | ({ \ | |
212 | register unsigned int resultvar; \ | |
213 | @@ -384,6 +384,18 @@ | |
214 | : "0" (name), "i" (offsetof (tcbhead_t, sysinfo)) \ | |
215 | ASMFMT_##nr(args) : "memory", "cc"); \ | |
216 | (int) resultvar; }) | |
217 | +# define INTERNAL_SYSCALL_NOSYSENTER(name, err, nr, args...) \ | |
218 | + ({ \ | |
219 | + register unsigned int resultvar; \ | |
220 | + EXTRAVAR_##nr \ | |
221 | + asm volatile ( \ | |
222 | + LOADARGS_NOSYSENTER_##nr \ | |
223 | + "movl %1, %%eax\n\t" \ | |
224 | + "int $0x80\n\t" \ | |
225 | + RESTOREARGS_NOSYSENTER_##nr \ | |
226 | + : "=a" (resultvar) \ | |
227 | + : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc"); \ | |
228 | + (int) resultvar; }) | |
229 | # else | |
230 | # define INTERNAL_SYSCALL(name, err, nr, args...) \ | |
231 | ({ \ | |
232 | @@ -447,12 +459,20 @@ | |
233 | ||
234 | #define LOADARGS_0 | |
235 | #ifdef __PIC__ | |
236 | -# if defined I386_USE_SYSENTER && defined SHARED | |
237 | +# if defined I386_USE_SYSENTER && ( defined SHARED || defined __PIC__ ) | |
238 | # define LOADARGS_1 \ | |
239 | "bpushl .L__X'%k3, %k3\n\t" | |
240 | # define LOADARGS_5 \ | |
241 | "movl %%ebx, %4\n\t" \ | |
242 | "movl %3, %%ebx\n\t" | |
243 | +# define LOADARGS_NOSYSENTER_1 \ | |
244 | + "bpushl .L__X'%k2, %k2\n\t" | |
245 | +# define LOADARGS_NOSYSENTER_2 LOADARGS_NOSYSENTER_1 | |
246 | +# define LOADARGS_NOSYSENTER_3 LOADARGS_3 | |
247 | +# define LOADARGS_NOSYSENTER_4 LOADARGS_3 | |
248 | +# define LOADARGS_NOSYSENTER_5 \ | |
249 | + "movl %%ebx, %3\n\t" \ | |
250 | + "movl %2, %%ebx\n\t" | |
251 | # else | |
252 | # define LOADARGS_1 \ | |
253 | "bpushl .L__X'%k2, %k2\n\t" | |
254 | @@ -474,11 +495,18 @@ | |
255 | ||
256 | #define RESTOREARGS_0 | |
257 | #ifdef __PIC__ | |
258 | -# if defined I386_USE_SYSENTER && defined SHARED | |
259 | +# if defined I386_USE_SYSENTER && ( defined SHARED || defined __PIC__ ) | |
260 | # define RESTOREARGS_1 \ | |
261 | "bpopl .L__X'%k3, %k3\n\t" | |
262 | # define RESTOREARGS_5 \ | |
263 | "movl %4, %%ebx" | |
264 | +# define RESTOREARGS_NOSYSENTER_1 \ | |
265 | + "bpopl .L__X'%k2, %k2\n\t" | |
266 | +# define RESTOREARGS_NOSYSENTER_2 RESTOREARGS_NOSYSENTER_1 | |
267 | +# define RESTOREARGS_NOSYSENTER_3 RESTOREARGS_3 | |
268 | +# define RESTOREARGS_NOSYSENTER_4 RESTOREARGS_3 | |
269 | +# define RESTOREARGS_NOSYSENTER_5 \ | |
270 | + "movl %3, %%ebx" | |
271 | # else | |
272 | # define RESTOREARGS_1 \ | |
273 | "bpopl .L__X'%k2, %k2\n\t" |