1 // Inferno libmach/obj.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/libmach/obj.c
3 //
4 // Copyright © 1994-1999 Lucent Technologies Inc.
5 // Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
6 // Portions Copyright © 1997-1999 Vita Nuova Limited.
7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
8 // Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
9 // Portions Copyright © 2009 The Go Authors. All rights reserved.
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28
29 /*
30 * obj.c
31 * routines universal to all object files
32 */
33 #include <u.h>
34 #include <libc.h>
35 #include <bio.h>
36 #include <ar.h>
37 #include <mach.h>
38 #include "obj.h"
39
40 #define islocal(t) ((t)=='a' || (t)=='p')
41
42 enum
43 {
44 NNAMES = 50,
45 MAXIS = 8, /* max length to determine if a file is a .? file */
46 MAXOFF = 0x7fffffff, /* larger than any possible local offset */
47 NHASH = 1024, /* must be power of two */
48 HASHMUL = 79L,
49 };
50
51 int _is2(char*), /* in [$OS].c */
52 _is5(char*),
53 _is6(char*),
54 _is7(char*),
55 _is8(char*),
56 _is9(char*),
57 _isk(char*),
58 _isq(char*),
59 _isv(char*),
60 _isu(char*),
61 _read2(Biobuf*, Prog*),
62 _read5(Biobuf*, Prog*),
63 _read6(Biobuf*, Prog*),
64 _read7(Biobuf*, Prog*),
65 _read8(Biobuf*, Prog*),
66 _read9(Biobuf*, Prog*),
67 _readk(Biobuf*, Prog*),
68 _readq(Biobuf*, Prog*),
69 _readv(Biobuf*, Prog*),
70 _readu(Biobuf*, Prog*);
71
72 typedef struct Obj Obj;
73 typedef struct Symtab Symtab;
74
75 struct Obj /* functions to handle each intermediate (.$O) file */
76 {
77 char *name; /* name of each $O file */
78 int (*is)(char*); /* test for each type of $O file */
79 int (*read)(Biobuf*, Prog*); /* read for each type of $O file*/
80 };
81
82 static Obj obj[] =
83 { /* functions to identify and parse each type of obj */
84 [Obj68020] = { "68020 .2", _is2, _read2 },
85 [ObjAmd64] = { "amd64 .6", _is6 , _read6 },
86 [ObjArm] = { "arm .5", _is5, _read5 },
87 [ObjAlpha] = { "alpha .7", _is7, _read7 },
88 [Obj386] = { "386 .8", _is8, _read8 },
89 [ObjSparc] = { "sparc .k", _isk, _readk },
90 [ObjPower] = { "power .q", _isq, _readq },
91 [ObjMips] = { "mips .v", _isv, _readv },
92 [ObjSparc64] = { "sparc64 .u", _isu, _readu },
93 [ObjPower64] = { "power64 .9", _is9, _read9 },
94 [Maxobjtype] = { 0, 0, 0 }
95 };
96
97 struct Symtab
98 {
99 struct Sym s;
100 struct Symtab *next;
101 };
102
103 static Symtab *hash[NHASH];
104 static Sym *names[NNAMES]; /* working set of active names */
105
106 static int processprog(Prog*,int); /* decode each symbol reference */
107 static void objreset(void);
108 static void objlookup(int, char *, int, uint);
109 static void objupdate(int, int);
110
111 static int sequence;
112
113 int
114 objtype(Biobuf *bp, char **name)
115 {
116 int i;
117 char buf[MAXIS];
118 int c;
119 char *p;
120
121 /*
122 * Look for import block.
123 */
124 p = Brdline(bp, '\n');
125 if(p == nil)
126 return -1;
127 if(Blinelen(bp) < 10 || strncmp(p, "go object ", 10) != 0)
128 return -1;
129 Bseek(bp, -1, 1);
130
131 /*
132 * Found one. Skip until "\n!\n"
133 */
134 for(;;) {
135 if((c = Bgetc(bp)) == Beof)
136 return -1;
137 if(c != '\n')
138 continue;
139 c = Bgetc(bp);
140 if(c != '!'){
141 Bungetc(bp);
142 continue;
143 }
144 c = Bgetc(bp);
145 if(c != '\n'){
146 Bungetc(bp);
147 continue;
148 }
149 break;
150 }
151
152 if(Bread(bp, buf, MAXIS) < MAXIS)
153 return -1;
154 Bseek(bp, -MAXIS, 1);
155 for (i = 0; i < Maxobjtype; i++) {
156 if (obj[i].is && (*obj[i].is)(buf)) {
157 if (name)
158 *name = obj[i].name;
159 return i;
160 }
161 }
162
163 return -1;
164 }
165
166 int
167 isar(Biobuf *bp)
168 {
169 int n;
170 char magbuf[SARMAG];
171
172 n = Bread(bp, magbuf, SARMAG);
173 if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0)
174 return 1;
175 return 0;
176 }
177
178 /*
179 * determine what kind of object file this is and process it.
180 * return whether or not this was a recognized intermediate file.
181 */
182 int
183 readobj(Biobuf *bp, int objtype)
184 {
185 Prog p;
186
187 if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
188 return 1;
189 objreset();
190 while ((*obj[objtype].read)(bp, &p))
191 if (!processprog(&p, 1))
192 return 0;
193 return 1;
194 }
195
196 int
197 readar(Biobuf *bp, int objtype, vlong end, int doautos)
198 {
199 Prog p;
200
201 if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
202 return 1;
203 objreset();
204 while ((*obj[objtype].read)(bp, &p) && Boffset(bp) < end)
205 if (!processprog(&p, doautos))
206 return 0;
207 return 1;
208 }
209
210 /*
211 * decode a symbol reference or definition
212 */
213 static int
214 processprog(Prog *p, int doautos)
215 {
216 if(p->kind == aNone)
217 return 1;
218 if((schar)p->sym < 0 || p->sym >= NNAMES)
219 return 0;
220 switch(p->kind)
221 {
222 case aName:
223 if (!doautos)
224 if(p->type != 'U' && p->type != 'b')
225 break;
226 objlookup(p->sym, p->id, p->type, p->sig);
227 break;
228 case aText:
229 objupdate(p->sym, 'T');
230 break;
231 case aData:
232 objupdate(p->sym, 'D');
233 break;
234 default:
235 break;
236 }
237 return 1;
238 }
239
240 /*
241 * find the entry for s in the symbol array.
242 * make a new entry if it is not already there.
243 */
244 static void
245 objlookup(int id, char *name, int type, uint sig)
246 {
247 int32 h;
248 char *cp;
249 Sym *s;
250 Symtab *sp;
251
252 s = names[id];
253 if(s && strcmp(s->name, name) == 0) {
254 s->type = type;
255 s->sig = sig;
256 return;
257 }
258
259 h = *name;
260 for(cp = name+1; *cp; h += *cp++)
261 h *= HASHMUL;
262 h &= NHASH-1;
263 if (type == 'U' || type == 'b' || islocal(type)) {
264 for(sp = hash[h]; sp; sp = sp->next)
265 if(strcmp(sp->s.name, name) == 0) {
266 switch(sp->s.type) {
267 case 'T':
268 case 'D':
269 case 'U':
270 if (type == 'U') {
271 names[id] = &sp->s;
272 return;
273 }
274 break;
275 case 't':
276 case 'd':
277 case 'b':
278 if (type == 'b') {
279 names[id] = &sp->s;
280 return;
281 }
282 break;
283 case 'a':
284 case 'p':
285 if (islocal(type)) {
286 names[id] = &sp->s;
287 return;
288 }
289 break;
290 default:
291 break;
292 }
293 }
294 }
295 sp = malloc(sizeof(Symtab));
296 sp->s.name = name;
297 sp->s.type = type;
298 sp->s.sig = sig;
299 sp->s.value = islocal(type) ? MAXOFF : 0;
300 sp->s.sequence = sequence++;
301 names[id] = &sp->s;
302 sp->next = hash[h];
303 hash[h] = sp;
304 return;
305 }
306 /*
307 * traverse the symbol lists
308 */
309 void
310 objtraverse(void (*fn)(Sym*, void*), void *pointer)
311 {
312 int i;
313 Symtab *s;
314
315 for(i = 0; i < NHASH; i++)
316 for(s = hash[i]; s; s = s->next)
317 (*fn)(&s->s, pointer);
318 }
319
320 /*
321 * update the offset information for a 'a' or 'p' symbol in an intermediate file
322 */
323 void
324 _offset(int id, vlong off)
325 {
326 Sym *s;
327
328 s = names[id];
329 if (s && s->name[0] && islocal(s->type) && s->value > off)
330 s->value = off;
331 }
332
333 /*
334 * update the type of a global text or data symbol
335 */
336 static void
337 objupdate(int id, int type)
338 {
339 Sym *s;
340
341 s = names[id];
342 if (s && s->name[0])
343 if (s->type == 'U')
344 s->type = type;
345 else if (s->type == 'b')
346 s->type = tolower(type);
347 }
348
349 /*
350 * look for the next file in an archive
351 */
352 int
353 nextar(Biobuf *bp, int offset, char *buf)
354 {
355 struct ar_hdr a;
356 int i, r;
357 int32 arsize;
358
359 if (offset&01)
360 offset++;
361 Bseek(bp, offset, 0);
362 r = Bread(bp, &a, SAR_HDR);
363 if(r != SAR_HDR)
364 return 0;
365 if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag)))
366 return -1;
367 for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++)
368 buf[i] = a.name[i];
369 buf[i] = 0;
370 arsize = strtol(a.size, 0, 0);
371 if (arsize&1)
372 arsize++;
373 return arsize + SAR_HDR;
374 }
375
376 static void
377 objreset(void)
378 {
379 int i;
380 Symtab *s, *n;
381
382 for(i = 0; i < NHASH; i++) {
383 for(s = hash[i]; s; s = n) {
384 n = s->next;
385 free(s->s.name);
386 free(s);
387 }
388 hash[i] = 0;
389 }
390 memset(names, 0, sizeof names);
391 }