xref: /inferno-os/utils/ql/asm.c (revision 6e425a9de8c003b5a733621a6b6730ec3cc902b8)
1 #include	"l.h"
2 
3 #define	KMASK	0xF0000000
4 
5 #define	LPUT(c)\
6 	{\
7 		cbp[0] = (c)>>24;\
8 		cbp[1] = (c)>>16;\
9 		cbp[2] = (c)>>8;\
10 		cbp[3] = (c);\
11 		cbp += 4;\
12 		cbc -= 4;\
13 		if(cbc <= 0)\
14 			cflush();\
15 	}
16 
17 #define	CPUT(c)\
18 	{\
19 		cbp[0] = (c);\
20 		cbp++;\
21 		cbc--;\
22 		if(cbc <= 0)\
23 			cflush();\
24 	}
25 
26 void	strnput(char*, int);
27 
28 long
29 entryvalue(void)
30 {
31 	char *a;
32 	Sym *s;
33 
34 	a = INITENTRY;
35 	if(*a >= '0' && *a <= '9')
36 		return atolwhex(a);
37 	s = lookup(a, 0);
38 	if(s->type == 0)
39 		return INITTEXT;
40 	if(dlm && s->type == SDATA)
41 		return s->value+INITDAT;
42 	if(s->type != STEXT && s->type != SLEAF)
43 		diag("entry not text: %s", s->name);
44 	return s->value;
45 }
46 
47 void
48 asmb(void)
49 {
50 	Prog *p;
51 	long t;
52 	Optab *o;
53 
54 	if(debug['v'])
55 		Bprint(&bso, "%5.2f asm\n", cputime());
56 	Bflush(&bso);
57 	seek(cout, HEADR, 0);
58 	pc = INITTEXT;
59 	for(p = firstp; p != P; p = p->link) {
60 		if(p->as == ATEXT) {
61 			curtext = p;
62 			autosize = p->to.offset + 4;
63 			if(p->from3.type == D_CONST) {
64 				for(; pc < p->pc; pc++)
65 					CPUT(0);
66 			}
67 		}
68 		if(p->pc != pc) {
69 			diag("phase error %lux sb %lux",
70 				p->pc, pc);
71 			if(!debug['a'])
72 				prasm(curp);
73 			pc = p->pc;
74 		}
75 		curp = p;
76 		o = oplook(p);	/* could probably avoid this call */
77 		if(asmout(p, o, 0)) {
78 			p = p->link;
79 			pc += 4;
80 		}
81 		pc += o->size;
82 	}
83 	if(debug['a'])
84 		Bprint(&bso, "\n");
85 	Bflush(&bso);
86 	cflush();
87 
88 	curtext = P;
89 	switch(HEADTYPE) {
90 	case 0:
91 	case 1:
92 	case 2:
93 	case 5:
94 		seek(cout, HEADR+textsize, 0);
95 		break;
96 	case 3:
97 		seek(cout, rnd(HEADR+textsize, 4), 0);
98 		break;
99 	case 4:
100 		seek(cout, rnd(HEADR+textsize, 4096), 0);
101 		break;
102 	}
103 
104 	if(dlm){
105 		char buf[8];
106 
107 		write(cout, buf, INITDAT-textsize);
108 		textsize = INITDAT;
109 	}
110 
111 	for(t = 0; t < datsize; t += sizeof(buf)-100) {
112 		if(datsize-t > sizeof(buf)-100)
113 			datblk(t, sizeof(buf)-100);
114 		else
115 			datblk(t, datsize-t);
116 	}
117 
118 	symsize = 0;
119 	lcsize = 0;
120 	if(!debug['s']) {
121 		if(debug['v'])
122 			Bprint(&bso, "%5.2f sym\n", cputime());
123 		Bflush(&bso);
124 		switch(HEADTYPE) {
125 		case 0:
126 		case 1:
127 		case 2:
128 		case 5:
129 			seek(cout, HEADR+textsize+datsize, 0);
130 			break;
131 		case 3:
132 			seek(cout, rnd(HEADR+textsize, 4)+datsize, 0);
133 			break;
134 		case 4:
135 			seek(cout, rnd(HEADR+textsize, 4096)+datsize, 0);
136 			break;
137 		}
138 		if(!debug['s'])
139 			asmsym();
140 		if(debug['v'])
141 			Bprint(&bso, "%5.2f sp\n", cputime());
142 		Bflush(&bso);
143 		if(!debug['s'])
144 			asmlc();
145 		if(dlm)
146 			asmdyn();
147 		if(HEADTYPE == 0 || HEADTYPE == 1)	/* round up file length for boot image */
148 			if((symsize+lcsize) & 1)
149 				CPUT(0);
150 		cflush();
151 	}
152 	else if(dlm){
153 		asmdyn();
154 		cflush();
155 	}
156 
157 	seek(cout, 0L, 0);
158 	switch(HEADTYPE) {
159 	case 0:
160 		lput(0x1030107);		/* magic and sections */
161 		lput(textsize);			/* sizes */
162 		lput(datsize);
163 		lput(bsssize);
164 		lput(symsize);			/* nsyms */
165 		lput(entryvalue());		/* va of entry */
166 		lput(0L);
167 		lput(lcsize);
168 		break;
169 	case 1:
170 		lput(0x4a6f7921);		/* Joy! */
171 		lput(0x70656666);		/* peff */
172 		lput(0x70777063);		/* pwpc */
173 		lput(1);
174 		lput(0);
175 		lput(0);
176 		lput(0);
177 		lput(0);
178 		lput(0x30002);			/*YY*/
179 		lput(0);
180 		lput(~0);
181 		lput(0);
182 		lput(textsize+datsize);
183 		lput(textsize+datsize);
184 		lput(textsize+datsize);
185 		lput(0xd0);			/* header size */
186 		lput(0x10400);
187 		lput(~0);
188 		lput(0);
189 		lput(0xc);
190 		lput(0xc);
191 		lput(0xc);
192 		lput(0xc0);
193 		lput(0x01010400);
194 		lput(~0);
195 		lput(0);
196 		lput(0x38);
197 		lput(0x38);
198 		lput(0x38);
199 		lput(0x80);
200 		lput(0x04040400);
201 		lput(0);
202 		lput(1);
203 		lput(0);
204 		lput(~0);
205 		lput(0);
206 		lput(~0);
207 		lput(0);
208 		lput(0);
209 		lput(0);
210 		lput(0);
211 		lput(0);
212 		lput(0);
213 		lput(0);
214 		lput(0);
215 		lput(0);
216 		lput(0);
217 		lput(0);
218 		lput(0x3100);			/* load address */
219 		lput(0);
220 		lput(0);
221 		lput(0);			/* whew! */
222 		break;
223 	case 2:
224 		if(dlm)
225 			lput(0x80000000 | (4*21*21+7));		/* magic */
226 		else
227 			lput(4*21*21+7);	/* magic */
228 		lput(textsize);			/* sizes */
229 		lput(datsize);
230 		lput(bsssize);
231 		lput(symsize);			/* nsyms */
232 		lput(entryvalue());		/* va of entry */
233 		lput(0L);
234 		lput(lcsize);
235 		break;
236 	case 3:
237 		break;
238 	case 4:
239 		lput((0x1DFL<<16)|3L);		/* magic and sections */
240 		lput(time(0));			/* time and date */
241 		lput(rnd(HEADR+textsize, 4096)+datsize);
242 		lput(symsize);			/* nsyms */
243 		lput((0x48L<<16)|15L);		/* size of optional hdr and flags */
244 
245 		lput((0413<<16)|01L);		/* magic and version */
246 		lput(textsize);			/* sizes */
247 		lput(datsize);
248 		lput(bsssize);
249 		lput(entryvalue());		/* va of entry */
250 		lput(INITTEXT);			/* va of base of text */
251 		lput(INITDAT);			/* va of base of data */
252 		lput(INITDAT);			/* address of TOC */
253 		lput((1L<<16)|1);		/* sn(entry) | sn(text) */
254 		lput((2L<<16)|1);		/* sn(data) | sn(toc) */
255 		lput((0L<<16)|3);		/* sn(loader) | sn(bss) */
256 		lput((3L<<16)|3);		/* maxalign(text) | maxalign(data) */
257 		lput(('1'<<24)|('L'<<16)|0);	/* type field, and reserved */
258 		lput(0);			/* max stack allowed */
259 		lput(0);			/* max data allowed */
260 		lput(0); lput(0); lput(0);	/* reserved */
261 
262 		strnput(".text", 8);		/* text segment */
263 		lput(INITTEXT);			/* address */
264 		lput(INITTEXT);
265 		lput(textsize);
266 		lput(HEADR);
267 		lput(0L);
268 		lput(HEADR+textsize+datsize+symsize);
269 		lput(lcsize);			/* line number size */
270 		lput(0x20L);			/* flags */
271 
272 		strnput(".data", 8);		/* data segment */
273 		lput(INITDAT);			/* address */
274 		lput(INITDAT);
275 		lput(datsize);
276 		lput(rnd(HEADR+textsize, 4096));/* sizes */
277 		lput(0L);
278 		lput(0L);
279 		lput(0L);
280 		lput(0x40L);			/* flags */
281 
282 		strnput(".bss", 8);		/* bss segment */
283 		lput(INITDAT+datsize);		/* address */
284 		lput(INITDAT+datsize);
285 		lput(bsssize);
286 		lput(0L);
287 		lput(0L);
288 		lput(0L);
289 		lput(0L);
290 		lput(0x80L);			/* flags */
291 		break;
292 	case 5:
293 		strnput("\177ELF", 4);		/* e_ident */
294 		CPUT(1);			/* class = 32 bit */
295 		CPUT(2);			/* data = MSB */
296 		CPUT(1);			/* version = CURRENT */
297 		strnput("", 9);
298 		lput((2L<<16)|20L);		/* type = EXEC; machine = PowerPC */
299 		lput(1L);			/* version = CURRENT */
300 		lput(entryvalue() & ~KMASK);	/* entry vaddr */
301 		lput(52L);			/* offset to first phdr */
302 		lput(0L);			/* offset to first shdr */
303 		lput(0L);			/* flags = PPC */
304 		lput((52L<<16)|32L);		/* Ehdr & Phdr sizes*/
305 		lput((3L<<16)|0L);		/* # Phdrs & Shdr size */
306 		lput((0L<<16)|0L);		/* # Shdrs & shdr string size */
307 
308 		lput(1L);			/* text - type = PT_LOAD */
309 		lput(HEADR);			/* file offset */
310 		lput(INITTEXT & ~KMASK);	/* vaddr */
311 		lput(INITTEXT);			/* paddr */
312 		lput(textsize);			/* file size */
313 		lput(textsize);			/* memory size */
314 		lput(0x05L);			/* protections = RX */
315 		lput(0x10000L);			/* alignment */
316 
317 		lput(1L);			/* data - type = PT_LOAD */
318 		lput(HEADR+textsize);		/* file offset */
319 		lput(INITDAT & ~KMASK);		/* vaddr */
320 		lput(INITDAT);			/* paddr */
321 		lput(datsize);			/* file size */
322 		lput(datsize);			/* memory size */
323 		lput(0x07L);			/* protections = RWX */
324 		lput(0x10000L);			/* alignment */
325 
326 		lput(0L);			/* data - type = PT_NULL */
327 		lput(HEADR+textsize+datsize);	/* file offset */
328 		lput(0L);
329 		lput(0L);
330 		lput(symsize);			/* symbol table size */
331 		lput(lcsize);			/* line number size */
332 		lput(0x04L);			/* protections = R */
333 		lput(0x04L);			/* alignment code?? */
334 		break;
335 	}
336 	cflush();
337 }
338 
339 void
340 strnput(char *s, int n)
341 {
342 	for(; *s; s++){
343 		CPUT(*s);
344 		n--;
345 	}
346 	for(; n > 0; n--)
347 		CPUT(0);
348 }
349 
350 void
351 cput(long l)
352 {
353 	CPUT(l);
354 }
355 
356 void
357 wput(long l)
358 {
359 	cbp[0] = l>>8;
360 	cbp[1] = l;
361 	cbp += 2;
362 	cbc -= 2;
363 	if(cbc <= 0)
364 		cflush();
365 }
366 
367 void
368 lput(long l)
369 {
370 
371 	LPUT(l);
372 }
373 
374 void
375 cflush(void)
376 {
377 	int n;
378 
379 	n = sizeof(buf.cbuf) - cbc;
380 	if(n)
381 		write(cout, buf.cbuf, n);
382 	cbp = buf.cbuf;
383 	cbc = sizeof(buf.cbuf);
384 }
385 
386 void
387 asmsym(void)
388 {
389 	Prog *p;
390 	Auto *a;
391 	Sym *s;
392 	int h;
393 
394 	s = lookup("etext", 0);
395 	if(s->type == STEXT)
396 		putsymb(s->name, 'T', s->value, s->version);
397 
398 	for(h=0; h<NHASH; h++)
399 		for(s=hash[h]; s!=S; s=s->link)
400 			switch(s->type) {
401 			case SCONST:
402 				putsymb(s->name, 'D', s->value, s->version);
403 				continue;
404 
405 			case SDATA:
406 				putsymb(s->name, 'D', s->value+INITDAT, s->version);
407 				continue;
408 
409 			case SBSS:
410 				putsymb(s->name, 'B', s->value+INITDAT, s->version);
411 				continue;
412 
413 			case SFILE:
414 				putsymb(s->name, 'f', s->value, s->version);
415 				continue;
416 			}
417 
418 	for(p=textp; p!=P; p=p->cond) {
419 		s = p->from.sym;
420 		if(s->type != STEXT && s->type != SLEAF)
421 			continue;
422 
423 		/* filenames first */
424 		for(a=p->to.autom; a; a=a->link)
425 			if(a->type == D_FILE)
426 				putsymb(a->sym->name, 'z', a->aoffset, 0);
427 			else
428 			if(a->type == D_FILE1)
429 				putsymb(a->sym->name, 'Z', a->aoffset, 0);
430 
431 		if(s->type == STEXT)
432 			putsymb(s->name, 'T', s->value, s->version);
433 		else
434 			putsymb(s->name, 'L', s->value, s->version);
435 
436 		/* frame, auto and param after */
437 		putsymb(".frame", 'm', p->to.offset+4, 0);
438 		for(a=p->to.autom; a; a=a->link)
439 			if(a->type == D_AUTO)
440 				putsymb(a->sym->name, 'a', -a->aoffset, 0);
441 			else
442 			if(a->type == D_PARAM)
443 				putsymb(a->sym->name, 'p', a->aoffset, 0);
444 	}
445 	if(debug['v'] || debug['n'])
446 		Bprint(&bso, "symsize = %lud\n", symsize);
447 	Bflush(&bso);
448 }
449 
450 void
451 putsymb(char *s, int t, long v, int ver)
452 {
453 	int i, f;
454 
455 	if(t == 'f')
456 		s++;
457 	LPUT(v);
458 	if(ver)
459 		t += 'a' - 'A';
460 	CPUT(t+0x80);			/* 0x80 is variable length */
461 
462 	if(t == 'Z' || t == 'z') {
463 		CPUT(s[0]);
464 		for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
465 			CPUT(s[i]);
466 			CPUT(s[i+1]);
467 		}
468 		CPUT(0);
469 		CPUT(0);
470 		i++;
471 	}
472 	else {
473 		for(i=0; s[i]; i++)
474 			CPUT(s[i]);
475 		CPUT(0);
476 	}
477 	symsize += 4 + 1 + i + 1;
478 
479 	if(debug['n']) {
480 		if(t == 'z' || t == 'Z') {
481 			Bprint(&bso, "%c %.8lux ", t, v);
482 			for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
483 				f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
484 				Bprint(&bso, "/%x", f);
485 			}
486 			Bprint(&bso, "\n");
487 			return;
488 		}
489 		if(ver)
490 			Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
491 		else
492 			Bprint(&bso, "%c %.8lux %s\n", t, v, s);
493 	}
494 }
495 
496 #define	MINLC	4
497 void
498 asmlc(void)
499 {
500 	long oldpc, oldlc;
501 	Prog *p;
502 	long v, s;
503 
504 	oldpc = INITTEXT;
505 	oldlc = 0;
506 	for(p = firstp; p != P; p = p->link) {
507 		if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
508 			if(p->as == ATEXT)
509 				curtext = p;
510 			if(debug['L'])
511 				Bprint(&bso, "%6lux %P\n",
512 					p->pc, p);
513 			continue;
514 		}
515 		if(debug['L'])
516 			Bprint(&bso, "\t\t%6ld", lcsize);
517 		v = (p->pc - oldpc) / MINLC;
518 		while(v) {
519 			s = 127;
520 			if(v < 127)
521 				s = v;
522 			CPUT(s+128);	/* 129-255 +pc */
523 			if(debug['L'])
524 				Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
525 			v -= s;
526 			lcsize++;
527 		}
528 		s = p->line - oldlc;
529 		oldlc = p->line;
530 		oldpc = p->pc + MINLC;
531 		if(s > 64 || s < -64) {
532 			CPUT(0);	/* 0 vv +lc */
533 			CPUT(s>>24);
534 			CPUT(s>>16);
535 			CPUT(s>>8);
536 			CPUT(s);
537 			if(debug['L']) {
538 				if(s > 0)
539 					Bprint(&bso, " lc+%ld(%d,%ld)\n",
540 						s, 0, s);
541 				else
542 					Bprint(&bso, " lc%ld(%d,%ld)\n",
543 						s, 0, s);
544 				Bprint(&bso, "%6lux %P\n",
545 					p->pc, p);
546 			}
547 			lcsize += 5;
548 			continue;
549 		}
550 		if(s > 0) {
551 			CPUT(0+s);	/* 1-64 +lc */
552 			if(debug['L']) {
553 				Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
554 				Bprint(&bso, "%6lux %P\n",
555 					p->pc, p);
556 			}
557 		} else {
558 			CPUT(64-s);	/* 65-128 -lc */
559 			if(debug['L']) {
560 				Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
561 				Bprint(&bso, "%6lux %P\n",
562 					p->pc, p);
563 			}
564 		}
565 		lcsize++;
566 	}
567 	while(lcsize & 1) {
568 		s = 129;
569 		CPUT(s);
570 		lcsize++;
571 	}
572 	if(debug['v'] || debug['L'])
573 		Bprint(&bso, "lcsize = %ld\n", lcsize);
574 	Bflush(&bso);
575 }
576 
577 void
578 datblk(long s, long n)
579 {
580 	Prog *p;
581 	char *cast;
582 	long l, fl, j, d;
583 	int i, c;
584 
585 	memset(buf.dbuf, 0, n+100);
586 	for(p = datap; p != P; p = p->link) {
587 		curp = p;
588 		l = p->from.sym->value + p->from.offset - s;
589 		c = p->reg;
590 		i = 0;
591 		if(l < 0) {
592 			if(l+c <= 0)
593 				continue;
594 			while(l < 0) {
595 				l++;
596 				i++;
597 			}
598 		}
599 		if(l >= n)
600 			continue;
601 		if(p->as != AINIT && p->as != ADYNT) {
602 			for(j=l+(c-i)-1; j>=l; j--)
603 				if(buf.dbuf[j]) {
604 					print("%P\n", p);
605 					diag("multiple initialization");
606 					break;
607 				}
608 		}
609 		switch(p->to.type) {
610 		default:
611 			diag("unknown mode in initialization\n%P", p);
612 			break;
613 
614 		case D_FCONST:
615 			switch(c) {
616 			default:
617 			case 4:
618 				fl = ieeedtof(&p->to.ieee);
619 				cast = (char*)&fl;
620 				for(; i<c; i++) {
621 					buf.dbuf[l] = cast[fnuxi8[i+4]];
622 					l++;
623 				}
624 				break;
625 			case 8:
626 				cast = (char*)&p->to.ieee;
627 				for(; i<c; i++) {
628 					buf.dbuf[l] = cast[fnuxi8[i]];
629 					l++;
630 				}
631 				break;
632 			}
633 			break;
634 
635 		case D_SCONST:
636 			for(; i<c; i++) {
637 				buf.dbuf[l] = p->to.sval[i];
638 				l++;
639 			}
640 			break;
641 
642 		case D_CONST:
643 			d = p->to.offset;
644 			if(p->to.sym) {
645 				if(p->to.sym->type == SUNDEF){
646 					ckoff(p->to.sym, d);
647 					d += p->to.sym->value;
648 				}
649 				if(p->to.sym->type == STEXT ||
650 				   p->to.sym->type == SLEAF)
651 					d += p->to.sym->value;
652 				if(p->to.sym->type == SDATA)
653 					d += p->to.sym->value + INITDAT;
654 				if(p->to.sym->type == SBSS)
655 					d += p->to.sym->value + INITDAT;
656 				if(dlm)
657 					dynreloc(p->to.sym, l+s+INITDAT, 1, 0, 0);
658 			}
659 			cast = (char*)&d;
660 			switch(c) {
661 			default:
662 				diag("bad nuxi %d %d\n%P", c, i, curp);
663 				break;
664 			case 1:
665 				for(; i<c; i++) {
666 					buf.dbuf[l] = cast[inuxi1[i]];
667 					l++;
668 				}
669 				break;
670 			case 2:
671 				for(; i<c; i++) {
672 					buf.dbuf[l] = cast[inuxi2[i]];
673 					l++;
674 				}
675 				break;
676 			case 4:
677 				for(; i<c; i++) {
678 					buf.dbuf[l] = cast[inuxi4[i]];
679 					l++;
680 				}
681 				break;
682 			}
683 			break;
684 		}
685 	}
686 	write(cout, buf.dbuf, n);
687 }
688