diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/8prefix.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/8prefix.c')
-rwxr-xr-x | sys/src/cmd/aux/8prefix.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/8prefix.c b/sys/src/cmd/aux/8prefix.c new file mode 100755 index 000000000..2ca7b7ae2 --- /dev/null +++ b/sys/src/cmd/aux/8prefix.c @@ -0,0 +1,294 @@ +/* + * 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: 8prelink [-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; + } + } +} + |