github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/8g/gobj.c (about) 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 <u.h> 32 #include <libc.h> 33 #include "gg.h" 34 35 void 36 zname(Biobuf *b, Sym *s, int t) 37 { 38 Bputc(b, ANAME); /* as */ 39 Bputc(b, ANAME>>8); /* as */ 40 Bputc(b, t); /* type */ 41 Bputc(b, s->sym); /* sym */ 42 43 Bputname(b, s); 44 } 45 46 void 47 zfile(Biobuf *b, char *p, int n) 48 { 49 Bputc(b, ANAME); 50 Bputc(b, ANAME>>8); 51 Bputc(b, D_FILE); 52 Bputc(b, 1); 53 Bputc(b, '<'); 54 Bwrite(b, p, n); 55 Bputc(b, 0); 56 } 57 58 void 59 zhist(Biobuf *b, int line, vlong offset) 60 { 61 Addr a; 62 63 Bputc(b, AHISTORY); 64 Bputc(b, AHISTORY>>8); 65 Bputc(b, line); 66 Bputc(b, line>>8); 67 Bputc(b, line>>16); 68 Bputc(b, line>>24); 69 zaddr(b, &zprog.from, 0, 0); 70 a = zprog.to; 71 if(offset != 0) { 72 a.offset = offset; 73 a.type = D_CONST; 74 } 75 zaddr(b, &a, 0, 0); 76 } 77 78 void 79 zaddr(Biobuf *b, Addr *a, int s, int gotype) 80 { 81 int32 l; 82 uint64 e; 83 int i, t; 84 char *n; 85 86 t = 0; 87 if(a->index != D_NONE || a->scale != 0) 88 t |= T_INDEX; 89 if(s != 0) 90 t |= T_SYM; 91 if(gotype != 0) 92 t |= T_GOTYPE; 93 94 switch(a->type) { 95 96 case D_BRANCH: 97 if(a->u.branch == nil) 98 fatal("unpatched branch"); 99 a->offset = a->u.branch->loc; 100 101 default: 102 t |= T_TYPE; 103 104 case D_NONE: 105 if(a->offset != 0) 106 t |= T_OFFSET; 107 if(a->offset2 != 0) 108 t |= T_OFFSET2; 109 break; 110 case D_FCONST: 111 t |= T_FCONST; 112 break; 113 case D_SCONST: 114 t |= T_SCONST; 115 break; 116 } 117 Bputc(b, t); 118 119 if(t & T_INDEX) { /* implies index, scale */ 120 Bputc(b, a->index); 121 Bputc(b, a->scale); 122 } 123 if(t & T_OFFSET) { /* implies offset */ 124 l = a->offset; 125 Bputc(b, l); 126 Bputc(b, l>>8); 127 Bputc(b, l>>16); 128 Bputc(b, l>>24); 129 } 130 if(t & T_OFFSET2) { /* implies offset */ 131 l = a->offset2; 132 Bputc(b, l); 133 Bputc(b, l>>8); 134 Bputc(b, l>>16); 135 Bputc(b, l>>24); 136 } 137 if(t & T_SYM) /* implies sym */ 138 Bputc(b, s); 139 if(t & T_FCONST) { 140 ieeedtod(&e, a->u.dval); 141 l = e; 142 Bputc(b, l); 143 Bputc(b, l>>8); 144 Bputc(b, l>>16); 145 Bputc(b, l>>24); 146 l = e >> 32; 147 Bputc(b, l); 148 Bputc(b, l>>8); 149 Bputc(b, l>>16); 150 Bputc(b, l>>24); 151 return; 152 } 153 if(t & T_SCONST) { 154 n = a->u.sval; 155 for(i=0; i<NSNAME; i++) { 156 Bputc(b, *n); 157 n++; 158 } 159 return; 160 } 161 if(t & T_TYPE) 162 Bputc(b, a->type); 163 if(t & T_GOTYPE) 164 Bputc(b, gotype); 165 } 166 167 static struct { 168 struct { Sym *sym; short type; } h[NSYM]; 169 int sym; 170 } z; 171 172 static void 173 zsymreset(void) 174 { 175 for(z.sym=0; z.sym<NSYM; z.sym++) { 176 z.h[z.sym].sym = S; 177 z.h[z.sym].type = 0; 178 } 179 z.sym = 1; 180 } 181 182 static int 183 zsym(Sym *s, int t, int *new) 184 { 185 int i; 186 187 *new = 0; 188 if(s == S) 189 return 0; 190 191 i = s->sym; 192 if(i < 0 || i >= NSYM) 193 i = 0; 194 if(z.h[i].type == t && z.h[i].sym == s) 195 return i; 196 i = z.sym; 197 s->sym = i; 198 zname(bout, s, t); 199 z.h[i].sym = s; 200 z.h[i].type = t; 201 if(++z.sym >= NSYM) 202 z.sym = 1; 203 *new = 1; 204 return i; 205 } 206 207 static int 208 zsymaddr(Addr *a, int *new) 209 { 210 int t; 211 212 t = a->type; 213 if(t == D_ADDR) 214 t = a->index; 215 return zsym(a->sym, t, new); 216 } 217 218 void 219 dumpfuncs(void) 220 { 221 Plist *pl; 222 int sf, st, gf, gt, new; 223 Sym *s; 224 Prog *p; 225 226 zsymreset(); 227 228 // fix up pc 229 pcloc = 0; 230 for(pl=plist; pl!=nil; pl=pl->link) { 231 if(isblank(pl->name)) 232 continue; 233 for(p=pl->firstpc; p!=P; p=p->link) { 234 p->loc = pcloc; 235 if(p->as != ADATA && p->as != AGLOBL) 236 pcloc++; 237 } 238 } 239 240 // put out functions 241 for(pl=plist; pl!=nil; pl=pl->link) { 242 if(isblank(pl->name)) 243 continue; 244 245 // -S prints code; -SS prints code and data 246 if(debug['S'] && (pl->name || debug['S']>1)) { 247 s = S; 248 if(pl->name != N) 249 s = pl->name->sym; 250 print("\n--- prog list \"%S\" ---\n", s); 251 for(p=pl->firstpc; p!=P; p=p->link) 252 print("%P\n", p); 253 } 254 255 for(p=pl->firstpc; p!=P; p=p->link) { 256 for(;;) { 257 sf = zsymaddr(&p->from, &new); 258 gf = zsym(p->from.gotype, D_EXTERN, &new); 259 if(new && sf == gf) 260 continue; 261 st = zsymaddr(&p->to, &new); 262 if(new && (st == sf || st == gf)) 263 continue; 264 gt = zsym(p->to.gotype, D_EXTERN, &new); 265 if(new && (gt == sf || gt == gf || gt == st)) 266 continue; 267 break; 268 } 269 270 Bputc(bout, p->as); 271 Bputc(bout, p->as>>8); 272 Bputc(bout, p->lineno); 273 Bputc(bout, p->lineno>>8); 274 Bputc(bout, p->lineno>>16); 275 Bputc(bout, p->lineno>>24); 276 zaddr(bout, &p->from, sf, gf); 277 zaddr(bout, &p->to, st, gt); 278 } 279 } 280 } 281 282 int 283 dsname(Sym *s, int off, char *t, int n) 284 { 285 Prog *p; 286 287 p = gins(ADATA, N, N); 288 p->from.type = D_EXTERN; 289 p->from.index = D_NONE; 290 p->from.offset = off; 291 p->from.scale = n; 292 p->from.sym = s; 293 294 p->to.type = D_SCONST; 295 p->to.index = D_NONE; 296 memmove(p->to.u.sval, t, n); 297 return off + n; 298 } 299 300 /* 301 * make a refer to the data s, s+len 302 * emitting DATA if needed. 303 */ 304 void 305 datastring(char *s, int len, Addr *a) 306 { 307 Sym *sym; 308 309 sym = stringsym(s, len); 310 a->type = D_EXTERN; 311 a->sym = sym; 312 a->node = sym->def; 313 a->offset = widthptr+4; // skip header 314 a->etype = TINT32; 315 } 316 317 /* 318 * make a refer to the string sval, 319 * emitting DATA if needed. 320 */ 321 void 322 datagostring(Strlit *sval, Addr *a) 323 { 324 Sym *sym; 325 326 sym = stringsym(sval->s, sval->len); 327 a->type = D_EXTERN; 328 a->sym = sym; 329 a->node = sym->def; 330 a->offset = 0; // header 331 a->etype = TINT32; 332 } 333 334 void 335 gdata(Node *nam, Node *nr, int wid) 336 { 337 Prog *p; 338 vlong v; 339 340 if(nr->op == OLITERAL) { 341 switch(nr->val.ctype) { 342 case CTCPLX: 343 gdatacomplex(nam, nr->val.u.cval); 344 return; 345 case CTSTR: 346 gdatastring(nam, nr->val.u.sval); 347 return; 348 } 349 } 350 351 if(wid == 8 && is64(nr->type)) { 352 v = mpgetfix(nr->val.u.xval); 353 p = gins(ADATA, nam, nodintconst(v)); 354 p->from.scale = 4; 355 p = gins(ADATA, nam, nodintconst(v>>32)); 356 p->from.scale = 4; 357 p->from.offset += 4; 358 return; 359 } 360 p = gins(ADATA, nam, nr); 361 p->from.scale = wid; 362 } 363 364 void 365 gdatacomplex(Node *nam, Mpcplx *cval) 366 { 367 Prog *p; 368 int w; 369 370 w = cplxsubtype(nam->type->etype); 371 w = types[w]->width; 372 373 p = gins(ADATA, nam, N); 374 p->from.scale = w; 375 p->to.type = D_FCONST; 376 p->to.u.dval = mpgetflt(&cval->real); 377 378 p = gins(ADATA, nam, N); 379 p->from.scale = w; 380 p->from.offset += w; 381 p->to.type = D_FCONST; 382 p->to.u.dval = mpgetflt(&cval->imag); 383 } 384 385 void 386 gdatastring(Node *nam, Strlit *sval) 387 { 388 Prog *p; 389 Node nod1; 390 391 p = gins(ADATA, nam, N); 392 datastring(sval->s, sval->len, &p->to); 393 p->from.scale = types[tptr]->width; 394 p->to.index = p->to.type; 395 p->to.type = D_ADDR; 396 //print("%P\n", p); 397 398 nodconst(&nod1, types[TINT32], sval->len); 399 p = gins(ADATA, nam, &nod1); 400 p->from.scale = types[TINT32]->width; 401 p->from.offset += types[tptr]->width; 402 } 403 404 int 405 dstringptr(Sym *s, int off, char *str) 406 { 407 Prog *p; 408 409 off = rnd(off, widthptr); 410 p = gins(ADATA, N, N); 411 p->from.type = D_EXTERN; 412 p->from.index = D_NONE; 413 p->from.sym = s; 414 p->from.offset = off; 415 p->from.scale = widthptr; 416 417 datastring(str, strlen(str)+1, &p->to); 418 p->to.index = p->to.type; 419 p->to.type = D_ADDR; 420 p->to.etype = TINT32; 421 off += widthptr; 422 423 return off; 424 } 425 426 int 427 dgostrlitptr(Sym *s, int off, Strlit *lit) 428 { 429 Prog *p; 430 431 if(lit == nil) 432 return duintptr(s, off, 0); 433 434 off = rnd(off, widthptr); 435 p = gins(ADATA, N, N); 436 p->from.type = D_EXTERN; 437 p->from.index = D_NONE; 438 p->from.sym = s; 439 p->from.offset = off; 440 p->from.scale = widthptr; 441 datagostring(lit, &p->to); 442 p->to.index = p->to.type; 443 p->to.type = D_ADDR; 444 p->to.etype = TINT32; 445 off += widthptr; 446 447 return off; 448 } 449 450 int 451 dgostringptr(Sym *s, int off, char *str) 452 { 453 int n; 454 Strlit *lit; 455 456 if(str == nil) 457 return duintptr(s, off, 0); 458 459 n = strlen(str); 460 lit = mal(sizeof *lit + n); 461 strcpy(lit->s, str); 462 lit->len = n; 463 return dgostrlitptr(s, off, lit); 464 } 465 466 467 int 468 duintxx(Sym *s, int off, uint64 v, int wid) 469 { 470 Prog *p; 471 472 off = rnd(off, wid); 473 474 p = gins(ADATA, N, N); 475 p->from.type = D_EXTERN; 476 p->from.index = D_NONE; 477 p->from.sym = s; 478 p->from.offset = off; 479 p->from.scale = wid; 480 p->to.type = D_CONST; 481 p->to.index = D_NONE; 482 p->to.offset = v; 483 off += wid; 484 485 return off; 486 } 487 488 int 489 dsymptr(Sym *s, int off, Sym *x, int xoff) 490 { 491 Prog *p; 492 493 off = rnd(off, widthptr); 494 495 p = gins(ADATA, N, N); 496 p->from.type = D_EXTERN; 497 p->from.index = D_NONE; 498 p->from.sym = s; 499 p->from.offset = off; 500 p->from.scale = widthptr; 501 p->to.type = D_ADDR; 502 p->to.index = D_EXTERN; 503 p->to.sym = x; 504 p->to.offset = xoff; 505 off += widthptr; 506 507 return off; 508 } 509 510 void 511 genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface) 512 { 513 Sym *e; 514 int c, d, o, mov, add, loaded; 515 Prog *p; 516 Type *f; 517 518 USED(iface); 519 520 e = method->sym; 521 for(d=0; d<nelem(dotlist); d++) { 522 c = adddot1(e, rcvr, d, nil, 0); 523 if(c == 1) 524 goto out; 525 } 526 fatal("genembedtramp %T.%S", rcvr, method->sym); 527 528 out: 529 newplist()->name = newname(newnam); 530 531 //TEXT main·S_test2(SB),7,$0 532 p = pc; 533 gins(ATEXT, N, N); 534 p->from.type = D_EXTERN; 535 p->from.sym = newnam; 536 p->to.type = D_CONST; 537 p->to.offset = 0; 538 p->from.scale = 7; 539 //print("1. %P\n", p); 540 541 mov = AMOVL; 542 add = AADDL; 543 544 loaded = 0; 545 o = 0; 546 for(c=d-1; c>=0; c--) { 547 f = dotlist[c].field; 548 o += f->width; 549 if(!isptr[f->type->etype]) 550 continue; 551 if(!loaded) { 552 loaded = 1; 553 //MOVL 4(SP), AX 554 p = pc; 555 gins(mov, N, N); 556 p->from.type = D_INDIR+D_SP; 557 p->from.offset = widthptr; 558 p->to.type = D_AX; 559 //print("2. %P\n", p); 560 } 561 562 //MOVL o(AX), AX 563 p = pc; 564 gins(mov, N, N); 565 p->from.type = D_INDIR+D_AX; 566 p->from.offset = o; 567 p->to.type = D_AX; 568 //print("3. %P\n", p); 569 o = 0; 570 } 571 if(o != 0) { 572 //ADDL $XX, AX 573 p = pc; 574 gins(add, N, N); 575 p->from.type = D_CONST; 576 p->from.offset = o; 577 if(loaded) 578 p->to.type = D_AX; 579 else { 580 p->to.type = D_INDIR+D_SP; 581 p->to.offset = widthptr; 582 } 583 //print("4. %P\n", p); 584 } 585 586 //MOVL AX, 4(SP) 587 if(loaded) { 588 p = pc; 589 gins(mov, N, N); 590 p->from.type = D_AX; 591 p->to.type = D_INDIR+D_SP; 592 p->to.offset = widthptr; 593 //print("5. %P\n", p); 594 } else { 595 // TODO(rsc): obviously this is unnecessary, 596 // but 6l has a bug, and it can't handle 597 // JMP instructions too close to the top of 598 // a new function. 599 gins(ANOP, N, N); 600 } 601 602 f = dotlist[0].field; 603 //JMP main·*Sub_test2(SB) 604 if(isptr[f->type->etype]) 605 f = f->type; 606 p = pc; 607 gins(AJMP, N, N); 608 p->to.type = D_EXTERN; 609 p->to.sym = methodsym(method->sym, ptrto(f->type), 0); 610 //print("6. %P\n", p); 611 612 pc->as = ARET; // overwrite AEND 613 } 614 615 void 616 nopout(Prog *p) 617 { 618 p->as = ANOP; 619 } 620