1 /* 2 * Pre-resolve references inside an object file. 3 * Mark such functions static so that linking with 4 * other object files can't get at them. 5 * Also rename "main". 6 */ 7 #include <u.h> 8 #include <libc.h> 9 #include <bio.h> 10 #include "/sys/src/cmd/8c/8.out.h" 11 12 typedef struct Sym Sym; 13 struct Sym 14 { 15 char *name; 16 char *newname; 17 short type; 18 short version; 19 Sym *link; 20 }; 21 22 typedef struct Obj Obj; 23 struct Obj 24 { 25 int fd; 26 int version; 27 uchar *bp; 28 uchar *ep; 29 char *name; 30 }; 31 32 enum 33 { 34 NHASH = 10007 35 }; 36 37 Sym *hash[NHASH]; 38 int nsymbol; 39 int renamemain = 1; 40 Sym *xsym[256]; 41 int version = 1; 42 Obj **obj; 43 int nobj; 44 Biobuf bout; 45 char *prefix; 46 int verbose; 47 48 void *emalloc(ulong); 49 Sym *lookup(char*, int); 50 Obj *openobj(char*); 51 void walkobj(Obj*, void (*fn)(int, Sym*, uchar*, int)); 52 void walkobjs(void (*fn)(int, Sym*, uchar*, int)); 53 void dump(int, Sym*, uchar*, int); 54 void nop(int, Sym*, uchar*, int); 55 void owrite(int, Sym*, uchar*, int); 56 int zaddr(uchar*, Sym**); 57 void renamesyms(int, Sym*, uchar*, int); 58 59 void 60 usage(void) 61 { 62 fprint(2, "usage: 8prelink [-mv] prefix file.8...\n"); 63 exits("usage"); 64 } 65 66 void 67 main(int argc, char **argv) 68 { 69 int i; 70 Obj *o; 71 72 ARGBEGIN{ 73 case 'm': 74 renamemain = 0; 75 break; 76 case 'v': 77 verbose = 1; 78 break; 79 default: 80 usage(); 81 }ARGEND 82 83 if(argc < 2) 84 usage(); 85 86 prefix = argv[0]; 87 argv++; 88 argc--; 89 90 nobj = argc; 91 obj = emalloc(nobj*sizeof obj[0]); 92 for(i=0; i<argc; i++) 93 obj[i] = openobj(argv[i]); 94 95 walkobjs(nop); /* initialize symbol table */ 96 if(verbose) 97 walkobjs(dump); 98 walkobjs(renamesyms); 99 100 for(i=0; i<nobj; i++){ 101 o = obj[i]; 102 seek(o->fd, 0, 0); 103 Binit(&bout, o->fd, OWRITE); 104 walkobj(o, owrite); 105 Bflush(&bout); 106 } 107 exits(0); 108 } 109 110 void 111 renamesyms(int op, Sym *sym, uchar*, int) 112 { 113 if(sym && sym->version==0 && !sym->newname) 114 switch(op){ 115 case AGLOBL: 116 case AINIT: 117 case ADATA: 118 case ATEXT: 119 if(!renamemain && strcmp(sym->name, "main") == 0) 120 break; 121 sym->newname = smprint("%s%s", prefix, sym->name); 122 break; 123 } 124 } 125 126 void 127 dump(int op, Sym *sym, uchar*, int) 128 { 129 if(sym && sym->version==0) 130 switch(op){ 131 case AGLOBL: 132 case AINIT: 133 case ADATA: 134 case ATEXT: 135 print("%s\n", sym->name); 136 break; 137 } 138 } 139 140 void 141 nop(int, Sym*, uchar*, int) 142 { 143 } 144 145 void 146 owrite(int op, Sym *sym, uchar *p, int l) 147 { 148 switch(op){ 149 case ASIGNAME: 150 Bwrite(&bout, p, 4); 151 p += 4; 152 l -= 4; 153 case ANAME: 154 if(sym->newname){ 155 Bwrite(&bout, p, 4); 156 Bwrite(&bout, sym->newname, strlen(sym->newname)+1); 157 break; 158 } 159 default: 160 Bwrite(&bout, p, l); 161 break; 162 } 163 } 164 165 int 166 zaddr(uchar *p, Sym **symp) 167 { 168 int c, t; 169 170 t = p[0]; 171 c = 1; 172 if(t & T_INDEX) 173 c += 2; 174 if(t & T_OFFSET) 175 c += 4; 176 if(t & T_SYM){ 177 if(symp) 178 *symp = xsym[p[c]]; 179 c++; 180 } 181 if(t & T_FCONST) 182 c += 8; 183 else if(t & T_SCONST) 184 c += NSNAME; 185 if(t & T_TYPE) 186 c++; 187 return c; 188 } 189 190 void* 191 emalloc(ulong n) 192 { 193 void *v; 194 195 v = mallocz(n, 1); 196 if(v == nil) 197 sysfatal("out of memory"); 198 return v; 199 } 200 201 Sym* 202 lookup(char *symb, int v) 203 { 204 Sym *s; 205 char *p; 206 long h; 207 int l, c; 208 209 h = v; 210 for(p=symb; c = *p; p++) 211 h = h+h+h + c; 212 l = (p - symb) + 1; 213 if(h < 0) 214 h = ~h; 215 h %= NHASH; 216 for(s = hash[h]; s != nil; s = s->link) 217 if(s->version == v) 218 if(memcmp(s->name, symb, l) == 0) 219 return s; 220 221 s = emalloc(sizeof *s); 222 s->name = emalloc(l + 1); 223 memmove(s->name, symb, l); 224 225 s->link = hash[h]; 226 s->type = 0; 227 s->version = v; 228 hash[h] = s; 229 nsymbol++; 230 return s; 231 } 232 233 Obj* 234 openobj(char *name) 235 { 236 Dir *d; 237 Obj *obj; 238 239 obj = emalloc(sizeof *obj); 240 obj->name = name; 241 obj->version = version++; 242 if((obj->fd = open(name, ORDWR)) < 0) 243 sysfatal("open %s: %r", name); 244 if((d = dirfstat(obj->fd)) == nil) 245 sysfatal("dirfstat: %r"); 246 obj->bp = emalloc(d->length); 247 if(readn(obj->fd, obj->bp, d->length) != d->length) 248 sysfatal("read %s: %r", name); 249 obj->ep = obj->bp+d->length; 250 return obj; 251 } 252 253 void 254 walkobjs(void (*fn)(int, Sym*, uchar*, int)) 255 { 256 int i; 257 258 for(i=0; i<nobj; i++) 259 walkobj(obj[i], fn); 260 } 261 262 void 263 walkobj(Obj *obj, void (*fn)(int, Sym*, uchar*, int)) 264 { 265 int op, type; 266 Sym *sym; 267 uchar *p, *p0; 268 269 for(p=obj->bp; p+4<=obj->ep; ){ 270 op = p[0] | (p[1]<<8); 271 if(op <= AXXX || op >= ALAST) 272 sysfatal("%s: opcode out of range - probably not a .8 file", obj->name); 273 p0 = p; 274 switch(op){ 275 case ASIGNAME: 276 p += 4; /* sign */ 277 case ANAME: 278 type = p[2]; 279 sym = lookup((char*)p+4, type==D_STATIC ? obj->version : 0); 280 xsym[p[3]] = sym; 281 p += 4+strlen(sym->name)+1; 282 fn(op, sym, p0, p-p0); 283 break; 284 285 default: 286 p += 6; 287 p += zaddr(p, &sym); 288 p += zaddr(p, nil); 289 fn(op, sym, p0, p-p0); 290 break; 291 } 292 } 293 } 294 295