scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

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 }