int vsnprintf(char *str, size_t size, const char *format, va_list ap) { int rv, bytes; if (size > BUFFER_SIZE) { nasm_panic("vsnprintf: size (%d) > BUFFER_SIZE (%d)", size, BUFFER_SIZE); size = BUFFER_SIZE; } rv = vsprintf(snprintf_buffer, format, ap); if (rv >= BUFFER_SIZE) nasm_panic("vsnprintf buffer overflow"); if (size > 0) { if ((size_t)rv < size-1) bytes = rv; else bytes = size-1; memcpy(str, snprintf_buffer, bytes); str[bytes] = '\0'; } return rv; }
static int64_t eval_ifunc(int64_t val, enum ifunc func) { int errtype; uint64_t uval = (uint64_t)val; int64_t rv; switch (func) { case IFUNC_ILOG2E: case IFUNC_ILOG2W: errtype = (func == IFUNC_ILOG2E) ? ERR_NONFATAL : ERR_WARNING; if (!is_power2(uval)) nasm_error(errtype, "ilog2 argument is not a power of two"); /* fall through */ case IFUNC_ILOG2F: rv = ilog2_64(uval); break; case IFUNC_ILOG2C: rv = (uval < 2) ? 0 : ilog2_64(uval-1) + 1; break; default: nasm_panic(0, "invalid IFUNC token %d", func); rv = 0; break; } return rv; }
/* * because this routine is not bracketed in * the main program, this routine will be called even if there * is no request for debug info * so, we have to make sure the ??LINE segment is avaialbe * as the first segment when this debug format is selected */ static void dbgls_linnum(const char *lnfname, int32_t lineno, int32_t segto) { struct FileName *fn; struct ieeeSection *seg; int i = 0; if (segto == NO_SEG) return; /* * If `any_segs' is still false, we must define a default * segment. */ if (!any_segs) { int tempint; /* ignored */ if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint)) nasm_panic(0, "strange segment conditions in OBJ driver"); } /* * Find the segment we are targetting. */ for (seg = seghead; seg; seg = seg->next) if (seg->index == segto) break; if (!seg) nasm_panic(0, "lineno directed to nonexistent segment?"); for (fn = fnhead; fn; fn = fn->next) { if (!nasm_stricmp(lnfname, fn->name)) break; i++; } if (!fn) { fn = nasm_malloc(sizeof(*fn)); fn->name = nasm_malloc(strlen(lnfname) + 1); fn->index = i; strcpy(fn->name, lnfname); fn->next = NULL; *fntail = fn; fntail = &fn->next; } ieee_write_byte(seghead, fn->index); ieee_write_word(seghead, lineno); ieee_write_fixup(segto, NO_SEG, seghead, 4, OUT_ADDRESS, seg->currentpos); }
static void as86_set_rsize(int size) { if (as86_reloc_size != size) { switch (as86_reloc_size = size) { case 1: fputc(0x01, ofile); break; case 2: fputc(0x02, ofile); break; case 4: fputc(0x03, ofile); break; default: nasm_panic(0, "bizarre relocation size %d", size); break; } } }
static void as86_out(int32_t segto, const void *data, enum out_type type, uint64_t size, int32_t segment, int32_t wrt) { struct Section *s; int32_t offset; uint8_t mydata[4], *p; if (wrt != NO_SEG) { wrt = NO_SEG; /* continue to do _something_ */ nasm_error(ERR_NONFATAL, "WRT not supported by as86 output format"); } /* * handle absolute-assembly (structure definitions) */ if (segto == NO_SEG) { if (type != OUT_RESERVE) nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" " space"); return; } if (segto == stext.index) s = &stext; else if (segto == sdata.index) s = &sdata; else if (segto == bssindex) s = NULL; else { nasm_error(ERR_WARNING, "attempt to assemble code in" " segment %d: defaulting to `.text'", segto); s = &stext; } if (!s && type != OUT_RESERVE) { nasm_error(ERR_WARNING, "attempt to initialize memory in the" " BSS section: ignored"); bsslen += realsize(type, size); return; } memset(mydata, 0, sizeof(mydata)); if (type == OUT_RESERVE) { if (s) { nasm_error(ERR_WARNING, "uninitialized space declared in" " %s section: zeroing", (segto == stext.index ? "code" : "data")); as86_sect_write(s, NULL, size); as86_add_piece(s, 0, 0L, 0L, size, 0); } else bsslen += size; } else if (type == OUT_RAWDATA) { if (segment != NO_SEG) nasm_panic(0, "OUT_RAWDATA with other than NO_SEG"); as86_sect_write(s, data, size); as86_add_piece(s, 0, 0L, 0L, size, 0); } else if (type == OUT_ADDRESS) { int asize = abs((int)size); if (segment != NO_SEG) { if (segment % 2) { nasm_error(ERR_NONFATAL, "as86 format does not support" " segment base references"); } else { offset = *(int64_t *)data; as86_add_piece(s, 1, offset, segment, asize, 0); } } else { p = mydata; WRITELONG(p, *(int64_t *)data); as86_sect_write(s, data, asize); as86_add_piece(s, 0, 0L, 0L, asize, 0); } } else if (type == OUT_REL2ADR) { if (segment == segto) nasm_panic(0, "intra-segment OUT_REL2ADR"); if (segment != NO_SEG) { if (segment % 2) { nasm_error(ERR_NONFATAL, "as86 format does not support" " segment base references"); } else { offset = *(int64_t *)data; as86_add_piece(s, 1, offset - size + 2, segment, 2L, 1); } } } else if (type == OUT_REL4ADR) { if (segment == segto) nasm_panic(0, "intra-segment OUT_REL4ADR"); if (segment != NO_SEG) { if (segment % 2) { nasm_error(ERR_NONFATAL, "as86 format does not support" " segment base references"); } else { offset = *(int64_t *)data; as86_add_piece(s, 1, offset - size + 4, segment, 4L, 1); } } } }
static void ieee_write_file(void) { struct tm *thetime; time_t reltime; struct FileName *fn; struct ieeeSection *seg; struct ieeePublic *pub, *loc; struct ieeeExternal *ext; struct ieeeObjData *data; struct ieeeFixupp *fix; struct Array *arr; int i; const bool debuginfo = (dfmt == &ladsoft_debug_form); /* * Write the module header */ ieee_putascii("MBFNASM,%02X%s.\n", strlen(ieee_infile), ieee_infile); /* * Write the NASM boast comment. */ ieee_putascii("CO0,%02X%s.\n", strlen(nasm_comment), nasm_comment); /* * write processor-specific information */ ieee_putascii("AD8,4,L.\n"); /* * date and time */ time(&reltime); thetime = localtime(&reltime); ieee_putascii("DT%04d%02d%02d%02d%02d%02d.\n", 1900 + thetime->tm_year, thetime->tm_mon + 1, thetime->tm_mday, thetime->tm_hour, thetime->tm_min, thetime->tm_sec); /* * if debugging, dump file names */ for (fn = fnhead; fn && debuginfo; fn = fn->next) { ieee_putascii("C0105,%02X%s.\n", strlen(fn->name), fn->name); } ieee_putascii("CO101,07ENDHEAD.\n"); /* * the standard doesn't specify when to put checksums, * we'll just do it periodically. */ ieee_putcs(false); /* * Write the section headers */ seg = seghead; if (!debuginfo && !strcmp(seg->name, "??LINE")) seg = seg->next; while (seg) { char buf[256]; char attrib; switch (seg->combine) { case CMB_PUBLIC: default: attrib = 'C'; break; case CMB_PRIVATE: attrib = 'S'; break; case CMB_COMMON: attrib = 'M'; break; } ieee_unqualified_name(buf, seg->name); if (seg->align >= SEG_ABS) { ieee_putascii("ST%X,A,%02X%s.\n", seg->ieee_index, strlen(buf), buf); ieee_putascii("ASL%X,%lX.\n", seg->ieee_index, (seg->align - SEG_ABS) * 16); } else { ieee_putascii("ST%X,%c,%02X%s.\n", seg->ieee_index, attrib, strlen(buf), buf); ieee_putascii("SA%X,%lX.\n", seg->ieee_index, seg->align); ieee_putascii("ASS%X,%X.\n", seg->ieee_index, seg->currentpos); } seg = seg->next; } /* * write the start address if there is one */ if (ieee_entry_seg) { for (seg = seghead; seg; seg = seg->next) if (seg->index == ieee_entry_seg) break; if (!seg) nasm_panic(0, "Start address records are incorrect"); else ieee_putascii("ASG,R%X,%lX,+.\n", seg->ieee_index, ieee_entry_ofs); } ieee_putcs(false); /* * Write the publics */ i = 1; for (seg = seghead; seg; seg = seg->next) { for (pub = seg->pubhead; pub; pub = pub->next) { char buf[256]; ieee_unqualified_name(buf, pub->name); ieee_putascii("NI%X,%02X%s.\n", i, strlen(buf), buf); if (pub->segment == -1) ieee_putascii("ASI%X,R%X,%lX,+.\n", i, pub->index, pub->offset); else ieee_putascii("ASI%X,%lX,%lX,+.\n", i, pub->segment * 16, pub->offset); if (debuginfo) { if (pub->type >= 0x100) ieee_putascii("ATI%X,T%X.\n", i, pub->type - 0x100); else ieee_putascii("ATI%X,%X.\n", i, pub->type); } i++; } } pub = fpubhead; i = 1; while (pub) { char buf[256]; ieee_unqualified_name(buf, pub->name); ieee_putascii("NI%X,%02X%s.\n", i, strlen(buf), buf); if (pub->segment == -1) ieee_putascii("ASI%X,R%X,%lX,+.\n", i, pub->index, pub->offset); else ieee_putascii("ASI%X,%lX,%lX,+.\n", i, pub->segment * 16, pub->offset); if (debuginfo) { if (pub->type >= 0x100) ieee_putascii("ATI%X,T%X.\n", i, pub->type - 0x100); else ieee_putascii("ATI%X,%X.\n", i, pub->type); } i++; pub = pub->next; } /* * Write the externals */ ext = exthead; i = 1; while (ext) { char buf[256]; ieee_unqualified_name(buf, ext->name); ieee_putascii("NX%X,%02X%s.\n", i++, strlen(buf), buf); ext = ext->next; } ieee_putcs(false); /* * IEEE doesn't have a standard pass break record * so use the ladsoft variant */ ieee_putascii("CO100,06ENDSYM.\n"); /* * now put types */ i = ARRAY_BOT; for (arr = arrhead; arr && debuginfo; arr = arr->next) { ieee_putascii("TY%X,20,%X,%lX.\n", i++, arr->basetype, arr->size); } /* * now put locals */ i = 1; for (seg = seghead; seg && debuginfo; seg = seg->next) { for (loc = seg->lochead; loc; loc = loc->next) { char buf[256]; ieee_unqualified_name(buf, loc->name); ieee_putascii("NN%X,%02X%s.\n", i, strlen(buf), buf); if (loc->segment == -1) ieee_putascii("ASN%X,R%X,%lX,+.\n", i, loc->index, loc->offset); else ieee_putascii("ASN%X,%lX,%lX,+.\n", i, loc->segment * 16, loc->offset); if (debuginfo) { if (loc->type >= 0x100) ieee_putascii("ATN%X,T%X.\n", i, loc->type - 0x100); else ieee_putascii("ATN%X,%X.\n", i, loc->type); } i++; } } /* * put out section data; */ seg = seghead; if (!debuginfo && !strcmp(seg->name, "??LINE")) seg = seg->next; while (seg) { if (seg->currentpos) { int32_t size, org = 0; data = seg->data; ieee_putascii("SB%X.\n", seg->ieee_index); fix = seg->fptr; while (fix) { size = HUNKSIZE - (org % HUNKSIZE); size = size + org > seg->currentpos ? seg->currentpos - org : size; size = fix->offset - org > size ? size : fix->offset - org; org = ieee_putld(org, org + size, data->data); if (org % HUNKSIZE == 0) data = data->next; if (org == fix->offset) { org += ieee_putlr(fix); fix = fix->next; } } while (org < seg->currentpos && data) { size = seg->currentpos - org > HUNKSIZE ? HUNKSIZE : seg->currentpos - org; org = ieee_putld(org, org + size, data->data); data = data->next; } ieee_putcs(false); } seg = seg->next; } /* * module end record */ ieee_putascii("ME.\n"); }
/* * this routine is unalduterated bloatware. I usually don't do this * but I might as well see what it is like on a harmless program. * If anyone wants to optimize this is a good canditate! */ static void ieee_write_fixup(int32_t segment, int32_t wrt, struct ieeeSection *segto, int size, uint64_t realtype, int32_t offset) { struct ieeeSection *target; struct ieeeFixupp s; /* Don't put a fixup for things NASM can calculate */ if (wrt == NO_SEG && segment == NO_SEG) return; s.ftype = -1; /* if it is a WRT offset */ if (wrt != NO_SEG) { s.ftype = FT_WRT; s.addend = offset; if (wrt >= SEG_ABS) s.id1 = -(wrt - SEG_ABS); else { if (wrt % 2 && realtype != OUT_REL2ADR && realtype != OUT_REL4ADR) { wrt--; for (target = seghead; target; target = target->next) if (target->index == wrt) break; if (target) { s.id1 = target->ieee_index; for (target = seghead; target; target = target->next) if (target->index == segment) break; if (target) s.id2 = target->ieee_index; else { /* * Now we assume the segment field is being used * to hold an extern index */ int32_t i = segment / 2; struct ExtBack *eb = ebhead; while (i > EXT_BLKSIZ) { if (eb) eb = eb->next; else break; i -= EXT_BLKSIZ; } /* if we have an extern decide the type and make a record */ if (eb) { s.ftype = FT_EXTWRT; s.addend = 0; s.id2 = eb->index[i]; } else nasm_error(ERR_NONFATAL, "Source of WRT must be an offset"); } } else nasm_panic(0, "unrecognised WRT value in ieee_write_fixup"); } else nasm_error(ERR_NONFATAL, "target of WRT must be a section "); } s.size = size; ieee_install_fixup(segto, &s); return; } /* Pure segment fixup ? */ if (segment != NO_SEG) { s.ftype = FT_SEG; s.id1 = 0; if (segment >= SEG_ABS) { /* absolute far segment fixup */ s.id1 = -(segment - ~SEG_ABS); } else if (segment % 2) { /* fixup to named segment */ /* look it up */ for (target = seghead; target; target = target->next) if (target->index == segment - 1) break; if (target) s.id1 = target->ieee_index; else { /* * Now we assume the segment field is being used * to hold an extern index */ int32_t i = segment / 2; struct ExtBack *eb = ebhead; while (i > EXT_BLKSIZ) { if (eb) eb = eb->next; else break; i -= EXT_BLKSIZ; } /* if we have an extern decide the type and make a record */ if (eb) { if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { nasm_panic(0, "Segment of a rel not supported in ieee_write_fixup"); } else { /* If we want the segment */ s.ftype = FT_EXTSEG; s.addend = 0; s.id1 = eb->index[i]; } } else /* If we get here the seg value doesn't make sense */ nasm_panic(0, "unrecognised segment value in ieee_write_fixup"); } } else { /* Assume we are offsetting directly from a section * So look up the target segment */ for (target = seghead; target; target = target->next) if (target->index == segment) break; if (target) { if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { /* PC rel to a known offset */ s.id1 = target->ieee_index; s.ftype = FT_REL; s.size = size; s.addend = offset; } else { /* We were offsetting from a seg */ s.id1 = target->ieee_index; s.ftype = FT_OFS; s.size = size; s.addend = offset; } } else { /* * Now we assume the segment field is being used * to hold an extern index */ int32_t i = segment / 2; struct ExtBack *eb = ebhead; while (i > EXT_BLKSIZ) { if (eb) eb = eb->next; else break; i -= EXT_BLKSIZ; } /* if we have an extern decide the type and make a record */ if (eb) { if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { s.ftype = FT_EXTREL; s.addend = 0; s.id1 = eb->index[i]; } else { /* else we want the external offset */ s.ftype = FT_EXT; s.addend = 0; s.id1 = eb->index[i]; } } else /* If we get here the seg value doesn't make sense */ nasm_panic(0, "unrecognised segment value in ieee_write_fixup"); } } if (size != 2 && s.ftype == FT_SEG) nasm_error(ERR_NONFATAL, "IEEE format can only handle 2-byte" " segment base references"); s.size = size; ieee_install_fixup(segto, &s); return; } /* should never get here */ }
/* * Put data out */ static void ieee_out(int32_t segto, const void *data, enum out_type type, uint64_t size, int32_t segment, int32_t wrt) { const uint8_t *ucdata; int32_t ldata; struct ieeeSection *seg; /* * handle absolute-assembly (structure definitions) */ if (segto == NO_SEG) { if (type != OUT_RESERVE) nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" " space"); return; } /* * If `any_segs' is still false, we must define a default * segment. */ if (!any_segs) { int tempint; /* ignored */ if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint)) nasm_panic(0, "strange segment conditions in IEEE driver"); } /* * Find the segment we are targetting. */ for (seg = seghead; seg; seg = seg->next) if (seg->index == segto) break; if (!seg) nasm_panic(0, "code directed to nonexistent segment?"); if (type == OUT_RAWDATA) { ucdata = data; while (size--) ieee_write_byte(seg, *ucdata++); } else if (type == OUT_ADDRESS || type == OUT_REL2ADR || type == OUT_REL4ADR) { if (type == OUT_ADDRESS) size = abs((int)size); else if (segment == NO_SEG) nasm_error(ERR_NONFATAL, "relative call to absolute address not" " supported by IEEE format"); ldata = *(int64_t *)data; if (type == OUT_REL2ADR) ldata += (size - 2); if (type == OUT_REL4ADR) ldata += (size - 4); ieee_write_fixup(segment, wrt, seg, size, type, ldata); if (size == 2) ieee_write_word(seg, ldata); else ieee_write_dword(seg, ldata); } else if (type == OUT_RESERVE) { while (size--) ieee_write_byte(seg, 0); } }