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 (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 }