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