static int bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val, /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) { bytecode_align *align = (bytecode_align *)bc->contents; unsigned long end; unsigned long boundary = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0)); if (boundary == 0) { bc->len = 0; *pos_thres = new_val; return 0; } end = (unsigned long)new_val; if ((unsigned long)new_val & (boundary-1)) end = ((unsigned long)new_val & ~(boundary-1)) + boundary; *pos_thres = (long)end; bc->len = end - (unsigned long)new_val; if (align->maxskip) { unsigned long maxskip = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0)); if (bc->len > maxskip) { *pos_thres = (long)end-maxskip-1; bc->len = 0; } } return 1; }
static void x86_dir_cpu(yasm_object *object, yasm_valparamhead *valparams, yasm_valparamhead *objext_valparams, unsigned long line) { yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch; yasm_valparam *vp; yasm_vps_foreach(vp, valparams) { /*@null@*/ /*@dependent@*/ const char *s = yasm_vp_string(vp); if (s) yasm_x86__parse_cpu(arch_x86, s, strlen(s)); else if (vp->type == YASM_PARAM_EXPR) { const yasm_intnum *intcpu; intcpu = yasm_expr_get_intnum(&vp->param.e, 0); if (!intcpu) yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"), "CPU"); else { char strcpu[16]; sprintf(strcpu, "%lu", yasm_intnum_get_uint(intcpu)); yasm_x86__parse_cpu(arch_x86, strcpu, strlen(strcpu)); } } else yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"), "CPU"); } }
static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d, yasm_output_value_func output_value, /*@unused@*/ yasm_output_reloc_func output_reloc) { bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; FILE *f; /*@dependent@*/ /*@null@*/ const yasm_intnum *num; unsigned long start = 0; /* Convert start to integer value */ if (incbin->start) { num = yasm_expr_get_intnum(&incbin->start, 0); if (!num) yasm_internal_error( N_("could not determine start in bc_tobytes_incbin")); start = yasm_intnum_get_uint(num); } /* Open file */ f = yasm_fopen_include(incbin->filename, incbin->from, "rb", NULL); if (!f) { yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to open file `%s'"), incbin->filename); return 1; } /* Seek to start of data */ if (fseek(f, (long)start, SEEK_SET) < 0) { yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to seek on file `%s'"), incbin->filename); fclose(f); return 1; } /* Read len bytes */ if (fread(*bufp, 1, (size_t)bc->len, f) < (size_t)bc->len) { yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to read %lu bytes from file `%s'"), bc->len, incbin->filename); fclose(f); return 1; } *bufp += bc->len; fclose(f); return 0; }
static int bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data) { bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; FILE *f; /*@dependent@*/ /*@null@*/ const yasm_intnum *num; unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen; /* Try to convert start to integer value */ if (incbin->start) { num = yasm_expr_get_intnum(&incbin->start, 0); if (num) start = yasm_intnum_get_uint(num); if (!num) { /* FIXME */ yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED, N_("incbin does not yet understand non-constant")); return -1; } } /* Try to convert maxlen to integer value */ if (incbin->maxlen) { num = yasm_expr_get_intnum(&incbin->maxlen, 0); if (num) maxlen = yasm_intnum_get_uint(num); if (!num) { /* FIXME */ yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED, N_("incbin does not yet understand non-constant")); return -1; } } /* Open file and determine its length */ f = yasm_fopen_include(incbin->filename, incbin->from, "rb", NULL); if (!f) { yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to open file `%s'"), incbin->filename); return -1; } if (fseek(f, 0L, SEEK_END) < 0) { yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to seek on file `%s'"), incbin->filename); return -1; } flen = (unsigned long)ftell(f); fclose(f); /* Compute length of incbin from start, maxlen, and len */ if (start > flen) { yasm_warn_set(YASM_WARN_GENERAL, N_("`incbin': start past end of file `%s'"), incbin->filename); start = flen; } flen -= start; if (incbin->maxlen) if (maxlen < flen) flen = maxlen; bc->len += flen; return 0; }
static int value_finalize_scan(yasm_value *value, yasm_expr *e, /*@null@*/ yasm_bytecode *expr_precbc, int ssym_not_ok) { int i; /*@dependent@*/ yasm_section *sect; /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; unsigned long shamt; /* for SHR */ /* Yes, this has a maximum upper bound on 32 terms, based on an * "insane number of terms" (and ease of implementation) WAG. * The right way to do this would be a stack-based alloca, but that's * not ISO C. We really don't want to malloc here as this function is * hit a lot! * * This is a bitmask to keep things small, as this is a recursive * routine and we don't want to eat up stack space. */ unsigned long used; /* for ADD */ /* Thanks to this running after a simplify, we don't need to iterate * down through IDENTs or handle SUB. * * We scan for a single symrec, gathering info along the way. After * we've found the symrec, we keep scanning but error if we find * another one. We pull out the single symrec and any legal operations * performed on it. * * Also, if we find a float anywhere, we don't allow mixing of a single * symrec with it. */ switch (e->op) { case YASM_EXPR_ADD: /* Okay for single symrec anywhere in expr. * Check for single symrec anywhere. * Handle symrec-symrec by checking for (-1*symrec) * and symrec term pairs (where both symrecs are in the same * segment). */ if (e->numterms > 32) yasm__fatal(N_("expression on line %d has too many add terms;" " internal limit of 32"), e->line); used = 0; for (i=0; i<e->numterms; i++) { int j; yasm_expr *sube; yasm_intnum *intn; yasm_symrec *sym; /*@dependent@*/ yasm_section *sect2; /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2; /* First look for an (-1*symrec) term */ if (e->terms[i].type != YASM_EXPR_EXPR) continue; sube = e->terms[i].data.expn; if (sube->op != YASM_EXPR_MUL || sube->numterms != 2) { /* recurse instead */ if (value_finalize_scan(value, sube, expr_precbc, ssym_not_ok)) return 1; continue; } if (sube->terms[0].type == YASM_EXPR_INT && sube->terms[1].type == YASM_EXPR_SYM) { intn = sube->terms[0].data.intn; sym = sube->terms[1].data.sym; } else if (sube->terms[0].type == YASM_EXPR_SYM && sube->terms[1].type == YASM_EXPR_INT) { sym = sube->terms[0].data.sym; intn = sube->terms[1].data.intn; } else { if (value_finalize_scan(value, sube, expr_precbc, ssym_not_ok)) return 1; continue; } if (!yasm_intnum_is_neg1(intn)) { if (value_finalize_scan(value, sube, expr_precbc, ssym_not_ok)) return 1; continue; } /* Look for the same symrec term; even if both are external, * they should cancel out. */ for (j=0; j<e->numterms; j++) { if (e->terms[j].type == YASM_EXPR_SYM && e->terms[j].data.sym == sym && (used & (1<<j)) == 0) { /* Mark as used */ used |= 1<<j; /* Replace both symrec portions with 0 */ yasm_expr_destroy(sube); e->terms[i].type = YASM_EXPR_INT; e->terms[i].data.intn = yasm_intnum_create_uint(0); e->terms[j].type = YASM_EXPR_INT; e->terms[j].data.intn = yasm_intnum_create_uint(0); break; /* stop looking */ } } if (j != e->numterms) continue; if (!yasm_symrec_get_label(sym, &precbc)) { if (value_finalize_scan(value, sube, expr_precbc, ssym_not_ok)) return 1; continue; } sect2 = yasm_bc_get_section(precbc); /* Now look for a unused symrec term in the same segment */ for (j=0; j<e->numterms; j++) { if (e->terms[j].type == YASM_EXPR_SYM && yasm_symrec_get_label(e->terms[j].data.sym, &precbc2) && (sect = yasm_bc_get_section(precbc2)) && sect == sect2 && (used & (1<<j)) == 0) { /* Mark as used */ used |= 1<<j; break; /* stop looking */ } } /* We didn't match in the same segment. If the * -1*symrec is actually -1*curpos, we can match * unused symrec terms in other segments and generate * a curpos-relative reloc. * * Similarly, handle -1*symrec in other segment via the * following transformation: * other-this = (other-.)+(.-this) * We can only do this transformation if "this" is in * this expr's segment. * * Don't do this if we've already become curpos-relative. * The unmatched symrec will be caught below. */ if (j == e->numterms && !value->curpos_rel && (yasm_symrec_is_curpos(sym) || (expr_precbc && sect2 == yasm_bc_get_section(expr_precbc)))) { for (j=0; j<e->numterms; j++) { if (e->terms[j].type == YASM_EXPR_SYM && !yasm_symrec_get_equ(e->terms[j].data.sym) && !yasm_symrec_is_special(e->terms[j].data.sym) && (used & (1<<j)) == 0) { /* Mark as used */ used |= 1<<j; /* Mark value as curpos-relative */ if (value->rel || ssym_not_ok) return 1; value->rel = e->terms[j].data.sym; value->curpos_rel = 1; if (yasm_symrec_is_curpos(sym)) { /* Replace both symrec portions with 0 */ yasm_expr_destroy(sube); e->terms[i].type = YASM_EXPR_INT; e->terms[i].data.intn = yasm_intnum_create_uint(0); e->terms[j].type = YASM_EXPR_INT; e->terms[j].data.intn = yasm_intnum_create_uint(0); } else { /* Replace positive portion with curpos */ yasm_object *object = yasm_section_get_object(sect2); yasm_symtab *symtab = object->symtab; e->terms[j].data.sym = yasm_symtab_define_curpos (symtab, ".", expr_precbc, e->line); } break; /* stop looking */ } } } if (j == e->numterms) return 1; /* We didn't find a match! */ } /* Look for unmatched symrecs. If we've already found one or * we don't WANT to find one, error out. */ for (i=0; i<e->numterms; i++) { if (e->terms[i].type == YASM_EXPR_SYM && (used & (1<<i)) == 0) { if (value->rel || ssym_not_ok) return 1; value->rel = e->terms[i].data.sym; /* and replace with 0 */ e->terms[i].type = YASM_EXPR_INT; e->terms[i].data.intn = yasm_intnum_create_uint(0); } } break; case YASM_EXPR_SHR: /* Okay for single symrec in LHS and constant on RHS. * Single symrecs are not okay on RHS. * If RHS is non-constant, don't allow single symrec on LHS. * XXX: should rshift be an expr instead?? */ /* Check for single sym on LHS */ if (e->terms[0].type != YASM_EXPR_SYM) break; /* If we already have a sym, we can't take another one */ if (value->rel || ssym_not_ok) return 1; /* RHS must be a positive integer */ if (e->terms[1].type != YASM_EXPR_INT) return 1; /* can't shift sym by non-constant integer */ shamt = yasm_intnum_get_uint(e->terms[1].data.intn); if ((shamt + value->rshift) > YASM_VALUE_RSHIFT_MAX) return 1; /* total shift would be too large */ /* Update value */ value->rshift += shamt; value->rel = e->terms[0].data.sym; /* Replace symbol with 0 */ e->terms[0].type = YASM_EXPR_INT; e->terms[0].data.intn = yasm_intnum_create_uint(0); /* Just leave SHR in place */ break; case YASM_EXPR_SEG: /* Okay for single symrec (can only be done once). * Not okay for anything BUT a single symrec as an immediate * child. */ if (e->terms[0].type != YASM_EXPR_SYM) return 1; if (value->seg_of) return 1; /* multiple SEG not legal */ value->seg_of = 1; if (value->rel || ssym_not_ok) return 1; /* got a relative portion somewhere else? */ value->rel = e->terms[0].data.sym; /* replace with ident'ed 0 */ e->op = YASM_EXPR_IDENT; e->terms[0].type = YASM_EXPR_INT; e->terms[0].data.intn = yasm_intnum_create_uint(0); break; case YASM_EXPR_WRT: /* Okay for single symrec in LHS and either a register or single * symrec (as an immediate child) on RHS. * If a single symrec on RHS, can only be done once. * WRT reg is left in expr for arch to look at. */ /* Handle RHS */ switch (e->terms[1].type) { case YASM_EXPR_SYM: if (value->wrt) return 1; value->wrt = e->terms[1].data.sym; /* and drop the WRT portion */ e->op = YASM_EXPR_IDENT; e->numterms = 1; break; case YASM_EXPR_REG: break; /* ignore */ default: return 1; } /* Handle LHS */ switch (e->terms[0].type) { case YASM_EXPR_SYM: if (value->rel || ssym_not_ok) return 1; value->rel = e->terms[0].data.sym; /* and replace with 0 */ e->terms[0].type = YASM_EXPR_INT; e->terms[0].data.intn = yasm_intnum_create_uint(0); break; case YASM_EXPR_EXPR: /* recurse */ return value_finalize_scan(value, e->terms[0].data.expn, expr_precbc, ssym_not_ok); default: break; /* ignore */ } break; default: /* Single symrec not allowed anywhere */ for (i=0; i<e->numterms; i++) { switch (e->terms[i].type) { case YASM_EXPR_SYM: return 1; case YASM_EXPR_EXPR: /* recurse */ return value_finalize_scan(value, e->terms[i].data.expn, expr_precbc, 1); default: break; } } break; } return 0; }
static int xdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d) { /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; yasm_sym_vis vis = yasm_symrec_get_visibility(sym); assert(info != NULL); if (info->all_syms || vis != YASM_SYM_LOCAL) { /*@only@*/ char *name = yasm_symrec_get_global_name(sym, info->object); const yasm_expr *equ_val; const yasm_intnum *intn; size_t len = strlen(name); unsigned long value = 0; long scnum = -3; /* -3 = debugging symbol */ /*@dependent@*/ /*@null@*/ yasm_section *sect; /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; unsigned long flags = 0; unsigned char *localbuf; if (vis & YASM_SYM_GLOBAL) flags = XDF_SYM_GLOBAL; /* Look at symrec for value/scnum/etc. */ if (yasm_symrec_get_label(sym, &precbc)) { if (precbc) sect = yasm_bc_get_section(precbc); else sect = NULL; /* it's a label: get value and offset. * If there is not a section, leave as debugging symbol. */ if (sect) { /*@dependent@*/ /*@null@*/ xdf_section_data *csectd; csectd = yasm_section_get_data(sect, &xdf_section_data_cb); if (csectd) scnum = csectd->scnum; else yasm_internal_error(N_("didn't understand section")); if (precbc) value += yasm_bc_next_offset(precbc); } } else if ((equ_val = yasm_symrec_get_equ(sym))) { yasm_expr *equ_val_copy = yasm_expr_copy(equ_val); intn = yasm_expr_get_intnum(&equ_val_copy, 1); if (!intn) { if (vis & YASM_SYM_GLOBAL) { yasm_error_set(YASM_ERROR_NOT_CONSTANT, N_("global EQU value not an integer expression")); yasm_errwarn_propagate(info->errwarns, equ_val->line); } } else value = yasm_intnum_get_uint(intn); yasm_expr_destroy(equ_val_copy); flags |= XDF_SYM_EQU; scnum = -2; /* -2 = absolute symbol */ } else { if (vis & YASM_SYM_EXTERN) { flags = XDF_SYM_EXTERN; scnum = -1; } } localbuf = info->buf; YASM_WRITE_32_L(localbuf, scnum); /* section number */ YASM_WRITE_32_L(localbuf, value); /* value */ YASM_WRITE_32_L(localbuf, info->strtab_offset); info->strtab_offset += (unsigned long)(len+1); YASM_WRITE_32_L(localbuf, flags); /* flags */ fwrite(info->buf, 16, 1, info->f); yasm_xfree(name); } return 0; }
static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, yasm_output_value_func output_value, /*@unused@*/ yasm_output_reloc_func output_reloc) { bytecode_align *align = (bytecode_align *)bc->contents; unsigned long len; unsigned long boundary = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0)); if (boundary == 0) return 0; else { unsigned long end = bc->offset; if (bc->offset & (boundary-1)) end = (bc->offset & ~(boundary-1)) + boundary; len = end - bc->offset; if (len == 0) return 0; if (align->maxskip) { unsigned long maxskip = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0)); if (len > maxskip) return 0; } } if (align->fill) { unsigned long v; v = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->fill, 0)); memset(*bufp, (int)v, len); *bufp += len; } else if (align->code_fill) { unsigned long maxlen = 15; while (!align->code_fill[maxlen] && maxlen>0) maxlen--; if (maxlen == 0) { yasm_error_set(YASM_ERROR_GENERAL, N_("could not find any code alignment size")); return 1; } /* Fill with maximum code fill as much as possible */ while (len > maxlen) { memcpy(*bufp, align->code_fill[maxlen], maxlen); *bufp += maxlen; len -= maxlen; } if (!align->code_fill[len]) { yasm_error_set(YASM_ERROR_VALUE, N_("invalid alignment size %d"), len); return 1; } /* Handle rest of code fill */ memcpy(*bufp, align->code_fill[len], len); *bufp += len; } else { /* Just fill with 0 */ memset(*bufp, 0, len); *bufp += len; } return 0; }