xref: /inferno-os/utils/8l/asm.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include	"l.h"
2 
3 #define	Dbufslop	100
4 
5 long
6 entryvalue(void)
7 {
8 	char *a;
9 	Sym *s;
10 
11 	a = INITENTRY;
12 	if(*a >= '0' && *a <= '9')
13 		return atolwhex(a);
14 	s = lookup(a, 0);
15 	if(s->type == 0)
16 		return INITTEXT;
17 	switch(s->type) {
18 	case STEXT:
19 		break;
20 	case SDATA:
21 		if(dlm)
22 			return s->value+INITDAT;
23 	default:
24 		diag("entry not text: %s", s->name);
25 	}
26 	return s->value;
27 }
28 
29 /* these need to take long arguments to be compatible with elf.c */
30 void
31 wputl(long w)
32 {
33 	cput(w);
34 	cput(w>>8);
35 }
36 
37 void
38 wput(long w)
39 {
40 	cput(w>>8);
41 	cput(w);
42 }
43 
44 void
45 lput(long l)
46 {
47 	cput(l>>24);
48 	cput(l>>16);
49 	cput(l>>8);
50 	cput(l);
51 }
52 
53 void
54 lputl(long l)
55 {
56 	cput(l);
57 	cput(l>>8);
58 	cput(l>>16);
59 	cput(l>>24);
60 }
61 
62 void
63 llput(vlong v)
64 {
65 	lput(v>>32);
66 	lput(v);
67 }
68 
69 void
70 llputl(vlong v)
71 {
72 	lputl(v);
73 	lputl(v>>32);
74 }
75 
76 void
77 strnput(char *s, int n)
78 {
79 	for(; *s && n > 0; s++){
80 		cput(*s);
81 		n--;
82 	}
83 	while(n > 0){
84 		cput(0);
85 		n--;
86 	}
87 }
88 
89 void
90 asmb(void)
91 {
92 	Prog *p;
93 	long v, magic;
94 	int a;
95 	uchar *op1;
96 
97 	if(debug['v'])
98 		Bprint(&bso, "%5.2f asmb\n", cputime());
99 	Bflush(&bso);
100 
101 	seek(cout, HEADR, 0);
102 	pc = INITTEXT;
103 	curp = firstp;
104 	for(p = firstp; p != P; p = p->link) {
105 		if(p->as == ATEXT)
106 			curtext = p;
107 		if(p->pc != pc) {
108 			if(!debug['a'])
109 				print("%P\n", curp);
110 			diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME);
111 			pc = p->pc;
112 		}
113 		curp = p;
114 		asmins(p);
115 		if(cbc < sizeof(and))
116 			cflush();
117 		a = (andptr - and);
118 		if(debug['a']) {
119 			Bprint(&bso, pcstr, pc);
120 			for(op1 = and; op1 < andptr; op1++)
121 				Bprint(&bso, "%.2ux", *op1 & 0xff);
122 			Bprint(&bso, "\t%P\n", curp);
123 		}
124 		if(dlm) {
125 			if(p->as == ATEXT)
126 				reloca = nil;
127 			else if(reloca != nil)
128 				diag("reloc failure: %P", curp);
129 		}
130 		memmove(cbp, and, a);
131 		cbp += a;
132 		pc += a;
133 		cbc -= a;
134 	}
135 	cflush();
136 	switch(HEADTYPE) {
137 	default:
138 		diag("unknown header type %ld", HEADTYPE);
139 	case 0:
140 		seek(cout, rnd(HEADR+textsize, 8192), 0);
141 		break;
142 	case 1:
143 		textsize = rnd(HEADR+textsize, 4096)-HEADR;
144 		seek(cout, textsize+HEADR, 0);
145 		break;
146 	case 2:
147 	case 5:
148 		seek(cout, HEADR+textsize, 0);
149 		break;
150 	case 3:
151 	case 4:
152 		seek(cout, HEADR+rnd(textsize, INITRND), 0);
153 		break;
154 	}
155 
156 	if(debug['v'])
157 		Bprint(&bso, "%5.2f datblk\n", cputime());
158 	Bflush(&bso);
159 
160 	if(dlm){
161 		char buf[8];
162 
163 		write(cout, buf, INITDAT-textsize);
164 		textsize = INITDAT;
165 	}
166 
167 	for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
168 		if(datsize-v > sizeof(buf)-Dbufslop)
169 			datblk(v, sizeof(buf)-Dbufslop);
170 		else
171 			datblk(v, datsize-v);
172 	}
173 
174 	symsize = 0;
175 	spsize = 0;
176 	lcsize = 0;
177 	if(!debug['s']) {
178 		if(debug['v'])
179 			Bprint(&bso, "%5.2f sym\n", cputime());
180 		Bflush(&bso);
181 		switch(HEADTYPE) {
182 		default:
183 		case 0:
184 			seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
185 			break;
186 		case 1:
187 			seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
188 			break;
189 		case 2:
190 		case 5:
191 			seek(cout, HEADR+textsize+datsize, 0);
192 			break;
193 		case 3:
194 		case 4:
195 			debug['s'] = 1;
196 			break;
197 		}
198 		if(!debug['s'])
199 			asmsym();
200 		if(debug['v'])
201 			Bprint(&bso, "%5.2f sp\n", cputime());
202 		Bflush(&bso);
203 		if(debug['v'])
204 			Bprint(&bso, "%5.2f pc\n", cputime());
205 		Bflush(&bso);
206 		if(!debug['s'])
207 			asmlc();
208 		if(dlm)
209 			asmdyn();
210 		cflush();
211 	}
212 	else if(dlm){
213 		seek(cout, HEADR+textsize+datsize, 0);
214 		asmdyn();
215 		cflush();
216 	}
217 	if(debug['v'])
218 		Bprint(&bso, "%5.2f headr\n", cputime());
219 	Bflush(&bso);
220 	seek(cout, 0L, 0);
221 	switch(HEADTYPE) {
222 	default:
223 	case 0:	/* garbage */
224 		lput(0x160L<<16);		/* magic and sections */
225 		lput(0L);			/* time and date */
226 		lput(rnd(HEADR+textsize, 4096)+datsize);
227 		lput(symsize);			/* nsyms */
228 		lput((0x38L<<16)|7L);		/* size of optional hdr and flags */
229 		lput((0413<<16)|0437L);		/* magic and version */
230 		lput(rnd(HEADR+textsize, 4096));/* sizes */
231 		lput(datsize);
232 		lput(bsssize);
233 		lput(entryvalue());		/* va of entry */
234 		lput(INITTEXT-HEADR);		/* va of base of text */
235 		lput(INITDAT);			/* va of base of data */
236 		lput(INITDAT+datsize);		/* va of base of bss */
237 		lput(~0L);			/* gp reg mask */
238 		lput(0L);
239 		lput(0L);
240 		lput(0L);
241 		lput(0L);
242 		lput(~0L);			/* gp value ?? */
243 		break;
244 	case 1:	/* unix coff */
245 		/*
246 		 * file header
247 		 */
248 		lputl(0x0004014c);		/* 4 sections, magic */
249 		lputl(0);			/* unix time stamp */
250 		lputl(0);			/* symbol table */
251 		lputl(0);			/* nsyms */
252 		lputl(0x0003001c);		/* flags, sizeof a.out header */
253 		/*
254 		 * a.out header
255 		 */
256 		lputl(0x10b);			/* magic, version stamp */
257 		lputl(rnd(textsize, INITRND));	/* text sizes */
258 		lputl(datsize);			/* data sizes */
259 		lputl(bsssize);			/* bss sizes */
260 		lput(entryvalue());		/* va of entry */
261 		lputl(INITTEXT);		/* text start */
262 		lputl(INITDAT);			/* data start */
263 		/*
264 		 * text section header
265 		 */
266 		strnput(".text", 8);
267 		lputl(HEADR);			/* pa */
268 		lputl(HEADR);			/* va */
269 		lputl(textsize);		/* text size */
270 		lputl(HEADR);			/* file offset */
271 		lputl(0);			/* relocation */
272 		lputl(0);			/* line numbers */
273 		lputl(0);			/* relocation, line numbers */
274 		lputl(0x20);			/* flags text only */
275 		/*
276 		 * data section header
277 		 */
278 		strnput(".data", 8);
279 		lputl(INITDAT);			/* pa */
280 		lputl(INITDAT);			/* va */
281 		lputl(datsize);			/* data size */
282 		lputl(HEADR+textsize);		/* file offset */
283 		lputl(0);			/* relocation */
284 		lputl(0);			/* line numbers */
285 		lputl(0);			/* relocation, line numbers */
286 		lputl(0x40);			/* flags data only */
287 		/*
288 		 * bss section header
289 		 */
290 		strnput(".bss", 8);
291 		lputl(INITDAT+datsize);		/* pa */
292 		lputl(INITDAT+datsize);		/* va */
293 		lputl(bsssize);			/* bss size */
294 		lputl(0);			/* file offset */
295 		lputl(0);			/* relocation */
296 		lputl(0);			/* line numbers */
297 		lputl(0);			/* relocation, line numbers */
298 		lputl(0x80);			/* flags bss only */
299 		/*
300 		 * comment section header
301 		 */
302 		strnput(".comment", 8);
303 		lputl(0);			/* pa */
304 		lputl(0);			/* va */
305 		lputl(symsize+lcsize);		/* comment size */
306 		lputl(HEADR+textsize+datsize);	/* file offset */
307 		lputl(HEADR+textsize+datsize);	/* offset of syms */
308 		lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */
309 		lputl(0);			/* relocation, line numbers */
310 		lputl(0x200);			/* flags comment only */
311 		break;
312 	case 2:	/* plan9 */
313 		magic = 4*11*11+7;
314 		if(dlm)
315 			magic |= 0x80000000;
316 		lput(magic);			/* magic */
317 		lput(textsize);			/* sizes */
318 		lput(datsize);
319 		lput(bsssize);
320 		lput(symsize);			/* nsyms */
321 		lput(entryvalue());		/* va of entry */
322 		lput(spsize);			/* sp offsets */
323 		lput(lcsize);			/* line offsets */
324 		break;
325 	case 3:
326 		/* MS-DOS .COM */
327 		break;
328 	case 4:
329 		/* fake MS-DOS .EXE */
330 		v = rnd(HEADR+textsize, INITRND)+datsize;
331 		wputl(0x5A4D);			/* 'MZ' */
332 		wputl(v % 512);			/* bytes in last page */
333 		wputl(rnd(v, 512)/512);		/* total number of pages */
334 		wputl(0x0000);			/* number of reloc items */
335 		v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
336 		wputl(v/16);			/* size of header */
337 		wputl(0x0000);			/* minimum allocation */
338 		wputl(0xFFFF);			/* maximum allocation */
339 		wputl(0x0000);			/* initial ss value */
340 		wputl(0x0100);			/* initial sp value */
341 		wputl(0x0000);			/* complemented checksum */
342 		v = entryvalue();
343 		wputl(v);			/* initial ip value (!) */
344 		wputl(0x0000);			/* initial cs value */
345 		wputl(0x0000);
346 		wputl(0x0000);
347 		wputl(0x003E);			/* reloc table offset */
348 		wputl(0x0000);			/* overlay number */
349 		break;
350 	case 5:
351 		elf32(I386, ELFDATA2LSB, 0, nil);
352 		break;
353 	}
354 	cflush();
355 }
356 
357 void
358 cflush(void)
359 {
360 	int n;
361 
362 	n = sizeof(buf.cbuf) - cbc;
363 	if(n)
364 		write(cout, buf.cbuf, n);
365 	cbp = buf.cbuf;
366 	cbc = sizeof(buf.cbuf);
367 }
368 
369 void
370 datblk(long s, long n)
371 {
372 	Prog *p;
373 	char *cast;
374 	long l, fl, j;
375 	int i, c;
376 
377 	memset(buf.dbuf, 0, n+Dbufslop);
378 	for(p = datap; p != P; p = p->link) {
379 		curp = p;
380 		l = p->from.sym->value + p->from.offset - s;
381 		c = p->from.scale;
382 		i = 0;
383 		if(l < 0) {
384 			if(l+c <= 0)
385 				continue;
386 			while(l < 0) {
387 				l++;
388 				i++;
389 			}
390 		}
391 		if(l >= n)
392 			continue;
393 		if(p->as != AINIT && p->as != ADYNT) {
394 			for(j=l+(c-i)-1; j>=l; j--)
395 				if(buf.dbuf[j]) {
396 					print("%P\n", p);
397 					diag("multiple initialization");
398 					break;
399 				}
400 		}
401 		switch(p->to.type) {
402 		case D_FCONST:
403 			switch(c) {
404 			default:
405 			case 4:
406 				fl = ieeedtof(&p->to.ieee);
407 				cast = (char*)&fl;
408 				if(debug['a'] && i == 0) {
409 					Bprint(&bso, pcstr, l+s+INITDAT);
410 					for(j=0; j<c; j++)
411 						Bprint(&bso, "%.2ux", cast[fnuxi4[j]] & 0xff);
412 					Bprint(&bso, "\t%P\n", curp);
413 				}
414 				for(; i<c; i++) {
415 					buf.dbuf[l] = cast[fnuxi4[i]];
416 					l++;
417 				}
418 				break;
419 			case 8:
420 				cast = (char*)&p->to.ieee;
421 				if(debug['a'] && i == 0) {
422 					Bprint(&bso, pcstr, l+s+INITDAT);
423 					for(j=0; j<c; j++)
424 						Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
425 					Bprint(&bso, "\t%P\n", curp);
426 				}
427 				for(; i<c; i++) {
428 					buf.dbuf[l] = cast[fnuxi8[i]];
429 					l++;
430 				}
431 				break;
432 			}
433 			break;
434 
435 		case D_SCONST:
436 			if(debug['a'] && i == 0) {
437 				Bprint(&bso, pcstr, l+s+INITDAT);
438 				for(j=0; j<c; j++)
439 					Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
440 				Bprint(&bso, "\t%P\n", curp);
441 			}
442 			for(; i<c; i++) {
443 				buf.dbuf[l] = p->to.scon[i];
444 				l++;
445 			}
446 			break;
447 		default:
448 			fl = p->to.offset;
449 			if(p->to.type == D_ADDR) {
450 				if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
451 					diag("DADDR type%P", p);
452 				if(p->to.sym) {
453 					if(p->to.sym->type == SUNDEF)
454 						ckoff(p->to.sym, fl);
455 					fl += p->to.sym->value;
456 					if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
457 						fl += INITDAT;
458 					if(dlm)
459 						dynreloc(p->to.sym, l+s+INITDAT, 1);
460 				}
461 			}
462 			cast = (char*)&fl;
463 			switch(c) {
464 			default:
465 				diag("bad nuxi %d %d\n%P", c, i, curp);
466 				break;
467 			case 1:
468 				if(debug['a'] && i == 0) {
469 					Bprint(&bso, pcstr, l+s+INITDAT);
470 					for(j=0; j<c; j++)
471 						Bprint(&bso, "%.2ux", cast[inuxi1[j]] & 0xff);
472 					Bprint(&bso, "\t%P\n", curp);
473 				}
474 				for(; i<c; i++) {
475 					buf.dbuf[l] = cast[inuxi1[i]];
476 					l++;
477 				}
478 				break;
479 			case 2:
480 				if(debug['a'] && i == 0) {
481 					Bprint(&bso, pcstr, l+s+INITDAT);
482 					for(j=0; j<c; j++)
483 						Bprint(&bso, "%.2ux", cast[inuxi2[j]] & 0xff);
484 					Bprint(&bso, "\t%P\n", curp);
485 				}
486 				for(; i<c; i++) {
487 					buf.dbuf[l] = cast[inuxi2[i]];
488 					l++;
489 				}
490 				break;
491 			case 4:
492 				if(debug['a'] && i == 0) {
493 					Bprint(&bso, pcstr, l+s+INITDAT);
494 					for(j=0; j<c; j++)
495 						Bprint(&bso, "%.2ux", cast[inuxi4[j]] & 0xff);
496 					Bprint(&bso, "\t%P\n", curp);
497 				}
498 				for(; i<c; i++) {
499 					buf.dbuf[l] = cast[inuxi4[i]];
500 					l++;
501 				}
502 				break;
503 			}
504 			break;
505 		}
506 	}
507 	write(cout, buf.dbuf, n);
508 }
509 
510 long
511 rnd(long v, long r)
512 {
513 	long c;
514 
515 	if(r <= 0)
516 		return v;
517 	v += r - 1;
518 	c = v % r;
519 	if(c < 0)
520 		c += r;
521 	v -= c;
522 	return v;
523 }
524