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