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