blob: 156270c8fabcd57f108486abde69f6604bba2574 [file] [log] [blame]
Colin Cross7bb052a2015-02-03 12:59:37 -08001// Inferno utils/6l/span.c
2// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
3//
4// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6// Portions Copyright © 1997-1999 Vita Nuova Limited
7// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8// Portions Copyright © 2004,2006 Bruce Ellis
9// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11// Portions Copyright © 2009 The Go Authors. All rights reserved.
12//
13// Permission is hereby granted, free of charge, to any person obtaining a copy
14// of this software and associated documentation files (the "Software"), to deal
15// in the Software without restriction, including without limitation the rights
16// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17// copies of the Software, and to permit persons to whom the Software is
18// furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included in
21// all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29// THE SOFTWARE.
30
31// Symbol table.
32
33#include "l.h"
34#include "../ld/lib.h"
35#include "../ld/elf.h"
36
37static int maxelfstr;
38
39static int
40putelfstr(char *s)
41{
42 int off, n;
43 char *p, *q;
44
45 if(elfstrsize == 0 && s[0] != 0) {
46 // first entry must be empty string
47 putelfstr("");
48 }
49
50 n = strlen(s)+1;
51 if(elfstrsize+n > maxelfstr) {
52 maxelfstr = 2*(elfstrsize+n+(1<<20));
53 elfstrdat = realloc(elfstrdat, maxelfstr);
54 }
55 off = elfstrsize;
56 elfstrsize += n;
57 memmove(elfstrdat+off, s, n);
58 // replace "·" as ".", because DTrace cannot handle it.
59 p = strstr(s, "·");
60 if(p != nil) {
61 p = q = elfstrdat+off;
62 while (*q != '\0') {
63 if((uchar)*q == 0xc2 && (uchar)*(q+1) == 0xb7) {
64 q += 2;
65 *p++ = '.';
66 elfstrsize--;
67 } else {
68 *p++ = *q++;
69 }
70 }
71 *p = '\0';
72 }
73 return off;
74}
75
76static void
77putelfsyment(int off, vlong addr, vlong size, int info, int shndx, int other)
78{
79 switch(thechar) {
80 case '6':
81 LPUT(off);
82 cput(info);
83 cput(other);
84 WPUT(shndx);
85 VPUT(addr);
86 VPUT(size);
87 symsize += ELF64SYMSIZE;
88 break;
89 default:
90 LPUT(off);
91 LPUT(addr);
92 LPUT(size);
93 cput(info);
94 cput(other);
95 WPUT(shndx);
96 symsize += ELF32SYMSIZE;
97 break;
98 }
99}
100
101static int numelfsym = 1; // 0 is reserved
102static int elfbind;
103
104static void
105putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
106{
107 int bind, type, off;
108 LSym *xo;
109
110 USED(go);
111 switch(t) {
112 default:
113 return;
114 case 'T':
115 type = STT_FUNC;
116 break;
117 case 'D':
118 type = STT_OBJECT;
119 break;
120 case 'B':
121 type = STT_OBJECT;
122 break;
123 }
124 xo = x;
125 while(xo->outer != nil)
126 xo = xo->outer;
127 if(xo->sect == nil) {
128 ctxt->cursym = x;
129 diag("missing section in putelfsym");
130 return;
131 }
132 if(xo->sect->elfsect == nil) {
133 ctxt->cursym = x;
134 diag("missing ELF section in putelfsym");
135 return;
136 }
137
138 // One pass for each binding: STB_LOCAL, STB_GLOBAL,
139 // maybe one day STB_WEAK.
140 bind = STB_GLOBAL;
141 if(ver || (x->type & SHIDDEN))
142 bind = STB_LOCAL;
143
144 // In external linking mode, we have to invoke gcc with -rdynamic
145 // to get the exported symbols put into the dynamic symbol table.
146 // To avoid filling the dynamic table with lots of unnecessary symbols,
147 // mark all Go symbols local (not global) in the final executable.
148 if(linkmode == LinkExternal && !(x->cgoexport&CgoExportStatic))
149 bind = STB_LOCAL;
150
151 if(bind != elfbind)
152 return;
153
154 off = putelfstr(s);
155 if(linkmode == LinkExternal)
156 addr -= xo->sect->vaddr;
157 putelfsyment(off, addr, size, (bind<<4)|(type&0xf), xo->sect->elfsect->shnum, (x->type & SHIDDEN) ? 2 : 0);
158 x->elfsym = numelfsym++;
159}
160
161void
162putelfsectionsym(LSym* s, int shndx)
163{
164 putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0);
165 s->elfsym = numelfsym++;
166}
167
168void
169putelfsymshndx(vlong sympos, int shndx)
170{
171 vlong here;
172
173 here = cpos();
174 switch(thechar) {
175 case '6':
176 cseek(sympos+6);
177 break;
178 default:
179 cseek(sympos+14);
180 break;
181 }
182 WPUT(shndx);
183 cseek(here);
184}
185
186void
187asmelfsym(void)
188{
189 LSym *s;
190 char *name;
191
192 // the first symbol entry is reserved
193 putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0);
194
195 dwarfaddelfsectionsyms();
196
197 elfbind = STB_LOCAL;
198 genasmsym(putelfsym);
199
200 if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) {
201 s = linklookup(ctxt, "runtime.tlsg", 0);
202 if(s->sect == nil) {
203 ctxt->cursym = nil;
204 diag("missing section for %s", s->name);
205 errorexit();
206 }
207 if (strcmp(goos, "android") == 0) {
208 // Android emulates runtime.tlsg as a regular variable.
209 putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_OBJECT, s->sect->elfsect->shnum, 0);
210 } else {
211 putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0);
212 }
213 s->elfsym = numelfsym++;
214 }
215
216 elfbind = STB_GLOBAL;
217 elfglobalsymndx = numelfsym;
218 genasmsym(putelfsym);
219
220 for(s=ctxt->allsym; s!=S; s=s->allsym) {
221 if(s->type != SHOSTOBJ && !(s->type == SDYNIMPORT && s->reachable))
222 continue;
223 if(s->type == SDYNIMPORT)
224 name = s->extname;
225 else
226 name = s->name;
227 putelfsyment(putelfstr(name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0);
228 s->elfsym = numelfsym++;
229 }
230}
231
232static void
233putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
234{
235 int i, l;
236
237 USED(go);
238 USED(ver);
239 USED(size);
240 USED(x);
241 switch(t) {
242 case 'T':
243 case 'L':
244 case 'D':
245 case 'B':
246 if(ver)
247 t += 'a' - 'A';
248 case 'a':
249 case 'p':
250 case 'f':
251 case 'z':
252 case 'Z':
253 case 'm':
254 l = 4;
255 if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) {
256 lputb(addr>>32);
257 l = 8;
258 }
259 lputb(addr);
260 cput(t+0x80); /* 0x80 is variable length */
261
262 if(t == 'z' || t == 'Z') {
263 cput(s[0]);
264 for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
265 cput(s[i]);
266 cput(s[i+1]);
267 }
268 cput(0);
269 cput(0);
270 i++;
271 } else {
272 /* skip the '<' in filenames */
273 if(t == 'f')
274 s++;
275 for(i=0; s[i]; i++)
276 cput(s[i]);
277 cput(0);
278 }
279 symsize += l + 1 + i + 1;
280 break;
281 default:
282 return;
283 };
284}
285
286void
287asmplan9sym(void)
288{
289 genasmsym(putplan9sym);
290}
291
292static LSym *symt;
293
294void
295wputl(ushort w)
296{
297 cput(w);
298 cput(w>>8);
299}
300
301void
302wputb(ushort w)
303{
304 cput(w>>8);
305 cput(w);
306}
307
308void
309lputb(int32 l)
310{
311 cput(l>>24);
312 cput(l>>16);
313 cput(l>>8);
314 cput(l);
315}
316
317void
318lputl(int32 l)
319{
320 cput(l);
321 cput(l>>8);
322 cput(l>>16);
323 cput(l>>24);
324}
325
326void
327vputb(uint64 v)
328{
329 lputb(v>>32);
330 lputb(v);
331}
332
333void
334vputl(uint64 v)
335{
336 lputl(v);
337 lputl(v >> 32);
338}
339
340void
341symtab(void)
342{
343 LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
344
345 dosymtype();
346
347 // Define these so that they'll get put into the symbol table.
348 // data.c:/^address will provide the actual values.
349 xdefine("runtime.text", STEXT, 0);
350 xdefine("runtime.etext", STEXT, 0);
351 xdefine("runtime.typelink", SRODATA, 0);
352 xdefine("runtime.etypelink", SRODATA, 0);
353 xdefine("runtime.rodata", SRODATA, 0);
354 xdefine("runtime.erodata", SRODATA, 0);
355 xdefine("runtime.noptrdata", SNOPTRDATA, 0);
356 xdefine("runtime.enoptrdata", SNOPTRDATA, 0);
357 xdefine("runtime.data", SDATA, 0);
358 xdefine("runtime.edata", SDATA, 0);
359 xdefine("runtime.bss", SBSS, 0);
360 xdefine("runtime.ebss", SBSS, 0);
361 xdefine("runtime.noptrbss", SNOPTRBSS, 0);
362 xdefine("runtime.enoptrbss", SNOPTRBSS, 0);
363 xdefine("runtime.end", SBSS, 0);
364 xdefine("runtime.epclntab", SRODATA, 0);
365 xdefine("runtime.esymtab", SRODATA, 0);
366
367 // garbage collection symbols
368 s = linklookup(ctxt, "runtime.gcdata", 0);
369 s->type = SRODATA;
370 s->size = 0;
371 s->reachable = 1;
372 xdefine("runtime.egcdata", SRODATA, 0);
373
374 s = linklookup(ctxt, "runtime.gcbss", 0);
375 s->type = SRODATA;
376 s->size = 0;
377 s->reachable = 1;
378 xdefine("runtime.egcbss", SRODATA, 0);
379
380 // pseudo-symbols to mark locations of type, string, and go string data.
381 s = linklookup(ctxt, "type.*", 0);
382 s->type = STYPE;
383 s->size = 0;
384 s->reachable = 1;
385 symtype = s;
386
387 s = linklookup(ctxt, "go.string.*", 0);
388 s->type = SGOSTRING;
389 s->size = 0;
390 s->reachable = 1;
391 symgostring = s;
392
393 s = linklookup(ctxt, "go.func.*", 0);
394 s->type = SGOFUNC;
395 s->size = 0;
396 s->reachable = 1;
397 symgofunc = s;
398
399 symtypelink = linklookup(ctxt, "runtime.typelink", 0);
400
401 symt = linklookup(ctxt, "runtime.symtab", 0);
402 symt->type = SSYMTAB;
403 symt->size = 0;
404 symt->reachable = 1;
405
406 // assign specific types so that they sort together.
407 // within a type they sort by size, so the .* symbols
408 // just defined above will be first.
409 // hide the specific symbols.
410 for(s = ctxt->allsym; s != S; s = s->allsym) {
411 if(!s->reachable || s->special || s->type != SRODATA)
412 continue;
413 if(strncmp(s->name, "type.", 5) == 0) {
414 s->type = STYPE;
415 s->hide = 1;
416 s->outer = symtype;
417 }
418 if(strncmp(s->name, "go.typelink.", 12) == 0) {
419 s->type = STYPELINK;
420 s->hide = 1;
421 s->outer = symtypelink;
422 }
423 if(strncmp(s->name, "go.string.", 10) == 0) {
424 s->type = SGOSTRING;
425 s->hide = 1;
426 s->outer = symgostring;
427 }
428 if(strncmp(s->name, "go.func.", 8) == 0) {
429 s->type = SGOFUNC;
430 s->hide = 1;
431 s->outer = symgofunc;
432 }
433 if(strncmp(s->name, "gcargs.", 7) == 0 || strncmp(s->name, "gclocals.", 9) == 0 || strncmp(s->name, "gclocals·", 10) == 0) {
434 s->type = SGOFUNC;
435 s->hide = 1;
436 s->outer = symgofunc;
437 s->align = 4;
438 liveness += (s->size+s->align-1)&~(s->align-1);
439 }
440 }
441}