]>
Commit | Line | Data |
---|---|---|
3ef1f32e | 1 | // Bionic-specific support for sections. |
2 | // Copyright (C) 2019 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/>. | |
03385ed3 | 22 | |
3ef1f32e | 23 | module gcc.sections.android; |
03385ed3 | 24 | |
25 | version (CRuntime_Bionic): | |
26 | ||
27 | // debug = PRINTF; | |
28 | debug(PRINTF) import core.stdc.stdio; | |
29 | import core.stdc.stdlib : malloc, free; | |
30 | import rt.deh, rt.minfo; | |
31 | import core.sys.posix.pthread; | |
32 | import core.stdc.stdlib : calloc; | |
33 | import core.stdc.string : memcpy; | |
34 | ||
35 | struct 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 | ||
69 | private: | |
70 | ModuleGroup _moduleGroup; | |
71 | void[][1] _gcRanges; | |
72 | } | |
73 | ||
74 | void 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__; | |
3ef1f32e | 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); | |
03385ed3 | 86 | _sections._gcRanges[0] = pbeg[0 .. pend - pbeg]; |
87 | } | |
88 | ||
89 | void finiSections() nothrow @nogc | |
90 | { | |
91 | pthread_key_delete(_tlsKey); | |
92 | } | |
93 | ||
94 | void[]* initTLSRanges() nothrow @nogc | |
95 | { | |
96 | return &getTLSBlock(); | |
97 | } | |
98 | ||
99 | void finiTLSRanges(void[]* rng) nothrow @nogc | |
100 | { | |
101 | .free(rng.ptr); | |
102 | .free(rng); | |
103 | } | |
104 | ||
105 | void 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 | ||
3ef1f32e | 122 | extern(C) void* __tls_get_addr( void* p ) nothrow @nogc |
03385ed3 | 123 | { |
3ef1f32e | 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; | |
03385ed3 | 129 | } |
03385ed3 | 130 | |
131 | private: | |
132 | ||
133 | __gshared pthread_key_t _tlsKey; | |
134 | ||
135 | ref 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 | ||
151 | ref 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 | ||
167 | extern(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 | ||
3ef1f32e | 181 | int _tlsstart; |
182 | int _tlsend; | |
03385ed3 | 183 | } |
184 | } |