symbol.c - scc - simple c99 compiler
(HTM) git clone git://git.simple-cc.org/scc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) 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 }