// 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" char *elfstrdat; int elfstrsize; int maxelfstr; int elftextsh; int putelfstr(char *s) { int off, n; 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); return off; } void putelfsym64(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) { int bind, type, shndx, stroff; bind = STB_GLOBAL; switch(t) { default: return; case 'T': type = STT_FUNC; shndx = elftextsh + 0; break; case 'D': type = STT_OBJECT; shndx = elftextsh + 1; break; case 'B': type = STT_OBJECT; shndx = elftextsh + 2; break; } stroff = putelfstr(s); LPUT(stroff); // string cput((bind<<4)|(type&0xF)); cput(0); WPUT(shndx); VPUT(addr); VPUT(size); } void asmelfsym64(void) { genasmsym(putelfsym64); } void putelfsym32(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) { int bind, type, shndx, stroff; bind = STB_GLOBAL; switch(t) { default: return; case 'T': type = STT_FUNC; shndx = elftextsh + 0; break; case 'D': type = STT_OBJECT; shndx = elftextsh + 1; break; case 'B': type = STT_OBJECT; shndx = elftextsh + 2; break; } stroff = putelfstr(s); LPUT(stroff); // string LPUT(addr); LPUT(size); cput((bind<<4)|(type&0xF)); cput(0); WPUT(shndx); } void asmelfsym32(void) { genasmsym(putelfsym32); } void putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) { int i; 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': 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 += 4 + 1 + i + 1; break; default: return; }; } void asmplan9sym(void) { genasmsym(putplan9sym); } static Sym *symt; static void scput(int b) { uchar *p; symgrow(symt, symt->size+1); p = symt->p + symt->size; *p = b; symt->size++; } static void slputb(int32 v) { uchar *p; symgrow(symt, symt->size+4); p = symt->p + symt->size; *p++ = v>>24; *p++ = v>>16; *p++ = v>>8; *p = v; symt->size += 4; } 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 putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) { int i, f, l; Reloc *rel; if(t == 'f') name++; l = 4; // if(!debug['8']) // l = 8; if(s != nil) { rel = addrel(symt); rel->siz = l + Rbig; rel->sym = s; rel->type = D_ADDR; rel->off = symt->size; v = 0; } if(l == 8) slputb(v>>32); slputb(v); if(ver) t += 'a' - 'A'; scput(t+0x80); /* 0x80 is variable length */ if(t == 'Z' || t == 'z') { scput(name[0]); for(i=1; name[i] != 0 || name[i+1] != 0; i += 2) { scput(name[i]); scput(name[i+1]); } scput(0); scput(0); i++; } else { for(i=0; name[i]; i++) scput(name[i]); scput(0); } if(typ) { if(!typ->reachable) diag("unreachable type %s", typ->name); rel = addrel(symt); rel->siz = l; rel->sym = typ; rel->type = D_ADDR; rel->off = symt->size; } if(l == 8) slputb(0); slputb(0); if(debug['n']) { if(t == 'z' || t == 'Z') { Bprint(&bso, "%c %.8llux ", t, v); for(i=1; name[i] != 0 || name[i+1] != 0; i+=2) { f = ((name[i]&0xff) << 8) | (name[i+1]&0xff); Bprint(&bso, "/%x", f); } Bprint(&bso, "\n"); return; } if(ver) Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, s, ver, typ ? typ->name : ""); else Bprint(&bso, "%c %.8llux %s %s\n", t, v, s, typ ? typ->name : ""); } } void symtab(void) { Sym *s; // Define these so that they'll get put into the symbol table. // data.c:/^address will provide the actual values. xdefine("text", STEXT, 0); xdefine("etext", STEXT, 0); xdefine("rodata", SRODATA, 0); xdefine("erodata", SRODATA, 0); xdefine("data", SBSS, 0); xdefine("edata", SBSS, 0); xdefine("end", SBSS, 0); xdefine("epclntab", SRODATA, 0); xdefine("esymtab", SRODATA, 0); // pseudo-symbols to mark locations of type, string, and go string data. s = lookup("type.*", 0); s->type = STYPE; s->size = 0; s->reachable = 1; s = lookup("go.string.*", 0); s->type = SGOSTRING; s->size = 0; s->reachable = 1; symt = lookup("symtab", 0); symt->type = SRODATA; 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 = 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; } if(strncmp(s->name, "go.string.", 10) == 0) { s->type = SGOSTRING; s->hide = 1; } } genasmsym(putsymb); }