xref: /inferno-os/utils/8l/asm.c (revision d90014f6464dd122afdd1a8cd81933e72c72619a)
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