mirror of https://github.com/golang/go.git
443 lines
9.6 KiB
C
443 lines
9.6 KiB
C
// Inferno utils/6l/span.c
|
|
// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
|
|
//
|
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
// Symbol table.
|
|
|
|
#include "l.h"
|
|
#include "../ld/lib.h"
|
|
#include "../ld/elf.h"
|
|
|
|
static int maxelfstr;
|
|
|
|
static int
|
|
putelfstr(char *s)
|
|
{
|
|
int off, n;
|
|
char *p, *q;
|
|
|
|
if(elfstrsize == 0 && s[0] != 0) {
|
|
// first entry must be empty string
|
|
putelfstr("");
|
|
}
|
|
|
|
n = strlen(s)+1;
|
|
if(elfstrsize+n > maxelfstr) {
|
|
maxelfstr = 2*(elfstrsize+n+(1<<20));
|
|
elfstrdat = realloc(elfstrdat, maxelfstr);
|
|
}
|
|
off = elfstrsize;
|
|
elfstrsize += n;
|
|
memmove(elfstrdat+off, s, n);
|
|
// replace "·" as ".", because DTrace cannot handle it.
|
|
p = strstr(s, "·");
|
|
if(p != nil) {
|
|
p = q = elfstrdat+off;
|
|
while (*q != '\0') {
|
|
if((uchar)*q == 0xc2 && (uchar)*(q+1) == 0xb7) {
|
|
q += 2;
|
|
*p++ = '.';
|
|
elfstrsize--;
|
|
} else {
|
|
*p++ = *q++;
|
|
}
|
|
}
|
|
*p = '\0';
|
|
}
|
|
return off;
|
|
}
|
|
|
|
static void
|
|
putelfsyment(int off, vlong addr, vlong size, int info, int shndx, int other)
|
|
{
|
|
switch(thechar) {
|
|
case '6':
|
|
case '9':
|
|
LPUT(off);
|
|
cput(info);
|
|
cput(other);
|
|
WPUT(shndx);
|
|
VPUT(addr);
|
|
VPUT(size);
|
|
symsize += ELF64SYMSIZE;
|
|
break;
|
|
default:
|
|
LPUT(off);
|
|
LPUT(addr);
|
|
LPUT(size);
|
|
cput(info);
|
|
cput(other);
|
|
WPUT(shndx);
|
|
symsize += ELF32SYMSIZE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int numelfsym = 1; // 0 is reserved
|
|
static int elfbind;
|
|
|
|
static void
|
|
putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
|
|
{
|
|
int bind, type, off;
|
|
LSym *xo;
|
|
|
|
USED(go);
|
|
switch(t) {
|
|
default:
|
|
return;
|
|
case 'T':
|
|
type = STT_FUNC;
|
|
break;
|
|
case 'D':
|
|
type = STT_OBJECT;
|
|
break;
|
|
case 'B':
|
|
type = STT_OBJECT;
|
|
break;
|
|
}
|
|
xo = x;
|
|
while(xo->outer != nil)
|
|
xo = xo->outer;
|
|
if(xo->sect == nil) {
|
|
ctxt->cursym = x;
|
|
diag("missing section in putelfsym");
|
|
return;
|
|
}
|
|
if(xo->sect->elfsect == nil) {
|
|
ctxt->cursym = x;
|
|
diag("missing ELF section in putelfsym");
|
|
return;
|
|
}
|
|
|
|
// One pass for each binding: STB_LOCAL, STB_GLOBAL,
|
|
// maybe one day STB_WEAK.
|
|
bind = STB_GLOBAL;
|
|
if(ver || (x->type & SHIDDEN))
|
|
bind = STB_LOCAL;
|
|
|
|
// In external linking mode, we have to invoke gcc with -rdynamic
|
|
// to get the exported symbols put into the dynamic symbol table.
|
|
// To avoid filling the dynamic table with lots of unnecessary symbols,
|
|
// mark all Go symbols local (not global) in the final executable.
|
|
if(linkmode == LinkExternal && !(x->cgoexport&CgoExportStatic))
|
|
bind = STB_LOCAL;
|
|
|
|
if(bind != elfbind)
|
|
return;
|
|
|
|
off = putelfstr(s);
|
|
if(linkmode == LinkExternal)
|
|
addr -= xo->sect->vaddr;
|
|
putelfsyment(off, addr, size, (bind<<4)|(type&0xf), xo->sect->elfsect->shnum, (x->type & SHIDDEN) ? 2 : 0);
|
|
x->elfsym = numelfsym++;
|
|
}
|
|
|
|
void
|
|
putelfsectionsym(LSym* s, int shndx)
|
|
{
|
|
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0);
|
|
s->elfsym = numelfsym++;
|
|
}
|
|
|
|
void
|
|
putelfsymshndx(vlong sympos, int shndx)
|
|
{
|
|
vlong here;
|
|
|
|
here = cpos();
|
|
switch(thechar) {
|
|
case '6':
|
|
cseek(sympos+6);
|
|
break;
|
|
default:
|
|
cseek(sympos+14);
|
|
break;
|
|
}
|
|
WPUT(shndx);
|
|
cseek(here);
|
|
}
|
|
|
|
void
|
|
asmelfsym(void)
|
|
{
|
|
LSym *s;
|
|
char *name;
|
|
|
|
// the first symbol entry is reserved
|
|
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0);
|
|
|
|
dwarfaddelfsectionsyms();
|
|
|
|
elfbind = STB_LOCAL;
|
|
genasmsym(putelfsym);
|
|
|
|
if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) {
|
|
s = linklookup(ctxt, "runtime.tlsg", 0);
|
|
if(s->sect == nil) {
|
|
ctxt->cursym = nil;
|
|
diag("missing section for %s", s->name);
|
|
errorexit();
|
|
}
|
|
if (strcmp(goos, "android") == 0) {
|
|
// Android emulates runtime.tlsg as a regular variable.
|
|
putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_OBJECT, s->sect->elfsect->shnum, 0);
|
|
} else {
|
|
putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0);
|
|
}
|
|
s->elfsym = numelfsym++;
|
|
}
|
|
|
|
elfbind = STB_GLOBAL;
|
|
elfglobalsymndx = numelfsym;
|
|
genasmsym(putelfsym);
|
|
|
|
for(s=ctxt->allsym; s!=S; s=s->allsym) {
|
|
if(s->type != SHOSTOBJ && !(s->type == SDYNIMPORT && s->reachable))
|
|
continue;
|
|
if(s->type == SDYNIMPORT)
|
|
name = s->extname;
|
|
else
|
|
name = s->name;
|
|
putelfsyment(putelfstr(name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0);
|
|
s->elfsym = numelfsym++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
|
|
{
|
|
int i, l;
|
|
|
|
USED(go);
|
|
USED(ver);
|
|
USED(size);
|
|
USED(x);
|
|
switch(t) {
|
|
case 'T':
|
|
case 'L':
|
|
case 'D':
|
|
case 'B':
|
|
if(ver)
|
|
t += 'a' - 'A';
|
|
case 'a':
|
|
case 'p':
|
|
case 'f':
|
|
case 'z':
|
|
case 'Z':
|
|
case 'm':
|
|
l = 4;
|
|
if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) {
|
|
lputb(addr>>32);
|
|
l = 8;
|
|
}
|
|
lputb(addr);
|
|
cput(t+0x80); /* 0x80 is variable length */
|
|
|
|
if(t == 'z' || t == 'Z') {
|
|
cput(s[0]);
|
|
for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
|
|
cput(s[i]);
|
|
cput(s[i+1]);
|
|
}
|
|
cput(0);
|
|
cput(0);
|
|
i++;
|
|
} else {
|
|
/* skip the '<' in filenames */
|
|
if(t == 'f')
|
|
s++;
|
|
for(i=0; s[i]; i++)
|
|
cput(s[i]);
|
|
cput(0);
|
|
}
|
|
symsize += l + 1 + i + 1;
|
|
break;
|
|
default:
|
|
return;
|
|
};
|
|
}
|
|
|
|
void
|
|
asmplan9sym(void)
|
|
{
|
|
genasmsym(putplan9sym);
|
|
}
|
|
|
|
static LSym *symt;
|
|
|
|
void
|
|
wputl(ushort w)
|
|
{
|
|
cput(w);
|
|
cput(w>>8);
|
|
}
|
|
|
|
void
|
|
wputb(ushort w)
|
|
{
|
|
cput(w>>8);
|
|
cput(w);
|
|
}
|
|
|
|
void
|
|
lputb(int32 l)
|
|
{
|
|
cput(l>>24);
|
|
cput(l>>16);
|
|
cput(l>>8);
|
|
cput(l);
|
|
}
|
|
|
|
void
|
|
lputl(int32 l)
|
|
{
|
|
cput(l);
|
|
cput(l>>8);
|
|
cput(l>>16);
|
|
cput(l>>24);
|
|
}
|
|
|
|
void
|
|
vputb(uint64 v)
|
|
{
|
|
lputb(v>>32);
|
|
lputb(v);
|
|
}
|
|
|
|
void
|
|
vputl(uint64 v)
|
|
{
|
|
lputl(v);
|
|
lputl(v >> 32);
|
|
}
|
|
|
|
void
|
|
symtab(void)
|
|
{
|
|
LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
|
|
|
|
dosymtype();
|
|
|
|
// Define these so that they'll get put into the symbol table.
|
|
// data.c:/^address will provide the actual values.
|
|
xdefine("runtime.text", STEXT, 0);
|
|
xdefine("runtime.etext", STEXT, 0);
|
|
xdefine("runtime.typelink", SRODATA, 0);
|
|
xdefine("runtime.etypelink", SRODATA, 0);
|
|
xdefine("runtime.rodata", SRODATA, 0);
|
|
xdefine("runtime.erodata", SRODATA, 0);
|
|
xdefine("runtime.noptrdata", SNOPTRDATA, 0);
|
|
xdefine("runtime.enoptrdata", SNOPTRDATA, 0);
|
|
xdefine("runtime.data", SDATA, 0);
|
|
xdefine("runtime.edata", SDATA, 0);
|
|
xdefine("runtime.bss", SBSS, 0);
|
|
xdefine("runtime.ebss", SBSS, 0);
|
|
xdefine("runtime.noptrbss", SNOPTRBSS, 0);
|
|
xdefine("runtime.enoptrbss", SNOPTRBSS, 0);
|
|
xdefine("runtime.end", SBSS, 0);
|
|
xdefine("runtime.epclntab", SRODATA, 0);
|
|
xdefine("runtime.esymtab", SRODATA, 0);
|
|
|
|
// garbage collection symbols
|
|
s = linklookup(ctxt, "runtime.gcdata", 0);
|
|
s->type = SRODATA;
|
|
s->size = 0;
|
|
s->reachable = 1;
|
|
xdefine("runtime.egcdata", SRODATA, 0);
|
|
|
|
s = linklookup(ctxt, "runtime.gcbss", 0);
|
|
s->type = SRODATA;
|
|
s->size = 0;
|
|
s->reachable = 1;
|
|
xdefine("runtime.egcbss", SRODATA, 0);
|
|
|
|
// pseudo-symbols to mark locations of type, string, and go string data.
|
|
s = linklookup(ctxt, "type.*", 0);
|
|
s->type = STYPE;
|
|
s->size = 0;
|
|
s->reachable = 1;
|
|
symtype = s;
|
|
|
|
s = linklookup(ctxt, "go.string.*", 0);
|
|
s->type = SGOSTRING;
|
|
s->size = 0;
|
|
s->reachable = 1;
|
|
symgostring = s;
|
|
|
|
s = linklookup(ctxt, "go.func.*", 0);
|
|
s->type = SGOFUNC;
|
|
s->size = 0;
|
|
s->reachable = 1;
|
|
symgofunc = s;
|
|
|
|
symtypelink = linklookup(ctxt, "runtime.typelink", 0);
|
|
|
|
symt = linklookup(ctxt, "runtime.symtab", 0);
|
|
symt->type = SSYMTAB;
|
|
symt->size = 0;
|
|
symt->reachable = 1;
|
|
|
|
// assign specific types so that they sort together.
|
|
// within a type they sort by size, so the .* symbols
|
|
// just defined above will be first.
|
|
// hide the specific symbols.
|
|
for(s = ctxt->allsym; s != S; s = s->allsym) {
|
|
if(!s->reachable || s->special || s->type != SRODATA)
|
|
continue;
|
|
if(strncmp(s->name, "type.", 5) == 0) {
|
|
s->type = STYPE;
|
|
s->hide = 1;
|
|
s->outer = symtype;
|
|
}
|
|
if(strncmp(s->name, "go.typelink.", 12) == 0) {
|
|
s->type = STYPELINK;
|
|
s->hide = 1;
|
|
s->outer = symtypelink;
|
|
}
|
|
if(strncmp(s->name, "go.string.", 10) == 0) {
|
|
s->type = SGOSTRING;
|
|
s->hide = 1;
|
|
s->outer = symgostring;
|
|
}
|
|
if(strncmp(s->name, "go.func.", 8) == 0) {
|
|
s->type = SGOFUNC;
|
|
s->hide = 1;
|
|
s->outer = symgofunc;
|
|
}
|
|
if(strncmp(s->name, "gcargs.", 7) == 0 || strncmp(s->name, "gclocals.", 9) == 0 || strncmp(s->name, "gclocals·", 10) == 0) {
|
|
s->type = SGOFUNC;
|
|
s->hide = 1;
|
|
s->outer = symgofunc;
|
|
s->align = 4;
|
|
liveness += (s->size+s->align-1)&~(s->align-1);
|
|
}
|
|
}
|
|
}
|