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