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>89#include <scc/cstd.h>10#include <scc/mach.h>11#include <scc/scc.h>1213#include "as.h"1415#define HASHSIZ 6416#define NALLOC 101718/*19 * sym must be the first field because we generate20 * a pointer to lsymbol from the symbol21 */22struct lsymbol {23 Symbol sym;24 Section *sec;25 struct lsymbol *next;26 struct lsymbol *hash;27};2829/*30 * sec must be the first field because we generate31 * a pointer to lsection from the section32 */33struct lsection {34 Section sec;35 FILE *fp;36 unsigned long long curpc;37 unsigned long long pc;38 struct lsection *next;39};4041Section *cursec;42Section *sbss, *sdata, *stext;43Symbol *linesym;44int pass;4546static Obj *obj;47static Map *map;48static struct lsection *seclist;49static struct lsymbol *hashtbl[HASHSIZ], *symlast, *symlist;5051static Symbol *cursym;52static Alloc *tmpalloc;53static int secindex, symindex;5455#ifndef NDEBUG56void57dumpstab(char *msg)58{59 struct lsymbol **bp, *lp;6061 fprintf(stderr, "%s\n", msg);62 for (bp = hashtbl; bp < &hashtbl[HASHSIZ]; ++bp) {63 if (*bp == NULL)64 continue;6566 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#endif7778Symbol *79lookup(char *name)80{81 int r;82 unsigned h;83 Symbol *sym;84 struct lsymbol *lp;85 char *curname, buf[INTIDENTSIZ+1];8687 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 }9697 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 }102103 lp = xmalloc(sizeof(*lp));104 lp->next = NULL;105 lp->hash = hashtbl[h];106 lp->sec = NULL;107 hashtbl[h] = lp;108109 if (symlast)110 symlast->next = lp;111 symlast = lp;112113 if (!symlist)114 symlist = lp;115116 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;121122 return sym;123}124125Symbol *126deflabel(char *name)127{128 int local = 0;129 Symbol *sym;130 struct lsection *lsec;131 char label[MAXSYM+1];132133 if (*name == '.') {134 int r;135136 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 }151152 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;157158 lsec = (struct lsection *) cursec;159 sym->value = lsec->curpc;160 sym->section = cursec->index;161162 if (!local)163 cursym = sym;164 return sym;165}166167int168toobig(Node *np, int type)169{170 unsigned long long val = np->sym->value;171172 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}191192unsigned long long193getpc(void)194{195 struct lsection *lsec;196197 lsec = (struct lsection *) cursec;198 return lsec->curpc;199}200201static void202incpc(int nbytes)203{204 struct lsection *lsec;205 unsigned long long siz;206 unsigned long long pc, curpc;207208 lsec = (struct lsection *) cursec;209210 pc = lsec->pc;211 curpc = lsec->curpc;212213 lsec->curpc += nbytes;214 lsec->pc += nbytes;215216 if (pass == 2)217 return;218219 siz = lsec->pc - cursec->base;220 if (siz > cursec->size)221 cursec->size = siz;222223 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}230231static int232secflags(char *attr)233{234 int c, flags;235236 if (!attr)237 return 0;238239 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 }266267 return flags;268}269270static int271sectype(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}281282static Section *283newsec(Symbol *sym, char *attr)284{285 int idx;286 Section *sec;287 struct lsection *lsec;288 struct lsymbol *lsym;289290 if (secindex == INT_MAX) {291 fputs("as: too many sections\n", stderr);292 exit(EXIT_FAILURE);293 }294295 lsec = xmalloc(sizeof(*lsec));296 lsec->pc = lsec->curpc = 0;297 lsec->next = seclist;298 lsec->fp = NULL;299 seclist = lsec;300301 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);310311 /* 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;317318 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 }324325 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 }331332 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 }338339 secindex++;340 symindex++;341342 return sec;343}344345Section *346defsec(char *name, char *attr)347{348 struct lsymbol *lsym;349 Section *sec;350 Symbol *sym;351352 cursec = NULL;353 sym = lookup(name);354 if (sym->flags & ~FSECT)355 error("invalid section name '%s'", name);356357 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 }365366 return cursec = sec;367}368369void370ibinfmt(void)371{372 int t;373374 if ((t = objtype("coff-z80")) < 0) {375 fprintf(stderr,376 "as: invalid binary format %s\n", "coff32-z80");377 exit(EXIT_FAILURE);378 }379380 if ((obj = newobj(t)) == NULL) {381 fputs("as: error allocating output\n", stderr);382 exit(EXIT_FAILURE);383 }384385 if ((map = newmap(4, 0)) == NULL) {386 perror("as");387 exit(EXIT_FAILURE);388 }389390 stext = defsec(".text", "mrxcl");391 sdata = defsec(".data", "mrwcl");392 sbss = defsec(".bss", "rwc");393}394395void396cleansecs(void)397{398 int r;399 Section *sec;400 struct lsection *lsec;401402 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;407408 lsec->fp = tmpfile();409 r = mapsec(map, sec, lsec->fp, sec->size);410411 if (!lsec->fp || r < 0) {412 perror("as: creating section mapping");413 exit(EXIT_FAILURE);414 }415 }416 cursec = stext;417}418419void420emit(unsigned char *bytes, int n)421{422 struct lsection *lsec = (struct lsection *) cursec;423424 if (lsec->fp)425 fwrite(bytes, n, 1, lsec->fp);426 incpc(n);427}428429Symbol *430tmpsym(unsigned long long val)431{432 Symbol *sym;433434 if (!tmpalloc)435 tmpalloc = alloc(sizeof(*sym), NALLOC);436 sym = new(tmpalloc);437 sym->value = val;438 sym->section = -1;439 sym->flags = FABS;440441 return sym;442}443444void445killtmp(void)446{447 if (!tmpalloc)448 return;449 dealloc(tmpalloc);450 tmpalloc = NULL;451}452453static int454dumpsec(FILE *src, FILE *dst)455{456 int c;457458 if (!src)459 return 0;460461 rewind(src);462 while ((c = getc(src)) != EOF)463 putc(c, dst);464465 if (ferror(src))466 return -1;467468 return 0;469}470471void472writecoff(char *fname)473{474 FILE *fp;475476 if ((fp = fopen(fname, "wb")) == NULL)477 goto error;478479 if (writeobj(obj, map, fp) < 0) {480 fputs("as: corrupted object type\n", stderr);481 goto error;482 }483484 if (fclose(fp) == EOF)485 goto error;486 outfile = NULL;487 return;488489error:490 fprintf(stderr, "as: %s: error writing output file\n", fname);491 if (errno)492 perror("as");493 exit(EXIT_FAILURE);494}495496void497writeout(char *fname)498{499 FILE *fp;500 struct lsection *lp;501502 if ((fp = fopen(fname, "wb")) == NULL)503 goto error;504505506 for (lp = seclist; lp; lp = lp->next) {507 if (dumpsec(lp->fp, fp) < 0)508 goto error;509 }510 fflush(fp);511512 if (ferror(fp))513 goto error;514515 fclose(fp);516 outfile = NULL;517518 return;519520error:521 fprintf(stderr, "as: %s: %s\n", fname, strerror(errno));522 exit(EXIT_FAILURE);523}