scc

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

symbol.c (8667B)


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