1 #include "auxi.h" 2 3 /* 4 * in some embedded coff files, edata and end have type 0 not 4, 5 * and file value is pointer to next file sym (as here), but the last one 6 * points to an external symbol, not 0 as here. 7 */ 8 9 #define C_NULL 0 10 #define C_AUTO 1 11 #define C_EXT 2 12 #define C_STAT 3 13 #define C_ARG 9 14 #define C_FCN 101 15 #define C_FILE 103 16 17 #define T_VOID 0 18 #define T_CHAR 2 19 #define T_SHORT 3 20 #define T_INT 4 21 #define T_LONG 5 22 23 #define DT_NON 0 24 #define DT_PTR 1 25 #define DT_FCN 2 26 #define DT_ARY 3 27 28 #define T(a, b) (((a)<<4)|b) 29 30 #define DOTTEXT ".text" 31 #define DOTDATA ".data" 32 #define DOTBSS ".bss" 33 #define DOTBF ".bf" 34 #define DOTEF ".ef" 35 36 #define SINDEX(s) (*((long*)(&s->become))) 37 #define LINDEX(s) (*((long*)(&s->used))) 38 39 typedef struct Hist Hist; 40 41 struct Hist{ 42 Auto *a; 43 Hist *n; 44 }; 45 46 static int nsym, nlc, lines; 47 48 static void cofflcsz(void); 49 50 static Hist *freeh, *curh; 51 52 static void 53 dohist(Auto *a) 54 { 55 Hist *h, **ha; 56 57 if(a->aoffset == 1){ /* new file */ 58 for(ha = &curh; *ha != nil; ha = &((*ha)->n)) 59 ; 60 *ha = freeh; 61 freeh = curh; 62 curh = nil; 63 } 64 if(freeh != nil){ 65 h = freeh; 66 freeh = freeh->n; 67 } 68 else 69 h = malloc(sizeof(Hist)); 70 h->a = a; 71 h->n = nil; 72 for(ha = &curh; *ha != nil; ha = &((*ha)->n)) 73 ; 74 *ha = h; 75 } 76 77 static long 78 lineno(long n) 79 { 80 long o, d; 81 Hist *h; 82 83 if(1) 84 return n; /* now using fileline() not pc2line() */ 85 86 if(curh == nil) 87 return 0; 88 o = curh->a->aoffset-1; 89 d = 1; 90 for(h = curh->n; d && h != nil; h = h->n){ 91 if(h->a->asym->name[1] || h->a->asym->name[2]){ 92 if(h->a->type == D_FILE1) { 93 ; 94 } 95 else if(d == 1 && n < h->a->aoffset) 96 break; 97 else if(d++ == 1) 98 o -= h->a->aoffset; 99 } 100 else if(--d == 1) 101 o += h->a->aoffset; 102 } 103 return n-o; 104 } 105 106 static char * 107 filelookup(int k) 108 { 109 int i; 110 Symx *s; 111 112 for(i = 0; i < NHASH; i++){ 113 for(s = hash[i]; s != nil; s = s->link){ 114 if(s->type == SFILE && k == s->value) 115 return s->name+1; 116 } 117 } 118 return ""; 119 } 120 121 static char* 122 filename(char *s) 123 { 124 int j, k, l; 125 static char buf[256]; 126 127 buf[0] = '\0'; 128 if(s[0] != 0) 129 diag("bad filename"); 130 for(j = 1; ; j += 2){ 131 k = (s[j]<<8)|s[j+1]; 132 if(k == 0) 133 break; 134 l = strlen(buf); 135 if(l != 0 && buf[l-1] != '/') 136 strcat(buf, "/"); 137 strcat(buf, filelookup(k)); 138 } 139 return buf; 140 } 141 142 static void 143 sput(char *s, int n) 144 { 145 int i; 146 147 for(i = 0; i < n && s != nil && *s != '\0'; i++, s++) 148 cput(*s); 149 for( ; i < n; i++) 150 cput(0); 151 } 152 153 static void 154 coffsect(char *s, long a, long sz, long o, long lp, long nl, long f) 155 { 156 if(0) 157 print("sect %s pa=%lux va=%lux sz=%lux\n", s, a, a, sz); 158 sput(s, 8); /* name <= 8 chars in len */ 159 lputl(a); /* pa */ 160 lputl(a); /* va */ 161 lputl(sz); /* size */ 162 lputl(o); /* file offset */ 163 lputl(0); /* reloc */ 164 lputl(lp); /* line nos */ 165 lputl(0); /* no reloc entries */ 166 lputl(nl); /* no line no entries */ 167 lputl(f); /* flags */ 168 hputl(0); /* reserved */ 169 hputl(0); /* mem page no */ 170 } 171 172 void 173 coffhdr(void) 174 { 175 if(0){ 176 print("H=%lux t=%lux d=%lux b=%lux\n", HEADR, textsize, datsize, bsssize); 177 print("e=%lux ts=%lux ds=%lux\n", entryvalue(), INITTEXT, INITDAT); 178 } 179 180 /* 181 * file header 182 */ 183 hputl(0xc2); /* version ID */ 184 hputl(3); /* no section hdrs */ 185 lputl(0); /* date stamp */ 186 lputl(HEADR+textsize+datsize+6*nlc); /* sym table */ 187 lputl(nsym); /* no sym table entries */ 188 hputl(28); /* size optional hdr */ 189 hputl(0x0103); /* flags */ 190 hputl(0x97); /* target ID */ 191 /* 192 * optional file header 193 */ 194 hputl(0x108); /* magic */ 195 hputl(0); /* version stamp */ 196 lputl(textsize); /* text size */ 197 lputl(datsize); /* data size */ 198 lputl(bsssize); /* bss size */ 199 lputl(entryvalue()); /* entry pt */ 200 lputl(INITTEXT); /* text start */ 201 lputl(INITDAT); /* data start */ 202 /* 203 * sections 204 */ 205 coffsect(DOTTEXT, INITTEXT, textsize, HEADR, HEADR+textsize+datsize, nlc, 0x20); 206 coffsect(DOTDATA, INITDAT, datsize, HEADR+textsize, 0, 0, 0x40); 207 coffsect(DOTBSS, INITDAT+datsize, bsssize, 0, 0, 0, 0x80); 208 } 209 210 static int 211 private(char *s) 212 { 213 return strcmp(s, "safe") == 0 || strcmp(s, "ret") == 0 || strcmp(s, "string") == 0; 214 } 215 216 static long stoff = 4; 217 218 static long 219 stput(char *s) 220 { 221 long r; 222 223 r = stoff; 224 stoff += strlen(s)+1; 225 return r; 226 } 227 228 static long 229 strput(char *s) 230 { 231 int l; 232 233 if((l = strlen(s)) > 8){ 234 if(*s == '.' && private(s+1)) 235 return 0; 236 while(*s) 237 cput(*s++); 238 cput(*s); 239 return l+1; 240 } 241 return 0; 242 } 243 244 static void 245 stflush(void) 246 { 247 int i; 248 long o; 249 Prog *p; 250 Auto *a, *f; 251 Symx *s; 252 char *fn, file[256]; 253 254 lputl(stoff); 255 o = 4; 256 for(p = firstp; p != P; p = p->link){ 257 if(p->as == ATEXT){ 258 f = nil; 259 fn = nil; 260 for(a = p->to.autom; a != nil; a = a->link){ 261 if(a->type == D_FILE){ 262 f = a; 263 break; 264 } 265 } 266 if(f != nil) 267 fn = filename(f->asym->name); 268 if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){ 269 strcpy(file, fn); 270 o += strput(file); 271 } 272 o += strput(p->from.sym->name); 273 for(a = p->to.autom; a != nil; a = a->link){ 274 if(a->type == D_AUTO || a->type == D_PARAM) 275 o += strput(a->asym->name); 276 } 277 } 278 } 279 for(i = 0; i < NHASH; i++){ 280 for(s = hash[i]; s != nil; s = s->link){ 281 if(s->version > 0 && (s->type == SDATA || s->type == SBSS)) 282 o += strput(s->name); 283 } 284 } 285 for(i = 0; i < NHASH; i++){ 286 for(s = hash[i]; s != nil; s = s->link){ 287 if(s->version == 0 && (s->type == SDATA || s->type == SBSS)) 288 o += strput(s->name); 289 } 290 } 291 if(o != stoff) 292 diag("bad stflush offset"); 293 } 294 295 static int 296 putsect(Symx *s) 297 { 298 int sz, ln; 299 300 sz = ln = 0; 301 // isn't this repetition ? 302 if(strcmp(s->name, DOTTEXT) == 0){ 303 sz = textsize; 304 ln = nlc; 305 } 306 else if(strcmp(s->name, DOTDATA) == 0) 307 sz = datsize; 308 else if(strcmp(s->name, DOTBSS) == 0) 309 sz = bsssize; 310 else 311 diag("bad putsect sym"); 312 lputl(sz); 313 hputl(0); 314 hputl(ln); 315 sput(nil, 10); 316 return 1; 317 } 318 319 static int 320 putfun(Symx *s) 321 { 322 /* lputl(SINDEX(s)+2); */ 323 lputl(0); 324 lputl(0); /* patched later */ 325 lputl(HEADR+textsize+datsize+LINDEX(s)); 326 lputl(0); /* patched later */ 327 sput(nil, 2); 328 return 1; 329 } 330 331 static int 332 putbf(int lno) 333 { 334 lputl(0); 335 hputl(lno); 336 hputl(lines); 337 lputl(autosize); 338 lputl(0); /* patched later */ 339 sput(nil, 2); 340 return 1; 341 } 342 343 static int 344 putef(int lno) 345 { 346 sput(nil, 4); 347 hputl(lno); 348 sput(nil, 12); 349 return 1; 350 } 351 352 static int 353 putsym(Symx *s, int sc, int t, int lno) 354 { 355 long v; 356 357 if(s == nil || s->name == nil || s->name[0] == '\0' || (s->name[0] == '.' && private(s->name+1))) 358 return 0; 359 if(0) 360 print("putsym %s %d %ld %d %d\n", s->name, s->type, s->value, sc, t); 361 if(strlen(s->name) <= 8) 362 sput(s->name, 8); 363 else{ 364 lputl(0); 365 lputl(stput(s->name)); 366 } 367 /* value */ 368 v = s->value; 369 if(s->type == SDATA || s->type == SDATA1 || s->type == SBSS) 370 lputl(INITDAT+v); 371 else if(sc == C_AUTO) 372 lputl(autosize+v); 373 else if(sc == C_ARG) 374 lputl(autosize+v+4); 375 else 376 lputl(v); 377 switch(s->type){ /* section number */ 378 case STEXT: 379 case SLEAF: 380 hputl(1); 381 break; 382 case SDATA: 383 case SDATA1: 384 hputl(2); 385 break; 386 case SBSS: 387 hputl(3); 388 break; 389 case SFILE: 390 hputl(-2); 391 break; 392 default: 393 diag("type %d in putsym", s->type); 394 break; 395 } 396 hputl(t); /* type */ 397 cput(sc); /* storage class */ 398 /* aux entries */ 399 if(sc == C_STAT && t == T_VOID && s->name[0] == '.'){ /* section */ 400 cput(1); 401 return 1+putsect(s); 402 } 403 else if((t>>4) == DT_FCN){ /* function */ 404 cput(1); 405 return 1+putfun(s); 406 } 407 else if(sc == C_FCN && strcmp(s->name, DOTBF) == 0){ /* bf */ 408 cput(1); 409 return 1+putbf(lno); 410 } 411 else if(sc == C_FCN && strcmp(s->name, DOTEF) == 0){ /* ef */ 412 cput(1); 413 return 1+putef(lno); 414 } 415 cput(0); /* 0 aux entry */ 416 return 1; 417 } 418 419 static Symx* 420 defsym(char *p, int t, long v) 421 { 422 Symx *s; 423 424 s = lookupsym(p, 0); 425 if(s->type == SDATA || s->type == SBSS) 426 return nil; /* already output */ 427 if(s->type == 0 || s->type == SXREF){ 428 s->type = t; 429 s->value = v; 430 } 431 return s; 432 } 433 434 static int 435 specsym(char *p, int t, long v, int c) 436 { 437 return putsym(defsym(p, t, v), c, T_VOID, 0); 438 } 439 440 static int 441 cclass(Symx *s) 442 { 443 /* 444 if(s->version > 0 && dclass == D_EXTERN) 445 diag("%s: version %d dclass EXTERN", s->name, s->version); 446 if(s->version == 0 && dclass == D_STATIC) 447 diag("%s: version %d dclass STATIC", s->name, s->version); 448 */ 449 return s->version > 0 ? C_STAT : C_EXT; 450 } 451 452 static void 453 patchsym(long i, long o, long v) 454 { 455 long oo; 456 457 cflush(); 458 oo = seek(cout, 0, 1); 459 seek(cout, HEADR+textsize+datsize+6*nlc+18*i+o, 0); 460 lputl(v); 461 cflush(); 462 seek(cout, oo, 0); 463 } 464 465 void 466 coffsym(void) 467 { 468 int i; 469 long ns, lno, lpc, v, vs, lastf; 470 Prog *p; 471 Auto *a, *f; 472 Symx *s, *bf, *ef, ts; 473 char *fn, file[256]; 474 475 file[0] = '\0'; 476 cofflcsz(); 477 seek(cout, 6*nlc, 1); /* advance over line table */ 478 ns = 0; 479 lpc = -1; 480 lno = -1; 481 lastf = -1; 482 bf = defsym(DOTBF, STEXT, 0); 483 ef = defsym(DOTEF, STEXT, 0); 484 for(p = firstp; p != P; p = p->link){ 485 if(p->as != ATEXT){ 486 if(p->line != 0) 487 lno = lineno(p->line); 488 } 489 if(p->as == ATEXT){ 490 curtext = p; 491 autosize = p->to.offset+4; 492 if(lpc >= 0){ 493 ef->value = lpc; 494 ns += putsym(ef, C_FCN, T_VOID, lno); 495 } 496 f = nil; 497 fn = nil; 498 for(a = p->to.autom; a != nil; a = a->link){ 499 if(a->type == D_FILE || a->type == D_FILE1) 500 dohist(a); 501 if(f == nil && a->type == D_FILE) 502 f = a; /* main filename */ 503 } 504 if(f != nil) 505 fn = filename(f->asym->name); 506 if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){ 507 strcpy(file, fn); 508 ts.name = file; 509 ts.type = SFILE; 510 ts.value = 0; 511 if(lastf >= 0) 512 patchsym(lastf, 8, ns); 513 lastf = ns; 514 ns += putsym(&ts, C_FILE, T_VOID, 0); 515 } 516 if(p->link != P && p->link->line != 0) 517 lno = lineno(p->link->line); 518 else if(p->line != 0) 519 lno = lineno(p->line); 520 s = p->from.sym; 521 SINDEX(s) = ns; 522 ns += putsym(s, cclass(s), T(DT_FCN, T_INT), 0); 523 if(p->cond != P) 524 lines = LINDEX(p->cond->from.sym)-LINDEX(s)-1; 525 else 526 lines = 0; 527 bf->value = p->pc; 528 ns += putsym(bf, C_FCN, T_VOID, lno); 529 for(a = p->to.autom; a != nil; a = a->link){ 530 if(a->type == D_AUTO || a->type == D_PARAM){ 531 ts.name = a->asym->name; 532 ts.type = STEXT; 533 ts.value = a->aoffset; 534 ns += putsym(&ts, a->type == D_AUTO ? C_AUTO : C_ARG, T_INT, 0); 535 } 536 } 537 } 538 lpc = p->pc; 539 } 540 if(lpc >= 0){ 541 ef->value = lpc; 542 ns += putsym(ef, C_FCN, T_VOID, lno); 543 } 544 /* patch up */ 545 for(p = textp; p != P; p = p->cond){ 546 s = p->from.sym; 547 if(p->cond != P){ 548 v = SINDEX(p->cond->from.sym); 549 vs = p->cond->pc - p->pc; 550 } 551 else{ 552 v = 0; 553 vs = INITTEXT+textsize-p->pc; 554 } 555 patchsym(SINDEX(s)+1, 4, 8*vs); 556 patchsym(SINDEX(s)+1, 12, v); 557 patchsym(SINDEX(s)+3, 12, v); 558 } 559 for(i = 0; i < NHASH; i++){ 560 for(s = hash[i]; s != nil; s = s->link){ 561 if(s->version > 0 && (s->type == SDATA || s->type == SBSS)) 562 ns += putsym(s, cclass(s), T_INT, 0); 563 } 564 } 565 for(i = 0; i < NHASH; i++){ 566 for(s = hash[i]; s != nil; s = s->link){ 567 if(s->version == 0 && (s->type == SDATA || s->type == SBSS)) 568 ns += putsym(s, cclass(s), T_INT, 0); 569 } 570 } 571 ns += specsym(DOTTEXT, STEXT, INITTEXT, C_STAT); 572 ns += specsym(DOTDATA, SDATA, 0, C_STAT); 573 ns += specsym(DOTBSS, SBSS, datsize, C_STAT); 574 ns += specsym("etext", STEXT, INITTEXT+textsize, C_EXT); 575 ns += specsym("edata", SDATA, datsize, C_EXT); 576 ns += specsym("end", SBSS, datsize+bsssize, C_EXT); 577 nsym = ns; 578 stflush(); 579 } 580 581 void 582 cofflc(void) 583 { 584 long olc, nl; 585 Symx *s; 586 Prog *p; 587 Auto *a; 588 589 cflush(); 590 seek(cout, HEADR+textsize+datsize, 0); 591 nl = 0; 592 /* opc = INITTEXT; */ 593 olc = 0; 594 for(p = firstp; p != P; p = p->link){ 595 if(p->as == ATEXT){ 596 curtext = p; 597 s = p->from.sym; 598 /* opc = p->pc; */ 599 for(a = p->to.autom; a != nil; a = a->link){ 600 if(a->type == D_FILE || a->type == D_FILE1) 601 dohist(a); 602 } 603 lputl(SINDEX(s)); 604 hputl(0); 605 nl++; 606 continue; 607 } 608 if(p->line == 0 || p->line == olc || p->as == ANOP) 609 continue; 610 lputl(p->pc); 611 hputl(lineno(p->line)); 612 nl++; 613 olc = p->line; 614 } 615 if(nl != nlc) 616 diag("bad line count in cofflc()"); 617 nlc = nl; 618 } 619 620 static void 621 cofflcsz(void) 622 { 623 long olc, nl; 624 Prog *p; 625 626 nl = 0; 627 olc = 0; 628 for(p = firstp; p != P; p = p->link){ 629 if(p->as == ATEXT){ 630 LINDEX(p->from.sym) = nl; 631 nl++; 632 continue; 633 } 634 if(p->line == 0 || p->line == olc || p->as == ANOP) 635 continue; 636 nl++; 637 olc = p->line; 638 } 639 nlc = nl; 640 } 641