xref: /plan9/sys/src/cmd/ql/asm.c (revision 60014d6756a98ad10929607ca84a1b7488a16cfc)
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 
303 		if(debug['S']){
304 			lput(HEADR+textsize+datsize+symsize);	/* offset to first shdr */
305 			lput(0L);		/* flags = PPC */
306 			lput((52L<<16)|32L);	/* Ehdr & Phdr sizes*/
307 			lput((3L<<16)|40L);	/* # Phdrs & Shdr size */
308 			lput((3L<<16)|2L);	/* # Shdrs & shdr string size */
309 		}
310 		else{
311 			lput(0L);
312 			lput(0L);		/* flags = PPC */
313 			lput((52L<<16)|32L);	/* Ehdr & Phdr sizes*/
314 			lput((3L<<16)|0L);	/* # Phdrs & Shdr size */
315 			lput((3L<<16)|0L);	/* # Shdrs & shdr string size */
316 		}
317 
318 		lput(1L);			/* text - type = PT_LOAD */
319 		lput(HEADR);			/* file offset */
320 		lput(INITTEXT & ~KMASK);	/* vaddr */
321 		lput(INITTEXT);			/* paddr */
322 		lput(textsize);			/* file size */
323 		lput(textsize);			/* memory size */
324 		lput(0x05L);			/* protections = RX */
325 		lput(0x10000L);			/* alignment */
326 
327 		lput(1L);			/* data - type = PT_LOAD */
328 		lput(HEADR+textsize);		/* file offset */
329 		lput(INITDAT & ~KMASK);		/* vaddr */
330 		lput(INITDAT);			/* paddr */
331 		lput(datsize);			/* file size */
332 		lput(datsize);			/* memory size */
333 		lput(0x07L);			/* protections = RWX */
334 		lput(0x10000L);			/* alignment */
335 
336 		lput(0L);			/* data - type = PT_NULL */
337 		lput(HEADR+textsize+datsize);	/* file offset */
338 		lput(0L);
339 		lput(0L);
340 		lput(symsize);			/* symbol table size */
341 		lput(lcsize);			/* line number size */
342 		lput(0x04L);			/* protections = R */
343 		lput(0x04L);			/* alignment code?? */
344 		cflush();
345 
346 		if(!debug['S'])
347 			break;
348 
349 		seek(cout, HEADR+textsize+datsize+symsize, 0);
350 		lput(1);			/* Section name (string tbl index) */
351 		lput(1);			/* Section type */
352 		lput(2|4);			/* Section flags */
353 		lput(INITTEXT & ~KMASK);	/* Section virtual addr at execution */
354 		lput(HEADR);			/* Section file offset */
355 		lput(textsize);			/* Section size in bytes */
356 		lput(0);			/* Link to another section */
357 		lput(0);			/* Additional section information */
358 		lput(0x10000L);			/* Section alignment */
359 		lput(0);			/* Entry size if section holds table */
360 
361 		lput(7);			/* Section name (string tbl index) */
362 		lput(1);			/* Section type */
363 		lput(2|1);			/* Section flags */
364 		lput(INITDAT & ~KMASK);		/* Section virtual addr at execution */
365 		lput(HEADR+textsize);		/* Section file offset */
366 		lput(datsize);			/* Section size in bytes */
367 		lput(0);			/* Link to another section */
368 		lput(0);			/* Additional section information */
369 		lput(0x10000L);			/* Section alignment */
370 		lput(0);			/* Entry size if section holds table */
371 
372 		/* string section header */
373 		lput(12);			/* Section name (string tbl index) */
374 		lput(3);			/* Section type */
375 		lput(1 << 5);			/* Section flags */
376 		lput(0);			/* Section virtual addr at execution */
377 		lput(HEADR+textsize+datsize+symsize+3*40);	/* Section file offset */
378 		lput(14);			/* Section size in bytes */
379 		lput(0);			/* Link to another section */
380 		lput(0);			/* Additional section information */
381 		lput(1);			/* Section alignment */
382 		lput(0);			/* Entry size if section holds table */
383 
384 		/* string table */
385 		cput(0);
386 		strnput(".text", 5);
387 		cput(0);
388 		strnput(".data", 5);
389 		cput(0);
390 		strnput(".strtab", 7);
391 		cput(0);
392 		cput(0);
393 
394 		break;
395 	}
396 	cflush();
397 }
398 
399 void
400 strnput(char *s, int n)
401 {
402 	for(; *s; s++){
403 		CPUT(*s);
404 		n--;
405 	}
406 	for(; n > 0; n--)
407 		CPUT(0);
408 }
409 
410 void
411 cput(long l)
412 {
413 	CPUT(l);
414 }
415 
416 void
417 wput(long l)
418 {
419 	cbp[0] = l>>8;
420 	cbp[1] = l;
421 	cbp += 2;
422 	cbc -= 2;
423 	if(cbc <= 0)
424 		cflush();
425 }
426 
427 void
428 lput(long l)
429 {
430 
431 	LPUT(l);
432 }
433 
434 void
435 cflush(void)
436 {
437 	int n;
438 
439 	n = sizeof(buf.cbuf) - cbc;
440 	if(n)
441 		write(cout, buf.cbuf, n);
442 	cbp = buf.cbuf;
443 	cbc = sizeof(buf.cbuf);
444 }
445 
446 void
447 asmsym(void)
448 {
449 	Prog *p;
450 	Auto *a;
451 	Sym *s;
452 	int h;
453 
454 	s = lookup("etext", 0);
455 	if(s->type == STEXT)
456 		putsymb(s->name, 'T', s->value, s->version);
457 
458 	for(h=0; h<NHASH; h++)
459 		for(s=hash[h]; s!=S; s=s->link)
460 			switch(s->type) {
461 			case SCONST:
462 				putsymb(s->name, 'D', s->value, s->version);
463 				continue;
464 
465 			case SDATA:
466 				putsymb(s->name, 'D', s->value+INITDAT, s->version);
467 				continue;
468 
469 			case SBSS:
470 				putsymb(s->name, 'B', s->value+INITDAT, s->version);
471 				continue;
472 
473 			case SFILE:
474 				putsymb(s->name, 'f', s->value, s->version);
475 				continue;
476 			}
477 
478 	for(p=textp; p!=P; p=p->cond) {
479 		s = p->from.sym;
480 		if(s->type != STEXT && s->type != SLEAF)
481 			continue;
482 
483 		/* filenames first */
484 		for(a=p->to.autom; a; a=a->link)
485 			if(a->type == D_FILE)
486 				putsymb(a->sym->name, 'z', a->aoffset, 0);
487 			else
488 			if(a->type == D_FILE1)
489 				putsymb(a->sym->name, 'Z', a->aoffset, 0);
490 
491 		if(s->type == STEXT)
492 			putsymb(s->name, 'T', s->value, s->version);
493 		else
494 			putsymb(s->name, 'L', s->value, s->version);
495 
496 		/* frame, auto and param after */
497 		putsymb(".frame", 'm', p->to.offset+4, 0);
498 		for(a=p->to.autom; a; a=a->link)
499 			if(a->type == D_AUTO)
500 				putsymb(a->sym->name, 'a', -a->aoffset, 0);
501 			else
502 			if(a->type == D_PARAM)
503 				putsymb(a->sym->name, 'p', a->aoffset, 0);
504 	}
505 	if(debug['v'] || debug['n'])
506 		Bprint(&bso, "symsize = %lud\n", symsize);
507 	Bflush(&bso);
508 }
509 
510 void
511 putsymb(char *s, int t, long v, int ver)
512 {
513 	int i, f;
514 
515 	if(t == 'f')
516 		s++;
517 	LPUT(v);
518 	if(ver)
519 		t += 'a' - 'A';
520 	CPUT(t+0x80);			/* 0x80 is variable length */
521 
522 	if(t == 'Z' || t == 'z') {
523 		CPUT(s[0]);
524 		for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
525 			CPUT(s[i]);
526 			CPUT(s[i+1]);
527 		}
528 		CPUT(0);
529 		CPUT(0);
530 		i++;
531 	}
532 	else {
533 		for(i=0; s[i]; i++)
534 			CPUT(s[i]);
535 		CPUT(0);
536 	}
537 	symsize += 4 + 1 + i + 1;
538 
539 	if(debug['n']) {
540 		if(t == 'z' || t == 'Z') {
541 			Bprint(&bso, "%c %.8lux ", t, v);
542 			for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
543 				f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
544 				Bprint(&bso, "/%x", f);
545 			}
546 			Bprint(&bso, "\n");
547 			return;
548 		}
549 		if(ver)
550 			Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
551 		else
552 			Bprint(&bso, "%c %.8lux %s\n", t, v, s);
553 	}
554 }
555 
556 #define	MINLC	4
557 void
558 asmlc(void)
559 {
560 	long oldpc, oldlc;
561 	Prog *p;
562 	long v, s;
563 
564 	oldpc = INITTEXT;
565 	oldlc = 0;
566 	for(p = firstp; p != P; p = p->link) {
567 		if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
568 			if(p->as == ATEXT)
569 				curtext = p;
570 			if(debug['L'])
571 				Bprint(&bso, "%6lux %P\n",
572 					p->pc, p);
573 			continue;
574 		}
575 		if(debug['L'])
576 			Bprint(&bso, "\t\t%6ld", lcsize);
577 		v = (p->pc - oldpc) / MINLC;
578 		while(v) {
579 			s = 127;
580 			if(v < 127)
581 				s = v;
582 			CPUT(s+128);	/* 129-255 +pc */
583 			if(debug['L'])
584 				Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
585 			v -= s;
586 			lcsize++;
587 		}
588 		s = p->line - oldlc;
589 		oldlc = p->line;
590 		oldpc = p->pc + MINLC;
591 		if(s > 64 || s < -64) {
592 			CPUT(0);	/* 0 vv +lc */
593 			CPUT(s>>24);
594 			CPUT(s>>16);
595 			CPUT(s>>8);
596 			CPUT(s);
597 			if(debug['L']) {
598 				if(s > 0)
599 					Bprint(&bso, " lc+%ld(%d,%ld)\n",
600 						s, 0, s);
601 				else
602 					Bprint(&bso, " lc%ld(%d,%ld)\n",
603 						s, 0, s);
604 				Bprint(&bso, "%6lux %P\n",
605 					p->pc, p);
606 			}
607 			lcsize += 5;
608 			continue;
609 		}
610 		if(s > 0) {
611 			CPUT(0+s);	/* 1-64 +lc */
612 			if(debug['L']) {
613 				Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
614 				Bprint(&bso, "%6lux %P\n",
615 					p->pc, p);
616 			}
617 		} else {
618 			CPUT(64-s);	/* 65-128 -lc */
619 			if(debug['L']) {
620 				Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
621 				Bprint(&bso, "%6lux %P\n",
622 					p->pc, p);
623 			}
624 		}
625 		lcsize++;
626 	}
627 	while(lcsize & 1) {
628 		s = 129;
629 		CPUT(s);
630 		lcsize++;
631 	}
632 	if(debug['v'] || debug['L'])
633 		Bprint(&bso, "lcsize = %ld\n", lcsize);
634 	Bflush(&bso);
635 }
636 
637 void
638 datblk(long s, long n)
639 {
640 	Prog *p;
641 	char *cast;
642 	long l, fl, j, d;
643 	int i, c;
644 
645 	memset(buf.dbuf, 0, n+100);
646 	for(p = datap; p != P; p = p->link) {
647 		curp = p;
648 		l = p->from.sym->value + p->from.offset - s;
649 		c = p->reg;
650 		i = 0;
651 		if(l < 0) {
652 			if(l+c <= 0)
653 				continue;
654 			while(l < 0) {
655 				l++;
656 				i++;
657 			}
658 		}
659 		if(l >= n)
660 			continue;
661 		if(p->as != AINIT && p->as != ADYNT) {
662 			for(j=l+(c-i)-1; j>=l; j--)
663 				if(buf.dbuf[j]) {
664 					print("%P\n", p);
665 					diag("multiple initialization");
666 					break;
667 				}
668 		}
669 		switch(p->to.type) {
670 		default:
671 			diag("unknown mode in initialization\n%P", p);
672 			break;
673 
674 		case D_FCONST:
675 			switch(c) {
676 			default:
677 			case 4:
678 				fl = ieeedtof(&p->to.ieee);
679 				cast = (char*)&fl;
680 				for(; i<c; i++) {
681 					buf.dbuf[l] = cast[fnuxi8[i+4]];
682 					l++;
683 				}
684 				break;
685 			case 8:
686 				cast = (char*)&p->to.ieee;
687 				for(; i<c; i++) {
688 					buf.dbuf[l] = cast[fnuxi8[i]];
689 					l++;
690 				}
691 				break;
692 			}
693 			break;
694 
695 		case D_SCONST:
696 			for(; i<c; i++) {
697 				buf.dbuf[l] = p->to.sval[i];
698 				l++;
699 			}
700 			break;
701 
702 		case D_CONST:
703 			d = p->to.offset;
704 			if(p->to.sym) {
705 				if(p->to.sym->type == SUNDEF){
706 					ckoff(p->to.sym, d);
707 					d += p->to.sym->value;
708 				}
709 				if(p->to.sym->type == STEXT ||
710 				   p->to.sym->type == SLEAF)
711 					d += p->to.sym->value;
712 				if(p->to.sym->type == SDATA)
713 					d += p->to.sym->value + INITDAT;
714 				if(p->to.sym->type == SBSS)
715 					d += p->to.sym->value + INITDAT;
716 				if(dlm)
717 					dynreloc(p->to.sym, l+s+INITDAT, 1, 0, 0);
718 			}
719 			cast = (char*)&d;
720 			switch(c) {
721 			default:
722 				diag("bad nuxi %d %d\n%P", c, i, curp);
723 				break;
724 			case 1:
725 				for(; i<c; i++) {
726 					buf.dbuf[l] = cast[inuxi1[i]];
727 					l++;
728 				}
729 				break;
730 			case 2:
731 				for(; i<c; i++) {
732 					buf.dbuf[l] = cast[inuxi2[i]];
733 					l++;
734 				}
735 				break;
736 			case 4:
737 				for(; i<c; i++) {
738 					buf.dbuf[l] = cast[inuxi4[i]];
739 					l++;
740 				}
741 				break;
742 			}
743 			break;
744 		}
745 	}
746 	write(cout, buf.dbuf, n);
747 }
748