1// Bionic-specific support for sections. 2// Copyright (C) 2019-2020 Free Software Foundation, Inc. 3 4// GCC is free software; you can redistribute it and/or modify it under 5// the terms of the GNU General Public License as published by the Free 6// Software Foundation; either version 3, or (at your option) any later 7// version. 8 9// GCC is distributed in the hope that it will be useful, but WITHOUT ANY 10// WARRANTY; without even the implied warranty of MERCHANTABILITY or 11// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12// for more details. 13 14// Under Section 7 of GPL version 3, you are granted additional 15// permissions described in the GCC Runtime Library Exception, version 16// 3.1, as published by the Free Software Foundation. 17 18// You should have received a copy of the GNU General Public License and 19// a copy of the GCC Runtime Library Exception along with this program; 20// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 21// <http://www.gnu.org/licenses/>. 22 23module gcc.sections.android; 24 25version (CRuntime_Bionic): 26 27// debug = PRINTF; 28debug(PRINTF) import core.stdc.stdio; 29import core.stdc.stdlib : malloc, free; 30import rt.deh, rt.minfo; 31import core.sys.posix.pthread; 32import core.stdc.stdlib : calloc; 33import core.stdc.string : memcpy; 34 35struct SectionGroup 36{ 37 static int opApply(scope int delegate(ref SectionGroup) dg) 38 { 39 return dg(_sections); 40 } 41 42 static int opApplyReverse(scope int delegate(ref SectionGroup) dg) 43 { 44 return dg(_sections); 45 } 46 47 @property immutable(ModuleInfo*)[] modules() const nothrow @nogc 48 { 49 return _moduleGroup.modules; 50 } 51 52 @property ref inout(ModuleGroup) moduleGroup() inout nothrow @nogc 53 { 54 return _moduleGroup; 55 } 56 57 @property immutable(FuncTable)[] ehTables() const nothrow @nogc 58 { 59 auto pbeg = cast(immutable(FuncTable)*)&__start_deh; 60 auto pend = cast(immutable(FuncTable)*)&__stop_deh; 61 return pbeg[0 .. pend - pbeg]; 62 } 63 64 @property inout(void[])[] gcRanges() inout nothrow @nogc 65 { 66 return _gcRanges[]; 67 } 68 69private: 70 ModuleGroup _moduleGroup; 71 void[][1] _gcRanges; 72} 73 74void initSections() nothrow @nogc 75{ 76 pthread_key_create(&_tlsKey, null); 77 78 auto mbeg = cast(immutable ModuleInfo**)&__start_minfo; 79 auto mend = cast(immutable ModuleInfo**)&__stop_minfo; 80 _sections.moduleGroup = ModuleGroup(mbeg[0 .. mend - mbeg]); 81 82 auto pbeg = cast(void*)&_tlsend; 83 auto pend = cast(void*)&__bss_end__; 84 // _tlsend is a 32-bit int and may not be 64-bit void*-aligned, so align pbeg. 85 version (D_LP64) pbeg = cast(void*)(cast(size_t)(pbeg + 7) & ~cast(size_t)7); 86 _sections._gcRanges[0] = pbeg[0 .. pend - pbeg]; 87} 88 89void finiSections() nothrow @nogc 90{ 91 pthread_key_delete(_tlsKey); 92} 93 94void[]* initTLSRanges() nothrow @nogc 95{ 96 return &getTLSBlock(); 97} 98 99void finiTLSRanges(void[]* rng) nothrow @nogc 100{ 101 .free(rng.ptr); 102 .free(rng); 103} 104 105void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow 106{ 107 dg(rng.ptr, rng.ptr + rng.length); 108} 109 110/* NOTE: The Bionic C library ignores thread-local data stored in the normal 111 * .tbss/.tdata ELF sections, which are marked with the SHF_TLS/STT_TLS 112 * flags. So instead we roll our own by keeping TLS data in the 113 * .tdata/.tbss sections but removing the SHF_TLS/STT_TLS flags, and 114 * access the TLS data using this function and the _tlsstart/_tlsend 115 * symbols as delimiters. 116 * 117 * This function is called by the code emitted by the compiler. It 118 * is expected to translate an address in the TLS static data to 119 * the corresponding address in the TLS dynamic per-thread data. 120 */ 121 122extern(C) void* __tls_get_addr( void* p ) nothrow @nogc 123{ 124 debug(PRINTF) printf(" __tls_get_addr input - %p\n", p); 125 immutable offset = cast(size_t)(p - cast(void*)&_tlsstart); 126 auto tls = getTLSBlockAlloc(); 127 assert(offset < tls.length); 128 return tls.ptr + offset; 129} 130 131private: 132 133__gshared pthread_key_t _tlsKey; 134 135ref void[] getTLSBlock() nothrow @nogc 136{ 137 auto pary = cast(void[]*)pthread_getspecific(_tlsKey); 138 if (pary is null) 139 { 140 pary = cast(void[]*).calloc(1, (void[]).sizeof); 141 if (pthread_setspecific(_tlsKey, pary) != 0) 142 { 143 import core.stdc.stdio; 144 perror("pthread_setspecific failed with"); 145 assert(0); 146 } 147 } 148 return *pary; 149} 150 151ref void[] getTLSBlockAlloc() nothrow @nogc 152{ 153 auto pary = &getTLSBlock(); 154 if (!pary.length) 155 { 156 auto pbeg = cast(void*)&_tlsstart; 157 auto pend = cast(void*)&_tlsend; 158 auto p = .malloc(pend - pbeg); 159 memcpy(p, pbeg, pend - pbeg); 160 *pary = p[0 .. pend - pbeg]; 161 } 162 return *pary; 163} 164 165__gshared SectionGroup _sections; 166 167extern(C) 168{ 169 /* Symbols created by the compiler/linker and inserted into the 170 * object file that 'bracket' sections. 171 */ 172 extern __gshared 173 { 174 void* __start_deh; 175 void* __stop_deh; 176 void* __start_minfo; 177 void* __stop_minfo; 178 179 size_t __bss_end__; 180 181 int _tlsstart; 182 int _tlsend; 183 } 184} 185