1 // Derived from Inferno utils/8c/swt.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.c
3 //
4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6 // Portions Copyright © 1997-1999 Vita Nuova Limited
7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8 // Portions Copyright © 2004,2006 Bruce Ellis
9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11 // Portions Copyright © 2009 The Go Authors. All rights reserved.
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a copy
14 // of this software and associated documentation files (the "Software"), to deal
15 // in the Software without restriction, including without limitation the rights
16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 // copies of the Software, and to permit persons to whom the Software is
18 // furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included in
21 // all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 // THE SOFTWARE.
30
31 #include "gg.h"
32
33 void
34 zname(Biobuf *b, Sym *s, int t)
35 {
36 Bputc(b, ANAME); /* as */
37 Bputc(b, ANAME>>8); /* as */
38 Bputc(b, t); /* type */
39 Bputc(b, s->sym); /* sym */
40
41 Bputname(b, s);
42 }
43
44 void
45 zfile(Biobuf *b, char *p, int n)
46 {
47 Bputc(b, ANAME);
48 Bputc(b, ANAME>>8);
49 Bputc(b, D_FILE);
50 Bputc(b, 1);
51 Bputc(b, '<');
52 Bwrite(b, p, n);
53 Bputc(b, 0);
54 }
55
56 void
57 zhist(Biobuf *b, int line, vlong offset)
58 {
59 Addr a;
60
61 Bputc(b, AHISTORY);
62 Bputc(b, AHISTORY>>8);
63 Bputc(b, line);
64 Bputc(b, line>>8);
65 Bputc(b, line>>16);
66 Bputc(b, line>>24);
67 zaddr(b, &zprog.from, 0, 0);
68 a = zprog.to;
69 if(offset != 0) {
70 a.offset = offset;
71 a.type = D_CONST;
72 }
73 zaddr(b, &a, 0, 0);
74 }
75
76 void
77 zaddr(Biobuf *b, Addr *a, int s, int gotype)
78 {
79 int32 l;
80 uint64 e;
81 int i, t;
82 char *n;
83
84 t = 0;
85 if(a->index != D_NONE || a->scale != 0)
86 t |= T_INDEX;
87 if(s != 0)
88 t |= T_SYM;
89 if(gotype != 0)
90 t |= T_GOTYPE;
91
92 switch(a->type) {
93
94 case D_BRANCH:
95 if(a->branch == nil)
96 fatal("unpatched branch");
97 a->offset = a->branch->loc;
98
99 default:
100 t |= T_TYPE;
101
102 case D_NONE:
103 if(a->offset != 0)
104 t |= T_OFFSET;
105 if(a->offset2 != 0)
106 t |= T_OFFSET2;
107 break;
108 case D_FCONST:
109 t |= T_FCONST;
110 break;
111 case D_SCONST:
112 t |= T_SCONST;
113 break;
114 }
115 Bputc(b, t);
116
117 if(t & T_INDEX) { /* implies index, scale */
118 Bputc(b, a->index);
119 Bputc(b, a->scale);
120 }
121 if(t & T_OFFSET) { /* implies offset */
122 l = a->offset;
123 Bputc(b, l);
124 Bputc(b, l>>8);
125 Bputc(b, l>>16);
126 Bputc(b, l>>24);
127 }
128 if(t & T_OFFSET2) { /* implies offset */
129 l = a->offset2;
130 Bputc(b, l);
131 Bputc(b, l>>8);
132 Bputc(b, l>>16);
133 Bputc(b, l>>24);
134 }
135 if(t & T_SYM) /* implies sym */
136 Bputc(b, s);
137 if(t & T_FCONST) {
138 ieeedtod(&e, a->dval);
139 l = e;
140 Bputc(b, l);
141 Bputc(b, l>>8);
142 Bputc(b, l>>16);
143 Bputc(b, l>>24);
144 l = e >> 32;
145 Bputc(b, l);
146 Bputc(b, l>>8);
147 Bputc(b, l>>16);
148 Bputc(b, l>>24);
149 return;
150 }
151 if(t & T_SCONST) {
152 n = a->sval;
153 for(i=0; i<NSNAME; i++) {
154 Bputc(b, *n);
155 n++;
156 }
157 return;
158 }
159 if(t & T_TYPE)
160 Bputc(b, a->type);
161 if(t & T_GOTYPE)
162 Bputc(b, gotype);
163 }
164
165 static struct {
166 struct { Sym *sym; short type; } h[NSYM];
167 int sym;
168 } z;
169
170 static void
171 zsymreset(void)
172 {
173 for(z.sym=0; z.sym<NSYM; z.sym++) {
174 z.h[z.sym].sym = S;
175 z.h[z.sym].type = 0;
176 }
177 z.sym = 1;
178 }
179
180 static int
181 zsym(Sym *s, int t, int *new)
182 {
183 int i;
184
185 *new = 0;
186 if(s == S)
187 return 0;
188
189 i = s->sym;
190 if(i < 0 || i >= NSYM)
191 i = 0;
192 if(z.h[i].type == t && z.h[i].sym == s)
193 return i;
194 i = z.sym;
195 s->sym = i;
196 zname(bout, s, t);
197 z.h[i].sym = s;
198 z.h[i].type = t;
199 if(++z.sym >= NSYM)
200 z.sym = 1;
201 *new = 1;
202 return i;
203 }
204
205 static int
206 zsymaddr(Addr *a, int *new)
207 {
208 int t;
209
210 t = a->type;
211 if(t == D_ADDR)
212 t = a->index;
213 return zsym(a->sym, t, new);
214 }
215
216 void
217 dumpfuncs(void)
218 {
219 Plist *pl;
220 int sf, st, gf, gt, new;
221 Sym *s;
222 Prog *p;
223
224 zsymreset();
225
226 // fix up pc
227 pcloc = 0;
228 for(pl=plist; pl!=nil; pl=pl->link) {
229 if(isblank(pl->name))
230 continue;
231 for(p=pl->firstpc; p!=P; p=p->link) {
232 p->loc = pcloc;
233 if(p->as != ADATA && p->as != AGLOBL)
234 pcloc++;
235 }
236 }
237
238 // put out functions
239 for(pl=plist; pl!=nil; pl=pl->link) {
240 if(isblank(pl->name))
241 continue;
242
243 if(debug['S']) {
244 s = S;
245 if(pl->name != N)
246 s = pl->name->sym;
247 print("\n--- prog list \"%S\" ---\n", s);
248 for(p=pl->firstpc; p!=P; p=p->link)
249 print("%P\n", p);
250 }
251
252 for(p=pl->firstpc; p!=P; p=p->link) {
253 for(;;) {
254 sf = zsymaddr(&p->from, &new);
255 gf = zsym(p->from.gotype, D_EXTERN, &new);
256 if(new && sf == gf)
257 continue;
258 st = zsymaddr(&p->to, &new);
259 if(new && (st == sf || st == gf))
260 continue;
261 gt = zsym(p->to.gotype, D_EXTERN, &new);
262 if(new && (gt == sf || gt == gf || gt == st))
263 continue;
264 break;
265 }
266
267 Bputc(bout, p->as);
268 Bputc(bout, p->as>>8);
269 Bputc(bout, p->lineno);
270 Bputc(bout, p->lineno>>8);
271 Bputc(bout, p->lineno>>16);
272 Bputc(bout, p->lineno>>24);
273 zaddr(bout, &p->from, sf, gf);
274 zaddr(bout, &p->to, st, gt);
275 }
276 }
277 }
278
279 /* deferred DATA output */
280 static Prog *strdat;
281 static Prog *estrdat;
282 static int gflag;
283 static Prog *savepc;
284
285 void
286 data(void)
287 {
288 gflag = debug['g'];
289 debug['g'] = 0;
290
291 if(estrdat == nil) {
292 strdat = mal(sizeof(*pc));
293 clearp(strdat);
294 estrdat = strdat;
295 }
296 if(savepc)
297 fatal("data phase error");
298 savepc = pc;
299 pc = estrdat;
300 }
301
302 void
303 text(void)
304 {
305 if(!savepc)
306 fatal("text phase error");
307 debug['g'] = gflag;
308 estrdat = pc;
309 pc = savepc;
310 savepc = nil;
311 }
312
313 void
314 dumpdata(void)
315 {
316 Prog *p;
317
318 if(estrdat == nil)
319 return;
320 *pc = *strdat;
321 if(gflag)
322 for(p=pc; p!=estrdat; p=p->link)
323 print("%P\n", p);
324 pc = estrdat;
325 }
326
327 int
328 dsname(Sym *s, int off, char *t, int n)
329 {
330 Prog *p;
331
332 p = gins(ADATA, N, N);
333 p->from.type = D_EXTERN;
334 p->from.index = D_NONE;
335 p->from.offset = off;
336 p->from.scale = n;
337 p->from.sym = s;
338
339 p->to.type = D_SCONST;
340 p->to.index = D_NONE;
341 memmove(p->to.sval, t, n);
342 return off + n;
343 }
344
345 /*
346 * make a refer to the data s, s+len
347 * emitting DATA if needed.
348 */
349 void
350 datastring(char *s, int len, Addr *a)
351 {
352 Sym *sym;
353
354 sym = stringsym(s, len);
355 a->type = D_EXTERN;
356 a->sym = sym;
357 a->offset = widthptr+4; // skip header
358 a->etype = TINT32;
359 }
360
361 /*
362 * make a refer to the string sval,
363 * emitting DATA if needed.
364 */
365 void
366 datagostring(Strlit *sval, Addr *a)
367 {
368 Sym *sym;
369
370 sym = stringsym(sval->s, sval->len);
371 a->type = D_EXTERN;
372 a->sym = sym;
373 a->offset = 0; // header
374 a->etype = TINT32;
375 }
376
377 void
378 gdata(Node *nam, Node *nr, int wid)
379 {
380 Prog *p;
381 vlong v;
382
383 if(wid == 8 && is64(nr->type)) {
384 v = mpgetfix(nr->val.u.xval);
385 p = gins(ADATA, nam, nodintconst(v));
386 p->from.scale = 4;
387 p = gins(ADATA, nam, nodintconst(v>>32));
388 p->from.scale = 4;
389 p->from.offset += 4;
390 return;
391 }
392 p = gins(ADATA, nam, nr);
393 p->from.scale = wid;
394 }
395
396 void
397 gdatacomplex(Node *nam, Mpcplx *cval)
398 {
399 Prog *p;
400 int w;
401
402 w = cplxsubtype(nam->type->etype);
403 w = types[w]->width;
404
405 p = gins(ADATA, nam, N);
406 p->from.scale = w;
407 p->to.type = D_FCONST;
408 p->to.dval = mpgetflt(&cval->real);
409
410 p = gins(ADATA, nam, N);
411 p->from.scale = w;
412 p->from.offset += w;
413 p->to.type = D_FCONST;
414 p->to.dval = mpgetflt(&cval->imag);
415 }
416
417 void
418 gdatastring(Node *nam, Strlit *sval)
419 {
420 Prog *p;
421 Node nod1;
422
423 p = gins(ADATA, nam, N);
424 datastring(sval->s, sval->len, &p->to);
425 p->from.scale = types[tptr]->width;
426 p->to.index = p->to.type;
427 p->to.type = D_ADDR;
428 //print("%P\n", p);
429
430 nodconst(&nod1, types[TINT32], sval->len);
431 p = gins(ADATA, nam, &nod1);
432 p->from.scale = types[TINT32]->width;
433 p->from.offset += types[tptr]->width;
434 }
435
436 int
437 dstringptr(Sym *s, int off, char *str)
438 {
439 Prog *p;
440
441 off = rnd(off, widthptr);
442 p = gins(ADATA, N, N);
443 p->from.type = D_EXTERN;
444 p->from.index = D_NONE;
445 p->from.sym = s;
446 p->from.offset = off;
447 p->from.scale = widthptr;
448
449 datastring(str, strlen(str)+1, &p->to);
450 p->to.index = p->to.type;
451 p->to.type = D_ADDR;
452 p->to.etype = TINT32;
453 off += widthptr;
454
455 return off;
456 }
457
458 int
459 dgostrlitptr(Sym *s, int off, Strlit *lit)
460 {
461 Prog *p;
462
463 if(lit == nil)
464 return duintptr(s, off, 0);
465
466 off = rnd(off, widthptr);
467 p = gins(ADATA, N, N);
468 p->from.type = D_EXTERN;
469 p->from.index = D_NONE;
470 p->from.sym = s;
471 p->from.offset = off;
472 p->from.scale = widthptr;
473 datagostring(lit, &p->to);
474 p->to.index = p->to.type;
475 p->to.type = D_ADDR;
476 p->to.etype = TINT32;
477 off += widthptr;
478
479 return off;
480 }
481
482 int
483 dgostringptr(Sym *s, int off, char *str)
484 {
485 int n;
486 Strlit *lit;
487
488 if(str == nil)
489 return duintptr(s, off, 0);
490
491 n = strlen(str);
492 lit = mal(sizeof *lit + n);
493 strcpy(lit->s, str);
494 lit->len = n;
495 return dgostrlitptr(s, off, lit);
496 }
497
498
499 int
500 duintxx(Sym *s, int off, uint64 v, int wid)
501 {
502 Prog *p;
503
504 off = rnd(off, wid);
505
506 p = gins(ADATA, N, N);
507 p->from.type = D_EXTERN;
508 p->from.index = D_NONE;
509 p->from.sym = s;
510 p->from.offset = off;
511 p->from.scale = wid;
512 p->to.type = D_CONST;
513 p->to.index = D_NONE;
514 p->to.offset = v;
515 off += wid;
516
517 return off;
518 }
519
520 int
521 dsymptr(Sym *s, int off, Sym *x, int xoff)
522 {
523 Prog *p;
524
525 off = rnd(off, widthptr);
526
527 p = gins(ADATA, N, N);
528 p->from.type = D_EXTERN;
529 p->from.index = D_NONE;
530 p->from.sym = s;
531 p->from.offset = off;
532 p->from.scale = widthptr;
533 p->to.type = D_ADDR;
534 p->to.index = D_EXTERN;
535 p->to.sym = x;
536 p->to.offset = xoff;
537 off += widthptr;
538
539 return off;
540 }
541
542 void
543 genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
544 {
545 Sym *e;
546 int c, d, o, mov, add, loaded;
547 Prog *p;
548 Type *f;
549
550 e = method->sym;
551 for(d=0; d<nelem(dotlist); d++) {
552 c = adddot1(e, rcvr, d, nil, 0);
553 if(c == 1)
554 goto out;
555 }
556 fatal("genembedtramp %T.%S", rcvr, method->sym);
557
558 out:
559 newplist()->name = newname(newnam);
560
561 //TEXT main·S_test2(SB),7,$0
562 p = pc;
563 gins(ATEXT, N, N);
564 p->from.type = D_EXTERN;
565 p->from.sym = newnam;
566 p->to.type = D_CONST;
567 p->to.offset = 0;
568 p->from.scale = 7;
569 //print("1. %P\n", p);
570
571 mov = AMOVL;
572 add = AADDL;
573
574 loaded = 0;
575 o = 0;
576 for(c=d-1; c>=0; c--) {
577 f = dotlist[c].field;
578 o += f->width;
579 if(!isptr[f->type->etype])
580 continue;
581 if(!loaded) {
582 loaded = 1;
583 //MOVL 4(SP), AX
584 p = pc;
585 gins(mov, N, N);
586 p->from.type = D_INDIR+D_SP;
587 p->from.offset = widthptr;
588 p->to.type = D_AX;
589 //print("2. %P\n", p);
590 }
591
592 //MOVL o(AX), AX
593 p = pc;
594 gins(mov, N, N);
595 p->from.type = D_INDIR+D_AX;
596 p->from.offset = o;
597 p->to.type = D_AX;
598 //print("3. %P\n", p);
599 o = 0;
600 }
601 if(o != 0) {
602 //ADDL $XX, AX
603 p = pc;
604 gins(add, N, N);
605 p->from.type = D_CONST;
606 p->from.offset = o;
607 if(loaded)
608 p->to.type = D_AX;
609 else {
610 p->to.type = D_INDIR+D_SP;
611 p->to.offset = widthptr;
612 }
613 //print("4. %P\n", p);
614 }
615
616 //MOVL AX, 4(SP)
617 if(loaded) {
618 p = pc;
619 gins(mov, N, N);
620 p->from.type = D_AX;
621 p->to.type = D_INDIR+D_SP;
622 p->to.offset = widthptr;
623 //print("5. %P\n", p);
624 } else {
625 // TODO(rsc): obviously this is unnecessary,
626 // but 6l has a bug, and it can't handle
627 // JMP instructions too close to the top of
628 // a new function.
629 p = pc;
630 gins(ANOP, N, N);
631 }
632
633 f = dotlist[0].field;
634 //JMP main·*Sub_test2(SB)
635 if(isptr[f->type->etype])
636 f = f->type;
637 p = pc;
638 gins(AJMP, N, N);
639 p->to.type = D_EXTERN;
640 p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
641 //print("6. %P\n", p);
642
643 pc->as = ARET; // overwrite AEND
644 }
645
646 void
647 nopout(Prog *p)
648 {
649 p->as = ANOP;
650 }
651