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
usage(void)60 usage(void)
61 {
62 fprint(2, "usage: 8prelink [-mv] prefix file.8...\n");
63 exits("usage");
64 }
65
66 void
main(int argc,char ** argv)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
renamesyms(int op,Sym * sym,uchar *,int)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
dump(int op,Sym * sym,uchar *,int)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
nop(int,Sym *,uchar *,int)141 nop(int, Sym*, uchar*, int)
142 {
143 }
144
145 void
owrite(int op,Sym * sym,uchar * p,int l)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
zaddr(uchar * p,Sym ** symp)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*
emalloc(ulong n)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*
lookup(char * symb,int v)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*
openobj(char * name)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
walkobjs(void (* fn)(int,Sym *,uchar *,int))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
walkobj(Obj * obj,void (* fn)(int,Sym *,uchar *,int))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