145
|
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
|
|
23 module gcc.sections.android;
|
|
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__;
|
|
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
|
|
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
|
|
122 extern(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
|
|
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
|
|
181 int _tlsstart;
|
|
182 int _tlsend;
|
|
183 }
|
|
184 }
|