scc

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

symbol.c (8733B)


      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 		/* TODO: What happens with SRELOC ? */
    260 		default:
    261 			abort();
    262 		}
    263 	}
    264 
    265 	return flags;
    266 }
    267 
    268 static int
    269 sectype(int flags)
    270 {
    271 	if (flags & SEXEC)
    272 		return 'T';
    273 	if ((flags & (SALLOC|SLOAD|SREAD)) == (SALLOC|SLOAD|SREAD))
    274 		return 'D';
    275 	if ((flags  & (SALLOC|SLOAD|SREAD)) == (SALLOC|SREAD))
    276 		return 'B';
    277 	return '?';
    278 }
    279 
    280 static Section *
    281 newsec(Symbol *sym, char *attr)
    282 {
    283 	int idx;
    284 	Section *sec;
    285 	struct lsection *lsec;
    286 	struct lsymbol *lsym;
    287 
    288 	if (secindex == INT_MAX) {
    289 		fputs("as: too many sections\n", stderr);
    290 		exit(EXIT_FAILURE);
    291 	}
    292 
    293 	lsec = xmalloc(sizeof(*lsec));
    294 	lsec->pc = lsec->curpc = 0;
    295 	lsec->next = seclist;
    296 	lsec->fp = NULL;
    297 	seclist = lsec;
    298 
    299 	sec = &lsec->sec;
    300 	sec->name = sym->name;
    301 	sec->base = sec->size = 0;
    302 	sec->flags = 0;
    303 	sec->fill = 0;
    304 	sec->align = 0;
    305 	sec->index = secindex;
    306 	sec->flags |= secflags(attr);
    307 	sec->type = sectype(sec->flags);
    308 
    309 	/* sym->flags = ? */
    310 	sym->section = sec->index;
    311 	sym->type = tolower(sec->type);
    312 	sym->index = symindex;
    313 	lsym = (struct lsymbol *) sym;
    314 	lsym->sec = sec;
    315 
    316 	if (setmap(map, sym->name, NULL, 0, 0, 0) < 0) {
    317 		fprintf(stderr,
    318 		       "as: error allocating section mapping '%s'\n",
    319 		        sym->name);
    320 		exit(EXIT_FAILURE);
    321 	}
    322 
    323 	if (!setsec(obj, &secindex, sec)) {
    324 		fprintf(stderr,
    325 		        "as: error adding section '%s' to output\n",
    326 		        sym->name);
    327 		exit(EXIT_FAILURE);
    328 	}
    329 
    330 	if (!setsym(obj, &symindex, sym)) {
    331 		fprintf(stderr,
    332 		        "as: error adding section symbol '%s' to output\n",
    333 		        sym->name);
    334 		exit(EXIT_FAILURE);
    335 	}
    336 
    337 	secindex++;
    338 	symindex++;
    339 
    340 	return sec;
    341 }
    342 
    343 Section *
    344 defsec(char *name, char *attr)
    345 {
    346 	struct lsymbol *lsym;
    347 	Section *sec;
    348 	Symbol *sym;
    349 
    350 	cursec = NULL;
    351 	sym = lookup(name);
    352 	if (sym->flags & ~FSECT)
    353 		error("invalid section name '%s'", name);
    354 
    355 	lsym = (struct lsymbol *) sym;
    356 	sec = lsym->sec;
    357 	if (sec == NULL) {
    358 		sec = newsec(sym, attr);
    359 		lsym->sec = sec;
    360 		sym->section = sec->index;
    361 		sym->flags = FSECT;
    362 	}
    363 
    364 	return cursec = sec;
    365 }
    366 
    367 void
    368 ibinfmt(void)
    369 {
    370 	int t;
    371 
    372 	if ((t = objtype("coff32-z80")) < 0) {
    373 		fprintf(stderr,
    374 		        "as: invalid binary format %s\n", "coff32-z80");
    375 		exit(EXIT_FAILURE);
    376 	}
    377 
    378 	if ((obj = newobj(t)) < 0) {
    379 		fputs("as: error allocating output\n", stderr);
    380 		exit(EXIT_FAILURE);
    381 	}
    382 
    383 	if ((map = newmap(NULL, 4)) == NULL) {
    384 		perror("as");
    385 		exit(EXIT_FAILURE);
    386 	}
    387 
    388 	stext = defsec(".text", "rxcl");
    389 	sdata = defsec(".data", "rwcl");
    390 	sbss = defsec(".bss", "rwc");
    391 }
    392 
    393 void
    394 cleansecs(void)
    395 {
    396 	int r;
    397 	Section *sec;
    398 	struct lsection *lsec;
    399 
    400 	for (lsec = seclist; lsec; lsec = lsec->next) {
    401 		sec = &lsec->sec;
    402 		lsec->curpc = lsec->pc = sec->base;
    403 		if (pass == 1 || (sec->flags & SALLOC) == 0)
    404 			continue;
    405 
    406 		lsec->fp = tmpfile();
    407 		r = setmap(map,
    408 		           sec->name,
    409 		           lsec->fp,
    410 		           sec->base,
    411 		           sec->size, 0);
    412 
    413 		if (!lsec->fp || r < 0) {
    414 			perror("as: creating section mapping");
    415 			exit(EXIT_FAILURE);
    416 		}
    417 	}
    418 	cursec = stext;
    419 }
    420 
    421 void
    422 emit(char *bytes, int n)
    423 {
    424 	struct lsection *lsec = (struct lsection *) cursec;
    425 
    426 	if (lsec->fp)
    427 		fwrite(bytes, n, 1, lsec->fp);
    428 	incpc(n);
    429 }
    430 
    431 Symbol *
    432 tmpsym(TUINT val)
    433 {
    434 	Symbol *sym;
    435 
    436 	if (!tmpalloc)
    437 		tmpalloc = alloc(sizeof(*sym), NALLOC);
    438 	sym = new(tmpalloc);
    439 	sym->value = val;
    440 	sym->section = -1;
    441 	sym->flags = FABS;
    442 
    443 	return sym;
    444 }
    445 
    446 void
    447 killtmp(void)
    448 {
    449 	if (!tmpalloc)
    450 		return;
    451 	dealloc(tmpalloc);
    452 	tmpalloc = NULL;
    453 }
    454 
    455 static int
    456 dumpsec(FILE *src, FILE *dst)
    457 {
    458 	int c;
    459 
    460 	if (!src)
    461 		return 0;
    462 
    463 	rewind(src);
    464 	while ((c = getc(src)) != EOF)
    465 		putc(c, dst);
    466 
    467 	if (ferror(src))
    468 		return -1;
    469 
    470 	return 0;
    471 }
    472 
    473 void
    474 writecoff(char *fname)
    475 {
    476 	FILE *fp;
    477 
    478 	if ((fp = fopen(fname, "wb")) == NULL)
    479 		goto error;
    480 
    481 	if (writeobj(obj, map, fp) < 0) {
    482 		fputs("as: corrupted object type\n", stderr);
    483 		goto error;
    484 	}
    485 
    486 	if (fclose(fp) == EOF)
    487 		goto error;
    488 	outfile = NULL;
    489 	return;
    490 
    491 error:
    492 	fprintf(stderr, "as: %s: error writing output file\n", fname);
    493 	if (errno)
    494 		perror("as");
    495 	exit(EXIT_FAILURE);
    496 }
    497 
    498 void
    499 writeout(char *fname)
    500 {
    501 	FILE *fp;
    502 	struct lsection *lp;
    503 
    504 	if ((fp = fopen(fname, "wb")) == NULL)
    505 		goto error;
    506 
    507 
    508 	for (lp = seclist; lp; lp = lp->next) {
    509 		if (dumpsec(lp->fp, fp) < 0)
    510 			goto error;
    511 	}
    512 	fflush(fp);
    513 
    514 	if (ferror(fp))
    515 		goto error;
    516 
    517 	fclose(fp);
    518 	outfile = NULL;
    519 
    520 	return;
    521 
    522 error:
    523 	fprintf(stderr, "as: %s: %s\n", fname, strerror(errno));
    524 	exit(EXIT_FAILURE);
    525 }