1 /*
2 * obj.c
3 * routines universal to all object files
4 */
5 #include <u.h>
6 #include <libc.h>
7 #include <bio.h>
8 #include <ar.h>
9 #include <mach.h>
10 #include "obj.h"
11
12 #define islocal(t) ((t)=='a' || (t)=='p')
13
14 enum
15 {
16 NNAMES = 50,
17 MAXIS = 8, /* max length to determine if a file is a .? file */
18 MAXOFF = 0x7fffffff, /* larger than any possible local offset */
19 NHASH = 1024, /* must be power of two */
20 HASHMUL = 79L,
21 };
22
23 int _is2(char*), /* in [$OS].c */
24 _is4(char*),
25 _is5(char*),
26 _is6(char*),
27 _is7(char*),
28 _is8(char*),
29 _is9(char*),
30 _isk(char*),
31 _isq(char*),
32 _isv(char*),
33 _isu(char*),
34 _isi(char*),
35 _read2(Biobuf*, Prog*),
36 _read4(Biobuf*, Prog*),
37 _read5(Biobuf*, Prog*),
38 _read6(Biobuf*, Prog*),
39 _read7(Biobuf*, Prog*),
40 _read8(Biobuf*, Prog*),
41 _read9(Biobuf*, Prog*),
42 _readk(Biobuf*, Prog*),
43 _readq(Biobuf*, Prog*),
44 _readv(Biobuf*, Prog*),
45 _readu(Biobuf*, Prog*),
46 _readi(Biobuf*, Prog*);
47
48 typedef struct Obj Obj;
49 typedef struct Symtab Symtab;
50
51 struct Obj /* functions to handle each intermediate (.$O) file */
52 {
53 char *name; /* name of each $O file */
54 int (*is)(char*); /* test for each type of $O file */
55 int (*read)(Biobuf*, Prog*); /* read for each type of $O file*/
56 };
57
58 static Obj obj[] =
59 { /* functions to identify and parse each type of obj */
60 [Obj68020] "68020 .2", _is2, _read2,
61 [ObjAmd64] "amd64 .6", _is6, _read6,
62 [ObjArm] "arm .5", _is5, _read5,
63 [ObjAlpha] "alpha .7", _is7, _read7,
64 [Obj386] "386 .8", _is8, _read8,
65 [ObjSparc] "sparc .k", _isk, _readk,
66 [ObjPower] "power .q", _isq, _readq,
67 [ObjMips] "mips .v", _isv, _readv,
68 [ObjSparc64] "sparc64 .u", _isu, _readu,
69 [ObjPower64] "power64 .9", _is9, _read9,
70 [ObjRiscv] "riscv .i", _isi, _readi,
71 [ObjRiscv64] "riscv64 .j", _isi, _readi,
72 [ObjMips2] "mips64 .4", _is4, _read4,
73 [Maxobjtype] 0, 0
74 };
75
76 struct Symtab
77 {
78 struct Sym s;
79 struct Symtab *next;
80 };
81
82 static Symtab *hash[NHASH];
83 static Sym *names[NNAMES]; /* working set of active names */
84
85 static int processprog(Prog*,int); /* decode each symbol reference */
86 static void objreset(void);
87 static void objlookup(int, char *, int, uint);
88 static void objupdate(int, int);
89
90 int
objtype(Biobuf * bp,char ** name)91 objtype(Biobuf *bp, char **name)
92 {
93 int i;
94 char buf[MAXIS];
95
96 if(Bread(bp, buf, MAXIS) < MAXIS)
97 return -1;
98 Bseek(bp, -MAXIS, 1);
99 for (i = 0; i < Maxobjtype; i++) {
100 if (obj[i].is && (*obj[i].is)(buf)) {
101 if (name)
102 *name = obj[i].name;
103 return i;
104 }
105 }
106 return -1;
107 }
108
109 int
isar(Biobuf * bp)110 isar(Biobuf *bp)
111 {
112 int n;
113 char magbuf[SARMAG];
114
115 n = Bread(bp, magbuf, SARMAG);
116 if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0)
117 return 1;
118 return 0;
119 }
120
121 /*
122 * determine what kind of object file this is and process it.
123 * return whether or not this was a recognized intermediate file.
124 */
125 int
readobj(Biobuf * bp,int objtype)126 readobj(Biobuf *bp, int objtype)
127 {
128 Prog p;
129
130 if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
131 return 1;
132 objreset();
133 while ((*obj[objtype].read)(bp, &p))
134 if (!processprog(&p, 1))
135 return 0;
136 return 1;
137 }
138
139 int
readar(Biobuf * bp,int objtype,vlong end,int doautos)140 readar(Biobuf *bp, int objtype, vlong end, int doautos)
141 {
142 Prog p;
143
144 if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
145 return 1;
146 objreset();
147 while ((*obj[objtype].read)(bp, &p) && Boffset(bp) < end)
148 if (!processprog(&p, doautos))
149 return 0;
150 return 1;
151 }
152
153 /*
154 * decode a symbol reference or definition
155 */
156 static int
processprog(Prog * p,int doautos)157 processprog(Prog *p, int doautos)
158 {
159 if(p->kind == aNone)
160 return 1;
161 if(p->sym < 0 || p->sym >= NNAMES)
162 return 0;
163 switch(p->kind)
164 {
165 case aName:
166 if (!doautos)
167 if(p->type != 'U' && p->type != 'b')
168 break;
169 objlookup(p->sym, p->id, p->type, p->sig);
170 break;
171 case aText:
172 objupdate(p->sym, 'T');
173 break;
174 case aData:
175 objupdate(p->sym, 'D');
176 break;
177 default:
178 break;
179 }
180 return 1;
181 }
182
183 /*
184 * find the entry for s in the symbol array.
185 * make a new entry if it is not already there.
186 */
187 static void
objlookup(int id,char * name,int type,uint sig)188 objlookup(int id, char *name, int type, uint sig)
189 {
190 long h;
191 char *cp;
192 Sym *s;
193 Symtab *sp;
194
195 s = names[id];
196 if(s && strcmp(s->name, name) == 0) {
197 s->type = type;
198 s->sig = sig;
199 return;
200 }
201
202 h = *name;
203 for(cp = name+1; *cp; h += *cp++)
204 h *= HASHMUL;
205 if(h < 0)
206 h = ~h;
207 h &= (NHASH-1);
208 if (type == 'U' || type == 'b' || islocal(type)) {
209 for(sp = hash[h]; sp; sp = sp->next)
210 if(strcmp(sp->s.name, name) == 0) {
211 switch(sp->s.type) {
212 case 'T':
213 case 'D':
214 case 'U':
215 if (type == 'U') {
216 names[id] = &sp->s;
217 return;
218 }
219 break;
220 case 't':
221 case 'd':
222 case 'b':
223 if (type == 'b') {
224 names[id] = &sp->s;
225 return;
226 }
227 break;
228 case 'a':
229 case 'p':
230 if (islocal(type)) {
231 names[id] = &sp->s;
232 return;
233 }
234 break;
235 default:
236 break;
237 }
238 }
239 }
240 sp = malloc(sizeof(Symtab));
241 sp->s.name = name;
242 sp->s.type = type;
243 sp->s.sig = sig;
244 sp->s.value = islocal(type) ? MAXOFF : 0;
245 names[id] = &sp->s;
246 sp->next = hash[h];
247 hash[h] = sp;
248 return;
249 }
250 /*
251 * traverse the symbol lists
252 */
253 void
objtraverse(void (* fn)(Sym *,void *),void * pointer)254 objtraverse(void (*fn)(Sym*, void*), void *pointer)
255 {
256 int i;
257 Symtab *s;
258
259 for(i = 0; i < NHASH; i++)
260 for(s = hash[i]; s; s = s->next)
261 (*fn)(&s->s, pointer);
262 }
263
264 /*
265 * update the offset information for a 'a' or 'p' symbol in an intermediate file
266 */
267 void
_offset(int id,vlong off)268 _offset(int id, vlong off)
269 {
270 Sym *s;
271
272 s = names[id];
273 if (s && s->name[0] && islocal(s->type) && s->value > off)
274 s->value = off;
275 }
276
277 /*
278 * update the type of a global text or data symbol
279 */
280 static void
objupdate(int id,int type)281 objupdate(int id, int type)
282 {
283 Sym *s;
284
285 s = names[id];
286 if (s && s->name[0])
287 if (s->type == 'U')
288 s->type = type;
289 else if (s->type == 'b')
290 s->type = tolower(type);
291 }
292
293 /*
294 * look for the next file in an archive
295 */
296 int
nextar(Biobuf * bp,int offset,char * buf)297 nextar(Biobuf *bp, int offset, char *buf)
298 {
299 struct ar_hdr a;
300 int i, r;
301 long arsize;
302
303 if (offset&01)
304 offset++;
305 Bseek(bp, offset, 0);
306 r = Bread(bp, &a, SAR_HDR);
307 if(r != SAR_HDR)
308 return 0;
309 if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag)))
310 return -1;
311 for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++)
312 buf[i] = a.name[i];
313 buf[i] = 0;
314 arsize = strtol(a.size, 0, 0);
315 if (arsize&1)
316 arsize++;
317 return arsize + SAR_HDR;
318 }
319
320 static void
objreset(void)321 objreset(void)
322 {
323 int i;
324 Symtab *s, *n;
325
326 for(i = 0; i < NHASH; i++) {
327 for(s = hash[i]; s; s = n) {
328 n = s->next;
329 free(s->s.name);
330 free(s);
331 }
332 hash[i] = 0;
333 }
334 memset(names, 0, sizeof names);
335 }
336