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 }