]> git.ipfire.org Git - thirdparty/gcc.git/blob - libphobos/libdruntime/rt/sections_android.d
16c54655129b9ae15084b4165bfc0590dc19dcf6
[thirdparty/gcc.git] / libphobos / libdruntime / rt / sections_android.d
1 /**
2 * Written in the D programming language.
3 * This module provides bionic-specific support for sections.
4 *
5 * Copyright: Copyright Martin Nowak 2012-2013.
6 * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
7 * Authors: Martin Nowak
8 * Source: $(DRUNTIMESRC src/rt/_sections_android.d)
9 */
10
11 module rt.sections_android;
12
13 version (CRuntime_Bionic):
14
15 // debug = PRINTF;
16 debug(PRINTF) import core.stdc.stdio;
17 import core.stdc.stdlib : malloc, free;
18 import rt.deh, rt.minfo;
19 import core.sys.posix.pthread;
20 import core.stdc.stdlib : calloc;
21 import core.stdc.string : memcpy;
22
23 struct SectionGroup
24 {
25 static int opApply(scope int delegate(ref SectionGroup) dg)
26 {
27 return dg(_sections);
28 }
29
30 static int opApplyReverse(scope int delegate(ref SectionGroup) dg)
31 {
32 return dg(_sections);
33 }
34
35 @property immutable(ModuleInfo*)[] modules() const nothrow @nogc
36 {
37 return _moduleGroup.modules;
38 }
39
40 @property ref inout(ModuleGroup) moduleGroup() inout nothrow @nogc
41 {
42 return _moduleGroup;
43 }
44
45 @property immutable(FuncTable)[] ehTables() const nothrow @nogc
46 {
47 auto pbeg = cast(immutable(FuncTable)*)&__start_deh;
48 auto pend = cast(immutable(FuncTable)*)&__stop_deh;
49 return pbeg[0 .. pend - pbeg];
50 }
51
52 @property inout(void[])[] gcRanges() inout nothrow @nogc
53 {
54 return _gcRanges[];
55 }
56
57 private:
58 ModuleGroup _moduleGroup;
59 void[][1] _gcRanges;
60 }
61
62 void initSections() nothrow @nogc
63 {
64 pthread_key_create(&_tlsKey, null);
65
66 auto mbeg = cast(immutable ModuleInfo**)&__start_minfo;
67 auto mend = cast(immutable ModuleInfo**)&__stop_minfo;
68 _sections.moduleGroup = ModuleGroup(mbeg[0 .. mend - mbeg]);
69
70 auto pbeg = cast(void*)&_tlsend;
71 auto pend = cast(void*)&__bss_end__;
72 _sections._gcRanges[0] = pbeg[0 .. pend - pbeg];
73 }
74
75 void finiSections() nothrow @nogc
76 {
77 pthread_key_delete(_tlsKey);
78 }
79
80 void[]* initTLSRanges() nothrow @nogc
81 {
82 return &getTLSBlock();
83 }
84
85 void finiTLSRanges(void[]* rng) nothrow @nogc
86 {
87 .free(rng.ptr);
88 .free(rng);
89 }
90
91 void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow
92 {
93 dg(rng.ptr, rng.ptr + rng.length);
94 }
95
96 /* NOTE: The Bionic C library ignores thread-local data stored in the normal
97 * .tbss/.tdata ELF sections, which are marked with the SHF_TLS/STT_TLS
98 * flags. So instead we roll our own by keeping TLS data in the
99 * .tdata/.tbss sections but removing the SHF_TLS/STT_TLS flags, and
100 * access the TLS data using this function and the _tlsstart/_tlsend
101 * symbols as delimiters.
102 *
103 * This function is called by the code emitted by the compiler. It
104 * is expected to translate an address in the TLS static data to
105 * the corresponding address in the TLS dynamic per-thread data.
106 */
107
108 version (X86)
109 {
110 // NB: the compiler mangles this function as '___tls_get_addr'
111 // even though it is extern(D)
112 extern(D) void* ___tls_get_addr( void* p ) nothrow @nogc
113 {
114 debug(PRINTF) printf(" ___tls_get_addr input - %p\n", p);
115 immutable offset = cast(size_t)(p - cast(void*)&_tlsstart);
116 auto tls = getTLSBlockAlloc();
117 assert(offset < tls.length);
118 return tls.ptr + offset;
119 }
120 }
121 else version (ARM)
122 {
123 extern(C) void* __tls_get_addr( void** p ) nothrow @nogc
124 {
125 debug(PRINTF) printf(" __tls_get_addr input - %p\n", *p);
126 immutable offset = cast(size_t)(*p - cast(void*)&_tlsstart);
127 auto tls = getTLSBlockAlloc();
128 assert(offset < tls.length);
129 return tls.ptr + offset;
130 }
131 }
132 else
133 static assert( false, "Android architecture not supported." );
134
135 private:
136
137 __gshared pthread_key_t _tlsKey;
138
139 ref void[] getTLSBlock() nothrow @nogc
140 {
141 auto pary = cast(void[]*)pthread_getspecific(_tlsKey);
142 if (pary is null)
143 {
144 pary = cast(void[]*).calloc(1, (void[]).sizeof);
145 if (pthread_setspecific(_tlsKey, pary) != 0)
146 {
147 import core.stdc.stdio;
148 perror("pthread_setspecific failed with");
149 assert(0);
150 }
151 }
152 return *pary;
153 }
154
155 ref void[] getTLSBlockAlloc() nothrow @nogc
156 {
157 auto pary = &getTLSBlock();
158 if (!pary.length)
159 {
160 auto pbeg = cast(void*)&_tlsstart;
161 auto pend = cast(void*)&_tlsend;
162 auto p = .malloc(pend - pbeg);
163 memcpy(p, pbeg, pend - pbeg);
164 *pary = p[0 .. pend - pbeg];
165 }
166 return *pary;
167 }
168
169 __gshared SectionGroup _sections;
170
171 extern(C)
172 {
173 /* Symbols created by the compiler/linker and inserted into the
174 * object file that 'bracket' sections.
175 */
176 extern __gshared
177 {
178 void* __start_deh;
179 void* __stop_deh;
180 void* __start_minfo;
181 void* __stop_minfo;
182
183 size_t __bss_end__;
184
185 void* _tlsstart;
186 void* _tlsend;
187 }
188 }