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