symbol.c (8734B)
1 #include <ctype.h> 2 #include <errno.h> 3 #include <limits.h> 4 #include <stdio.h> 5 #include <stdint.h> 6 #include <stdlib.h> 7 #include <string.h> 8 9 #include <scc/cstd.h> 10 #include <scc/mach.h> 11 #include <scc/scc.h> 12 13 #include "as.h" 14 15 #define HASHSIZ 64 16 #define NALLOC 10 17 18 /* 19 * sym must be the first field because we generate 20 * a pointer to lsymbol from the symbol 21 */ 22 struct lsymbol { 23 Symbol sym; 24 Section *sec; 25 struct lsymbol *next; 26 struct lsymbol *hash; 27 }; 28 29 /* 30 * sec must be the first field because we generate 31 * a pointer to lsection from the section 32 */ 33 struct lsection { 34 Section sec; 35 FILE *fp; 36 unsigned long long curpc; 37 unsigned long long pc; 38 struct lsection *next; 39 }; 40 41 Section *cursec; 42 Section *sbss, *sdata, *stext; 43 Symbol *linesym; 44 int pass; 45 46 static Obj *obj; 47 static Map *map; 48 static struct lsection *seclist; 49 static struct lsymbol *hashtbl[HASHSIZ], *symlast, *symlist; 50 51 static Symbol *cursym; 52 static Alloc *tmpalloc; 53 static int secindex, symindex; 54 55 #ifndef NDEBUG 56 void 57 dumpstab(char *msg) 58 { 59 struct lsymbol **bp, *lp; 60 61 fprintf(stderr, "%s\n", msg); 62 for (bp = hashtbl; bp < &hashtbl[HASHSIZ]; ++bp) { 63 if (*bp == NULL) 64 continue; 65 66 fprintf(stderr, "[%d]", (int) (bp - hashtbl)); 67 for (lp = *bp; lp; lp = lp->hash) { 68 fprintf(stderr, " -> %s:%0X:%0llX", 69 lp->sym.name, 70 lp->sym.flags, 71 lp->sym.value); 72 } 73 putc('\n', stderr); 74 } 75 } 76 #endif 77 78 Symbol * 79 lookup(char *name) 80 { 81 int r; 82 unsigned h; 83 Symbol *sym; 84 struct lsymbol *lp; 85 char *curname, buf[INTIDENTSIZ+1]; 86 87 if (*name == '.' && cursym) { 88 if (!cursym) 89 error("local label '%s' without global label", name); 90 curname = cursym->name; 91 r = snprintf(buf, sizeof(buf), "%s%s", curname, name); 92 if (r < 0 || r >= sizeof(buf)) 93 error("too long local label '%s%s'", curname, name); 94 name = buf; 95 } 96 97 h = genhash(name) & HASHSIZ-1; 98 for (lp = hashtbl[h]; lp; lp = lp->hash) { 99 if (!casecmp(lp->sym.name, name)) 100 return &lp->sym; 101 } 102 103 lp = xmalloc(sizeof(*lp)); 104 lp->next = NULL; 105 lp->hash = hashtbl[h]; 106 lp->sec = NULL; 107 hashtbl[h] = lp; 108 109 if (symlast) 110 symlast->next = lp; 111 symlast = lp; 112 113 if (!symlist) 114 symlist = lp; 115 116 sym = &lp->sym; 117 sym->name = xstrdup(name); 118 sym->flags = 0; 119 sym->size = sym->value = 0; 120 sym->section = cursec ? cursec->index : -1; 121 122 return sym; 123 } 124 125 Symbol * 126 deflabel(char *name) 127 { 128 int local = 0; 129 Symbol *sym; 130 struct lsection *lsec; 131 char label[MAXSYM+1]; 132 133 if (*name == '.') { 134 int r; 135 136 local = 1; 137 if (!cursym) { 138 error("local label '%s' without global label", name); 139 return NULL; 140 } 141 r = snprintf(label, sizeof(label), 142 "%s%s", 143 cursym->name, name); 144 if (r == sizeof(label)) { 145 error("local label '%s' in '%s' produces too long symbol", 146 name, cursym->name); 147 return NULL; 148 } 149 name = label; 150 } 151 152 sym = lookup(name); 153 if (pass == 1 && (sym->flags & FDEF)) 154 error("redefinition of label '%s'", name); 155 if (cursec->flags & SABS) 156 sym->flags |= FABS; 157 158 lsec = (struct lsection *) cursec; 159 sym->value = lsec->curpc; 160 sym->section = cursec->index; 161 162 if (!local) 163 cursym = sym; 164 return sym; 165 } 166 167 int 168 toobig(Node *np, int type) 169 { 170 unsigned long long val = np->sym->value; 171 172 switch (type) { 173 case AIMM2: 174 return val > 3; 175 case AIMM3: 176 return val > 7; 177 case AIMM5: 178 return val > 0x1F; 179 case AIMM8: 180 return val > 0xFF; 181 case AIMM16: 182 return val > 0xFFFF; 183 case AIMM32: 184 return val > 0xFFFFFFFF; 185 case AIMM64: 186 return 1; 187 default: 188 abort(); 189 } 190 } 191 192 unsigned long long 193 getpc(void) 194 { 195 struct lsection *lsec; 196 197 lsec = (struct lsection *) cursec; 198 return lsec->curpc; 199 } 200 201 static void 202 incpc(int nbytes) 203 { 204 struct lsection *lsec; 205 unsigned long long siz; 206 TUINT pc, curpc; 207 208 lsec = (struct lsection *) cursec; 209 210 pc = lsec->pc; 211 curpc = lsec->curpc; 212 213 lsec->curpc += nbytes; 214 lsec->pc += nbytes; 215 216 if (pass == 2) 217 return; 218 219 siz = lsec->pc - cursec->base; 220 if (siz > cursec->size) 221 cursec->size = siz; 222 223 if (pc > lsec->pc || 224 curpc > lsec->curpc || 225 lsec->curpc > maxaddr || 226 lsec->pc > maxaddr) { 227 die("as: address overflow in section '%s'"); 228 } 229 } 230 231 static int 232 secflags(char *attr) 233 { 234 int c, flags; 235 236 if (!attr) 237 return 0; 238 239 for (flags = 0; c = *attr++; ) { 240 switch (c) { 241 case 'w': 242 flags |= SWRITE; 243 break; 244 case 'r': 245 flags |= SREAD; 246 break; 247 case 'x': 248 flags |= SEXEC; 249 break; 250 case 'c': 251 flags |= SALLOC; 252 break; 253 case 'l': 254 flags |= SLOAD; 255 break; 256 case 'a': 257 flags |= SABS; 258 break; 259 case 'm': 260 flags |= SRELOC; 261 break; 262 default: 263 abort(); 264 } 265 } 266 267 return flags; 268 } 269 270 static int 271 sectype(int flags) 272 { 273 if (flags & SEXEC) 274 return 'T'; 275 if ((flags & (SALLOC|SLOAD|SREAD)) == (SALLOC|SLOAD|SREAD)) 276 return 'D'; 277 if ((flags & (SALLOC|SLOAD|SREAD)) == (SALLOC|SREAD)) 278 return 'B'; 279 return '?'; 280 } 281 282 static Section * 283 newsec(Symbol *sym, char *attr) 284 { 285 int idx; 286 Section *sec; 287 struct lsection *lsec; 288 struct lsymbol *lsym; 289 290 if (secindex == INT_MAX) { 291 fputs("as: too many sections\n", stderr); 292 exit(EXIT_FAILURE); 293 } 294 295 lsec = xmalloc(sizeof(*lsec)); 296 lsec->pc = lsec->curpc = 0; 297 lsec->next = seclist; 298 lsec->fp = NULL; 299 seclist = lsec; 300 301 sec = &lsec->sec; 302 sec->name = sym->name; 303 sec->base = sec->size = 0; 304 sec->flags = 0; 305 sec->fill = 0; 306 sec->align = 0; 307 sec->index = secindex; 308 sec->flags |= secflags(attr); 309 sec->type = sectype(sec->flags); 310 311 /* sym->flags = ? */ 312 sym->section = sec->index; 313 sym->type = tolower(sec->type); 314 sym->index = symindex; 315 lsym = (struct lsymbol *) sym; 316 lsym->sec = sec; 317 318 if (setmap(map, sym->name, NULL, 0, 0, 0) < 0) { 319 fprintf(stderr, 320 "as: error allocating section mapping '%s'\n", 321 sym->name); 322 exit(EXIT_FAILURE); 323 } 324 325 if (!setsec(obj, &secindex, sec)) { 326 fprintf(stderr, 327 "as: error adding section '%s' to output\n", 328 sym->name); 329 exit(EXIT_FAILURE); 330 } 331 332 if (!setsym(obj, &symindex, sym)) { 333 fprintf(stderr, 334 "as: error adding section symbol '%s' to output\n", 335 sym->name); 336 exit(EXIT_FAILURE); 337 } 338 339 secindex++; 340 symindex++; 341 342 return sec; 343 } 344 345 Section * 346 defsec(char *name, char *attr) 347 { 348 struct lsymbol *lsym; 349 Section *sec; 350 Symbol *sym; 351 352 cursec = NULL; 353 sym = lookup(name); 354 if (sym->flags & ~FSECT) 355 error("invalid section name '%s'", name); 356 357 lsym = (struct lsymbol *) sym; 358 sec = lsym->sec; 359 if (sec == NULL) { 360 sec = newsec(sym, attr); 361 lsym->sec = sec; 362 sym->section = sec->index; 363 sym->flags = FSECT; 364 } 365 366 return cursec = sec; 367 } 368 369 void 370 ibinfmt(void) 371 { 372 int t; 373 374 if ((t = objtype("coff-z80")) < 0) { 375 fprintf(stderr, 376 "as: invalid binary format %s\n", "coff32-z80"); 377 exit(EXIT_FAILURE); 378 } 379 380 if ((obj = newobj(t)) < 0) { 381 fputs("as: error allocating output\n", stderr); 382 exit(EXIT_FAILURE); 383 } 384 385 if ((map = newmap(NULL, 4)) == NULL) { 386 perror("as"); 387 exit(EXIT_FAILURE); 388 } 389 390 stext = defsec(".text", "mrxcl"); 391 sdata = defsec(".data", "mrwcl"); 392 sbss = defsec(".bss", "rwc"); 393 } 394 395 void 396 cleansecs(void) 397 { 398 int r; 399 Section *sec; 400 struct lsection *lsec; 401 402 for (lsec = seclist; lsec; lsec = lsec->next) { 403 sec = &lsec->sec; 404 lsec->curpc = lsec->pc = sec->base; 405 if (pass == 1 || (sec->flags & SALLOC) == 0) 406 continue; 407 408 lsec->fp = tmpfile(); 409 r = setmap(map, 410 sec->name, 411 lsec->fp, 412 sec->base, 413 sec->size, 0); 414 415 if (!lsec->fp || r < 0) { 416 perror("as: creating section mapping"); 417 exit(EXIT_FAILURE); 418 } 419 } 420 cursec = stext; 421 } 422 423 void 424 emit(char *bytes, int n) 425 { 426 struct lsection *lsec = (struct lsection *) cursec; 427 428 if (lsec->fp) 429 fwrite(bytes, n, 1, lsec->fp); 430 incpc(n); 431 } 432 433 Symbol * 434 tmpsym(TUINT val) 435 { 436 Symbol *sym; 437 438 if (!tmpalloc) 439 tmpalloc = alloc(sizeof(*sym), NALLOC); 440 sym = new(tmpalloc); 441 sym->value = val; 442 sym->section = -1; 443 sym->flags = FABS; 444 445 return sym; 446 } 447 448 void 449 killtmp(void) 450 { 451 if (!tmpalloc) 452 return; 453 dealloc(tmpalloc); 454 tmpalloc = NULL; 455 } 456 457 static int 458 dumpsec(FILE *src, FILE *dst) 459 { 460 int c; 461 462 if (!src) 463 return 0; 464 465 rewind(src); 466 while ((c = getc(src)) != EOF) 467 putc(c, dst); 468 469 if (ferror(src)) 470 return -1; 471 472 return 0; 473 } 474 475 void 476 writecoff(char *fname) 477 { 478 FILE *fp; 479 480 if ((fp = fopen(fname, "wb")) == NULL) 481 goto error; 482 483 if (writeobj(obj, map, fp) < 0) { 484 fputs("as: corrupted object type\n", stderr); 485 goto error; 486 } 487 488 if (fclose(fp) == EOF) 489 goto error; 490 outfile = NULL; 491 return; 492 493 error: 494 fprintf(stderr, "as: %s: error writing output file\n", fname); 495 if (errno) 496 perror("as"); 497 exit(EXIT_FAILURE); 498 } 499 500 void 501 writeout(char *fname) 502 { 503 FILE *fp; 504 struct lsection *lp; 505 506 if ((fp = fopen(fname, "wb")) == NULL) 507 goto error; 508 509 510 for (lp = seclist; lp; lp = lp->next) { 511 if (dumpsec(lp->fp, fp) < 0) 512 goto error; 513 } 514 fflush(fp); 515 516 if (ferror(fp)) 517 goto error; 518 519 fclose(fp); 520 outfile = NULL; 521 522 return; 523 524 error: 525 fprintf(stderr, "as: %s: %s\n", fname, strerror(errno)); 526 exit(EXIT_FAILURE); 527 }