295 lines
4.4 KiB
C
295 lines
4.4 KiB
C
/*
|
|
* Pre-resolve references inside an object file.
|
|
* Mark such functions static so that linking with
|
|
* other object files can't get at them.
|
|
* Also rename "main".
|
|
*/
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include "/sys/src/cmd/8c/8.out.h"
|
|
|
|
typedef struct Sym Sym;
|
|
struct Sym
|
|
{
|
|
char *name;
|
|
char *newname;
|
|
short type;
|
|
short version;
|
|
Sym *link;
|
|
};
|
|
|
|
typedef struct Obj Obj;
|
|
struct Obj
|
|
{
|
|
int fd;
|
|
int version;
|
|
uchar *bp;
|
|
uchar *ep;
|
|
char *name;
|
|
};
|
|
|
|
enum
|
|
{
|
|
NHASH = 10007
|
|
};
|
|
|
|
Sym *hash[NHASH];
|
|
int nsymbol;
|
|
int renamemain = 1;
|
|
Sym *xsym[256];
|
|
int version = 1;
|
|
Obj **obj;
|
|
int nobj;
|
|
Biobuf bout;
|
|
char *prefix;
|
|
int verbose;
|
|
|
|
void *emalloc(ulong);
|
|
Sym *lookup(char*, int);
|
|
Obj *openobj(char*);
|
|
void walkobj(Obj*, void (*fn)(int, Sym*, uchar*, int));
|
|
void walkobjs(void (*fn)(int, Sym*, uchar*, int));
|
|
void dump(int, Sym*, uchar*, int);
|
|
void nop(int, Sym*, uchar*, int);
|
|
void owrite(int, Sym*, uchar*, int);
|
|
int zaddr(uchar*, Sym**);
|
|
void renamesyms(int, Sym*, uchar*, int);
|
|
|
|
void
|
|
usage(void)
|
|
{
|
|
fprint(2, "usage: 8prefix [-mv] prefix file.8...\n");
|
|
exits("usage");
|
|
}
|
|
|
|
void
|
|
main(int argc, char **argv)
|
|
{
|
|
int i;
|
|
Obj *o;
|
|
|
|
ARGBEGIN{
|
|
case 'm':
|
|
renamemain = 0;
|
|
break;
|
|
case 'v':
|
|
verbose = 1;
|
|
break;
|
|
default:
|
|
usage();
|
|
}ARGEND
|
|
|
|
if(argc < 2)
|
|
usage();
|
|
|
|
prefix = argv[0];
|
|
argv++;
|
|
argc--;
|
|
|
|
nobj = argc;
|
|
obj = emalloc(nobj*sizeof obj[0]);
|
|
for(i=0; i<argc; i++)
|
|
obj[i] = openobj(argv[i]);
|
|
|
|
walkobjs(nop); /* initialize symbol table */
|
|
if(verbose)
|
|
walkobjs(dump);
|
|
walkobjs(renamesyms);
|
|
|
|
for(i=0; i<nobj; i++){
|
|
o = obj[i];
|
|
seek(o->fd, 0, 0);
|
|
Binit(&bout, o->fd, OWRITE);
|
|
walkobj(o, owrite);
|
|
Bflush(&bout);
|
|
}
|
|
exits(0);
|
|
}
|
|
|
|
void
|
|
renamesyms(int op, Sym *sym, uchar*, int)
|
|
{
|
|
if(sym && sym->version==0 && !sym->newname)
|
|
switch(op){
|
|
case AGLOBL:
|
|
case AINIT:
|
|
case ADATA:
|
|
case ATEXT:
|
|
if(!renamemain && strcmp(sym->name, "main") == 0)
|
|
break;
|
|
sym->newname = smprint("%s%s", prefix, sym->name);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
dump(int op, Sym *sym, uchar*, int)
|
|
{
|
|
if(sym && sym->version==0)
|
|
switch(op){
|
|
case AGLOBL:
|
|
case AINIT:
|
|
case ADATA:
|
|
case ATEXT:
|
|
print("%s\n", sym->name);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
nop(int, Sym*, uchar*, int)
|
|
{
|
|
}
|
|
|
|
void
|
|
owrite(int op, Sym *sym, uchar *p, int l)
|
|
{
|
|
switch(op){
|
|
case ASIGNAME:
|
|
Bwrite(&bout, p, 4);
|
|
p += 4;
|
|
l -= 4;
|
|
case ANAME:
|
|
if(sym->newname){
|
|
Bwrite(&bout, p, 4);
|
|
Bwrite(&bout, sym->newname, strlen(sym->newname)+1);
|
|
break;
|
|
}
|
|
default:
|
|
Bwrite(&bout, p, l);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
zaddr(uchar *p, Sym **symp)
|
|
{
|
|
int c, t;
|
|
|
|
t = p[0];
|
|
c = 1;
|
|
if(t & T_INDEX)
|
|
c += 2;
|
|
if(t & T_OFFSET)
|
|
c += 4;
|
|
if(t & T_SYM){
|
|
if(symp)
|
|
*symp = xsym[p[c]];
|
|
c++;
|
|
}
|
|
if(t & T_FCONST)
|
|
c += 8;
|
|
else if(t & T_SCONST)
|
|
c += NSNAME;
|
|
if(t & T_TYPE)
|
|
c++;
|
|
return c;
|
|
}
|
|
|
|
void*
|
|
emalloc(ulong n)
|
|
{
|
|
void *v;
|
|
|
|
v = mallocz(n, 1);
|
|
if(v == nil)
|
|
sysfatal("out of memory");
|
|
return v;
|
|
}
|
|
|
|
Sym*
|
|
lookup(char *symb, int v)
|
|
{
|
|
Sym *s;
|
|
char *p;
|
|
long h;
|
|
int l, c;
|
|
|
|
h = v;
|
|
for(p=symb; c = *p; p++)
|
|
h = h+h+h + c;
|
|
l = (p - symb) + 1;
|
|
if(h < 0)
|
|
h = ~h;
|
|
h %= NHASH;
|
|
for(s = hash[h]; s != nil; s = s->link)
|
|
if(s->version == v)
|
|
if(memcmp(s->name, symb, l) == 0)
|
|
return s;
|
|
|
|
s = emalloc(sizeof *s);
|
|
s->name = emalloc(l + 1);
|
|
memmove(s->name, symb, l);
|
|
|
|
s->link = hash[h];
|
|
s->type = 0;
|
|
s->version = v;
|
|
hash[h] = s;
|
|
nsymbol++;
|
|
return s;
|
|
}
|
|
|
|
Obj*
|
|
openobj(char *name)
|
|
{
|
|
Dir *d;
|
|
Obj *obj;
|
|
|
|
obj = emalloc(sizeof *obj);
|
|
obj->name = name;
|
|
obj->version = version++;
|
|
if((obj->fd = open(name, ORDWR)) < 0)
|
|
sysfatal("open %s: %r", name);
|
|
if((d = dirfstat(obj->fd)) == nil)
|
|
sysfatal("dirfstat: %r");
|
|
obj->bp = emalloc(d->length);
|
|
if(readn(obj->fd, obj->bp, d->length) != d->length)
|
|
sysfatal("read %s: %r", name);
|
|
obj->ep = obj->bp+d->length;
|
|
return obj;
|
|
}
|
|
|
|
void
|
|
walkobjs(void (*fn)(int, Sym*, uchar*, int))
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i<nobj; i++)
|
|
walkobj(obj[i], fn);
|
|
}
|
|
|
|
void
|
|
walkobj(Obj *obj, void (*fn)(int, Sym*, uchar*, int))
|
|
{
|
|
int op, type;
|
|
Sym *sym;
|
|
uchar *p, *p0;
|
|
|
|
for(p=obj->bp; p+4<=obj->ep; ){
|
|
op = p[0] | (p[1]<<8);
|
|
if(op <= AXXX || op >= ALAST)
|
|
sysfatal("%s: opcode out of range - probably not a .8 file", obj->name);
|
|
p0 = p;
|
|
switch(op){
|
|
case ASIGNAME:
|
|
p += 4; /* sign */
|
|
case ANAME:
|
|
type = p[2];
|
|
sym = lookup((char*)p+4, type==D_STATIC ? obj->version : 0);
|
|
xsym[p[3]] = sym;
|
|
p += 4+strlen(sym->name)+1;
|
|
fn(op, sym, p0, p-p0);
|
|
break;
|
|
|
|
default:
|
|
p += 6;
|
|
p += zaddr(p, &sym);
|
|
p += zaddr(p, nil);
|
|
fn(op, sym, p0, p-p0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|