scc

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

symbol.c (8647B)


      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 (mapsec(map, sec, NULL, 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(4, 0)) == 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 = mapsec(map, sec, lsec->fp, sec->size);
    410 
    411 		if (!lsec->fp || r < 0) {
    412 			perror("as: creating section mapping");
    413 			exit(EXIT_FAILURE);
    414 		}
    415 	}
    416 	cursec = stext;
    417 }
    418 
    419 void
    420 emit(char *bytes, int n)
    421 {
    422 	struct lsection *lsec = (struct lsection *) cursec;
    423 
    424 	if (lsec->fp)
    425 		fwrite(bytes, n, 1, lsec->fp);
    426 	incpc(n);
    427 }
    428 
    429 Symbol *
    430 tmpsym(TUINT val)
    431 {
    432 	Symbol *sym;
    433 
    434 	if (!tmpalloc)
    435 		tmpalloc = alloc(sizeof(*sym), NALLOC);
    436 	sym = new(tmpalloc);
    437 	sym->value = val;
    438 	sym->section = -1;
    439 	sym->flags = FABS;
    440 
    441 	return sym;
    442 }
    443 
    444 void
    445 killtmp(void)
    446 {
    447 	if (!tmpalloc)
    448 		return;
    449 	dealloc(tmpalloc);
    450 	tmpalloc = NULL;
    451 }
    452 
    453 static int
    454 dumpsec(FILE *src, FILE *dst)
    455 {
    456 	int c;
    457 
    458 	if (!src)
    459 		return 0;
    460 
    461 	rewind(src);
    462 	while ((c = getc(src)) != EOF)
    463 		putc(c, dst);
    464 
    465 	if (ferror(src))
    466 		return -1;
    467 
    468 	return 0;
    469 }
    470 
    471 void
    472 writecoff(char *fname)
    473 {
    474 	FILE *fp;
    475 
    476 	if ((fp = fopen(fname, "wb")) == NULL)
    477 		goto error;
    478 
    479 	if (writeobj(obj, map, fp) < 0) {
    480 		fputs("as: corrupted object type\n", stderr);
    481 		goto error;
    482 	}
    483 
    484 	if (fclose(fp) == EOF)
    485 		goto error;
    486 	outfile = NULL;
    487 	return;
    488 
    489 error:
    490 	fprintf(stderr, "as: %s: error writing output file\n", fname);
    491 	if (errno)
    492 		perror("as");
    493 	exit(EXIT_FAILURE);
    494 }
    495 
    496 void
    497 writeout(char *fname)
    498 {
    499 	FILE *fp;
    500 	struct lsection *lp;
    501 
    502 	if ((fp = fopen(fname, "wb")) == NULL)
    503 		goto error;
    504 
    505 
    506 	for (lp = seclist; lp; lp = lp->next) {
    507 		if (dumpsec(lp->fp, fp) < 0)
    508 			goto error;
    509 	}
    510 	fflush(fp);
    511 
    512 	if (ferror(fp))
    513 		goto error;
    514 
    515 	fclose(fp);
    516 	outfile = NULL;
    517 
    518 	return;
    519 
    520 error:
    521 	fprintf(stderr, "as: %s: %s\n", fname, strerror(errno));
    522 	exit(EXIT_FAILURE);
    523 }