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