xref: /inferno-os/utils/5coff/coff.c (revision e45fa0eb0763b57d6fb0649c064bc3b95ccdea6c)
1 #include	"auxi.h"
2 
3 /*
4  * in some embedded coff files, edata and end have type 0 not 4,
5  * and file value is pointer to next file sym (as here), but the last one
6  * points to an external symbol, not 0 as here.
7  */
8 
9 #define C_NULL	0
10 #define C_AUTO	1
11 #define C_EXT		2
12 #define C_STAT	3
13 #define C_ARG		9
14 #define C_FCN		101
15 #define C_FILE		103
16 
17 #define T_VOID	0
18 #define T_CHAR	2
19 #define T_SHORT	3
20 #define T_INT		4
21 #define T_LONG	5
22 
23 #define DT_NON	0
24 #define DT_PTR	1
25 #define DT_FCN	2
26 #define DT_ARY	3
27 
28 #define T(a, b)	(((a)<<4)|b)
29 
30 #define DOTTEXT	".text"
31 #define DOTDATA	".data"
32 #define DOTBSS	".bss"
33 #define DOTBF		".bf"
34 #define DOTEF		".ef"
35 
36 #define SINDEX(s)	(*((long*)(&s->become)))
37 #define LINDEX(s)	(*((long*)(&s->used)))
38 
39 typedef struct Hist Hist;
40 
41 struct Hist{
42 	Auto *a;
43 	Hist *n;
44 };
45 
46 static int nsym, nlc, lines;
47 
48 static void cofflcsz(void);
49 
50 static Hist *freeh, *curh;
51 
52 static void
53 dohist(Auto *a)
54 {
55 	Hist *h, **ha;
56 
57 	if(a->aoffset == 1){	/* new file */
58 		for(ha = &curh; *ha != nil; ha = &((*ha)->n))
59 			;
60 		*ha = freeh;
61 		freeh = curh;
62 		curh = nil;
63 	}
64 	if(freeh != nil){
65 		h = freeh;
66 		freeh = freeh->n;
67 	}
68 	else
69 		h = malloc(sizeof(Hist));
70 	h->a = a;
71 	h->n = nil;
72 	for(ha = &curh; *ha != nil; ha = &((*ha)->n))
73 		;
74 	*ha = h;
75 }
76 
77 static long
78 lineno(long n)
79 {
80 	long o, d;
81 	Hist *h;
82 
83 	if(1)
84 		return n;	/* now using fileline() not pc2line() */
85 
86 	if(curh == nil)
87 		return 0;
88 	o = curh->a->aoffset-1;
89 	d = 1;
90 	for(h = curh->n; d && h != nil; h = h->n){
91 		if(h->a->asym->name[1] || h->a->asym->name[2]){
92 			if(h->a->type == D_FILE1) {
93 				;
94 			}
95 			else if(d == 1 && n < h->a->aoffset)
96 				break;
97 			else if(d++ == 1)
98 				o -= h->a->aoffset;
99 		}
100 		else if(--d == 1)
101 			o += h->a->aoffset;
102 	}
103 	return n-o;
104 }
105 
106 static char *
107 filelookup(int k)
108 {
109 	int i;
110 	Symx *s;
111 
112 	for(i = 0; i < NHASH; i++){
113 		for(s = hash[i]; s != nil; s = s->link){
114 			if(s->type == SFILE && k == s->value)
115 				return s->name+1;
116 		}
117 	}
118 	return "";
119 }
120 
121 static char*
122 filename(char *s)
123 {
124 	int j, k, l;
125 	static char buf[256];
126 
127 	buf[0] = '\0';
128 	if(s[0] != 0)
129 		diag("bad filename");
130 	for(j = 1; ; j += 2){
131 		k = (s[j]<<8)|s[j+1];
132 		if(k == 0)
133 			break;
134 		l = strlen(buf);
135 		if(l != 0 && buf[l-1] != '/')
136 			strcat(buf, "/");
137 		strcat(buf, filelookup(k));
138 	}
139 	return buf;
140 }
141 
142 static void
143 sput(char *s, int n)
144 {
145 	int i;
146 
147 	for(i = 0; i < n && s != nil && *s != '\0'; i++, s++)
148 		cput(*s);
149 	for( ; i < n; i++)
150 		cput(0);
151 }
152 
153 static void
154 coffsect(char *s, long a, long sz, long o, long lp, long nl, long f)
155 {
156 	if(0)
157 		print("sect %s pa=%lux va=%lux sz=%lux\n", s, a, a, sz);
158 	sput(s, 8);			/* name <= 8 chars in len */
159 	lputl(a);			/* pa */
160 	lputl(a);			/* va */
161 	lputl(sz);			/* size */
162 	lputl(o);			/* file offset */
163 	lputl(0);			/* reloc */
164 	lputl(lp);			/* line nos */
165 	lputl(0);			/* no reloc entries */
166 	lputl(nl);			/* no line no entries */
167 	lputl(f);			/* flags */
168 	hputl(0);			/* reserved */
169 	hputl(0);			/* mem page no */
170 }
171 
172 void
173 coffhdr(void)
174 {
175 	if(0){
176 		print("H=%lux t=%lux d=%lux b=%lux\n", HEADR, textsize, datsize, bsssize);
177 		print("e=%lux ts=%lux ds=%lux\n", entryvalue(), INITTEXT, INITDAT);
178 	}
179 
180 	/*
181 	 * file header
182 	 */
183 	hputl(0xc2);			/* version ID */
184 	hputl(3);				/* no section hdrs */
185 	lputl(0);				/* date stamp */
186 	lputl(HEADR+textsize+datsize+6*nlc);	/* sym table */
187 	lputl(nsym);			/* no sym table entries */
188 	hputl(28);				/* size optional hdr */
189 	hputl(0x0103);			/* flags */
190 	hputl(0x97);			/* target ID */
191 	/*
192 	 * optional file header
193 	 */
194 	hputl(0x108);			/* magic */
195 	hputl(0);				/* version stamp */
196 	lputl(textsize);			/* text size */
197 	lputl(datsize);			/* data size */
198 	lputl(bsssize);			/* bss size */
199 	lputl(entryvalue());		/* entry pt */
200 	lputl(INITTEXT);		/* text start */
201 	lputl(INITDAT);			/* data start */
202 	/*
203 	 * sections
204 	 */
205 	coffsect(DOTTEXT, INITTEXT, textsize, HEADR, HEADR+textsize+datsize, nlc, 0x20);
206 	coffsect(DOTDATA, INITDAT, datsize, HEADR+textsize, 0, 0, 0x40);
207 	coffsect(DOTBSS, INITDAT+datsize, bsssize, 0, 0, 0, 0x80);
208 }
209 
210 static int
211 private(char *s)
212 {
213 	return strcmp(s, "safe") == 0 || strcmp(s, "ret") == 0 || strcmp(s, "string") == 0;
214 }
215 
216 static long stoff = 4;
217 
218 static long
219 stput(char *s)
220 {
221 	long r;
222 
223 	r = stoff;
224 	stoff += strlen(s)+1;
225 	return r;
226 }
227 
228 static long
229 strput(char *s)
230 {
231 	int l;
232 
233 	if((l = strlen(s)) > 8){
234 		if(*s == '.' && private(s+1))
235 			return 0;
236 		while(*s)
237 			cput(*s++);
238 		cput(*s);
239 		return l+1;
240 	}
241 	return 0;
242 }
243 
244 static void
245 stflush(void)
246 {
247 	int i;
248 	long o;
249 	Prog *p;
250 	Auto *a, *f;
251 	Symx *s;
252 	char *fn, file[256];
253 
254 	lputl(stoff);
255 	o = 4;
256 	for(p = firstp; p != P; p = p->link){
257 		if(p->as == ATEXT){
258 			f = nil;
259 			fn = nil;
260 			for(a = p->to.autom; a != nil; a = a->link){
261 				if(a->type == D_FILE){
262 					f = a;
263 					break;
264 				}
265 			}
266 			if(f != nil)
267 				fn = filename(f->asym->name);
268 			if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){
269 				strcpy(file, fn);
270 				o += strput(file);
271 			}
272 			o += strput(p->from.sym->name);
273 			for(a = p->to.autom; a != nil; a = a->link){
274 				if(a->type == D_AUTO || a->type == D_PARAM)
275 					o += strput(a->asym->name);
276 			}
277 		}
278 	}
279 	for(i = 0; i < NHASH; i++){
280 		for(s = hash[i]; s != nil; s = s->link){
281 			if(s->version > 0 && (s->type == SDATA || s->type == SBSS))
282 				o += strput(s->name);
283 		}
284 	}
285 	for(i = 0; i < NHASH; i++){
286 		for(s = hash[i]; s != nil; s = s->link){
287 			if(s->version == 0 && (s->type == SDATA || s->type == SBSS))
288 				o += strput(s->name);
289 		}
290 	}
291 	if(o != stoff)
292 		diag("bad stflush offset");
293 }
294 
295 static int
296 putsect(Symx *s)
297 {
298 	int sz, ln;
299 
300 	sz = ln = 0;
301 	// isn't this repetition ?
302 	if(strcmp(s->name, DOTTEXT) == 0){
303 		sz = textsize;
304 		ln = nlc;
305 	}
306 	else if(strcmp(s->name, DOTDATA) == 0)
307 		sz = datsize;
308 	else if(strcmp(s->name, DOTBSS) == 0)
309 		sz = bsssize;
310 	else
311 		diag("bad putsect sym");
312 	lputl(sz);
313 	hputl(0);
314 	hputl(ln);
315 	sput(nil, 10);
316 	return 1;
317 }
318 
319 static int
320 putfun(Symx *s)
321 {
322 	/* lputl(SINDEX(s)+2); */
323 	lputl(0);
324 	lputl(0);	/* patched later */
325 	lputl(HEADR+textsize+datsize+LINDEX(s));
326 	lputl(0);	/* patched later */
327 	sput(nil, 2);
328 	return 1;
329 }
330 
331 static int
332 putbf(int lno)
333 {
334 	lputl(0);
335 	hputl(lno);
336 	hputl(lines);
337 	lputl(autosize);
338 	lputl(0);	/* patched later */
339 	sput(nil, 2);
340 	return 1;
341 }
342 
343 static int
344 putef(int lno)
345 {
346 	sput(nil, 4);
347 	hputl(lno);
348 	sput(nil, 12);
349 	return 1;
350 }
351 
352 static int
353 putsym(Symx *s, int sc, int t, int lno)
354 {
355 	long v;
356 
357 	if(s == nil || s->name == nil || s->name[0] == '\0' || (s->name[0] == '.' && private(s->name+1)))
358 		return 0;
359 	if(0)
360 		print("putsym %s %d %ld %d %d\n", s->name, s->type, s->value, sc, t);
361 	if(strlen(s->name) <= 8)
362 		sput(s->name, 8);
363 	else{
364 		lputl(0);
365 		lputl(stput(s->name));
366 	}
367 	/* value */
368 	v = s->value;
369 	if(s->type == SDATA || s->type == SDATA1 || s->type == SBSS)
370 		lputl(INITDAT+v);
371 	else if(sc == C_AUTO)
372 		lputl(autosize+v);
373 	else if(sc == C_ARG)
374 		lputl(autosize+v+4);
375 	else
376 		lputl(v);
377 	switch(s->type){	/* section number */
378 	case STEXT:
379 	case SLEAF:
380 		hputl(1);
381 		break;
382 	case SDATA:
383 	case SDATA1:
384 		hputl(2);
385 		break;
386 	case SBSS:
387 		hputl(3);
388 		break;
389 	case SFILE:
390 		hputl(-2);
391 		break;
392 	default:
393 		diag("type %d in putsym", s->type);
394 		break;
395 	}
396 	hputl(t);			/* type */
397 	cput(sc);			/* storage class */
398 	/* aux entries */
399 	if(sc == C_STAT && t == T_VOID && s->name[0] == '.'){	/* section */
400 		cput(1);
401 		return 1+putsect(s);
402 	}
403 	else if((t>>4) == DT_FCN){	/* function */
404 		cput(1);
405 		return 1+putfun(s);
406 	}
407 	else if(sc == C_FCN && strcmp(s->name, DOTBF) == 0){	/* bf */
408 		cput(1);
409 		return 1+putbf(lno);
410 	}
411 	else if(sc == C_FCN && strcmp(s->name, DOTEF) == 0){	/* ef */
412 		cput(1);
413 		return 1+putef(lno);
414 	}
415 	cput(0);			/* 0 aux entry */
416 	return 1;
417 }
418 
419 static Symx*
420 defsym(char *p, int t, long v)
421 {
422 	Symx *s;
423 
424 	s = lookupsym(p, 0);
425 	if(s->type == SDATA || s->type == SBSS)
426 		return nil;		/* already output */
427 	if(s->type == 0 || s->type == SXREF){
428 		s->type = t;
429 		s->value = v;
430 	}
431 	return s;
432 }
433 
434 static int
435 specsym(char *p, int t, long v, int c)
436 {
437 	return putsym(defsym(p, t, v), c, T_VOID, 0);
438 }
439 
440 static int
441 cclass(Symx *s)
442 {
443 /*
444 	if(s->version > 0 && dclass == D_EXTERN)
445 		diag("%s: version %d dclass EXTERN", s->name, s->version);
446 	if(s->version == 0 && dclass == D_STATIC)
447 		diag("%s: version %d dclass STATIC", s->name, s->version);
448 */
449 	return s->version > 0 ? C_STAT : C_EXT;
450 }
451 
452 static void
453 patchsym(long i, long o, long v)
454 {
455 	long oo;
456 
457 	cflush();
458 	oo = seek(cout, 0, 1);
459 	seek(cout, HEADR+textsize+datsize+6*nlc+18*i+o, 0);
460 	lputl(v);
461 	cflush();
462 	seek(cout, oo, 0);
463 }
464 
465 void
466 coffsym(void)
467 {
468 	int i;
469 	long ns, lno, lpc, v, vs, lastf;
470 	Prog *p;
471 	Auto *a, *f;
472 	Symx *s, *bf, *ef, ts;
473 	char *fn, file[256];
474 
475 	file[0] = '\0';
476 	cofflcsz();
477 	seek(cout, 6*nlc, 1);		/* advance over line table */
478 	ns = 0;
479 	lpc = -1;
480 	lno = -1;
481 	lastf = -1;
482 	bf = defsym(DOTBF, STEXT, 0);
483 	ef = defsym(DOTEF, STEXT, 0);
484 	for(p = firstp; p != P; p = p->link){
485 		if(p->as != ATEXT){
486 			if(p->line != 0)
487 				lno = lineno(p->line);
488 		}
489 		if(p->as == ATEXT){
490 			curtext = p;
491 			autosize = p->to.offset+4;
492 			if(lpc >= 0){
493 				ef->value = lpc;
494 				ns += putsym(ef, C_FCN, T_VOID, lno);
495 			}
496 			f = nil;
497 			fn = nil;
498 			for(a = p->to.autom; a != nil; a = a->link){
499 				if(a->type == D_FILE || a->type == D_FILE1)
500 					dohist(a);
501 				if(f == nil && a->type == D_FILE)
502 					f = a;		/* main filename */
503 			}
504 			if(f != nil)
505 				fn = filename(f->asym->name);
506 			if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){
507 				strcpy(file, fn);
508 				ts.name = file;
509 				ts.type = SFILE;
510 				ts.value = 0;
511 				if(lastf >= 0)
512 					patchsym(lastf, 8, ns);
513 				lastf = ns;
514 				ns += putsym(&ts, C_FILE, T_VOID, 0);
515 			}
516 			if(p->link != P && p->link->line != 0)
517 				lno = lineno(p->link->line);
518 			else if(p->line != 0)
519 				lno = lineno(p->line);
520 			s = p->from.sym;
521 			SINDEX(s) = ns;
522 			ns += putsym(s, cclass(s), T(DT_FCN, T_INT), 0);
523 			if(p->cond != P)
524 				lines = LINDEX(p->cond->from.sym)-LINDEX(s)-1;
525 			else
526 				lines = 0;
527 			bf->value = p->pc;
528 			ns += putsym(bf, C_FCN, T_VOID, lno);
529 			for(a = p->to.autom; a != nil; a = a->link){
530 				if(a->type == D_AUTO || a->type == D_PARAM){
531 					ts.name = a->asym->name;
532 					ts.type = STEXT;
533 					ts.value = a->aoffset;
534 					ns += putsym(&ts, a->type == D_AUTO ? C_AUTO : C_ARG, T_INT, 0);
535 				}
536 			}
537 		}
538 		lpc = p->pc;
539 	}
540 	if(lpc >= 0){
541 		ef->value = lpc;
542 		ns += putsym(ef, C_FCN, T_VOID, lno);
543 	}
544 	/* patch up */
545 	for(p = textp; p != P; p = p->cond){
546 		s = p->from.sym;
547 		if(p->cond != P){
548 			v = SINDEX(p->cond->from.sym);
549 			vs = p->cond->pc - p->pc;
550 		}
551 		else{
552 			v = 0;
553 			vs = INITTEXT+textsize-p->pc;
554 		}
555 		patchsym(SINDEX(s)+1, 4, 8*vs);
556 		patchsym(SINDEX(s)+1, 12, v);
557 		patchsym(SINDEX(s)+3, 12, v);
558 	}
559 	for(i = 0; i < NHASH; i++){
560 		for(s = hash[i]; s != nil; s = s->link){
561 			if(s->version > 0 && (s->type == SDATA || s->type == SBSS))
562 				ns += putsym(s, cclass(s), T_INT, 0);
563 		}
564 	}
565 	for(i = 0; i < NHASH; i++){
566 		for(s = hash[i]; s != nil; s = s->link){
567 			if(s->version == 0 && (s->type == SDATA || s->type == SBSS))
568 				ns += putsym(s, cclass(s), T_INT, 0);
569 		}
570 	}
571 	ns += specsym(DOTTEXT, STEXT, INITTEXT, C_STAT);
572 	ns += specsym(DOTDATA, SDATA, 0, C_STAT);
573 	ns += specsym(DOTBSS, SBSS, datsize, C_STAT);
574 	ns += specsym("etext", STEXT, INITTEXT+textsize, C_EXT);
575 	ns += specsym("edata", SDATA, datsize, C_EXT);
576 	ns += specsym("end", SBSS, datsize+bsssize, C_EXT);
577 	nsym = ns;
578 	stflush();
579 }
580 
581 void
582 cofflc(void)
583 {
584 	long olc, nl;
585 	Symx *s;
586 	Prog *p;
587 	Auto *a;
588 
589 	cflush();
590 	seek(cout, HEADR+textsize+datsize, 0);
591 	nl = 0;
592 	/* opc = INITTEXT; */
593 	olc = 0;
594 	for(p = firstp; p != P; p = p->link){
595 		if(p->as == ATEXT){
596 			curtext = p;
597 			s = p->from.sym;
598 			/* opc = p->pc; */
599 			for(a = p->to.autom; a != nil; a = a->link){
600 				if(a->type == D_FILE || a->type == D_FILE1)
601 					dohist(a);
602 			}
603 			lputl(SINDEX(s));
604 			hputl(0);
605 			nl++;
606 			continue;
607 		}
608 		if(p->line == 0 || p->line == olc || p->as == ANOP)
609 			continue;
610 		lputl(p->pc);
611 		hputl(lineno(p->line));
612 		nl++;
613 		olc = p->line;
614 	}
615 	if(nl != nlc)
616 		diag("bad line count in cofflc()");
617 	nlc = nl;
618 }
619 
620 static void
621 cofflcsz(void)
622 {
623 	long olc, nl;
624 	Prog *p;
625 
626 	nl = 0;
627 	olc = 0;
628 	for(p = firstp; p != P; p = p->link){
629 		if(p->as == ATEXT){
630 			LINDEX(p->from.sym) = nl;
631 			nl++;
632 			continue;
633 		}
634 		if(p->line == 0 || p->line == olc || p->as == ANOP)
635 			continue;
636 		nl++;
637 		olc = p->line;
638 	}
639 	nlc = nl;
640 }
641