1 /* $OpenBSD: tib.c,v 1.2 2017/12/01 23:30:05 guenther Exp $ */ 2 /* 3 * Copyright (c) 2016 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 #include <tib.h> 19 20 #ifndef PIC 21 # include <stdlib.h> /* posix_memalign and free */ 22 #endif 23 24 #define ELF_ROUND(x,malign) (((x) + (malign)-1) & ~((malign)-1)) 25 26 27 /* 28 * The functions here are weak so that the ld.so versions are used 29 * in dynamic links, whether or not libc is static 30 */ 31 void *_dl_allocate_tib(size_t _extra) __attribute__((weak)); 32 void _dl_free_tib(void *_tib, size_t _extra) __attribute__((weak)); 33 34 /* 35 * Allocate a TIB for passing to __tfork for a new thread. 'extra' 36 * is the amount of space to allocate on the side of the TIB opposite 37 * of the TLS data: before the TIB for variant 1 and after the TIB 38 * for variant 2. If non-zero, tib_thread is set to point to that area. 39 */ 40 void * 41 _dl_allocate_tib(size_t extra) 42 { 43 #ifdef PIC 44 return NULL; /* overriden by ld.so */ 45 #else 46 void *base; 47 char *thread; 48 49 # if TLS_VARIANT == 1 50 /* round up the extra size to align the TIB and TLS data after it */ 51 extra = (extra <= _static_tls_align_offset) ? 0 : 52 ELF_ROUND(extra - _static_tls_align_offset, _static_tls_align); 53 if (posix_memalign(&base, _static_tls_align, extra + 54 _static_tls_align_offset + sizeof(struct tib) + 55 _static_tls_size) != 0) 56 return NULL; 57 thread = base; 58 base = (char *)base + extra; 59 60 # elif TLS_VARIANT == 2 61 /* round up the TIB size to align the extra area after it */ 62 if (posix_memalign(&base, _static_tls_align, 63 _static_tls_align_offset + _static_tls_size + 64 ELF_ROUND(sizeof(struct tib), TIB_EXTRA_ALIGN) + extra) != 0) 65 return NULL; 66 thread = (char *)base + _static_tls_align_offset + _static_tls_size + 67 ELF_ROUND(sizeof(struct tib), TIB_EXTRA_ALIGN); 68 # endif 69 70 return _static_tls_init(base, thread); 71 #endif /* !PIC */ 72 } 73 74 void 75 _dl_free_tib(void *tib, size_t extra) 76 { 77 #ifndef PIC 78 size_t tib_offset; 79 80 # if TLS_VARIANT == 1 81 tib_offset = (extra <= _static_tls_align_offset) ? 0 : 82 ELF_ROUND(extra - _static_tls_align_offset, _static_tls_align); 83 # elif TLS_VARIANT == 2 84 tib_offset = _static_tls_size; 85 # endif 86 tib_offset += _static_tls_align_offset; 87 88 free((char *)tib - tib_offset); 89 #endif /* !PIC */ 90 } 91