xref: /plan9-contrib/sys/src/libmach/obj.c (revision ce95e1b3727b9cb1c223ffbed69aff21a8ced255)
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