static void dbgls_deflabel(char *name, int32_t segment, int64_t offset, int is_global, char *special) { struct ieeeSection *seg; /* Keep compiler from warning about special */ (void)special; /* * If it's a special-retry from pass two, discard it. */ if (is_global == 3) return; /* * First check for the double-period, signifying something * unusual. */ if (name[0] == '.' && name[1] == '.' && name[2] != '@') { return; } /* * Case (i): */ if (ieee_seg_needs_update) return; if (segment < SEG_ABS && segment != NO_SEG && segment % 2) return; if (segment >= SEG_ABS || segment == NO_SEG) { return; } /* * If `any_segs' is still false, we might need to define a * default segment, if they're trying to declare a label in * `first_seg'. But the label should exist due to a prior * call to ieee_deflabel so we can skip that. */ for (seg = seghead; seg; seg = seg->next) if (seg->index == segment) { struct ieeePublic *loc; /* * Case (ii). Maybe MODPUB someday? */ if (!is_global) { last_defined = loc = nasm_malloc(sizeof(*loc)); *seg->loctail = loc; seg->loctail = &loc->next; loc->next = NULL; loc->name = nasm_strdup(name); loc->offset = offset; loc->segment = -1; loc->index = seg->ieee_index; } } }
static memorybuffer * newmembuf(void){ memorybuffer * t; t = nasm_malloc(sizeof(memorybuffer)); t->length = 0; t->next = NULL; return t; }
void stabs_linenum(const char *filename, long linenumber, long segto) { if (!stabs_filename) { stabs_filename = (char *)nasm_malloc(strlen(filename) + 1); strcpy(stabs_filename, filename); } else { if (strcmp(stabs_filename, filename)) { /* yep, a memory leak...this program is one-shot anyway, so who cares... in fact, this leak comes in quite handy to maintain a list of files encountered so far in the symbol lines... */ /* why not nasm_free(stabs_filename); we're done with the old one */ stabs_filename = (char *)nasm_malloc(strlen(filename) + 1); strcpy(stabs_filename, filename); } } stabs_immcall = 1; currentline = linenumber; }
int init_labels(void) { hash_init(<ab, HASH_LARGE); ldata = lfree = nasm_malloc(LBLK_SIZE); init_block(lfree); perm_head = perm_tail = nasm_malloc(sizeof(struct permts)); perm_head->next = NULL; perm_head->size = PERMTS_SIZE; perm_head->usage = 0; prevlabel = ""; initialized = true; return 0; }
struct SAA *saa_init(size_t elem_len) { struct SAA *s; char *data; s = nasm_zalloc(sizeof(struct SAA)); if (elem_len >= SAA_BLKLEN) s->blk_len = elem_len; else s->blk_len = SAA_BLKLEN - (SAA_BLKLEN % elem_len); s->elem_len = elem_len; s->length = s->blk_len; data = nasm_malloc(s->blk_len); s->nblkptrs = s->nblks = 1; s->blk_ptrs = nasm_malloc(sizeof(char *)); s->blk_ptrs[0] = data; s->wblk = s->rblk = &s->blk_ptrs[0]; return s; }
/* * Internal routine: finds the `union label' corresponding to the * given label name. Creates a new one, if it isn't found, and if * `create' is TRUE. */ static union label *find_label(char *label, int create) { int hash = 0; char *p, *prev; int prevlen; union label *lptr; if (islocal(label)) prev = prevlabel; else prev = ""; prevlen = strlen(prev); p = prev; while (*p) hash += *p++; p = label; while (*p) hash += *p++; hash %= LABEL_HASHES; lptr = ltab[hash]; while (lptr->admin.movingon != END_LIST) { if (lptr->admin.movingon == END_BLOCK) { lptr = lptr->admin.next; if (!lptr) break; } if (!strncmp(lptr->defn.label, prev, prevlen) && !strcmp(lptr->defn.label + prevlen, label)) return lptr; lptr++; } if (create) { if (lfree[hash]->admin.movingon == END_BLOCK) { /* * must allocate a new block */ lfree[hash]->admin.next = (union label *)nasm_malloc(LBLK_SIZE); lfree[hash] = lfree[hash]->admin.next; init_block(lfree[hash]); } lfree[hash]->admin.movingon = BOGUS_VALUE; lfree[hash]->defn.label = perm_copy(prev, label); lfree[hash]->defn.special = NULL; lfree[hash]->defn.is_global = NOT_DEFINED_YET; return lfree[hash]++; } else return NULL; }
/* * Internal routine: finds the `union label' corresponding to the * given label name. Creates a new one, if it isn't found, and if * `create' is true. */ static union label *find_label(char *label, int create) { char *prev; int prevlen, len; union label *lptr, **lpp; char label_str[IDLEN_MAX]; struct hash_insert ip; if (islocal(label)) { prev = prevlabel; prevlen = strlen(prev); len = strlen(label); if (prevlen + len >= IDLEN_MAX) { nasm_error(ERR_NONFATAL, "identifier length exceed %i bytes", IDLEN_MAX); return NULL; } memcpy(label_str, prev, prevlen); memcpy(label_str+prevlen, label, len+1); label = label_str; } else { prev = ""; prevlen = 0; } lpp = (union label **) hash_find(<ab, label, &ip); lptr = lpp ? *lpp : NULL; if (lptr || !create) return lptr; /* Create a new label... */ if (lfree->admin.movingon == END_BLOCK) { /* * must allocate a new block */ lfree->admin.next = (union label *)nasm_malloc(LBLK_SIZE); lfree = lfree->admin.next; init_block(lfree); } lfree->admin.movingon = BOGUS_VALUE; lfree->defn.label = perm_copy(label); lfree->defn.special = NULL; lfree->defn.is_global = NOT_DEFINED_YET; hash_add(&ip, lfree->defn.label, lfree); return lfree++; }
static void ieee_install_fixup(struct ieeeSection *seg, struct ieeeFixupp *fix) { struct ieeeFixupp *f; f = nasm_malloc(sizeof(struct ieeeFixupp)); memcpy(f, fix, sizeof(struct ieeeFixupp)); f->offset = seg->currentpos; seg->currentpos += fix->size; f->next = NULL; if (seg->fptr) seg->flptr = seg->flptr->next = f; else seg->fptr = seg->flptr = f; }
static char * safe_alloc perm_alloc(size_t len) { char *p; if (perm_tail->size - perm_tail->usage < len) { size_t alloc_len = (len > PERMTS_SIZE) ? len : PERMTS_SIZE; perm_tail->next = nasm_malloc(PERMTS_HEADER + alloc_len); perm_tail = perm_tail->next; perm_tail->next = NULL; perm_tail->size = alloc_len; perm_tail->usage = 0; } p = perm_tail->data + perm_tail->usage; perm_tail->usage += len; return p; }
static void descend_tree_add(struct segtabnode **node, int localseg, int destseg, int32_t offset) { struct segtabnode *n; if (*node == NULL) { *node = nasm_malloc(sizeof(**node)); if (!*node) { fprintf(stderr, "segment table: out of memory\n"); exit(1); } (*node)->localseg = localseg; (*node)->offset = offset; (*node)->left = NULL; (*node)->leftcount = 0; (*node)->right = NULL; (*node)->rightcount = 0; (*node)->destseg = destseg; return; } if (localseg < (*node)->localseg) { (*node)->leftcount++; descend_tree_add(&(*node)->left, localseg, destseg, offset); if ((*node)->leftcount > (*node)->rightcount + 2) { n = *node; *node = n->left; n->left = (*node)->right; n->leftcount = (*node)->rightcount; (*node)->right = n; (*node)->rightcount = n->leftcount + n->rightcount + 1; } } else { (*node)->rightcount++; descend_tree_add(&(*node)->right, localseg, destseg, offset); if ((*node)->rightcount > (*node)->leftcount + 2) { n = *node; *node = n->right; n->right = (*node)->left; n->rightcount = (*node)->leftcount; (*node)->left = n; (*node)->leftcount = n->leftcount + n->rightcount + 1; } } }
static char *stdscan_copy(char *p, int len) { char *text; text = nasm_malloc(len + 1); memcpy(text, p, len); text[len] = '\0'; if (stdscan_templen >= stdscan_tempsize) { stdscan_tempsize += STDSCAN_TEMP_DELTA; stdscan_tempstorage = nasm_realloc(stdscan_tempstorage, stdscan_tempsize * sizeof(char *)); } stdscan_tempstorage[stdscan_templen++] = text; return text; }
static void list_init(char *fname, efunc error) { listfp = fopen(fname, "w"); if (!listfp) { error(ERR_NONFATAL, "unable to open listing file `%s'", fname); return; } *listline = '\0'; listlineno = 0; listp = TRUE; listlevel = 0; suppress = 0; mistack = nasm_malloc(sizeof(MacroInhibit)); mistack->next = NULL; mistack->level = 0; mistack->inhibiting = TRUE; }
static char *perm_copy (char *string1, char *string2) { char *p, *q; int len = strlen(string1)+strlen(string2)+1; if (perm_tail->size - perm_tail->usage < len) { perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts)); perm_tail = perm_tail->next; perm_tail->next = NULL; perm_tail->size = PERMTS_SIZE; perm_tail->usage = 0; } p = q = perm_tail->data + perm_tail->usage; while ( (*q = *string1++) ) q++; while ( (*q++ = *string2++) ); perm_tail->usage = q - perm_tail->data; return p; }
static void dbgls_typevalue(int32_t type) { int elem = TYM_ELEMENTS(type); type = TYM_TYPE(type); if (!last_defined) return; switch (type) { case TY_BYTE: last_defined->type = 1; /* uint8_t */ break; case TY_WORD: last_defined->type = 3; /* unsigned word */ break; case TY_DWORD: last_defined->type = 5; /* unsigned dword */ break; case TY_FLOAT: last_defined->type = 9; /* float */ break; case TY_QWORD: last_defined->type = 10; /* qword */ break; case TY_TBYTE: last_defined->type = 11; /* TBYTE */ break; default: last_defined->type = 0x10; /* near label */ break; } if (elem > 1) { struct Array *arrtmp = nasm_malloc(sizeof(*arrtmp)); int vtype = last_defined->type; arrtmp->size = elem; arrtmp->basetype = vtype; arrtmp->next = NULL; last_defined->type = arrindex++ + 0x100; *arrtail = arrtmp; arrtail = &(arrtmp->next); } last_defined = NULL; }
/* Add one allocation block to an SAA */ static void saa_extend(struct SAA *s) { size_t blkn = s->nblks++; if (blkn >= s->nblkptrs) { size_t rindex = s->rblk - s->blk_ptrs; size_t windex = s->wblk - s->blk_ptrs; s->nblkptrs <<= 1; s->blk_ptrs = nasm_realloc(s->blk_ptrs, s->nblkptrs * sizeof(char *)); s->rblk = s->blk_ptrs + rindex; s->wblk = s->blk_ptrs + windex; } s->blk_ptrs[blkn] = nasm_malloc(s->blk_len); s->length += s->blk_len; }
/* * Internal routine: finds the `union label' corresponding to the * given label name. Creates a new one, if it isn't found, and if * `create' is true. */ static union label *find_label(const char *label, bool create, bool *created) { union label *lptr, **lpp; char *label_str = NULL; struct hash_insert ip; nasm_assert(label != NULL); if (islocal(label)) label = label_str = nasm_strcat(prevlabel, label); lpp = (union label **) hash_find(<ab, label, &ip); lptr = lpp ? *lpp : NULL; if (lptr || !create) { if (created) *created = false; return lptr; } /* Create a new label... */ if (lfree->admin.movingon == END_BLOCK) { /* * must allocate a new block */ lfree->admin.next = nasm_malloc(LBLK_SIZE); lfree = lfree->admin.next; init_block(lfree); } if (created) *created = true; nasm_zero(*lfree); lfree->defn.label = perm_copy(label); lfree->defn.subsection = NO_SEG; if (label_str) nasm_free(label_str); hash_add(&ip, lfree->defn.label, lfree); return lfree++; }
static void nop_reset(char *file, int pass, ListGen *listgen, StrList **deplist) { src_set_fname(nasm_strdup(file)); src_set_linnum(0); nop_lineinc = 1; nop_fp = fopen(file, "r"); if (!nop_fp) nasm_error(ERR_FATAL | ERR_NOFILE, "unable to open input file `%s'", file); nop_list = listgen; (void)pass; /* placate compilers */ if (deplist) { StrList *sl = nasm_malloc(strlen(file)+1+sizeof sl->next); sl->next = NULL; strcpy(sl->str, file); *deplist = sl; } }
static void aout_add_reloc (struct Section *sect, long segment, int reltype, int bytes) { struct Reloc *r; r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); sect->tail = &r->next; r->next = NULL; r->address = sect->len; r->symbol = (segment == NO_SEG ? -SECT_ABS : segment == stext.index ? -SECT_TEXT : segment == sdata.index ? -SECT_DATA : segment == sbss.index ? -SECT_BSS : raa_read(bsym, segment)); r->reltype = reltype; if (r->symbol >= 0) r->reltype |= RELTYPE_SYMFLAG; r->bytes = bytes; sect->nrelocs++; }
static char *perm_copy(const char *string) { char *p; int len = strlen(string)+1; nasm_assert(len <= PERMTS_SIZE); if (perm_tail->size - perm_tail->usage < len) { perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts)); perm_tail = perm_tail->next; perm_tail->next = NULL; perm_tail->size = PERMTS_SIZE; perm_tail->usage = 0; } p = perm_tail->data + perm_tail->usage; memcpy(p, string, len); perm_tail->usage += len; return p; }
static long coff_add_reloc (struct Section *sect, long segment, int relative) { struct Reloc *r; r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); sect->tail = &r->next; r->next = NULL; r->address = sect->len; if (segment == NO_SEG) r->symbol = 0, r->symbase = ABS_SYMBOL; else { int i; r->symbase = REAL_SYMBOLS; for (i=0; i<nsects; i++) if (segment == sects[i]->index) { r->symbol = i*2; r->symbase = SECT_SYMBOLS; break; } if (r->symbase == REAL_SYMBOLS) r->symbol = raa_read (bsym, segment); } r->relative = relative; sect->nrelocs++; /* * Return the fixup for standard COFF common variables. */ if (r->symbase == REAL_SYMBOLS && !win32) return raa_read (symval, segment); else return 0; }
static void elf_add_reloc(struct Section *sect, long segment, int type) { struct Reloc *r; r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); sect->tail = &r->next; r->next = NULL; r->address = sect->len; if (segment == NO_SEG) r->symbol = 2; else { int i; r->symbol = 0; for (i = 0; i < nsects; i++) if (segment == sects[i]->index) r->symbol = i + 3; if (!r->symbol) r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment); } r->type = type; sect->nrelocs++; }
/* * segment registry */ static int32_t ieee_segment(char *name, int pass, int *bits) { /* * We call the label manager here to define a name for the new * segment, and when our _own_ label-definition stub gets * called in return, it should register the new segment name * using the pointer it gets passed. That way we save memory, * by sponging off the label manager. */ if (!name) { *bits = 16; if (!any_segs) return 0; return seghead->index; } else { struct ieeeSection *seg; int ieee_idx, attrs; bool rn_error; char *p; /* * Look for segment attributes. */ attrs = 0; while (*name == '.') name++; /* hack, but a documented one */ p = name; while (*p && !nasm_isspace(*p)) p++; if (*p) { *p++ = '\0'; while (*p && nasm_isspace(*p)) *p++ = '\0'; } while (*p) { while (*p && !nasm_isspace(*p)) p++; if (*p) { *p++ = '\0'; while (*p && nasm_isspace(*p)) *p++ = '\0'; } attrs++; } ieee_idx = 1; for (seg = seghead; seg; seg = seg->next) { ieee_idx++; if (!strcmp(seg->name, name)) { if (attrs > 0 && pass == 1) nasm_error(ERR_WARNING, "segment attributes specified on" " redeclaration of segment: ignoring"); if (seg->use32) *bits = 32; else *bits = 16; return seg->index; } } *segtail = seg = nasm_malloc(sizeof(*seg)); seg->next = NULL; segtail = &seg->next; seg->index = seg_alloc(); seg->ieee_index = ieee_idx; any_segs = true; seg->name = NULL; seg->currentpos = 0; seg->align = 1; /* default */ seg->use32 = *bits == 32; /* default to user spec */ seg->combine = CMB_PUBLIC; /* default */ seg->pubhead = NULL; seg->pubtail = &seg->pubhead; seg->data = NULL; seg->fptr = NULL; seg->lochead = NULL; seg->loctail = &seg->lochead; /* * Process the segment attributes. */ p = name; while (attrs--) { p += strlen(p); while (!*p) p++; /* * `p' contains a segment attribute. */ if (!nasm_stricmp(p, "private")) seg->combine = CMB_PRIVATE; else if (!nasm_stricmp(p, "public")) seg->combine = CMB_PUBLIC; else if (!nasm_stricmp(p, "common")) seg->combine = CMB_COMMON; else if (!nasm_stricmp(p, "use16")) seg->use32 = false; else if (!nasm_stricmp(p, "use32")) seg->use32 = true; else if (!nasm_strnicmp(p, "align=", 6)) { seg->align = readnum(p + 6, &rn_error); if (seg->align == 0) seg->align = 1; if (rn_error) { seg->align = 1; nasm_error(ERR_NONFATAL, "segment alignment should be" " numeric"); } switch ((int)seg->align) { case 1: /* BYTE */ case 2: /* WORD */ case 4: /* DWORD */ case 16: /* PARA */ case 256: /* PAGE */ case 8: case 32: case 64: case 128: break; default: nasm_error(ERR_NONFATAL, "invalid alignment value %d", seg->align); seg->align = 1; break; } } else if (!nasm_strnicmp(p, "absolute=", 9)) { seg->align = SEG_ABS + readnum(p + 9, &rn_error); if (rn_error) nasm_error(ERR_NONFATAL, "argument to `absolute' segment" " attribute should be numeric"); } } ieee_seg_needs_update = seg; if (seg->align >= SEG_ABS) define_label(name, NO_SEG, seg->align - SEG_ABS, NULL, false, false); else define_label(name, seg->index + 1, 0L, NULL, false, false); ieee_seg_needs_update = NULL; if (seg->use32) *bits = 32; else *bits = 16; return seg->index; } }
insn *parse_line (int pass, char *buffer, insn *result, efunc errfunc, evalfunc evaluate, evalinfofunc einfo) { int operand; int critical; struct eval_hints hints; result->forw_ref = FALSE; error = errfunc; einfo ("", 0L, 0L); stdscan_reset(); stdscan_bufptr = buffer; i = stdscan(NULL, &tokval); result->eops = NULL; /* must do this, whatever happens */ result->operands = 0; /* must initialise this */ if (i==0) { /* blank line - ignore */ result->label = NULL; /* so, no label on it */ result->opcode = -1; /* and no instruction either */ return result; } if (i != TOKEN_ID && i != TOKEN_INSN && i != TOKEN_PREFIX && (i!=TOKEN_REG || (REG_SREG & ~reg_flags[tokval.t_integer]))) { error (ERR_NONFATAL, "label or instruction expected" " at start of line"); result->label = NULL; result->opcode = -1; return result; } if (i == TOKEN_ID) { /* there's a label here */ result->label = tokval.t_charptr; einfo (result->label, 0L, 0L); i = stdscan(NULL, &tokval); if (i == ':') { /* skip over the optional colon */ i = stdscan(NULL, &tokval); } else if (i == 0 && pass == 1) { error (ERR_WARNING|ERR_WARN_OL, "label alone on a line without a colon might be in error"); } } else /* no label; so, moving swiftly on */ result->label = NULL; if (i==0) { result->opcode = -1; /* this line contains just a label */ return result; } result->nprefix = 0; result->times = 1L; while (i == TOKEN_PREFIX || (i==TOKEN_REG && !(REG_SREG & ~reg_flags[tokval.t_integer]))) { /* * Handle special case: the TIMES prefix. */ if (i == TOKEN_PREFIX && tokval.t_integer == P_TIMES) { expr *value; i = stdscan(NULL, &tokval); value = evaluate (stdscan, NULL, &tokval, NULL, pass, error, NULL); i = tokval.t_type; if (!value) { /* but, error in evaluator */ result->opcode = -1; /* unrecoverable parse error: */ return result; /* ignore this instruction */ } if (!is_simple (value)) { error (ERR_NONFATAL, "non-constant argument supplied to TIMES"); result->times = 1L; } else { result->times = value->value; if (value->value < 0) error(ERR_NONFATAL, "TIMES value %d is negative", value->value); } } else { if (result->nprefix == MAXPREFIX) error (ERR_NONFATAL, "instruction has more than %d prefixes", MAXPREFIX); else result->prefixes[result->nprefix++] = tokval.t_integer; i = stdscan(NULL, &tokval); } } if (i != TOKEN_INSN) { if (result->nprefix > 0 && i == 0) { /* * Instruction prefixes are present, but no actual * instruction. This is allowed: at this point we * invent a notional instruction of RESB 0. */ result->opcode = I_RESB; result->operands = 1; result->oprs[0].type = IMMEDIATE; result->oprs[0].offset = 0L; result->oprs[0].segment = result->oprs[0].wrt = NO_SEG; return result; } else { error (ERR_NONFATAL, "parser: instruction expected"); result->opcode = -1; return result; } } result->opcode = tokval.t_integer; result->condition = tokval.t_inttwo; /* * RESB, RESW and RESD cannot be satisfied with incorrectly * evaluated operands, since the correct values _must_ be known * on the first pass. Hence, even in pass one, we set the * `critical' flag on calling evaluate(), so that it will bomb * out on undefined symbols. Nasty, but there's nothing we can * do about it. * * For the moment, EQU has the same difficulty, so we'll * include that. */ if (result->opcode == I_RESB || result->opcode == I_RESW || result->opcode == I_RESD || result->opcode == I_RESQ || result->opcode == I_REST || result->opcode == I_EQU) critical = pass; else critical = (pass==2 ? 2 : 0); if (result->opcode == I_DB || result->opcode == I_DW || result->opcode == I_DD || result->opcode == I_DQ || result->opcode == I_DT || result->opcode == I_INCBIN) { extop *eop, **tail = &result->eops, **fixptr; int oper_num = 0; /* * Begin to read the DB/DW/DD/DQ/DT operands. */ while (1) { i = stdscan(NULL, &tokval); if (i == 0) break; fixptr = tail; eop = *tail = nasm_malloc(sizeof(extop)); tail = &eop->next; eop->next = NULL; eop->type = EOT_NOTHING; oper_num++; if (i == TOKEN_NUM && tokval.t_charptr && is_comma_next()) { eop->type = EOT_DB_STRING; eop->stringval = tokval.t_charptr; eop->stringlen = tokval.t_inttwo; i = stdscan(NULL, &tokval); /* eat the comma */ continue; } if (i == TOKEN_FLOAT || i == '-') { long sign = +1L; if (i == '-') { char *save = stdscan_bufptr; i = stdscan(NULL, &tokval); sign = -1L; if (i != TOKEN_FLOAT) { stdscan_bufptr = save; i = tokval.t_type = '-'; } } if (i == TOKEN_FLOAT) { eop->type = EOT_DB_STRING; if (result->opcode == I_DD) eop->stringlen = 4; else if (result->opcode == I_DQ) eop->stringlen = 8; else if (result->opcode == I_DT) eop->stringlen = 10; else { error(ERR_NONFATAL, "floating-point constant" " encountered in `D%c' instruction", result->opcode == I_DW ? 'W' : 'B'); eop->type = EOT_NOTHING; } eop = nasm_realloc(eop, sizeof(extop)+eop->stringlen); tail = &eop->next; *fixptr = eop; eop->stringval = (char *)eop + sizeof(extop); if (!float_const (tokval.t_charptr, sign, (unsigned char *)eop->stringval, eop->stringlen, error)) eop->type = EOT_NOTHING; i = stdscan(NULL, &tokval); /* eat the comma */ continue; } } /* anything else */ { expr *value; value = evaluate (stdscan, NULL, &tokval, NULL, critical, error, NULL); i = tokval.t_type; if (!value) { /* error in evaluator */ result->opcode = -1;/* unrecoverable parse error: */ return result; /* ignore this instruction */ } if (is_unknown(value)) { eop->type = EOT_DB_NUMBER; eop->offset = 0; /* doesn't matter what we put */ eop->segment = eop->wrt = NO_SEG; /* likewise */ } else if (is_reloc(value)) { eop->type = EOT_DB_NUMBER; eop->offset = reloc_value(value); eop->segment = reloc_seg(value); eop->wrt = reloc_wrt(value); } else { error (ERR_NONFATAL, "operand %d: expression is not simple" " or relocatable", oper_num); } } /* * We're about to call stdscan(), which will eat the * comma that we're currently sitting on between * arguments. However, we'd better check first that it * _is_ a comma. */ if (i == 0) /* also could be EOL */ break; if (i != ',') { error (ERR_NONFATAL, "comma expected after operand %d", oper_num); result->opcode = -1;/* unrecoverable parse error: */ return result; /* ignore this instruction */ } } if (result->opcode == I_INCBIN) { /* * Correct syntax for INCBIN is that there should be * one string operand, followed by one or two numeric * operands. */ if (!result->eops || result->eops->type != EOT_DB_STRING) error (ERR_NONFATAL, "`incbin' expects a file name"); else if (result->eops->next && result->eops->next->type != EOT_DB_NUMBER) error (ERR_NONFATAL, "`incbin': second parameter is", " non-numeric"); else if (result->eops->next && result->eops->next->next && result->eops->next->next->type != EOT_DB_NUMBER) error (ERR_NONFATAL, "`incbin': third parameter is", " non-numeric"); else if (result->eops->next && result->eops->next->next && result->eops->next->next->next) error (ERR_NONFATAL, "`incbin': more than three parameters"); else return result; /* * If we reach here, one of the above errors happened. * Throw the instruction away. */ result->opcode = -1; return result; } return result; } /* right. Now we begin to parse the operands. There may be up to three * of these, separated by commas, and terminated by a zero token. */ for (operand = 0; operand < 3; operand++) { expr *value; /* used most of the time */ int mref; /* is this going to be a memory ref? */ int bracket; /* is it a [] mref, or a & mref? */ result->oprs[operand].addr_size = 0;/* have to zero this whatever */ result->oprs[operand].eaflags = 0; /* and this */ i = stdscan(NULL, &tokval); if (i == 0) break; /* end of operands: get out of here */ result->oprs[operand].type = 0; /* so far, no override */ while (i == TOKEN_SPECIAL) {/* size specifiers */ switch ((int)tokval.t_integer) { case S_BYTE: result->oprs[operand].type |= BITS8; break; case S_WORD: result->oprs[operand].type |= BITS16; break; case S_DWORD: case S_LONG: result->oprs[operand].type |= BITS32; break; case S_QWORD: result->oprs[operand].type |= BITS64; break; case S_TWORD: result->oprs[operand].type |= BITS80; break; case S_TO: result->oprs[operand].type |= TO; break; case S_FAR: result->oprs[operand].type |= FAR; break; case S_NEAR: result->oprs[operand].type |= NEAR; break; case S_SHORT: result->oprs[operand].type |= SHORT; break; } i = stdscan(NULL, &tokval); } if (i == '[' || i == '&') { /* memory reference */ mref = TRUE; bracket = (i == '['); i = stdscan(NULL, &tokval); if (i == TOKEN_SPECIAL) { /* check for address size override */ switch ((int)tokval.t_integer) { case S_NOSPLIT: result->oprs[operand].eaflags |= EAF_TIMESTWO; break; case S_BYTE: result->oprs[operand].eaflags |= EAF_BYTEOFFS; break; case S_WORD: result->oprs[operand].addr_size = 16; result->oprs[operand].eaflags |= EAF_WORDOFFS; break; case S_DWORD: case S_LONG: result->oprs[operand].addr_size = 32; result->oprs[operand].eaflags |= EAF_WORDOFFS; break; default: error (ERR_NONFATAL, "invalid size specification in" " effective address"); } i = stdscan(NULL, &tokval); } } else { /* immediate operand, or register */ mref = FALSE; bracket = FALSE; /* placate optimisers */ } value = evaluate (stdscan, NULL, &tokval, &result->forw_ref, critical, error, &hints); i = tokval.t_type; if (!value) { /* error in evaluator */ result->opcode = -1; /* unrecoverable parse error: */ return result; /* ignore this instruction */ } if (i == ':' && mref) { /* it was seg:offset */ /* * Process the segment override. */ if (value[1].type!=0 || value->value!=1 || REG_SREG & ~reg_flags[value->type]) error (ERR_NONFATAL, "invalid segment override"); else if (result->nprefix == MAXPREFIX) error (ERR_NONFATAL, "instruction has more than %d prefixes", MAXPREFIX); else result->prefixes[result->nprefix++] = value->type; i = stdscan(NULL, &tokval); /* then skip the colon */ if (i == TOKEN_SPECIAL) { /* another check for size override */ switch ((int)tokval.t_integer) { case S_WORD: result->oprs[operand].addr_size = 16; break; case S_DWORD: case S_LONG: result->oprs[operand].addr_size = 32; break; default: error (ERR_NONFATAL, "invalid size specification in" " effective address"); } i = stdscan(NULL, &tokval); } value = evaluate (stdscan, NULL, &tokval, &result->forw_ref, critical, error, &hints); i = tokval.t_type; /* and get the offset */ if (!value) { /* but, error in evaluator */ result->opcode = -1; /* unrecoverable parse error: */ return result; /* ignore this instruction */ } } if (mref && bracket) { /* find ] at the end */ if (i != ']') { error (ERR_NONFATAL, "parser: expecting ]"); do { /* error recovery again */ i = stdscan(NULL, &tokval); } while (i != 0 && i != ','); } else /* we got the required ] */ i = stdscan(NULL, &tokval); } else { /* immediate operand */ if (i != 0 && i != ',' && i != ':') { error (ERR_NONFATAL, "comma or end of line expected"); do { /* error recovery */ i = stdscan(NULL, &tokval); } while (i != 0 && i != ','); } else if (i == ':') { result->oprs[operand].type |= COLON; } } /* now convert the exprs returned from evaluate() into operand * descriptions... */ if (mref) { /* it's a memory reference */ expr *e = value; int b, i, s; /* basereg, indexreg, scale */ long o; /* offset */ b = i = -1, o = s = 0; result->oprs[operand].hintbase = hints.base; result->oprs[operand].hinttype = hints.type; if (e->type <= EXPR_REG_END) { /* this bit's a register */ if (e->value == 1) /* in fact it can be basereg */ b = e->type; else /* no, it has to be indexreg */ i = e->type, s = e->value; e++; } if (e->type && e->type <= EXPR_REG_END) {/* it's a 2nd register */ if (e->value != 1) { /* it has to be indexreg */ if (i != -1) { /* but it can't be */ error(ERR_NONFATAL, "invalid effective address"); result->opcode = -1; return result; } else i = e->type, s = e->value; } else { /* it can be basereg */ if (b != -1) /* or can it? */ i = e->type, s = 1; else b = e->type; } e++; } if (e->type != 0) { /* is there an offset? */ if (e->type <= EXPR_REG_END) {/* in fact, is there an error? */ error (ERR_NONFATAL, "invalid effective address"); result->opcode = -1; return result; } else { if (e->type == EXPR_UNKNOWN) { o = 0; /* doesn't matter what */ result->oprs[operand].wrt = NO_SEG; /* nor this */ result->oprs[operand].segment = NO_SEG; /* or this */ while (e->type) e++; /* go to the end of the line */ } else { if (e->type == EXPR_SIMPLE) { o = e->value; e++; } if (e->type == EXPR_WRT) { result->oprs[operand].wrt = e->value; e++; } else result->oprs[operand].wrt = NO_SEG; /* * Look for a segment base type. */ if (e->type && e->type < EXPR_SEGBASE) { error (ERR_NONFATAL, "invalid effective address"); result->opcode = -1; return result; } while (e->type && e->value == 0) e++; if (e->type && e->value != 1) { error (ERR_NONFATAL, "invalid effective address"); result->opcode = -1; return result; } if (e->type) { result->oprs[operand].segment = e->type - EXPR_SEGBASE; e++; } else result->oprs[operand].segment = NO_SEG; while (e->type && e->value == 0) e++; if (e->type) { error (ERR_NONFATAL, "invalid effective address"); result->opcode = -1; return result; } } } } else { o = 0; result->oprs[operand].wrt = NO_SEG; result->oprs[operand].segment = NO_SEG; } if (e->type != 0) { /* there'd better be nothing left! */ error (ERR_NONFATAL, "invalid effective address"); result->opcode = -1; return result; } result->oprs[operand].type |= MEMORY; if (b==-1 && (i==-1 || s==0)) result->oprs[operand].type |= MEM_OFFS; result->oprs[operand].basereg = b; result->oprs[operand].indexreg = i; result->oprs[operand].scale = s; result->oprs[operand].offset = o; } else { /* it's not a memory reference */ if (is_just_unknown(value)) { /* it's immediate but unknown */ result->oprs[operand].type |= IMMEDIATE; result->oprs[operand].offset = 0; /* don't care */ result->oprs[operand].segment = NO_SEG; /* don't care again */ result->oprs[operand].wrt = NO_SEG;/* still don't care */ } else if (is_reloc(value)) { /* it's immediate */ result->oprs[operand].type |= IMMEDIATE; result->oprs[operand].offset = reloc_value(value); result->oprs[operand].segment = reloc_seg(value); result->oprs[operand].wrt = reloc_wrt(value); if (is_simple(value) && reloc_value(value)==1) result->oprs[operand].type |= UNITY; } else { /* it's a register */ if (value->type>=EXPR_SIMPLE || value->value!=1) { error (ERR_NONFATAL, "invalid operand type"); result->opcode = -1; return result; } /* clear overrides, except TO which applies to FPU regs */ result->oprs[operand].type &= TO; result->oprs[operand].type |= REGISTER; result->oprs[operand].type |= reg_flags[value->type]; result->oprs[operand].basereg = value->type; } } } result->operands = operand; /* set operand count */ while (operand<3) /* clear remaining operands */ result->oprs[operand++].type = 0; /* * Transform RESW, RESD, RESQ, REST into RESB. */ switch (result->opcode) { case I_RESW: result->opcode=I_RESB; result->oprs[0].offset*=2; break; case I_RESD: result->opcode=I_RESB; result->oprs[0].offset*=4; break; case I_RESQ: result->opcode=I_RESB; result->oprs[0].offset*=8; break; case I_REST: result->opcode=I_RESB; result->oprs[0].offset*=10; break; } return result; }
/* * callback for labels */ static void ieee_deflabel(char *name, int32_t segment, int64_t offset, int is_global, char *special) { /* * We have three cases: * * (i) `segment' is a segment-base. If so, set the name field * for the segment structure it refers to, and then * return. * * (ii) `segment' is one of our segments, or a SEG_ABS segment. * Save the label position for later output of a PUBDEF record. * * * (iii) `segment' is not one of our segments. Save the label * position for later output of an EXTDEF. */ struct ieeeExternal *ext; struct ExtBack *eb; struct ieeeSection *seg; int i; if (special) { nasm_error(ERR_NONFATAL, "unrecognised symbol type `%s'", special); } /* * First check for the double-period, signifying something * unusual. */ if (name[0] == '.' && name[1] == '.') { if (!strcmp(name, "..start")) { ieee_entry_seg = segment; ieee_entry_ofs = offset; } return; } /* * Case (i): */ if (ieee_seg_needs_update) { ieee_seg_needs_update->name = name; return; } if (segment < SEG_ABS && segment != NO_SEG && segment % 2) return; /* * case (ii) */ if (segment >= SEG_ABS) { /* * SEG_ABS subcase of (ii). */ if (is_global) { struct ieeePublic *pub; pub = *fpubtail = nasm_malloc(sizeof(*pub)); fpubtail = &pub->next; pub->next = NULL; pub->name = name; pub->offset = offset; pub->segment = segment & ~SEG_ABS; } return; } for (seg = seghead; seg && is_global; seg = seg->next) if (seg->index == segment) { struct ieeePublic *pub; last_defined = pub = *seg->pubtail = nasm_malloc(sizeof(*pub)); seg->pubtail = &pub->next; pub->next = NULL; pub->name = name; pub->offset = offset; pub->index = seg->ieee_index; pub->segment = -1; return; } /* * Case (iii). */ if (is_global) { ext = *exttail = nasm_malloc(sizeof(*ext)); ext->next = NULL; exttail = &ext->next; ext->name = name; if (is_global == 2) ext->commonsize = offset; else ext->commonsize = 0; i = segment / 2; eb = ebhead; if (!eb) { eb = *ebtail = nasm_malloc(sizeof(*eb)); eb->next = NULL; ebtail = &eb->next; } while (i > EXT_BLKSIZ) { if (eb && eb->next) eb = eb->next; else { eb = *ebtail = nasm_malloc(sizeof(*eb)); eb->next = NULL; ebtail = &eb->next; } i -= EXT_BLKSIZ; } eb->index[i] = externals++; } }
insn *parse_line(char *buffer, insn *result) { int pass = 1; /* This used to be an argument. it's hardcoded now because we always want it as 1 */ bool insn_is_label = false; struct eval_hints hints; int operand; int critical; bool first; bool recover; int j; restart_parse: first = true; result->forw_ref = false; stdscan_reset(); stdscan_set(buffer); i = stdscan(NULL, &tokval); result->label = NULL; /* Assume no label */ result->eops = NULL; /* must do this, whatever happens */ result->operands = 0; /* must initialize this */ /* Ignore blank lines */ if (i == TOKEN_EOS) { result->opcode = I_none; return result; } if (i != TOKEN_ID && i != TOKEN_INSN && i != TOKEN_PREFIX && (i != TOKEN_REG || !IS_SREG(tokval.t_integer))) { nasm_error(ERR_NONFATAL, "label or instruction expected at start of line"); result->opcode = I_none; return result; } if (i == TOKEN_ID || (insn_is_label && i == TOKEN_INSN)) { /* there's a label here */ first = false; result->label = tokval.t_charptr; i = stdscan(NULL, &tokval); if (i == ':') { /* skip over the optional colon */ i = stdscan(NULL, &tokval); } else if (i == 0) { nasm_error(ERR_WARNING | ERR_WARN_OL | ERR_PASS1, "label alone on a line without a colon might be in error"); } } /* Just a label here */ if (i == TOKEN_EOS) { result->opcode = I_none; return result; } for (j = 0; j < MAXPREFIX; j++) result->prefixes[j] = P_none; result->times = 1L; while (i == TOKEN_PREFIX || (i == TOKEN_REG && IS_SREG(tokval.t_integer))) { first = false; /* * Handle special case: the TIMES prefix. */ if (i == TOKEN_PREFIX && tokval.t_integer == P_TIMES) { expr *value; i = stdscan(NULL, &tokval); value = evaluate(stdscan, NULL, &tokval, NULL, pass0, nasm_error, NULL); i = tokval.t_type; if (!value) { /* but, error in evaluator */ result->opcode = I_none; /* unrecoverable parse error: */ return result; /* ignore this instruction */ } if (!is_simple(value)) { nasm_error(ERR_NONFATAL, "non-constant argument supplied to TIMES"); result->times = 1L; } else { result->times = value->value; if (value->value < 0 && pass0 == 2) { nasm_error(ERR_NONFATAL, "TIMES value %"PRId64" is negative", value->value); result->times = 0; } } } else { int slot = prefix_slot(tokval.t_integer); if (result->prefixes[slot]) { if (result->prefixes[slot] == tokval.t_integer) nasm_error(ERR_WARNING | ERR_PASS1, "instruction has redundant prefixes"); else nasm_error(ERR_NONFATAL, "instruction has conflicting prefixes"); } result->prefixes[slot] = tokval.t_integer; i = stdscan(NULL, &tokval); } } if (i != TOKEN_INSN) { int j; enum prefixes pfx; for (j = 0; j < MAXPREFIX; j++) { if ((pfx = result->prefixes[j]) != P_none) break; } if (i == 0 && pfx != P_none) { /* * Instruction prefixes are present, but no actual * instruction. This is allowed: at this point we * invent a notional instruction of RESB 0. */ result->opcode = I_RESB; result->operands = 1; result->oprs[0].type = IMMEDIATE; result->oprs[0].offset = 0L; result->oprs[0].segment = result->oprs[0].wrt = NO_SEG; return result; } else { nasm_error(ERR_NONFATAL, "parser: instruction expected"); result->opcode = I_none; return result; } } result->opcode = tokval.t_integer; result->condition = tokval.t_inttwo; /* * INCBIN cannot be satisfied with incorrectly * evaluated operands, since the correct values _must_ be known * on the first pass. Hence, even in pass one, we set the * `critical' flag on calling evaluate(), so that it will bomb * out on undefined symbols. */ if (result->opcode == I_INCBIN) { critical = (pass0 < 2 ? 1 : 2); } else critical = (pass == 2 ? 2 : 0); if (result->opcode == I_DB || result->opcode == I_DW || result->opcode == I_DD || result->opcode == I_DQ || result->opcode == I_DT || result->opcode == I_DO || result->opcode == I_DY || result->opcode == I_INCBIN) { extop *eop, **tail = &result->eops, **fixptr; int oper_num = 0; int32_t sign; result->eops_float = false; /* * Begin to read the DB/DW/DD/DQ/DT/DO/INCBIN operands. */ while (1) { i = stdscan(NULL, &tokval); if (i == TOKEN_EOS) break; else if (first && i == ':') { insn_is_label = true; goto restart_parse; } first = false; fixptr = tail; eop = *tail = nasm_malloc(sizeof(extop)); tail = &eop->next; eop->next = NULL; eop->type = EOT_NOTHING; oper_num++; sign = +1; /* * is_comma_next() here is to distinguish this from * a string used as part of an expression... */ if (i == TOKEN_STR && is_comma_next()) { eop->type = EOT_DB_STRING; eop->stringval = tokval.t_charptr; eop->stringlen = tokval.t_inttwo; i = stdscan(NULL, &tokval); /* eat the comma */ } else if (i == TOKEN_STRFUNC) { bool parens = false; const char *funcname = tokval.t_charptr; enum strfunc func = tokval.t_integer; i = stdscan(NULL, &tokval); if (i == '(') { parens = true; i = stdscan(NULL, &tokval); } if (i != TOKEN_STR) { nasm_error(ERR_NONFATAL, "%s must be followed by a string constant", funcname); eop->type = EOT_NOTHING; } else { eop->type = EOT_DB_STRING_FREE; eop->stringlen = string_transform(tokval.t_charptr, tokval.t_inttwo, &eop->stringval, func); if (eop->stringlen == (size_t)-1) { nasm_error(ERR_NONFATAL, "invalid string for transform"); eop->type = EOT_NOTHING; } } if (parens && i && i != ')') { i = stdscan(NULL, &tokval); if (i != ')') { nasm_error(ERR_NONFATAL, "unterminated %s function", funcname); } } if (i && i != ',') i = stdscan(NULL, &tokval); } else if (i == '-' || i == '+') { char *save = stdscan_get(); int token = i; sign = (i == '-') ? -1 : 1; i = stdscan(NULL, &tokval); if (i != TOKEN_FLOAT) { stdscan_set(save); i = tokval.t_type = token; goto is_expression; } else { goto is_float; } } else if (i == TOKEN_FLOAT) { is_float: eop->type = EOT_DB_STRING; result->eops_float = true; eop->stringlen = idata_bytes(result->opcode); if (eop->stringlen > 16) { nasm_error(ERR_NONFATAL, "floating-point constant" " encountered in DY instruction"); eop->stringlen = 0; } else if (eop->stringlen < 1) { nasm_error(ERR_NONFATAL, "floating-point constant" " encountered in unknown instruction"); /* * fix suggested by Pedro Gimeno... original line was: * eop->type = EOT_NOTHING; */ eop->stringlen = 0; } eop = nasm_realloc(eop, sizeof(extop) + eop->stringlen); tail = &eop->next; *fixptr = eop; eop->stringval = (char *)eop + sizeof(extop); if (!eop->stringlen || !float_const(tokval.t_charptr, sign, (uint8_t *)eop->stringval, eop->stringlen, nasm_error)) eop->type = EOT_NOTHING; i = stdscan(NULL, &tokval); /* eat the comma */ } else { /* anything else, assume it is an expression */ expr *value; is_expression: value = evaluate(stdscan, NULL, &tokval, NULL, critical, nasm_error, NULL); i = tokval.t_type; if (!value) { /* error in evaluator */ result->opcode = I_none; /* unrecoverable parse error: */ return result; /* ignore this instruction */ } if (is_unknown(value)) { eop->type = EOT_DB_NUMBER; eop->offset = 0; /* doesn't matter what we put */ eop->segment = eop->wrt = NO_SEG; /* likewise */ } else if (is_reloc(value)) { eop->type = EOT_DB_NUMBER; eop->offset = reloc_value(value); eop->segment = reloc_seg(value); eop->wrt = reloc_wrt(value); } else { nasm_error(ERR_NONFATAL, "operand %d: expression is not simple" " or relocatable", oper_num); } } /* * We're about to call stdscan(), which will eat the * comma that we're currently sitting on between * arguments. However, we'd better check first that it * _is_ a comma. */ if (i == TOKEN_EOS) /* also could be EOL */ break; if (i != ',') { nasm_error(ERR_NONFATAL, "comma expected after operand %d", oper_num); result->opcode = I_none;/* unrecoverable parse error: */ return result; /* ignore this instruction */ } } if (result->opcode == I_INCBIN) { /* * Correct syntax for INCBIN is that there should be * one string operand, followed by one or two numeric * operands. */ if (!result->eops || result->eops->type != EOT_DB_STRING) nasm_error(ERR_NONFATAL, "`incbin' expects a file name"); else if (result->eops->next && result->eops->next->type != EOT_DB_NUMBER) nasm_error(ERR_NONFATAL, "`incbin': second parameter is" " non-numeric"); else if (result->eops->next && result->eops->next->next && result->eops->next->next->type != EOT_DB_NUMBER) nasm_error(ERR_NONFATAL, "`incbin': third parameter is" " non-numeric"); else if (result->eops->next && result->eops->next->next && result->eops->next->next->next) nasm_error(ERR_NONFATAL, "`incbin': more than three parameters"); else return result; /* * If we reach here, one of the above errors happened. * Throw the instruction away. */ result->opcode = I_none; return result; } else /* DB ... */ if (oper_num == 0) nasm_error(ERR_WARNING | ERR_PASS1, "no operand for data declaration"); else result->operands = oper_num; return result; } /* * Now we begin to parse the operands. There may be up to four * of these, separated by commas, and terminated by a zero token. */ for (operand = 0; operand < MAX_OPERANDS; operand++) { expr *value; /* used most of the time */ int mref; /* is this going to be a memory ref? */ int bracket; /* is it a [] mref, or a & mref? */ int setsize = 0; result->oprs[operand].disp_size = 0; /* have to zero this whatever */ result->oprs[operand].eaflags = 0; /* and this */ result->oprs[operand].opflags = 0; i = stdscan(NULL, &tokval); if (i == TOKEN_EOS) break; /* end of operands: get out of here */ else if (first && i == ':') { insn_is_label = true; goto restart_parse; } first = false; result->oprs[operand].type = 0; /* so far, no override */ while (i == TOKEN_SPECIAL) { /* size specifiers */ switch ((int)tokval.t_integer) { case S_BYTE: if (!setsize) /* we want to use only the first */ result->oprs[operand].type |= BITS8; setsize = 1; break; case S_WORD: if (!setsize) result->oprs[operand].type |= BITS16; setsize = 1; break; case S_DWORD: case S_LONG: if (!setsize) result->oprs[operand].type |= BITS32; setsize = 1; break; case S_QWORD: if (!setsize) result->oprs[operand].type |= BITS64; setsize = 1; break; case S_TWORD: if (!setsize) result->oprs[operand].type |= BITS80; setsize = 1; break; case S_OWORD: if (!setsize) result->oprs[operand].type |= BITS128; setsize = 1; break; case S_YWORD: if (!setsize) result->oprs[operand].type |= BITS256; setsize = 1; break; case S_TO: result->oprs[operand].type |= TO; break; case S_STRICT: result->oprs[operand].type |= STRICT; break; case S_FAR: result->oprs[operand].type |= FAR; break; case S_NEAR: result->oprs[operand].type |= NEAR; break; case S_SHORT: result->oprs[operand].type |= SHORT; break; default: nasm_error(ERR_NONFATAL, "invalid operand size specification"); } i = stdscan(NULL, &tokval); } if (i == '[' || i == '&') { /* memory reference */ mref = true; bracket = (i == '['); i = stdscan(NULL, &tokval); /* then skip the colon */ while (i == TOKEN_SPECIAL || i == TOKEN_PREFIX) { process_size_override(result, operand); i = stdscan(NULL, &tokval); } } else { /* immediate operand, or register */ mref = false; bracket = false; /* placate optimisers */ } if ((result->oprs[operand].type & FAR) && !mref && result->opcode != I_JMP && result->opcode != I_CALL) { nasm_error(ERR_NONFATAL, "invalid use of FAR operand specifier"); } value = evaluate(stdscan, NULL, &tokval, &result->oprs[operand].opflags, critical, nasm_error, &hints); i = tokval.t_type; if (result->oprs[operand].opflags & OPFLAG_FORWARD) { result->forw_ref = true; } if (!value) { /* nasm_error in evaluator */ result->opcode = I_none; /* unrecoverable parse error: */ return result; /* ignore this instruction */ } if (i == ':' && mref) { /* it was seg:offset */ /* * Process the segment override. */ if (value[1].type != 0 || value->value != 1 || !IS_SREG(value->type)) nasm_error(ERR_NONFATAL, "invalid segment override"); else if (result->prefixes[PPS_SEG]) nasm_error(ERR_NONFATAL, "instruction has conflicting segment overrides"); else { result->prefixes[PPS_SEG] = value->type; if (IS_FSGS(value->type)) result->oprs[operand].eaflags |= EAF_FSGS; } i = stdscan(NULL, &tokval); /* then skip the colon */ while (i == TOKEN_SPECIAL || i == TOKEN_PREFIX) { process_size_override(result, operand); i = stdscan(NULL, &tokval); } value = evaluate(stdscan, NULL, &tokval, &result->oprs[operand].opflags, critical, nasm_error, &hints); i = tokval.t_type; if (result->oprs[operand].opflags & OPFLAG_FORWARD) { result->forw_ref = true; } /* and get the offset */ if (!value) { /* but, error in evaluator */ result->opcode = I_none; /* unrecoverable parse error: */ return result; /* ignore this instruction */ } } recover = false; if (mref && bracket) { /* find ] at the end */ if (i != ']') { nasm_error(ERR_NONFATAL, "parser: expecting ]"); recover = true; } else { /* we got the required ] */ i = stdscan(NULL, &tokval); if (i != 0 && i != ',') { nasm_error(ERR_NONFATAL, "comma or end of line expected"); recover = true; } } } else { /* immediate operand */ if (i != 0 && i != ',' && i != ':') { nasm_error(ERR_NONFATAL, "comma, colon or end of line expected"); recover = true; } else if (i == ':') { result->oprs[operand].type |= COLON; } } if (recover) { do { /* error recovery */ i = stdscan(NULL, &tokval); } while (i != 0 && i != ','); } /* * now convert the exprs returned from evaluate() * into operand descriptions... */ if (mref) { /* it's a memory reference */ expr *e = value; int b, i, s; /* basereg, indexreg, scale */ int64_t o; /* offset */ b = i = -1, o = s = 0; result->oprs[operand].hintbase = hints.base; result->oprs[operand].hinttype = hints.type; if (e->type && e->type <= EXPR_REG_END) { /* this bit's a register */ if (e->value == 1) /* in fact it can be basereg */ b = e->type; else /* no, it has to be indexreg */ i = e->type, s = e->value; e++; } if (e->type && e->type <= EXPR_REG_END) { /* it's a 2nd register */ if (b != -1) /* If the first was the base, ... */ i = e->type, s = e->value; /* second has to be indexreg */ else if (e->value != 1) { /* If both want to be index */ nasm_error(ERR_NONFATAL, "beroset-p-592-invalid effective address"); result->opcode = I_none; return result; } else b = e->type; e++; } if (e->type != 0) { /* is there an offset? */ if (e->type <= EXPR_REG_END) { /* in fact, is there an error? */ nasm_error(ERR_NONFATAL, "beroset-p-603-invalid effective address"); result->opcode = I_none; return result; } else { if (e->type == EXPR_UNKNOWN) { result->oprs[operand].opflags |= OPFLAG_UNKNOWN; o = 0; /* doesn't matter what */ result->oprs[operand].wrt = NO_SEG; /* nor this */ result->oprs[operand].segment = NO_SEG; /* or this */ while (e->type) e++; /* go to the end of the line */ } else { if (e->type == EXPR_SIMPLE) { o = e->value; e++; } if (e->type == EXPR_WRT) { result->oprs[operand].wrt = e->value; e++; } else result->oprs[operand].wrt = NO_SEG; /* * Look for a segment base type. */ if (e->type && e->type < EXPR_SEGBASE) { nasm_error(ERR_NONFATAL, "beroset-p-630-invalid effective address"); result->opcode = I_none; return result; } while (e->type && e->value == 0) e++; if (e->type && e->value != 1) { nasm_error(ERR_NONFATAL, "beroset-p-637-invalid effective address"); result->opcode = I_none; return result; } if (e->type) { result->oprs[operand].segment = e->type - EXPR_SEGBASE; e++; } else result->oprs[operand].segment = NO_SEG; while (e->type && e->value == 0) e++; if (e->type) { nasm_error(ERR_NONFATAL, "beroset-p-650-invalid effective address"); result->opcode = I_none; return result; } } } } else { o = 0; result->oprs[operand].wrt = NO_SEG; result->oprs[operand].segment = NO_SEG; } if (e->type != 0) { /* there'd better be nothing left! */ nasm_error(ERR_NONFATAL, "beroset-p-663-invalid effective address"); result->opcode = I_none; return result; } /* It is memory, but it can match any r/m operand */ result->oprs[operand].type |= MEMORY_ANY; if (b == -1 && (i == -1 || s == 0)) { int is_rel = globalbits == 64 && !(result->oprs[operand].eaflags & EAF_ABS) && ((globalrel && !(result->oprs[operand].eaflags & EAF_FSGS)) || (result->oprs[operand].eaflags & EAF_REL)); result->oprs[operand].type |= is_rel ? IP_REL : MEM_OFFS; } result->oprs[operand].basereg = b; result->oprs[operand].indexreg = i; result->oprs[operand].scale = s; result->oprs[operand].offset = o; } else { /* it's not a memory reference */ if (is_just_unknown(value)) { /* it's immediate but unknown */ result->oprs[operand].type |= IMMEDIATE; result->oprs[operand].opflags |= OPFLAG_UNKNOWN; result->oprs[operand].offset = 0; /* don't care */ result->oprs[operand].segment = NO_SEG; /* don't care again */ result->oprs[operand].wrt = NO_SEG; /* still don't care */ if(optimizing >= 0 && !(result->oprs[operand].type & STRICT)) { /* Be optimistic */ result->oprs[operand].type |= SBYTE16 | SBYTE32 | SBYTE64 | UDWORD64 | SDWORD64; } } else if (is_reloc(value)) { /* it's immediate */ result->oprs[operand].type |= IMMEDIATE; result->oprs[operand].offset = reloc_value(value); result->oprs[operand].segment = reloc_seg(value); result->oprs[operand].wrt = reloc_wrt(value); if (is_simple(value)) { if (reloc_value(value) == 1) result->oprs[operand].type |= UNITY; if (optimizing >= 0 && !(result->oprs[operand].type & STRICT)) { int64_t v64 = reloc_value(value); int32_t v32 = (int32_t)v64; int16_t v16 = (int16_t)v32; if (v64 >= -128 && v64 <= 127) result->oprs[operand].type |= SBYTE64; if (v32 >= -128 && v32 <= 127) result->oprs[operand].type |= SBYTE32; if (v16 >= -128 && v16 <= 127) result->oprs[operand].type |= SBYTE16; if ((uint64_t)v64 <= UINT64_C(0xffffffff)) result->oprs[operand].type |= UDWORD64; if (v64 >= -INT64_C(0x80000000) && v64 <= INT64_C(0x7fffffff)) result->oprs[operand].type |= SDWORD64; } } } else { /* it's a register */ unsigned int rs; if (value->type >= EXPR_SIMPLE || value->value != 1) { nasm_error(ERR_NONFATAL, "invalid operand type"); result->opcode = I_none; return result; } /* * check that its only 1 register, not an expression... */ for (i = 1; value[i].type; i++) if (value[i].value) { nasm_error(ERR_NONFATAL, "invalid operand type"); result->opcode = I_none; return result; } /* clear overrides, except TO which applies to FPU regs */ if (result->oprs[operand].type & ~TO) { /* * we want to produce a warning iff the specified size * is different from the register size */ rs = result->oprs[operand].type & SIZE_MASK; } else rs = 0; result->oprs[operand].type &= TO; result->oprs[operand].type |= REGISTER; result->oprs[operand].type |= nasm_reg_flags[value->type]; result->oprs[operand].basereg = value->type; if (rs && (result->oprs[operand].type & SIZE_MASK) != rs) nasm_error(ERR_WARNING | ERR_PASS1, "register size specification ignored"); } } } result->operands = operand; /* set operand count */ /* clear remaining operands */ while (operand < MAX_OPERANDS) result->oprs[operand++].type = 0; /* * Transform RESW, RESD, RESQ, REST, RESO, RESY into RESB. */ switch (result->opcode) { case I_RESW: result->opcode = I_RESB; result->oprs[0].offset *= 2; break; case I_RESD: result->opcode = I_RESB; result->oprs[0].offset *= 4; break; case I_RESQ: result->opcode = I_RESB; result->oprs[0].offset *= 8; break; case I_REST: result->opcode = I_RESB; result->oprs[0].offset *= 10; break; case I_RESO: result->opcode = I_RESB; result->oprs[0].offset *= 16; break; case I_RESY: result->opcode = I_RESB; result->oprs[0].offset *= 32; break; default: break; } return result; }
void stabs_generate(void) { int i, numfiles, strsize, numstabs = 0, currfile, mainfileindex; unsigned char *sbuf, *ssbuf, *rbuf, *sptr, *rptr; char **allfiles; int *fileidx; struct linelist *ptr; ptr = stabslines; allfiles = (char **)nasm_malloc(numlinestabs * sizeof(char *)); for (i = 0; i < numlinestabs; i++) allfiles[i] = 0; numfiles = 0; while (ptr) { if (numfiles == 0) { allfiles[0] = ptr->filename; numfiles++; } else { for (i = 0; i < numfiles; i++) { if (!strcmp(allfiles[i], ptr->filename)) break; } if (i >= numfiles) { allfiles[i] = ptr->filename; numfiles++; } } ptr = ptr->next; } strsize = 1; fileidx = (int *)nasm_malloc(numfiles * sizeof(int)); for (i = 0; i < numfiles; i++) { fileidx[i] = strsize; strsize += strlen(allfiles[i]) + 1; } mainfileindex = 0; for (i = 0; i < numfiles; i++) { if (!strcmp(allfiles[i], elf_module)) { mainfileindex = i; break; } } /* worst case size of the stab buffer would be: the sourcefiles changes each line, which would mean 1 SOL, 1 SYMLIN per line */ sbuf = (unsigned char *)nasm_malloc((numlinestabs * 2 + 3) * sizeof(struct stabentry)); ssbuf = (unsigned char *)nasm_malloc(strsize); rbuf = (unsigned char *)nasm_malloc(numlinestabs * 8 * (2 + 3)); rptr = rbuf; for (i = 0; i < numfiles; i++) { strcpy((char *)ssbuf + fileidx[i], allfiles[i]); } ssbuf[0] = 0; stabstrlen = strsize; /* set global variable for length of stab strings */ sptr = sbuf; /* this is the first stab, its strx points to the filename of the the source-file, the n_desc field should be set to the number of remaining stabs */ WRITE_STAB(sptr, fileidx[0], 0, 0, 0, strlen(allfiles[0] + 12)); ptr = stabslines; numstabs = 0; if (ptr) { /* this is the stab for the main source file */ WRITE_STAB(sptr, fileidx[mainfileindex], N_SO, 0, 0, 0); /* relocation stuff */ /* IS THIS SANE? WHAT DOES SECTION+3 MEAN HERE? */ WRITELONG(rptr, (sptr - sbuf) - 4); WRITELONG(rptr, ((ptr->info.section + 3) << 8) | R_386_32); numstabs++; currfile = mainfileindex; } while (ptr) { if (strcmp(allfiles[currfile], ptr->filename)) { /* oops file has changed... */ for (i = 0; i < numfiles; i++) if (!strcmp(allfiles[i], ptr->filename)) break; currfile = i; WRITE_STAB(sptr, fileidx[currfile], N_SOL, 0, 0, ptr->info.offset); numstabs++; /* relocation stuff */ /* IS THIS SANE? WHAT DOES SECTION+3 MEAN HERE? */ WRITELONG(rptr, (sptr - sbuf) - 4); WRITELONG(rptr, ((ptr->info.section + 3) << 8) | R_386_32); } WRITE_STAB(sptr, 0, N_SLINE, 0, ptr->line, ptr->info.offset); numstabs++; /* relocation stuff */ /* IS THIS SANE? WHAT DOES SECTION+3 MEAN HERE? */ WRITELONG(rptr, (sptr - sbuf) - 4); WRITELONG(rptr, ((ptr->info.section + 3) << 8) | R_386_32); ptr = ptr->next; } ((struct stabentry *)sbuf)->n_desc = numstabs; nasm_free(allfiles); nasm_free(fileidx); stablen = (sptr - sbuf); stabrellen = (rptr - rbuf); stabrelbuf = rbuf; stabbuf = sbuf; stabstrbuf = ssbuf; }
/* * This routine deals with ..got and ..sym relocations: the more * complicated kinds. In shared-library writing, some relocations * with respect to global symbols must refer to the precise symbol * rather than referring to an offset from the base of the section * _containing_ the symbol. Such relocations call to this routine, * which searches the symbol list for the symbol in question. * * R_386_GOT32 references require the _exact_ symbol address to be * used; R_386_32 references can be at an offset from the symbol. * The boolean argument `exact' tells us this. * * Return value is the adjusted value of `addr', having become an * offset from the symbol rather than the section. Should always be * zero when returning from an exact call. * * Limitation: if you define two symbols at the same place, * confusion will occur. * * Inefficiency: we search, currently, using a linked list which * isn't even necessarily sorted. */ static long elf_add_gsym_reloc(struct Section *sect, long segment, long offset, int type, int exact) { struct Reloc *r; struct Section *s; struct Symbol *sym, *sm; int i; /* * First look up the segment/offset pair and find a global * symbol corresponding to it. If it's not one of our segments, * then it must be an external symbol, in which case we're fine * doing a normal elf_add_reloc after first sanity-checking * that the offset from the symbol is zero. */ s = NULL; for (i = 0; i < nsects; i++) if (segment == sects[i]->index) { s = sects[i]; break; } if (!s) { if (exact && offset != 0) error(ERR_NONFATAL, "unable to find a suitable global symbol" " for this reference"); else elf_add_reloc(sect, segment, type); return offset; } if (exact) { /* * Find a symbol pointing _exactly_ at this one. */ for (sym = s->gsyms; sym; sym = sym->next) if (sym->value == offset) break; } else { /* * Find the nearest symbol below this one. */ sym = NULL; for (sm = s->gsyms; sm; sm = sm->next) if (sm->value <= offset && (!sym || sm->value > sym->value)) sym = sm; } if (!sym && exact) { error(ERR_NONFATAL, "unable to find a suitable global symbol" " for this reference"); return 0; } r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); sect->tail = &r->next; r->next = NULL; r->address = sect->len; r->symbol = GLOBAL_TEMP_BASE + sym->globnum; r->type = type; sect->nrelocs++; return offset - sym->value; }
static void elf_write(void) { int nsections, align; int scount; char *p; int commlen; char comment[64]; int i; struct SAA *symtab; long symtablen, symtablocal; /* * Work out how many sections we will have. We have SHN_UNDEF, * then the flexible user sections, then the four fixed * sections `.comment', `.shstrtab', `.symtab' and `.strtab', * then optionally relocation sections for the user sections. */ if (of_elf.current_dfmt == &df_stabs) nsections = 8; else nsections = 5; /* SHN_UNDEF and the fixed ones */ add_sectname("", ".comment"); add_sectname("", ".shstrtab"); add_sectname("", ".symtab"); add_sectname("", ".strtab"); for (i = 0; i < nsects; i++) { nsections++; /* for the section itself */ if (sects[i]->head) { nsections++; /* for its relocations */ add_sectname(".rel", sects[i]->name); } } if (of_elf.current_dfmt == &df_stabs) { /* in case the debug information is wanted, just add these three sections... */ add_sectname("", ".stab"); add_sectname("", ".stabstr"); add_sectname(".rel", ".stab"); } /* * Do the comment. */ *comment = '\0'; commlen = 2 + sprintf(comment + 1, "The Netwide Assembler %s", NASM_VER); /* * Output the ELF header. */ fwrite("\177ELF\1\1\1\0\0\0\0\0\0\0\0\0", 16, 1, elffp); fwriteshort(1, elffp); /* ET_REL relocatable file */ fwriteshort(3, elffp); /* EM_386 processor ID */ fwritelong(1L, elffp); /* EV_CURRENT file format version */ fwritelong(0L, elffp); /* no entry point */ fwritelong(0L, elffp); /* no program header table */ fwritelong(0x40L, elffp); /* section headers straight after * ELF header plus alignment */ fwritelong(0L, elffp); /* 386 defines no special flags */ fwriteshort(0x34, elffp); /* size of ELF header */ fwriteshort(0, elffp); /* no program header table, again */ fwriteshort(0, elffp); /* still no program header table */ fwriteshort(0x28, elffp); /* size of section header */ fwriteshort(nsections, elffp); /* number of sections */ fwriteshort(nsects + 2, elffp); /* string table section index for * section header table */ fwritelong(0L, elffp); /* align to 0x40 bytes */ fwritelong(0L, elffp); fwritelong(0L, elffp); /* * Build the symbol table and relocation tables. */ symtab = elf_build_symtab(&symtablen, &symtablocal); for (i = 0; i < nsects; i++) if (sects[i]->head) sects[i]->rel = elf_build_reltab(§s[i]->rellen, sects[i]->head); /* * Now output the section header table. */ elf_foffs = 0x40 + 0x28 * nsections; align = ((elf_foffs + SEG_ALIGN_1) & ~SEG_ALIGN_1) - elf_foffs; elf_foffs += align; elf_nsect = 0; elf_sects = nasm_malloc(sizeof(*elf_sects) * (2 * nsects + 10)); elf_section_header(0, 0, 0, NULL, FALSE, 0L, 0, 0, 0, 0); /* SHN_UNDEF */ scount = 1; /* needed for the stabs debugging to track the symtable section */ p = shstrtab + 1; for (i = 0; i < nsects; i++) { elf_section_header(p - shstrtab, sects[i]->type, sects[i]->flags, (sects[i]->type == SHT_PROGBITS ? sects[i]->data : NULL), TRUE, sects[i]->len, 0, 0, sects[i]->align, 0); p += strlen(p) + 1; scount++; /* dito */ } elf_section_header(p - shstrtab, 1, 0, comment, FALSE, (long)commlen, 0, 0, 1, 0); /* .comment */ scount++; /* dito */ p += strlen(p) + 1; elf_section_header(p - shstrtab, 3, 0, shstrtab, FALSE, (long)shstrtablen, 0, 0, 1, 0); /* .shstrtab */ scount++; /* dito */ p += strlen(p) + 1; elf_section_header(p - shstrtab, 2, 0, symtab, TRUE, symtablen, nsects + 4, symtablocal, 4, 16); /* .symtab */ symtabsection = scount; /* now we got the symtab section index in the ELF file */ p += strlen(p) + 1; elf_section_header(p - shstrtab, 3, 0, strs, TRUE, strslen, 0, 0, 1, 0); /* .strtab */ for (i = 0; i < nsects; i++) if (sects[i]->head) { p += strlen(p) + 1; elf_section_header(p - shstrtab, 9, 0, sects[i]->rel, TRUE, sects[i]->rellen, nsects + 3, i + 1, 4, 8); } if (of_elf.current_dfmt == &df_stabs) { /* for debugging information, create the last three sections which are the .stab , .stabstr and .rel.stab sections respectively */ /* this function call creates the stab sections in memory */ stabs_generate(); if ((stabbuf) && (stabstrbuf) && (stabrelbuf)) { p += strlen(p) + 1; elf_section_header(p - shstrtab, 1, 0, stabbuf, 0, stablen, nsections - 2, 0, 4, 12); p += strlen(p) + 1; elf_section_header(p - shstrtab, 3, 0, stabstrbuf, 0, stabstrlen, 0, 0, 4, 0); p += strlen(p) + 1; /* link -> symtable info -> section to refer to */ elf_section_header(p - shstrtab, 9, 0, stabrelbuf, 0, stabrellen, symtabsection, nsections - 3, 4, 8); } } fwrite(align_str, align, 1, elffp); /* * Now output the sections. */ elf_write_sections(); nasm_free(elf_sects); saa_free(symtab); }
int rdl_searchlib(struct librarynode *lib, const char *label, rdffile * f) { char buf[512]; int i, t; void *hdr; rdfheaderrec *r; int32_t l; rdl_error = 0; lib->referenced++; if (!lib->fp) { lib->fp = fopen(lib->name, "rb"); if (!lib->fp) { rdl_error = 1; return 0; } } else rewind(lib->fp); while (!feof(lib->fp)) { /* * read the module name from the file, and prepend * the library name and '.' to it. */ strcpy(buf, lib->name); i = strlen(lib->name); buf[i++] = '.'; t = i; while (fread(buf + i, 1, 1, lib->fp) == 1 && i < 512 && buf[i]) i++; buf[i] = 0; if (feof(lib->fp)) break; if (!strcmp(buf + t, ".dir")) { /* skip over directory */ nasm_read(&l, 4, lib->fp); fseek(lib->fp, l, SEEK_CUR); continue; } /* * open the RDOFF module */ if (rdfopenhere(f, lib->fp, &lib->referenced, buf)) { rdl_error = 16 * rdf_errno; return 0; } /* * read in the header, and scan for exported symbols */ hdr = nasm_malloc(f->header_len); rdfloadseg(f, RDOFF_HEADER, hdr); while ((r = rdfgetheaderrec(f))) { if (r->type != 3) /* not an export */ continue; if (!strcmp(r->e.label, label)) { /* match! */ nasm_free(hdr); /* reset to 'just open' */ f->header_loc = NULL; /* state... */ f->header_fp = 0; return 1; } } /* find start of next module... */ i = f->eof_offset; rdfclose(f); fseek(lib->fp, i, SEEK_SET); } /* * close the file if nobody else is using it */ lib->referenced--; if (!lib->referenced) { fclose(lib->fp); lib->fp = NULL; } return 0; }
char *nasm_quote(char *str, size_t len) { char c, c1, *p, *q, *nstr, *ep; unsigned char uc; bool sq_ok, dq_ok; size_t qlen; sq_ok = dq_ok = true; ep = str+len; qlen = 0; /* Length if we need `...` quotes */ for (p = str; p < ep; p++) { c = *p; switch (c) { case '\'': sq_ok = false; qlen++; break; case '\"': dq_ok = false; qlen++; break; case '`': case '\\': qlen += 2; break; default: if (c < ' ' || c > '~') { sq_ok = dq_ok = false; switch (c) { case '\a': case '\b': case '\t': case '\n': case '\v': case '\f': case '\r': case 27: qlen += 2; break; default: c1 = (p+1 < ep) ? p[1] : 0; if (c1 >= '0' && c1 <= '7') uc = 0377; /* Must use the full form */ else uc = c; if (uc > 077) qlen++; if (uc > 07) qlen++; qlen += 2; break; } } else { qlen++; } break; } } if (sq_ok || dq_ok) { /* Use '...' or "..." */ nstr = nasm_malloc(len+3); nstr[0] = nstr[len+1] = sq_ok ? '\'' : '\"'; nstr[len+2] = '\0'; if (len > 0) memcpy(nstr+1, str, len); } else { /* Need to use `...` quoted syntax */ nstr = nasm_malloc(qlen+3); q = nstr; *q++ = '`'; for (p = str; p < ep; p++) { c = *p; switch (c) { case '`': case '\\': *q++ = '\\'; *q++ = c; break; case 7: *q++ = '\\'; *q++ = 'a'; break; case 8: *q++ = '\\'; *q++ = 'b'; break; case 9: *q++ = '\\'; *q++ = 't'; break; case 10: *q++ = '\\'; *q++ = 'n'; break; case 11: *q++ = '\\'; *q++ = 'v'; break; case 12: *q++ = '\\'; *q++ = 'f'; break; case 13: *q++ = '\\'; *q++ = 'r'; break; case 27: *q++ = '\\'; *q++ = 'e'; break; default: if (c < ' ' || c > '~') { c1 = (p+1 < ep) ? p[1] : 0; if (c1 >= '0' && c1 <= '7') uc = 0377; /* Must use the full form */ else uc = c; *q++ = '\\'; if (uc > 077) *q++ = ((unsigned char)c >> 6) + '0'; if (uc > 07) *q++ = (((unsigned char)c >> 3) & 7) + '0'; *q++ = ((unsigned char)c & 7) + '0'; break; } else { *q++ = c; } break; } }