NASM 0.98bf
[nasm.git] / zoutieee.c
blob6532ea25465e6fe3eef9f996647557c95a12529c
1 /* outieee.c output routines for the Netwide Assembler to produce
2 * IEEE-std object files
4 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
5 * Julian Hall. All rights reserved. The software is
6 * redistributable under the licence given in the file "Licence"
7 * distributed in the NASM archive.
8 */
10 /* notes: I have tried to make this correspond to the IEEE version
11 * of the standard, specifically the primary ASCII version. It should
12 * be trivial to create the binary version given this source (which is
13 * one of MANY things that have to be done to make this correspond to
14 * the hp-microtek version of the standard).
16 * 16-bit support is assumed to use 24-bit addresses
17 * The linker can sort out segmentation-specific stuff
18 * if it keeps track of externals
19 * in terms of being relative to section bases
21 * A non-standard variable type, the 'Yn' variable, has been introduced.
22 * Basically it is a reference to extern 'n'- denoting the low limit
23 * (L-variable) of the section that extern 'n' is defined in. Like the
24 * x variable, there may be no explicit assignment to it, it is derived
25 * from the public definition corresponding to the extern name. This
26 * is required because the one thing the mufom guys forgot to do well was
27 * take into account segmented architectures.
29 * I use comment classes for various things and these are undefined by
30 * the standard.
32 * Debug info should be considered totally non-standard (local labels are
33 * standard but linenum records are not covered by the standard.
34 * Type defs have the standard format but absolute meanings for ordinal
35 * types are not covered by the standard.)
37 * David Lindauer, LADsoft
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <stdarg.h> /* Note: we need the ANSI version of stdarg.h */
44 #include <ctype.h>
46 #include "nasm.h"
47 #include "nasmlib.h"
48 #include "outform.h"
50 #ifdef OF_IEEE
52 #define ARRAY_BOT 0x1
54 static char ieee_infile[FILENAME_MAX];
55 static int ieee_uppercase;
57 static efunc error;
58 static ldfunc deflabel;
59 static FILE *ofp;
60 static int any_segs;
61 static int arrindex;
63 #define HUNKSIZE 1024 /* Size of the data hunk */
64 #define EXT_BLKSIZ 512
65 #define LDPERLINE 32 /* bytes per line in output */
67 struct ieeeSection;
69 struct LineNumber {
70 struct LineNumber *next;
71 struct ieeeSection *segment;
72 long offset;
73 long lineno;
76 static struct FileName {
77 struct FileName *next;
78 char *name;
79 long index;
80 } *fnhead, **fntail;
82 static struct Array {
83 struct Array *next;
84 unsigned size;
85 int basetype;
86 } *arrhead, **arrtail;
88 static struct ieeePublic {
89 struct ieeePublic *next;
90 char *name;
91 long offset;
92 long segment; /* only if it's far-absolute */
93 long index;
94 int type; /* for debug purposes */
95 } *fpubhead, **fpubtail, *last_defined;
97 static struct ieeeExternal {
98 struct ieeeExternal *next;
99 char *name;
100 long commonsize;
101 } *exthead, **exttail;
103 static int externals;
105 static struct ExtBack {
106 struct ExtBack *next;
107 int index[EXT_BLKSIZ];
108 } *ebhead, **ebtail;
110 /* NOTE: the first segment MUST be the lineno segment */
111 static struct ieeeSection {
112 struct ieeeObjData *data,*datacurr;
113 struct ieeeSection *next;
114 struct ieeeFixupp *fptr, * flptr;
115 long index; /* the NASM segment id */
116 long ieee_index; /* the OBJ-file segment index */
117 long currentpos;
118 long align; /* can be SEG_ABS + absolute addr */
119 long startpos;
120 enum {
121 CMB_PRIVATE = 0,
122 CMB_PUBLIC = 2,
123 CMB_COMMON = 6
124 } combine;
125 long use32; /* is this segment 32-bit? */
126 struct ieeePublic *pubhead, **pubtail, *lochead, **loctail;
127 char *name;
128 } *seghead, **segtail, *ieee_seg_needs_update;
130 struct ieeeObjData {
131 struct ieeeObjData *next;
132 unsigned char data[HUNKSIZE];
135 struct ieeeFixupp {
136 struct ieeeFixupp *next;
137 enum {
138 FT_SEG = 0,
139 FT_REL = 1,
140 FT_OFS = 2,
141 FT_EXT = 3,
142 FT_WRT = 4,
143 FT_EXTREL = 5,
144 FT_EXTWRT = 6,
145 FT_EXTSEG = 7
146 } ftype;
147 short size;
148 long id1;
149 long id2;
150 long offset;
151 long addend;
154 static long ieee_entry_seg, ieee_entry_ofs;
155 static int checksum;
157 extern struct ofmt of_ieee;
159 static void ieee_data_new(struct ieeeSection *);
160 static void ieee_write_fixup (long, long, struct ieeeSection *,
161 int, unsigned long, long);
162 static void ieee_install_fixup(struct ieeeSection *, struct ieeeFixupp *);
163 static long ieee_segment (char *, int, int *);
164 static void ieee_write_file(int debuginfo);
165 static void ieee_write_byte(struct ieeeSection *, int);
166 static void ieee_write_word(struct ieeeSection *, int);
167 static void ieee_write_dword(struct ieeeSection *, long);
168 static void ieee_putascii(char *, ...);
169 static void ieee_putcs(int);
170 static long ieee_putld(long, long, unsigned char *);
171 static long ieee_putlr(struct ieeeFixupp *);
172 static void ieee_unqualified_name(char *, char *);
176 * pup init
178 static void ieee_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
180 (void) eval;
181 ofp = fp;
182 error = errfunc;
183 deflabel = ldef;
184 any_segs = FALSE;
185 fpubhead = NULL;
186 fpubtail = &fpubhead;
187 exthead = NULL;
188 exttail = &exthead;
189 externals = 1;
190 ebhead = NULL;
191 ebtail = &ebhead;
192 seghead = ieee_seg_needs_update = NULL;
193 segtail = &seghead;
194 ieee_entry_seg = NO_SEG;
195 ieee_uppercase = FALSE;
196 checksum = 0;
197 of_ieee.current_dfmt->init (&of_ieee,NULL,fp,errfunc);
199 static int ieee_set_info(enum geninfo type, char **val)
201 (void) type;
202 (void) val;
204 return 0;
207 * Rundown
209 static void ieee_cleanup (int debuginfo)
211 ieee_write_file(debuginfo);
212 of_ieee.current_dfmt->cleanup ();
213 fclose (ofp);
214 while (seghead) {
215 struct ieeeSection *segtmp = seghead;
216 seghead = seghead->next;
217 while (segtmp->pubhead) {
218 struct ieeePublic *pubtmp = segtmp->pubhead;
219 segtmp->pubhead = pubtmp->next;
220 nasm_free (pubtmp);
222 while (segtmp->fptr) {
223 struct ieeeFixupp *fixtmp = segtmp->fptr;
224 segtmp->fptr = fixtmp->next;
225 nasm_free(fixtmp);
227 while (segtmp->data) {
228 struct ieeeObjData *dattmp = segtmp->data;
229 segtmp->data = dattmp->next;
230 nasm_free(dattmp);
232 nasm_free (segtmp);
234 while (fpubhead) {
235 struct ieeePublic *pubtmp = fpubhead;
236 fpubhead = fpubhead->next;
237 nasm_free (pubtmp);
239 while (exthead) {
240 struct ieeeExternal *exttmp = exthead;
241 exthead = exthead->next;
242 nasm_free (exttmp);
244 while (ebhead) {
245 struct ExtBack *ebtmp = ebhead;
246 ebhead = ebhead->next;
247 nasm_free (ebtmp);
251 * callback for labels
253 static void ieee_deflabel (char *name, long segment,
254 long offset, int is_global, char *special) {
256 * We have three cases:
258 * (i) `segment' is a segment-base. If so, set the name field
259 * for the segment structure it refers to, and then
260 * return.
262 * (ii) `segment' is one of our segments, or a SEG_ABS segment.
263 * Save the label position for later output of a PUBDEF record.
266 * (iii) `segment' is not one of our segments. Save the label
267 * position for later output of an EXTDEF.
269 struct ieeeExternal *ext;
270 struct ExtBack *eb;
271 struct ieeeSection *seg;
272 int i;
274 if (special) {
275 error(ERR_NONFATAL, "unrecognised symbol type `%s'", special);
278 * First check for the double-period, signifying something
279 * unusual.
281 if (name[0] == '.' && name[1] == '.') {
282 if (!strcmp(name, "..start")) {
283 ieee_entry_seg = segment;
284 ieee_entry_ofs = offset;
286 return;
290 * Case (i):
292 if (ieee_seg_needs_update) {
293 ieee_seg_needs_update->name = name;
294 return;
296 if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
297 return;
300 * case (ii)
302 if (segment >= SEG_ABS) {
304 * SEG_ABS subcase of (ii).
306 if (is_global) {
307 struct ieeePublic *pub;
309 pub = *fpubtail = nasm_malloc(sizeof(*pub));
310 fpubtail = &pub->next;
311 pub->next = NULL;
312 pub->name = name;
313 pub->offset = offset;
314 pub->segment = segment & ~SEG_ABS;
316 return;
319 for (seg = seghead; seg && is_global; seg = seg->next)
320 if (seg->index == segment) {
321 struct ieeePublic *pub;
323 last_defined = pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
324 seg->pubtail = &pub->next;
325 pub->next = NULL;
326 pub->name = name;
327 pub->offset = offset;
328 pub->index = seg->ieee_index;
329 pub->segment = -1;
330 return;
334 * Case (iii).
336 if (is_global) {
337 ext = *exttail = nasm_malloc(sizeof(*ext));
338 ext->next = NULL;
339 exttail = &ext->next;
340 ext->name = name;
341 if (is_global == 2)
342 ext->commonsize = offset;
343 else
344 ext->commonsize = 0;
345 i = segment/2;
346 eb = ebhead;
347 if (!eb) {
348 eb = *ebtail = nasm_malloc(sizeof(*eb));
349 eb->next = NULL;
350 ebtail = &eb->next;
352 while (i > EXT_BLKSIZ) {
353 if (eb && eb->next)
354 eb = eb->next;
355 else {
356 eb = *ebtail = nasm_malloc(sizeof(*eb));
357 eb->next = NULL;
358 ebtail = &eb->next;
360 i -= EXT_BLKSIZ;
362 eb->index[i] = externals++;
368 * Put data out
370 static void ieee_out (long segto, void *data, unsigned long type,
371 long segment, long wrt) {
372 long size;
373 unsigned long realtype;
374 unsigned char *ucdata;
375 long ldata;
376 struct ieeeSection *seg;
379 * handle absolute-assembly (structure definitions)
381 if (segto == NO_SEG) {
382 if ((type & OUT_TYPMASK) != OUT_RESERVE)
383 error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
384 " space");
385 return;
389 * If `any_segs' is still FALSE, we must define a default
390 * segment.
392 if (!any_segs) {
393 int tempint; /* ignored */
394 if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint))
395 error (ERR_PANIC, "strange segment conditions in IEEE driver");
399 * Find the segment we are targetting.
401 for (seg = seghead; seg; seg = seg->next)
402 if (seg->index == segto)
403 break;
404 if (!seg)
405 error (ERR_PANIC, "code directed to nonexistent segment?");
407 size = type & OUT_SIZMASK;
408 realtype = type & OUT_TYPMASK;
409 if (realtype == OUT_RAWDATA) {
410 ucdata = data;
411 while (size--)
412 ieee_write_byte(seg,*ucdata++);
413 } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
414 realtype == OUT_REL4ADR) {
415 if (segment == NO_SEG && realtype != OUT_ADDRESS)
416 error(ERR_NONFATAL, "relative call to absolute address not"
417 " supported by IEEE format");
418 ldata = *(long *)data;
419 if (realtype == OUT_REL2ADR)
420 ldata += (size-2);
421 if (realtype == OUT_REL4ADR)
422 ldata += (size-4);
423 ieee_write_fixup (segment, wrt, seg, size, realtype,ldata);
424 if (size == 2)
425 ieee_write_word (seg, ldata);
426 else
427 ieee_write_dword (seg, ldata);
429 else if (realtype == OUT_RESERVE) {
430 while (size--)
431 ieee_write_byte(seg,0);
435 static void ieee_data_new(struct ieeeSection *segto) {
437 if (!segto->data)
438 segto->data = segto->datacurr = nasm_malloc(sizeof(*(segto->datacurr)));
439 else
440 segto->datacurr = segto->datacurr->next = nasm_malloc(sizeof(*(segto->datacurr)));
441 segto->datacurr->next = NULL;
446 * this routine is unalduterated bloatware. I usually don't do this
447 * but I might as well see what it is like on a harmless program.
448 * If anyone wants to optimize this is a good canditate!
450 static void ieee_write_fixup (long segment, long wrt, struct ieeeSection * segto,
451 int size, unsigned long realtype, long offset) {
452 struct ieeeSection *target;
453 struct ieeeFixupp s;
455 /* Don't put a fixup for things NASM can calculate */
456 if (wrt == NO_SEG && segment == NO_SEG)
457 return;
459 s.ftype = -1;
460 /* if it is a WRT offset */
461 if (wrt != NO_SEG) {
462 s.ftype = FT_WRT;
463 s.addend = offset;
464 if (wrt >= SEG_ABS)
465 s.id1 = -(wrt-SEG_ABS);
466 else {
467 if (wrt %2 && realtype != OUT_REL2ADR && realtype != OUT_REL4ADR) {
468 wrt--;
470 for (target = seghead; target; target = target->next)
471 if (target->index == wrt)
472 break;
473 if (target) {
474 s.id1 = target->ieee_index;
475 for (target = seghead; target; target = target->next)
476 if (target->index == segment)
477 break;
479 if (target)
480 s.id2 = target->ieee_index;
481 else {
483 * Now we assume the segment field is being used
484 * to hold an extern index
486 long i = segment/2;
487 struct ExtBack *eb = ebhead;
488 while (i > EXT_BLKSIZ) {
489 if (eb)
490 eb = eb->next;
491 else
492 break;
493 i -= EXT_BLKSIZ;
495 /* if we have an extern decide the type and make a record
497 if (eb) {
498 s.ftype = FT_EXTWRT;
499 s.addend = 0;
500 s.id2 = eb->index[i];
502 else
503 error(ERR_NONFATAL,
504 "Source of WRT must be an offset");
508 else
509 error(ERR_PANIC,
510 "unrecognised WRT value in ieee_write_fixup");
512 else
513 error(ERR_NONFATAL,"target of WRT must be a section ");
515 s.size = size;
516 ieee_install_fixup(segto,&s);
517 return;
519 /* Pure segment fixup ? */
520 if (segment != NO_SEG) {
521 s.ftype = FT_SEG;
522 s.id1 = 0;
523 if (segment >= SEG_ABS) {
524 /* absolute far segment fixup */
525 s.id1 = -(segment -~SEG_ABS);
527 else if (segment % 2) {
528 /* fixup to named segment */
529 /* look it up */
530 for (target = seghead; target; target = target->next)
531 if (target->index == segment-1)
532 break;
533 if (target)
534 s.id1 = target->ieee_index;
535 else {
537 * Now we assume the segment field is being used
538 * to hold an extern index
540 long i = segment/2;
541 struct ExtBack *eb = ebhead;
542 while (i > EXT_BLKSIZ) {
543 if (eb)
544 eb = eb->next;
545 else
546 break;
547 i -= EXT_BLKSIZ;
549 /* if we have an extern decide the type and make a record
551 if (eb) {
552 if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
553 error(ERR_PANIC,"Segment of a rel not supported in ieee_write_fixup");
555 else {
556 /* If we want the segment */
557 s.ftype = FT_EXTSEG;
558 s.addend = 0;
559 s.id1 = eb->index[i];
563 else
564 /* If we get here the seg value doesn't make sense */
565 error(ERR_PANIC,
566 "unrecognised segment value in ieee_write_fixup");
569 } else {
570 /* Assume we are offsetting directly from a section
571 * So look up the target segment
573 for (target = seghead; target; target = target->next)
574 if (target->index == segment)
575 break;
576 if (target) {
577 if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
578 /* PC rel to a known offset */
579 s.id1 = target->ieee_index;
580 s.ftype = FT_REL;
581 s.size = size;
582 s.addend = offset;
584 else {
585 /* We were offsetting from a seg */
586 s.id1 = target->ieee_index;
587 s.ftype = FT_OFS;
588 s.size = size;
589 s.addend = offset;
592 else {
594 * Now we assume the segment field is being used
595 * to hold an extern index
597 long i = segment/2;
598 struct ExtBack *eb = ebhead;
599 while (i > EXT_BLKSIZ) {
600 if (eb)
601 eb = eb->next;
602 else
603 break;
604 i -= EXT_BLKSIZ;
606 /* if we have an extern decide the type and make a record
608 if (eb) {
609 if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
610 s.ftype = FT_EXTREL;
611 s.addend = 0;
612 s.id1 = eb->index[i];
614 else {
615 /* else we want the external offset */
616 s.ftype = FT_EXT;
617 s.addend = 0;
618 s.id1 = eb->index[i];
622 else
623 /* If we get here the seg value doesn't make sense */
624 error(ERR_PANIC,
625 "unrecognised segment value in ieee_write_fixup");
628 if (size != 2 && s.ftype == FT_SEG)
629 error(ERR_NONFATAL, "IEEE format can only handle 2-byte"
630 " segment base references");
631 s.size = size;
632 ieee_install_fixup(segto,&s);
633 return;
635 /* should never get here */
637 static void ieee_install_fixup(struct ieeeSection *seg, struct ieeeFixupp *fix)
639 struct ieeeFixupp *f;
640 f = nasm_malloc(sizeof(struct ieeeFixupp));
641 memcpy(f,fix,sizeof(struct ieeeFixupp));
642 f->offset = seg->currentpos;
643 seg->currentpos += fix->size;
644 f->next = NULL;
645 if (seg->fptr)
646 seg->flptr = seg->flptr->next = f;
647 else
648 seg->fptr = seg->flptr = f;
653 * segment registry
655 static long ieee_segment (char *name, int pass, int *bits) {
657 * We call the label manager here to define a name for the new
658 * segment, and when our _own_ label-definition stub gets
659 * called in return, it should register the new segment name
660 * using the pointer it gets passed. That way we save memory,
661 * by sponging off the label manager.
663 if (!name) {
664 *bits = 16;
665 if (!any_segs)
666 return 0;
667 return seghead->index;
668 } else {
669 struct ieeeSection *seg;
670 int ieee_idx, attrs, rn_error;
671 char *p;
674 * Look for segment attributes.
676 attrs = 0;
677 while (*name == '.')
678 name++; /* hack, but a documented one */
679 p = name;
680 while (*p && !isspace(*p))
681 p++;
682 if (*p) {
683 *p++ = '\0';
684 while (*p && isspace(*p))
685 *p++ = '\0';
687 while (*p) {
688 while (*p && !isspace(*p))
689 p++;
690 if (*p) {
691 *p++ = '\0';
692 while (*p && isspace(*p))
693 *p++ = '\0';
696 attrs++;
699 ieee_idx = 1;
700 for (seg = seghead; seg; seg = seg->next) {
701 ieee_idx++;
702 if (!strcmp(seg->name, name)) {
703 if (attrs > 0 && pass == 1)
704 error(ERR_WARNING, "segment attributes specified on"
705 " redeclaration of segment: ignoring");
706 if (seg->use32)
707 *bits = 32;
708 else
709 *bits = 16;
710 return seg->index;
714 *segtail = seg = nasm_malloc(sizeof(*seg));
715 seg->next = NULL;
716 segtail = &seg->next;
717 seg->index = seg_alloc();
718 seg->ieee_index = ieee_idx;
719 any_segs = TRUE;
720 seg->name = NULL;
721 seg->currentpos = 0;
722 seg->align = 1; /* default */
723 seg->use32 = *bits == 32; /* default to user spec */
724 seg->combine = CMB_PUBLIC; /* default */
725 seg->pubhead = NULL;
726 seg->pubtail = &seg->pubhead;
727 seg->data = NULL;
728 seg->fptr = NULL;
729 seg->lochead = NULL;
730 seg->loctail = &seg->lochead;
733 * Process the segment attributes.
735 p = name;
736 while (attrs--) {
737 p += strlen(p);
738 while (!*p) p++;
741 * `p' contains a segment attribute.
743 if (!nasm_stricmp(p, "private"))
744 seg->combine = CMB_PRIVATE;
745 else if (!nasm_stricmp(p, "public"))
746 seg->combine = CMB_PUBLIC;
747 else if (!nasm_stricmp(p, "common"))
748 seg->combine = CMB_COMMON;
749 else if (!nasm_stricmp(p, "use16"))
750 seg->use32 = FALSE;
751 else if (!nasm_stricmp(p, "use32"))
752 seg->use32 = TRUE;
753 else if (!nasm_strnicmp(p, "align=", 6)) {
754 seg->align = readnum(p+6, &rn_error);
755 if (seg->align == 0)
756 seg->align = 1;
757 if (rn_error) {
758 seg->align = 1;
759 error (ERR_NONFATAL, "segment alignment should be"
760 " numeric");
762 switch ((int) seg->align) {
763 case 1: /* BYTE */
764 case 2: /* WORD */
765 case 4: /* DWORD */
766 case 16: /* PARA */
767 case 256: /* PAGE */
768 case 8:
769 case 32:
770 case 64:
771 case 128:
772 break;
773 default:
774 error(ERR_NONFATAL, "invalid alignment value %d",
775 seg->align);
776 seg->align = 1;
777 break;
779 } else if (!nasm_strnicmp(p, "absolute=", 9)) {
780 seg->align = SEG_ABS + readnum(p+9, &rn_error);
781 if (rn_error)
782 error (ERR_NONFATAL, "argument to `absolute' segment"
783 " attribute should be numeric");
787 ieee_seg_needs_update = seg;
788 if (seg->align >= SEG_ABS)
789 deflabel (name, NO_SEG, seg->align - SEG_ABS,
790 NULL, FALSE, FALSE, &of_ieee, error);
791 else
792 deflabel (name, seg->index+1, 0L,
793 NULL, FALSE, FALSE, &of_ieee, error);
794 ieee_seg_needs_update = NULL;
796 if (seg->use32)
797 *bits = 32;
798 else
799 *bits = 16;
800 return seg->index;
804 * directives supported
806 static int ieee_directive (char *directive, char *value, int pass)
809 (void) value;
810 (void) pass;
811 if (!strcmp(directive, "uppercase")) {
812 ieee_uppercase = TRUE;
813 return 1;
815 return 0;
818 * Return segment data
820 static long ieee_segbase (long segment)
822 struct ieeeSection *seg;
825 * Find the segment in our list.
827 for (seg = seghead; seg; seg = seg->next)
828 if (seg->index == segment-1)
829 break;
831 if (!seg)
832 return segment; /* not one of ours - leave it alone */
834 if (seg->align >= SEG_ABS)
835 return seg->align; /* absolute segment */
837 return segment; /* no special treatment */
840 * filename
842 static void ieee_filename (char *inname, char *outname, efunc error) {
843 strcpy(ieee_infile, inname);
844 standard_extension (inname, outname, ".o", error);
847 static void ieee_write_file (int debuginfo) {
848 struct tm *thetime;
849 time_t reltime;
850 struct FileName *fn;
851 struct ieeeSection *seg;
852 struct ieeePublic *pub, *loc;
853 struct ieeeExternal *ext;
854 struct ieeeObjData *data;
855 struct ieeeFixupp *fix;
856 struct Array *arr;
857 static char boast[] = "The Netwide Assembler " NASM_VER;
858 int i;
861 * Write the module header
863 ieee_putascii("MBFNASM,%02X%s.\r\n",strlen(ieee_infile),ieee_infile);
866 * Write the NASM boast comment.
868 ieee_putascii("CO0,%02X%s.\r\n",strlen(boast),boast);
871 * write processor-specific information
873 ieee_putascii("AD8,4,L.\r\n");
876 * date and time
878 time(&reltime);
879 thetime = localtime(&reltime);
880 ieee_putascii("DT%04d%02d%02d%02d%02d%02d.\r\n",
881 1900+thetime->tm_year,thetime->tm_mon+1,thetime->tm_mday,
882 thetime->tm_hour, thetime->tm_min, thetime->tm_sec);
884 * if debugging, dump file names
886 for (fn = fnhead; fn && debuginfo; fn = fn->next) {
887 ieee_putascii("C0105,%02X%s.\r\n",strlen(fn->name),fn->name);
890 ieee_putascii("CO101,07ENDHEAD.\r\n");
892 * the standard doesn't specify when to put checksums,
893 * we'll just do it periodically.
895 ieee_putcs(FALSE);
898 * Write the section headers
900 seg = seghead;
901 if (!debuginfo && !strcmp(seg->name,"??LINE"))
902 seg = seg->next;
903 while (seg) {
904 char buf[256];
905 char attrib;
906 switch(seg->combine) {
907 case CMB_PUBLIC:
908 default:
909 attrib = 'C';
910 break;
911 case CMB_PRIVATE:
912 attrib = 'S';
913 break;
914 case CMB_COMMON:
915 attrib = 'M';
916 break;
918 ieee_unqualified_name(buf,seg->name);
919 if (seg->align >= SEG_ABS) {
920 ieee_putascii("ST%X,A,%02X%s.\r\n",seg->ieee_index,strlen(buf), buf);
921 ieee_putascii("ASL%X,%lX.\r\n",seg->ieee_index, (seg->align - SEG_ABS)*16);
923 else {
924 ieee_putascii("ST%X,%c,%02X%s.\r\n",seg->ieee_index,attrib,strlen(buf), buf);
925 ieee_putascii("SA%X,%lX.\r\n",seg->ieee_index,seg->align);
926 ieee_putascii("ASS%X,%X.\r\n",seg->ieee_index, seg->currentpos);
928 seg = seg->next;
931 * write the start address if there is one
933 if (ieee_entry_seg) {
934 for (seg = seghead; seg; seg = seg->next)
935 if (seg->index == ieee_entry_seg)
936 break;
937 if (!seg)
938 error(ERR_PANIC,"Start address records are incorrect");
939 else
940 ieee_putascii("ASG,R%X,%lX,+.\r\n",seg->ieee_index, ieee_entry_ofs);
944 ieee_putcs(FALSE);
946 * Write the publics
948 i = 1;
949 for (seg = seghead; seg; seg = seg->next) {
950 for (pub = seg->pubhead; pub; pub = pub->next) {
951 char buf[256];
952 ieee_unqualified_name(buf,pub->name);
953 ieee_putascii("NI%X,%02X%s.\r\n",i, strlen(buf), buf);
954 if (pub->segment == -1)
955 ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,pub->offset);
956 else
957 ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset);
958 if (debuginfo) {
959 if (pub->type >= 0x100)
960 ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100);
961 else
962 ieee_putascii("ATI%X,%X.\r\n", i, pub->type);
964 i++;
967 pub = fpubhead;
968 i = 1;
969 while (pub) {
970 char buf[256];
971 ieee_unqualified_name(buf,pub->name);
972 ieee_putascii("NI%X,%02X%s.\r\n",i, strlen(buf), buf);
973 if (pub->segment == -1)
974 ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,pub->offset);
975 else
976 ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset);
977 if (debuginfo) {
978 if (pub->type >= 0x100)
979 ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100);
980 else
981 ieee_putascii("ATI%X,%X.\r\n", i, pub->type);
983 i++;
984 pub = pub->next;
987 * Write the externals
989 ext = exthead;
990 i = 1;
991 while (ext) {
992 char buf[256];
993 ieee_unqualified_name(buf,ext->name);
994 ieee_putascii("NX%X,%02X%s.\r\n",i++, strlen(buf), buf);
995 ext = ext->next;
997 ieee_putcs(FALSE);
1000 * IEEE doesn't have a standard pass break record
1001 * so use the ladsoft variant
1003 ieee_putascii("CO100,06ENDSYM.\r\n");
1006 * now put types
1008 i = ARRAY_BOT;
1009 for (arr = arrhead; arr && debuginfo; arr = arr->next) {
1010 ieee_putascii("TY%X,20,%X,%lX.\r\n",i++,arr->basetype,arr->size);
1013 * now put locals
1015 i = 1;
1016 for (seg = seghead; seg && debuginfo; seg = seg->next) {
1017 for (loc = seg->lochead; loc; loc = loc->next) {
1018 char buf[256];
1019 ieee_unqualified_name(buf,loc->name);
1020 ieee_putascii("NN%X,%02X%s.\r\n",i, strlen(buf), buf);
1021 if (loc->segment == -1)
1022 ieee_putascii("ASN%X,R%X,%lX,+.\r\n", i, loc->index,loc->offset);
1023 else
1024 ieee_putascii("ASN%X,%lX,%lX,+.\r\n", i, loc->segment*16,loc->offset);
1025 if (debuginfo) {
1026 if (loc->type >= 0x100)
1027 ieee_putascii("ATN%X,T%X.\r\n", i, loc->type - 0x100);
1028 else
1029 ieee_putascii("ATN%X,%X.\r\n", i, loc->type);
1031 i++;
1036 * put out section data;
1038 seg = seghead;
1039 if (!debuginfo && !strcmp(seg->name,"??LINE"))
1040 seg = seg->next;
1041 while (seg) {
1042 if (seg->currentpos) {
1043 long size,org = 0;
1044 data = seg->data;
1045 ieee_putascii("SB%X.\r\n",seg->ieee_index);
1046 fix = seg->fptr;
1047 while (fix) {
1048 size = HUNKSIZE - (org %HUNKSIZE);
1049 size = size +org > seg->currentpos ? seg->currentpos-org : size;
1050 size = fix->offset - org > size ? size : fix->offset-org;
1051 org = ieee_putld(org,org+size,data->data);
1052 if (org % HUNKSIZE == 0)
1053 data = data->next;
1054 if (org == fix->offset) {
1055 org += ieee_putlr(fix);
1056 fix = fix->next;
1059 while (org < seg->currentpos && data) {
1060 size = seg->currentpos-org > HUNKSIZE ? HUNKSIZE : seg->currentpos - org;
1061 org = ieee_putld(org,org+size,data->data);
1062 data = data->next;
1064 ieee_putcs(FALSE);
1067 seg = seg->next;
1070 * module end record
1072 ieee_putascii("ME.\r\n");
1075 static void ieee_write_byte(struct ieeeSection *seg, int data) {
1076 int temp;
1077 if (!(temp = seg->currentpos++ % HUNKSIZE))
1078 ieee_data_new(seg);
1079 seg->datacurr->data[temp] = data;
1082 static void ieee_write_word(struct ieeeSection *seg, int data) {
1083 ieee_write_byte(seg, data & 0xFF);
1084 ieee_write_byte(seg,(data >> 8) & 0xFF);
1087 static void ieee_write_dword(struct ieeeSection *seg, long data) {
1088 ieee_write_byte(seg, data & 0xFF);
1089 ieee_write_byte(seg,(data >> 8) & 0xFF);
1090 ieee_write_byte(seg,(data >> 16) & 0xFF);
1091 ieee_write_byte(seg,(data >> 24) & 0xFF);
1093 static void ieee_putascii(char *format, ...)
1095 char buffer[256];
1096 int i,l;
1097 va_list ap;
1099 va_start(ap, format);
1100 vsprintf(buffer, format, ap);
1101 l = strlen(buffer);
1102 for (i=0; i < l; i++)
1103 if ((buffer[i] & 0xff) > 31)
1104 checksum+=buffer[i];
1105 va_end(ap);
1106 fprintf(ofp,buffer);
1110 * put out a checksum record */
1111 static void ieee_putcs(int toclear)
1113 if (toclear) {
1114 ieee_putascii("CS.\r\n");
1116 else {
1117 checksum += 'C';
1118 checksum += 'S';
1119 ieee_putascii("CS%02X.\r\n",checksum & 127);
1121 checksum = 0;
1124 static long ieee_putld(long start, long end, unsigned char *buf)
1126 long val;
1127 if (start == end)
1128 return(start);
1129 val = start % HUNKSIZE;
1130 /* fill up multiple lines */
1131 while (end - start >= LDPERLINE) {
1132 int i;
1133 ieee_putascii("LD");
1134 for (i=0; i < LDPERLINE; i++) {
1135 ieee_putascii("%02X",buf[val++]);
1136 start++;
1138 ieee_putascii(".\r\n");
1140 /* if no partial lines */
1141 if (start == end)
1142 return(start);
1143 /* make a partial line */
1144 ieee_putascii("LD");
1145 while (start < end) {
1146 ieee_putascii("%02X",buf[val++]);
1147 start++;
1149 ieee_putascii(".\r\n");
1150 return(start);
1152 static long ieee_putlr(struct ieeeFixupp *p)
1155 * To deal with the vagaries of segmentation the LADsoft linker
1156 * defines two types of segments: absolute and virtual. Note that
1157 * 'absolute' in this context is a different thing from the IEEE
1158 * definition of an absolute segment type, which is also supported. If a
1159 * sement is linked in virtual mode the low limit (L-var) is
1160 * subtracted from each R,X, and P variable which appears in an
1161 * expression, so that we can have relative offsets. Meanwhile
1162 * in the ABSOLUTE mode this subtraction is not done and
1163 * so we can use absolute offsets from 0. In the LADsoft linker
1164 * this configuration is not done in the assemblker source but in
1165 * a source the linker reads. Generally this type of thing only
1166 * becomes an issue if real mode code is used. A pure 32-bit linker could
1167 * get away without defining the virtual mode...
1169 char buf[40];
1170 long size=p->size;
1171 switch(p->ftype) {
1172 case FT_SEG:
1173 if (p->id1 < 0)
1174 sprintf(buf,"%lX",-p->id1);
1175 else
1176 sprintf(buf,"L%lX,10,/",p->id1);
1177 break;
1178 case FT_OFS:
1179 sprintf(buf,"R%lX,%lX,+",p->id1,p->addend);
1180 break;
1181 case FT_REL:
1182 sprintf(buf,"R%lX,%lX,+,P,-,%X,-",p->id1,p->addend,p->size);
1183 break;
1185 case FT_WRT:
1186 if (p->id2 < 0)
1187 sprintf(buf,"R%lX,%lX,+,L%lX,+,%lX,-",p->id2,p->addend,p->id2,-p->id1*16);
1188 else
1189 sprintf(buf,"R%lX,%lX,+,L%lX,+,L%lX,-",p->id2,p->addend,p->id2,p->id1);
1190 break;
1191 case FT_EXT:
1192 sprintf(buf,"X%lX",p->id1);
1193 break;
1194 case FT_EXTREL:
1195 sprintf(buf,"X%lX,P,-,%lX,-",p->id1,size);
1196 break;
1197 case FT_EXTSEG:
1198 /* We needed a non-ieee hack here.
1199 * We introduce the Y variable, which is the low
1200 * limit of the native segment the extern resides in
1202 sprintf(buf,"Y%lX,10,/",p->id1);
1203 break;
1204 case FT_EXTWRT:
1205 if (p->id2 < 0)
1206 sprintf(buf,"X%lX,Y%lX,+,%lX,-",p->id2,p->id2,-p->id1*16);
1207 else
1208 sprintf(buf,"X%lX,Y%lX,+,L%lX,-",p->id2,p->id2,p->id1);
1209 break;
1211 ieee_putascii("LR(%s,%lX).\r\n", buf, size);
1213 return(size);
1215 /* Dump all segment data (text and fixups )*/
1217 static void ieee_unqualified_name(char *dest, char *source)
1219 if (ieee_uppercase) {
1220 while (*source)
1221 *dest++ = toupper(*source++);
1222 *dest = 0;
1224 else strcpy(dest,source);
1226 void dbgls_init(struct ofmt * of, void * id, FILE * fp, efunc error)
1228 int tempint;
1229 (void) of;
1230 (void) id;
1231 (void) fp;
1232 (void) error;
1234 fnhead = NULL;
1235 fntail = &fnhead;
1236 arrindex = ARRAY_BOT ;
1237 arrhead = NULL;
1238 arrtail = &arrhead;
1239 ieee_segment("??LINE", 2, &tempint);
1240 any_segs = FALSE;
1242 static void dbgls_cleanup(void)
1244 struct ieeeSection *segtmp;
1245 while (fnhead) {
1246 struct FileName *fntemp = fnhead;
1247 fnhead = fnhead->next;
1248 nasm_free (fntemp->name);
1249 nasm_free (fntemp);
1251 for (segtmp = seghead; segtmp; segtmp = segtmp->next) {
1252 while (segtmp->lochead) {
1253 struct ieeePublic *loctmp = segtmp->lochead;
1254 segtmp->lochead = loctmp->next;
1255 nasm_free (loctmp->name);
1256 nasm_free (loctmp);
1259 while (arrhead) {
1260 struct Array *arrtmp = arrhead;
1261 arrhead = arrhead->next;
1262 nasm_free (arrtmp);
1267 * because this routine is not bracketed in
1268 * the main program, this routine will be called even if there
1269 * is no request for debug info
1270 * so, we have to make sure the ??LINE segment is avaialbe
1271 * as the first segment when this debug format is selected
1273 static void dbgls_linnum (const char *lnfname, long lineno, long segto)
1275 struct FileName *fn;
1276 struct ieeeSection *seg;
1277 int i = 0;
1278 if (segto == NO_SEG)
1279 return;
1282 * If `any_segs' is still FALSE, we must define a default
1283 * segment.
1285 if (!any_segs) {
1286 int tempint; /* ignored */
1287 if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint))
1288 error (ERR_PANIC, "strange segment conditions in OBJ driver");
1292 * Find the segment we are targetting.
1294 for (seg = seghead; seg; seg = seg->next)
1295 if (seg->index == segto)
1296 break;
1297 if (!seg)
1298 error (ERR_PANIC, "lineno directed to nonexistent segment?");
1300 for (fn = fnhead; fn; fn = fnhead->next) {
1301 if (!nasm_stricmp(lnfname,fn->name))
1302 break;
1303 i++;
1305 if (!fn) {
1306 fn = nasm_malloc ( sizeof( *fn));
1307 fn->name = nasm_malloc ( strlen(lnfname) + 1) ;
1308 fn->index = i;
1309 strcpy (fn->name,lnfname);
1310 fn->next = NULL;
1311 *fntail = fn;
1312 fntail = &fn->next;
1314 ieee_write_byte(seghead, fn->index);
1315 ieee_write_word(seghead, lineno);
1316 ieee_write_fixup (segto, NO_SEG, seghead, 4,OUT_ADDRESS,seg->currentpos);
1319 static void dbgls_deflabel (char *name, long segment,
1320 long offset, int is_global, char *special)
1322 struct ieeeSection *seg;
1323 int used_special; /* have we used the special text? */
1325 /* Keep compiler from warning about special and used_special */
1326 used_special = special ? FALSE : FALSE;
1329 * If it's a special-retry from pass two, discard it.
1331 if (is_global == 3)
1332 return;
1335 * First check for the double-period, signifying something
1336 * unusual.
1338 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
1339 return;
1343 * Case (i):
1345 if (ieee_seg_needs_update)
1346 return;
1347 if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
1348 return;
1350 if (segment >= SEG_ABS || segment == NO_SEG) {
1351 return;
1355 * If `any_segs' is still FALSE, we might need to define a
1356 * default segment, if they're trying to declare a label in
1357 * `first_seg'. But the label should exist due to a prior
1358 * call to ieee_deflabel so we can skip that.
1361 for (seg = seghead; seg; seg = seg->next)
1362 if (seg->index == segment) {
1363 struct ieeePublic *loc;
1365 * Case (ii). Maybe MODPUB someday?
1367 if (!is_global) {
1368 last_defined = loc = nasm_malloc (sizeof(*loc));
1369 *seg->loctail = loc;
1370 seg->loctail = &loc->next;
1371 loc->next = NULL;
1372 loc->name = nasm_strdup(name);
1373 loc->offset = offset;
1374 loc->segment = -1;
1375 loc->index = seg->ieee_index;
1379 static void dbgls_typevalue (long type)
1381 int elem = TYM_ELEMENTS(type);
1382 type = TYM_TYPE(type);
1384 if (! last_defined)
1385 return;
1387 switch (type) {
1388 case TY_BYTE:
1389 last_defined->type = 1; /* unsigned char */
1390 break;
1391 case TY_WORD:
1392 last_defined->type = 3; /* unsigned word */
1393 break;
1394 case TY_DWORD:
1395 last_defined->type = 5; /* unsigned dword */
1396 break;
1397 case TY_FLOAT:
1398 last_defined->type = 9; /* float */
1399 break;
1400 case TY_QWORD:
1401 last_defined->type = 10; /* qword */
1402 break;
1403 case TY_TBYTE:
1404 last_defined->type = 11; /* TBYTE */
1405 break;
1406 default:
1407 last_defined->type = 0x10; /* near label */
1408 break;
1411 if (elem > 1) {
1412 struct Array *arrtmp = nasm_malloc (sizeof(*arrtmp));
1413 int vtype = last_defined->type;
1414 arrtmp->size = elem;
1415 arrtmp->basetype = vtype;
1416 arrtmp->next = NULL;
1417 last_defined->type = arrindex++ + 0x100;
1418 *arrtail = arrtmp;
1419 arrtail = & (arrtmp->next);
1421 last_defined = NULL;
1423 static void dbgls_output (int output_type, void *param)
1425 (void) output_type;
1426 (void) param;
1428 static struct dfmt ladsoft_debug_form = {
1429 "LADsoft Debug Records",
1430 "ladsoft",
1431 dbgls_init,
1432 dbgls_linnum,
1433 dbgls_deflabel,
1434 null_debug_routine,
1435 dbgls_typevalue,
1436 dbgls_output,
1437 dbgls_cleanup,
1439 static struct dfmt *ladsoft_debug_arr[3] = {
1440 &ladsoft_debug_form,
1441 &null_debug_form,
1442 NULL
1444 struct ofmt of_ieee = {
1445 "IEEE-695 (LADsoft variant) object file format",
1446 "ieee",
1447 NULL,
1448 ladsoft_debug_arr,
1449 &null_debug_form,
1450 NULL,
1451 ieee_init,
1452 ieee_set_info,
1453 ieee_out,
1454 ieee_deflabel,
1455 ieee_segment,
1456 ieee_segbase,
1457 ieee_directive,
1458 ieee_filename,
1459 ieee_cleanup
1462 #endif /* OF_IEEE */