blob: 129b13ea088a56e283c99e9fdfc1857fd1241bf3 [file] [log] [blame]
// 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;
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
putelfsyment(int off, vlong addr, vlong size, int info, int shndx)
{
switch(thechar) {
case '6':
LPUT(off);
cput(info);
cput(0);
WPUT(shndx);
VPUT(addr);
VPUT(size);
symsize += ELF64SYMSIZE;
break;
default:
LPUT(off);
LPUT(addr);
LPUT(size);
cput(info);
cput(0);
WPUT(shndx);
symsize += ELF32SYMSIZE;
break;
}
}
void
putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
{
int bind, type, shndx, off;
USED(go);
switch(t) {
default:
return;
case 'T':
type = STT_FUNC;
shndx = elftextsh + 0;
break;
case 'D':
type = STT_OBJECT;
if((x->type&~SSUB) == SRODATA)
shndx = elftextsh + 1;
else
shndx = elftextsh + 2;
break;
case 'B':
type = STT_OBJECT;
shndx = elftextsh + 3;
break;
}
bind = ver ? STB_LOCAL : STB_GLOBAL;
off = putelfstr(s);
putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx);
}
void
asmelfsym(void)
{
// the first symbol entry is reserved
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0);
genasmsym(putelfsym);
}
void
putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
{
int i;
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':
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;
USED(size);
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);
}
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->name, ver, typ ? typ->name : "");
else
Bprint(&bso, "%c %.8llux %s %s\n", t, v, s->name, typ ? typ->name : "");
}
}
void
symtab(void)
{
Sym *s;
dosymtype();
// 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("noptrdata", SNOPTRDATA, 0);
xdefine("enoptrdata", SNOPTRDATA, 0);
xdefine("data", SDATA, 0);
xdefine("edata", SDATA, 0);
xdefine("bss", SBSS, 0);
xdefine("ebss", SBSS, 0);
xdefine("noptrbss", SNOPTRBSS, 0);
xdefine("enoptrbss", SNOPTRBSS, 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 = 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 = 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;
}
}
if(debug['s'])
return;
genasmsym(putsymb);
}