Upgrade label functions to 64-bit
[platform/upstream/nasm.git] / output / outieee.c
1 /* outieee.c    output routines for the Netwide Assembler to produce
2  *              IEEE-std object files
3  *
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  */
9
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).
15  *
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
20  *
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.
28  *
29  * I use comment classes for various things and these are undefined by
30  * the standard.
31  *
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.)
36  *
37  * David Lindauer, LADsoft
38  */
39 #include "compiler.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <time.h>
45 #include <stdarg.h>             /* Note: we need the ANSI version of stdarg.h */
46 #include <ctype.h>
47 #include <inttypes.h>
48
49 #include "nasm.h"
50 #include "nasmlib.h"
51 #include "outform.h"
52
53 #ifdef OF_IEEE
54
55 #define ARRAY_BOT 0x1
56
57 static char ieee_infile[FILENAME_MAX];
58 static int ieee_uppercase;
59
60 static efunc error;
61 static ldfunc deflabel;
62 static FILE *ofp;
63 static bool any_segs;
64 static int arrindex;
65
66 #define HUNKSIZE 1024           /* Size of the data hunk */
67 #define EXT_BLKSIZ 512
68 #define LDPERLINE 32            /* bytes per line in output */
69
70 struct ieeeSection;
71
72 struct LineNumber {
73     struct LineNumber *next;
74     struct ieeeSection *segment;
75     int32_t offset;
76     int32_t lineno;
77 };
78
79 static struct FileName {
80     struct FileName *next;
81     char *name;
82     int32_t index;
83 } *fnhead, **fntail;
84
85 static struct Array {
86     struct Array *next;
87     unsigned size;
88     int basetype;
89 } *arrhead, **arrtail;
90
91 static struct ieeePublic {
92     struct ieeePublic *next;
93     char *name;
94     int32_t offset;
95     int32_t segment;               /* only if it's far-absolute */
96     int32_t index;
97     int type;                   /* for debug purposes */
98 } *fpubhead, **fpubtail, *last_defined;
99
100 static struct ieeeExternal {
101     struct ieeeExternal *next;
102     char *name;
103     int32_t commonsize;
104 } *exthead, **exttail;
105
106 static int externals;
107
108 static struct ExtBack {
109     struct ExtBack *next;
110     int index[EXT_BLKSIZ];
111 } *ebhead, **ebtail;
112
113 /* NOTE: the first segment MUST be the lineno segment */
114 static struct ieeeSection {
115     struct ieeeObjData *data, *datacurr;
116     struct ieeeSection *next;
117     struct ieeeFixupp *fptr, *flptr;
118     int32_t index;                 /* the NASM segment id */
119     int32_t ieee_index;            /* the OBJ-file segment index */
120     int32_t currentpos;
121     int32_t align;                 /* can be SEG_ABS + absolute addr */
122     int32_t startpos;
123     enum {
124         CMB_PRIVATE = 0,
125         CMB_PUBLIC = 2,
126         CMB_COMMON = 6
127     } combine;
128     int32_t use32;                 /* is this segment 32-bit? */
129     struct ieeePublic *pubhead, **pubtail, *lochead, **loctail;
130     char *name;
131 } *seghead, **segtail, *ieee_seg_needs_update;
132
133 struct ieeeObjData {
134     struct ieeeObjData *next;
135     uint8_t data[HUNKSIZE];
136 };
137
138 struct ieeeFixupp {
139     struct ieeeFixupp *next;
140     enum {
141         FT_SEG = 0,
142         FT_REL = 1,
143         FT_OFS = 2,
144         FT_EXT = 3,
145         FT_WRT = 4,
146         FT_EXTREL = 5,
147         FT_EXTWRT = 6,
148         FT_EXTSEG = 7
149     } ftype;
150     int16_t size;
151     int32_t id1;
152     int32_t id2;
153     int32_t offset;
154     int32_t addend;
155 };
156
157 static int32_t ieee_entry_seg, ieee_entry_ofs;
158 static int checksum;
159
160 extern struct ofmt of_ieee;
161
162 static void ieee_data_new(struct ieeeSection *);
163 static void ieee_write_fixup(int32_t, int32_t, struct ieeeSection *,
164                              int, uint32_t, int32_t);
165 static void ieee_install_fixup(struct ieeeSection *, struct ieeeFixupp *);
166 static int32_t ieee_segment(char *, int, int *);
167 static void ieee_write_file(int debuginfo);
168 static void ieee_write_byte(struct ieeeSection *, int);
169 static void ieee_write_word(struct ieeeSection *, int);
170 static void ieee_write_dword(struct ieeeSection *, int32_t);
171 static void ieee_putascii(char *, ...);
172 static void ieee_putcs(int);
173 static int32_t ieee_putld(int32_t, int32_t, uint8_t *);
174 static int32_t ieee_putlr(struct ieeeFixupp *);
175 static void ieee_unqualified_name(char *, char *);
176
177 /*
178  * pup init
179  */
180 static void ieee_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval)
181 {
182     (void)eval;
183     ofp = fp;
184     error = errfunc;
185     deflabel = ldef;
186     any_segs = false;
187     fpubhead = NULL;
188     fpubtail = &fpubhead;
189     exthead = NULL;
190     exttail = &exthead;
191     externals = 1;
192     ebhead = NULL;
193     ebtail = &ebhead;
194     seghead = ieee_seg_needs_update = NULL;
195     segtail = &seghead;
196     ieee_entry_seg = NO_SEG;
197     ieee_uppercase = false;
198     checksum = 0;
199     of_ieee.current_dfmt->init(&of_ieee, NULL, fp, errfunc);
200 }
201 static int ieee_set_info(enum geninfo type, char **val)
202 {
203     (void)type;
204     (void)val;
205
206     return 0;
207 }
208
209 /*
210  * Rundown
211  */
212 static void ieee_cleanup(int debuginfo)
213 {
214     ieee_write_file(debuginfo);
215     of_ieee.current_dfmt->cleanup();
216     fclose(ofp);
217     while (seghead) {
218         struct ieeeSection *segtmp = seghead;
219         seghead = seghead->next;
220         while (segtmp->pubhead) {
221             struct ieeePublic *pubtmp = segtmp->pubhead;
222             segtmp->pubhead = pubtmp->next;
223             nasm_free(pubtmp);
224         }
225         while (segtmp->fptr) {
226             struct ieeeFixupp *fixtmp = segtmp->fptr;
227             segtmp->fptr = fixtmp->next;
228             nasm_free(fixtmp);
229         }
230         while (segtmp->data) {
231             struct ieeeObjData *dattmp = segtmp->data;
232             segtmp->data = dattmp->next;
233             nasm_free(dattmp);
234         }
235         nasm_free(segtmp);
236     }
237     while (fpubhead) {
238         struct ieeePublic *pubtmp = fpubhead;
239         fpubhead = fpubhead->next;
240         nasm_free(pubtmp);
241     }
242     while (exthead) {
243         struct ieeeExternal *exttmp = exthead;
244         exthead = exthead->next;
245         nasm_free(exttmp);
246     }
247     while (ebhead) {
248         struct ExtBack *ebtmp = ebhead;
249         ebhead = ebhead->next;
250         nasm_free(ebtmp);
251     }
252 }
253
254 /*
255  * callback for labels
256  */
257 static void ieee_deflabel(char *name, int32_t segment,
258                           int64_t offset, int is_global, char *special)
259 {
260     /*
261      * We have three cases:
262      *
263      * (i) `segment' is a segment-base. If so, set the name field
264      * for the segment structure it refers to, and then
265      * return.
266      *
267      * (ii) `segment' is one of our segments, or a SEG_ABS segment.
268      * Save the label position for later output of a PUBDEF record.
269      *
270      *
271      * (iii) `segment' is not one of our segments. Save the label
272      * position for later output of an EXTDEF.
273      */
274     struct ieeeExternal *ext;
275     struct ExtBack *eb;
276     struct ieeeSection *seg;
277     int i;
278
279     if (special) {
280         error(ERR_NONFATAL, "unrecognised symbol type `%s'", special);
281     }
282     /*
283      * First check for the double-period, signifying something
284      * unusual.
285      */
286     if (name[0] == '.' && name[1] == '.') {
287         if (!strcmp(name, "..start")) {
288             ieee_entry_seg = segment;
289             ieee_entry_ofs = offset;
290         }
291         return;
292     }
293
294     /*
295      * Case (i):
296      */
297     if (ieee_seg_needs_update) {
298         ieee_seg_needs_update->name = name;
299         return;
300     }
301     if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
302         return;
303
304     /*
305      * case (ii)
306      */
307     if (segment >= SEG_ABS) {
308         /*
309          * SEG_ABS subcase of (ii).
310          */
311         if (is_global) {
312             struct ieeePublic *pub;
313
314             pub = *fpubtail = nasm_malloc(sizeof(*pub));
315             fpubtail = &pub->next;
316             pub->next = NULL;
317             pub->name = name;
318             pub->offset = offset;
319             pub->segment = segment & ~SEG_ABS;
320         }
321         return;
322     }
323
324     for (seg = seghead; seg && is_global; seg = seg->next)
325         if (seg->index == segment) {
326             struct ieeePublic *pub;
327
328             last_defined = pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
329             seg->pubtail = &pub->next;
330             pub->next = NULL;
331             pub->name = name;
332             pub->offset = offset;
333             pub->index = seg->ieee_index;
334             pub->segment = -1;
335             return;
336         }
337
338     /*
339      * Case (iii).
340      */
341     if (is_global) {
342         ext = *exttail = nasm_malloc(sizeof(*ext));
343         ext->next = NULL;
344         exttail = &ext->next;
345         ext->name = name;
346         if (is_global == 2)
347             ext->commonsize = offset;
348         else
349             ext->commonsize = 0;
350         i = segment / 2;
351         eb = ebhead;
352         if (!eb) {
353             eb = *ebtail = nasm_malloc(sizeof(*eb));
354             eb->next = NULL;
355             ebtail = &eb->next;
356         }
357         while (i > EXT_BLKSIZ) {
358             if (eb && eb->next)
359                 eb = eb->next;
360             else {
361                 eb = *ebtail = nasm_malloc(sizeof(*eb));
362                 eb->next = NULL;
363                 ebtail = &eb->next;
364             }
365             i -= EXT_BLKSIZ;
366         }
367         eb->index[i] = externals++;
368     }
369
370 }
371
372 /*
373  * Put data out
374  */
375 static void ieee_out(int32_t segto, const void *data, uint32_t type,
376                      int32_t segment, int32_t wrt)
377 {
378     uint32_t size, realtype;
379     const uint8_t *ucdata;
380     int32_t ldata;
381     struct ieeeSection *seg;
382
383     /*
384      * handle absolute-assembly (structure definitions)
385      */
386     if (segto == NO_SEG) {
387         if ((type & OUT_TYPMASK) != OUT_RESERVE)
388             error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
389                   " space");
390         return;
391     }
392
393     /*
394      * If `any_segs' is still false, we must define a default
395      * segment.
396      */
397     if (!any_segs) {
398         int tempint;            /* ignored */
399         if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint))
400             error(ERR_PANIC, "strange segment conditions in IEEE driver");
401     }
402
403     /*
404      * Find the segment we are targetting.
405      */
406     for (seg = seghead; seg; seg = seg->next)
407         if (seg->index == segto)
408             break;
409     if (!seg)
410         error(ERR_PANIC, "code directed to nonexistent segment?");
411
412     size = type & OUT_SIZMASK;
413     realtype = type & OUT_TYPMASK;
414     if (realtype == OUT_RAWDATA) {
415         ucdata = data;
416         while (size--)
417             ieee_write_byte(seg, *ucdata++);
418     } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
419                realtype == OUT_REL4ADR) {
420         if (segment == NO_SEG && realtype != OUT_ADDRESS)
421             error(ERR_NONFATAL, "relative call to absolute address not"
422                   " supported by IEEE format");
423         ldata = *(int32_t *)data;
424         if (realtype == OUT_REL2ADR)
425             ldata += (size - 2);
426         if (realtype == OUT_REL4ADR)
427             ldata += (size - 4);
428         ieee_write_fixup(segment, wrt, seg, size, realtype, ldata);
429         if (size == 2)
430             ieee_write_word(seg, ldata);
431         else
432             ieee_write_dword(seg, ldata);
433     } else if (realtype == OUT_RESERVE) {
434         while (size--)
435             ieee_write_byte(seg, 0);
436     }
437 }
438
439 static void ieee_data_new(struct ieeeSection *segto)
440 {
441
442     if (!segto->data)
443         segto->data = segto->datacurr =
444             nasm_malloc(sizeof(*(segto->datacurr)));
445     else
446         segto->datacurr = segto->datacurr->next =
447             nasm_malloc(sizeof(*(segto->datacurr)));
448     segto->datacurr->next = NULL;
449 }
450
451 /*
452  * this routine is unalduterated bloatware.  I usually don't do this
453  * but I might as well see what it is like on a harmless program.
454  * If anyone wants to optimize this is a good canditate!
455  */
456 static void ieee_write_fixup(int32_t segment, int32_t wrt,
457                              struct ieeeSection *segto, int size,
458                              uint32_t realtype, int32_t offset)
459 {
460     struct ieeeSection *target;
461     struct ieeeFixupp s;
462
463     /* Don't put a fixup for things NASM can calculate */
464     if (wrt == NO_SEG && segment == NO_SEG)
465         return;
466
467     s.ftype = -1;
468     /* if it is a WRT offset */
469     if (wrt != NO_SEG) {
470         s.ftype = FT_WRT;
471         s.addend = offset;
472         if (wrt >= SEG_ABS)
473             s.id1 = -(wrt - SEG_ABS);
474         else {
475             if (wrt % 2 && realtype != OUT_REL2ADR
476                 && realtype != OUT_REL4ADR) {
477                 wrt--;
478
479                 for (target = seghead; target; target = target->next)
480                     if (target->index == wrt)
481                         break;
482                 if (target) {
483                     s.id1 = target->ieee_index;
484                     for (target = seghead; target; target = target->next)
485                         if (target->index == segment)
486                             break;
487
488                     if (target)
489                         s.id2 = target->ieee_index;
490                     else {
491                         /*
492                          * Now we assume the segment field is being used
493                          * to hold an extern index
494                          */
495                         int32_t i = segment / 2;
496                         struct ExtBack *eb = ebhead;
497                         while (i > EXT_BLKSIZ) {
498                             if (eb)
499                                 eb = eb->next;
500                             else
501                                 break;
502                             i -= EXT_BLKSIZ;
503                         }
504                         /* if we have an extern decide the type and make a record
505                          */
506                         if (eb) {
507                             s.ftype = FT_EXTWRT;
508                             s.addend = 0;
509                             s.id2 = eb->index[i];
510                         } else
511                             error(ERR_NONFATAL,
512                                   "Source of WRT must be an offset");
513                     }
514
515                 } else
516                     error(ERR_PANIC,
517                           "unrecognised WRT value in ieee_write_fixup");
518             } else
519                 error(ERR_NONFATAL, "target of WRT must be a section ");
520         }
521         s.size = size;
522         ieee_install_fixup(segto, &s);
523         return;
524     }
525     /* Pure segment fixup ? */
526     if (segment != NO_SEG) {
527         s.ftype = FT_SEG;
528         s.id1 = 0;
529         if (segment >= SEG_ABS) {
530             /* absolute far segment fixup */
531             s.id1 = -(segment - ~SEG_ABS);
532         } else if (segment % 2) {
533             /* fixup to named segment */
534             /* look it up */
535             for (target = seghead; target; target = target->next)
536                 if (target->index == segment - 1)
537                     break;
538             if (target)
539                 s.id1 = target->ieee_index;
540             else {
541                 /*
542                  * Now we assume the segment field is being used
543                  * to hold an extern index
544                  */
545                 int32_t i = segment / 2;
546                 struct ExtBack *eb = ebhead;
547                 while (i > EXT_BLKSIZ) {
548                     if (eb)
549                         eb = eb->next;
550                     else
551                         break;
552                     i -= EXT_BLKSIZ;
553                 }
554                 /* if we have an extern decide the type and make a record
555                  */
556                 if (eb) {
557                     if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
558                         error(ERR_PANIC,
559                               "Segment of a rel not supported in ieee_write_fixup");
560                     } else {
561                         /* If we want the segment */
562                         s.ftype = FT_EXTSEG;
563                         s.addend = 0;
564                         s.id1 = eb->index[i];
565                     }
566
567                 } else
568                     /* If we get here the seg value doesn't make sense */
569                     error(ERR_PANIC,
570                           "unrecognised segment value in ieee_write_fixup");
571             }
572
573         } else {
574             /* Assume we are offsetting directly from a section
575              * So look up the target segment
576              */
577             for (target = seghead; target; target = target->next)
578                 if (target->index == segment)
579                     break;
580             if (target) {
581                 if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
582                     /* PC rel to a known offset */
583                     s.id1 = target->ieee_index;
584                     s.ftype = FT_REL;
585                     s.size = size;
586                     s.addend = offset;
587                 } else {
588                     /* We were offsetting from a seg */
589                     s.id1 = target->ieee_index;
590                     s.ftype = FT_OFS;
591                     s.size = size;
592                     s.addend = offset;
593                 }
594             } else {
595                 /*
596                  * Now we assume the segment field is being used
597                  * to hold an extern index
598                  */
599                 int32_t i = segment / 2;
600                 struct ExtBack *eb = ebhead;
601                 while (i > EXT_BLKSIZ) {
602                     if (eb)
603                         eb = eb->next;
604                     else
605                         break;
606                     i -= EXT_BLKSIZ;
607                 }
608                 /* if we have an extern decide the type and make a record
609                  */
610                 if (eb) {
611                     if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
612                         s.ftype = FT_EXTREL;
613                         s.addend = 0;
614                         s.id1 = eb->index[i];
615                     } else {
616                         /* else we want the external offset */
617                         s.ftype = FT_EXT;
618                         s.addend = 0;
619                         s.id1 = eb->index[i];
620                     }
621
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");
626             }
627         }
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;
634     }
635     /* should never get here */
636 }
637 static void ieee_install_fixup(struct ieeeSection *seg,
638                                struct ieeeFixupp *fix)
639 {
640     struct ieeeFixupp *f;
641     f = nasm_malloc(sizeof(struct ieeeFixupp));
642     memcpy(f, fix, sizeof(struct ieeeFixupp));
643     f->offset = seg->currentpos;
644     seg->currentpos += fix->size;
645     f->next = NULL;
646     if (seg->fptr)
647         seg->flptr = seg->flptr->next = f;
648     else
649         seg->fptr = seg->flptr = f;
650
651 }
652
653 /*
654  * segment registry
655  */
656 static int32_t ieee_segment(char *name, int pass, int *bits)
657 {
658     /*
659      * We call the label manager here to define a name for the new
660      * segment, and when our _own_ label-definition stub gets
661      * called in return, it should register the new segment name
662      * using the pointer it gets passed. That way we save memory,
663      * by sponging off the label manager.
664      */
665     if (!name) {
666         *bits = 16;
667         if (!any_segs)
668             return 0;
669         return seghead->index;
670     } else {
671         struct ieeeSection *seg;
672         int ieee_idx, attrs;
673         bool rn_error;
674         char *p;
675
676         /*
677          * Look for segment attributes.
678          */
679         attrs = 0;
680         while (*name == '.')
681             name++;             /* hack, but a documented one */
682         p = name;
683         while (*p && !isspace(*p))
684             p++;
685         if (*p) {
686             *p++ = '\0';
687             while (*p && isspace(*p))
688                 *p++ = '\0';
689         }
690         while (*p) {
691             while (*p && !isspace(*p))
692                 p++;
693             if (*p) {
694                 *p++ = '\0';
695                 while (*p && isspace(*p))
696                     *p++ = '\0';
697             }
698
699             attrs++;
700         }
701
702         ieee_idx = 1;
703         for (seg = seghead; seg; seg = seg->next) {
704             ieee_idx++;
705             if (!strcmp(seg->name, name)) {
706                 if (attrs > 0 && pass == 1)
707                     error(ERR_WARNING, "segment attributes specified on"
708                           " redeclaration of segment: ignoring");
709                 if (seg->use32)
710                     *bits = 32;
711                 else
712                     *bits = 16;
713                 return seg->index;
714             }
715         }
716
717         *segtail = seg = nasm_malloc(sizeof(*seg));
718         seg->next = NULL;
719         segtail = &seg->next;
720         seg->index = seg_alloc();
721         seg->ieee_index = ieee_idx;
722         any_segs = true;
723         seg->name = NULL;
724         seg->currentpos = 0;
725         seg->align = 1;         /* default */
726         seg->use32 = *bits == 32;       /* default to user spec */
727         seg->combine = CMB_PUBLIC;      /* default */
728         seg->pubhead = NULL;
729         seg->pubtail = &seg->pubhead;
730         seg->data = NULL;
731         seg->fptr = NULL;
732         seg->lochead = NULL;
733         seg->loctail = &seg->lochead;
734
735         /*
736          * Process the segment attributes.
737          */
738         p = name;
739         while (attrs--) {
740             p += strlen(p);
741             while (!*p)
742                 p++;
743
744             /*
745              * `p' contains a segment attribute.
746              */
747             if (!nasm_stricmp(p, "private"))
748                 seg->combine = CMB_PRIVATE;
749             else if (!nasm_stricmp(p, "public"))
750                 seg->combine = CMB_PUBLIC;
751             else if (!nasm_stricmp(p, "common"))
752                 seg->combine = CMB_COMMON;
753             else if (!nasm_stricmp(p, "use16"))
754                 seg->use32 = false;
755             else if (!nasm_stricmp(p, "use32"))
756                 seg->use32 = true;
757             else if (!nasm_strnicmp(p, "align=", 6)) {
758                 seg->align = readnum(p + 6, &rn_error);
759                 if (seg->align == 0)
760                     seg->align = 1;
761                 if (rn_error) {
762                     seg->align = 1;
763                     error(ERR_NONFATAL, "segment alignment should be"
764                           " numeric");
765                 }
766                 switch ((int)seg->align) {
767                 case 1:        /* BYTE */
768                 case 2:        /* WORD */
769                 case 4:        /* DWORD */
770                 case 16:       /* PARA */
771                 case 256:      /* PAGE */
772                 case 8:
773                 case 32:
774                 case 64:
775                 case 128:
776                     break;
777                 default:
778                     error(ERR_NONFATAL, "invalid alignment value %d",
779                           seg->align);
780                     seg->align = 1;
781                     break;
782                 }
783             } else if (!nasm_strnicmp(p, "absolute=", 9)) {
784                 seg->align = SEG_ABS + readnum(p + 9, &rn_error);
785                 if (rn_error)
786                     error(ERR_NONFATAL, "argument to `absolute' segment"
787                           " attribute should be numeric");
788             }
789         }
790
791         ieee_seg_needs_update = seg;
792         if (seg->align >= SEG_ABS)
793             deflabel(name, NO_SEG, seg->align - SEG_ABS,
794                      NULL, false, false, &of_ieee, error);
795         else
796             deflabel(name, seg->index + 1, 0L,
797                      NULL, false, false, &of_ieee, error);
798         ieee_seg_needs_update = NULL;
799
800         if (seg->use32)
801             *bits = 32;
802         else
803             *bits = 16;
804         return seg->index;
805     }
806 }
807
808 /*
809  * directives supported
810  */
811 static int ieee_directive(char *directive, char *value, int pass)
812 {
813
814     (void)value;
815     (void)pass;
816     if (!strcmp(directive, "uppercase")) {
817         ieee_uppercase = true;
818         return 1;
819     }
820     return 0;
821 }
822
823 /*
824  * Return segment data
825  */
826 static int32_t ieee_segbase(int32_t segment)
827 {
828     struct ieeeSection *seg;
829
830     /*
831      * Find the segment in our list.
832      */
833     for (seg = seghead; seg; seg = seg->next)
834         if (seg->index == segment - 1)
835             break;
836
837     if (!seg)
838         return segment;         /* not one of ours - leave it alone */
839
840     if (seg->align >= SEG_ABS)
841         return seg->align;      /* absolute segment */
842
843     return segment;             /* no special treatment */
844 }
845
846 /*
847  * filename
848  */
849 static void ieee_filename(char *inname, char *outname, efunc error)
850 {
851     strcpy(ieee_infile, inname);
852     standard_extension(inname, outname, ".o", error);
853 }
854
855 static void ieee_write_file(int debuginfo)
856 {
857     struct tm *thetime;
858     time_t reltime;
859     struct FileName *fn;
860     struct ieeeSection *seg;
861     struct ieeePublic *pub, *loc;
862     struct ieeeExternal *ext;
863     struct ieeeObjData *data;
864     struct ieeeFixupp *fix;
865     struct Array *arr;
866     static char boast[] = "The Netwide Assembler " NASM_VER;
867     int i;
868
869     /*
870      * Write the module header
871      */
872     ieee_putascii("MBFNASM,%02X%s.\r\n", strlen(ieee_infile), ieee_infile);
873
874     /*
875      * Write the NASM boast comment.
876      */
877     ieee_putascii("CO0,%02X%s.\r\n", strlen(boast), boast);
878
879     /*
880      * write processor-specific information
881      */
882     ieee_putascii("AD8,4,L.\r\n");
883
884     /*
885      * date and time
886      */
887     time(&reltime);
888     thetime = localtime(&reltime);
889     ieee_putascii("DT%04d%02d%02d%02d%02d%02d.\r\n",
890                   1900 + thetime->tm_year, thetime->tm_mon + 1,
891                   thetime->tm_mday, thetime->tm_hour, thetime->tm_min,
892                   thetime->tm_sec);
893     /*
894      * if debugging, dump file names
895      */
896     for (fn = fnhead; fn && debuginfo; fn = fn->next) {
897         ieee_putascii("C0105,%02X%s.\r\n", strlen(fn->name), fn->name);
898     }
899
900     ieee_putascii("CO101,07ENDHEAD.\r\n");
901     /*
902      * the standard doesn't specify when to put checksums,
903      * we'll just do it periodically.
904      */
905     ieee_putcs(false);
906
907     /*
908      * Write the section headers
909      */
910     seg = seghead;
911     if (!debuginfo && !strcmp(seg->name, "??LINE"))
912         seg = seg->next;
913     while (seg) {
914         char buf[256];
915         char attrib;
916         switch (seg->combine) {
917         case CMB_PUBLIC:
918         default:
919             attrib = 'C';
920             break;
921         case CMB_PRIVATE:
922             attrib = 'S';
923             break;
924         case CMB_COMMON:
925             attrib = 'M';
926             break;
927         }
928         ieee_unqualified_name(buf, seg->name);
929         if (seg->align >= SEG_ABS) {
930             ieee_putascii("ST%X,A,%02X%s.\r\n", seg->ieee_index,
931                           strlen(buf), buf);
932             ieee_putascii("ASL%X,%lX.\r\n", seg->ieee_index,
933                           (seg->align - SEG_ABS) * 16);
934         } else {
935             ieee_putascii("ST%X,%c,%02X%s.\r\n", seg->ieee_index, attrib,
936                           strlen(buf), buf);
937             ieee_putascii("SA%X,%lX.\r\n", seg->ieee_index, seg->align);
938             ieee_putascii("ASS%X,%X.\r\n", seg->ieee_index,
939                           seg->currentpos);
940         }
941         seg = seg->next;
942     }
943     /*
944      * write the start address if there is one
945      */
946     if (ieee_entry_seg) {
947         for (seg = seghead; seg; seg = seg->next)
948             if (seg->index == ieee_entry_seg)
949                 break;
950         if (!seg)
951             error(ERR_PANIC, "Start address records are incorrect");
952         else
953             ieee_putascii("ASG,R%X,%lX,+.\r\n", seg->ieee_index,
954                           ieee_entry_ofs);
955     }
956
957     ieee_putcs(false);
958     /*
959      * Write the publics
960      */
961     i = 1;
962     for (seg = seghead; seg; seg = seg->next) {
963         for (pub = seg->pubhead; pub; pub = pub->next) {
964             char buf[256];
965             ieee_unqualified_name(buf, pub->name);
966             ieee_putascii("NI%X,%02X%s.\r\n", i, strlen(buf), buf);
967             if (pub->segment == -1)
968                 ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,
969                               pub->offset);
970             else
971                 ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment * 16,
972                               pub->offset);
973             if (debuginfo) {
974                 if (pub->type >= 0x100)
975                     ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100);
976                 else
977                     ieee_putascii("ATI%X,%X.\r\n", i, pub->type);
978             }
979             i++;
980         }
981     }
982     pub = fpubhead;
983     i = 1;
984     while (pub) {
985         char buf[256];
986         ieee_unqualified_name(buf, pub->name);
987         ieee_putascii("NI%X,%02X%s.\r\n", i, strlen(buf), buf);
988         if (pub->segment == -1)
989             ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,
990                           pub->offset);
991         else
992             ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment * 16,
993                           pub->offset);
994         if (debuginfo) {
995             if (pub->type >= 0x100)
996                 ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100);
997             else
998                 ieee_putascii("ATI%X,%X.\r\n", i, pub->type);
999         }
1000         i++;
1001         pub = pub->next;
1002     }
1003     /*
1004      * Write the externals
1005      */
1006     ext = exthead;
1007     i = 1;
1008     while (ext) {
1009         char buf[256];
1010         ieee_unqualified_name(buf, ext->name);
1011         ieee_putascii("NX%X,%02X%s.\r\n", i++, strlen(buf), buf);
1012         ext = ext->next;
1013     }
1014     ieee_putcs(false);
1015
1016     /*
1017      * IEEE doesn't have a standard pass break record
1018      * so use the ladsoft variant
1019      */
1020     ieee_putascii("CO100,06ENDSYM.\r\n");
1021
1022     /*
1023      * now put types
1024      */
1025     i = ARRAY_BOT;
1026     for (arr = arrhead; arr && debuginfo; arr = arr->next) {
1027         ieee_putascii("TY%X,20,%X,%lX.\r\n", i++, arr->basetype,
1028                       arr->size);
1029     }
1030     /*
1031      * now put locals
1032      */
1033     i = 1;
1034     for (seg = seghead; seg && debuginfo; seg = seg->next) {
1035         for (loc = seg->lochead; loc; loc = loc->next) {
1036             char buf[256];
1037             ieee_unqualified_name(buf, loc->name);
1038             ieee_putascii("NN%X,%02X%s.\r\n", i, strlen(buf), buf);
1039             if (loc->segment == -1)
1040                 ieee_putascii("ASN%X,R%X,%lX,+.\r\n", i, loc->index,
1041                               loc->offset);
1042             else
1043                 ieee_putascii("ASN%X,%lX,%lX,+.\r\n", i, loc->segment * 16,
1044                               loc->offset);
1045             if (debuginfo) {
1046                 if (loc->type >= 0x100)
1047                     ieee_putascii("ATN%X,T%X.\r\n", i, loc->type - 0x100);
1048                 else
1049                     ieee_putascii("ATN%X,%X.\r\n", i, loc->type);
1050             }
1051             i++;
1052         }
1053     }
1054
1055     /*
1056      *  put out section data;
1057      */
1058     seg = seghead;
1059     if (!debuginfo && !strcmp(seg->name, "??LINE"))
1060         seg = seg->next;
1061     while (seg) {
1062         if (seg->currentpos) {
1063             int32_t size, org = 0;
1064             data = seg->data;
1065             ieee_putascii("SB%X.\r\n", seg->ieee_index);
1066             fix = seg->fptr;
1067             while (fix) {
1068                 size = HUNKSIZE - (org % HUNKSIZE);
1069                 size =
1070                     size + org >
1071                     seg->currentpos ? seg->currentpos - org : size;
1072                 size = fix->offset - org > size ? size : fix->offset - org;
1073                 org = ieee_putld(org, org + size, data->data);
1074                 if (org % HUNKSIZE == 0)
1075                     data = data->next;
1076                 if (org == fix->offset) {
1077                     org += ieee_putlr(fix);
1078                     fix = fix->next;
1079                 }
1080             }
1081             while (org < seg->currentpos && data) {
1082                 size =
1083                     seg->currentpos - org >
1084                     HUNKSIZE ? HUNKSIZE : seg->currentpos - org;
1085                 org = ieee_putld(org, org + size, data->data);
1086                 data = data->next;
1087             }
1088             ieee_putcs(false);
1089
1090         }
1091         seg = seg->next;
1092     }
1093     /*
1094      * module end record
1095      */
1096     ieee_putascii("ME.\r\n");
1097 }
1098
1099 static void ieee_write_byte(struct ieeeSection *seg, int data)
1100 {
1101     int temp;
1102     if (!(temp = seg->currentpos++ % HUNKSIZE))
1103         ieee_data_new(seg);
1104     seg->datacurr->data[temp] = data;
1105 }
1106
1107 static void ieee_write_word(struct ieeeSection *seg, int data)
1108 {
1109     ieee_write_byte(seg, data & 0xFF);
1110     ieee_write_byte(seg, (data >> 8) & 0xFF);
1111 }
1112
1113 static void ieee_write_dword(struct ieeeSection *seg, int32_t data)
1114 {
1115     ieee_write_byte(seg, data & 0xFF);
1116     ieee_write_byte(seg, (data >> 8) & 0xFF);
1117     ieee_write_byte(seg, (data >> 16) & 0xFF);
1118     ieee_write_byte(seg, (data >> 24) & 0xFF);
1119 }
1120 static void ieee_putascii(char *format, ...)
1121 {
1122     char buffer[256];
1123     int i, l;
1124     va_list ap;
1125
1126     va_start(ap, format);
1127     vsnprintf(buffer, sizeof(buffer), format, ap);
1128     l = strlen(buffer);
1129     for (i = 0; i < l; i++)
1130         if ((buffer[i] & 0xff) > 31)
1131             checksum += buffer[i];
1132     va_end(ap);
1133     fprintf(ofp, buffer);
1134 }
1135
1136 /*
1137  * put out a checksum record */
1138 static void ieee_putcs(int toclear)
1139 {
1140     if (toclear) {
1141         ieee_putascii("CS.\r\n");
1142     } else {
1143         checksum += 'C';
1144         checksum += 'S';
1145         ieee_putascii("CS%02X.\r\n", checksum & 127);
1146     }
1147     checksum = 0;
1148 }
1149
1150 static int32_t ieee_putld(int32_t start, int32_t end, uint8_t *buf)
1151 {
1152     int32_t val;
1153     if (start == end)
1154         return (start);
1155     val = start % HUNKSIZE;
1156     /* fill up multiple lines */
1157     while (end - start >= LDPERLINE) {
1158         int i;
1159         ieee_putascii("LD");
1160         for (i = 0; i < LDPERLINE; i++) {
1161             ieee_putascii("%02X", buf[val++]);
1162             start++;
1163         }
1164         ieee_putascii(".\r\n");
1165     }
1166     /* if no partial lines */
1167     if (start == end)
1168         return (start);
1169     /* make a partial line */
1170     ieee_putascii("LD");
1171     while (start < end) {
1172         ieee_putascii("%02X", buf[val++]);
1173         start++;
1174     }
1175     ieee_putascii(".\r\n");
1176     return (start);
1177 }
1178 static int32_t ieee_putlr(struct ieeeFixupp *p)
1179 {
1180 /*
1181  * To deal with the vagaries of segmentation the LADsoft linker
1182  * defines two types of segments: absolute and virtual.  Note that
1183  * 'absolute' in this context is a different thing from the IEEE
1184  * definition of an absolute segment type, which is also supported. If a
1185  * sement is linked in virtual mode the low limit (L-var) is
1186  * subtracted from each R,X, and P variable which appears in an
1187  * expression, so that we can have relative offsets.  Meanwhile
1188  * in the ABSOLUTE mode this subtraction is not done and
1189  * so we can use absolute offsets from 0.  In the LADsoft linker
1190  * this configuration is not done in the assemblker source but in
1191  * a source the linker reads.  Generally this type of thing only
1192  * becomes an issue if real mode code is used.  A pure 32-bit linker could
1193  * get away without defining the virtual mode...
1194  */
1195     char buf[40];
1196     int32_t size = p->size;
1197     switch (p->ftype) {
1198     case FT_SEG:
1199         if (p->id1 < 0)
1200             sprintf(buf, "%"PRIX32"", -p->id1);
1201         else
1202             sprintf(buf, "L%"PRIX32",10,/", p->id1);
1203         break;
1204     case FT_OFS:
1205         sprintf(buf, "R%"PRIX32",%"PRIX32",+", p->id1, p->addend);
1206         break;
1207     case FT_REL:
1208         sprintf(buf, "R%"PRIX32",%"PRIX32",+,P,-,%X,-", p->id1, p->addend, p->size);
1209         break;
1210
1211     case FT_WRT:
1212         if (p->id2 < 0)
1213             sprintf(buf, "R%"PRIX32",%"PRIX32",+,L%"PRIX32",+,%"PRIX32",-", p->id2, p->addend,
1214                     p->id2, -p->id1 * 16);
1215         else
1216             sprintf(buf, "R%"PRIX32",%"PRIX32",+,L%"PRIX32",+,L%"PRIX32",-", p->id2, p->addend,
1217                     p->id2, p->id1);
1218         break;
1219     case FT_EXT:
1220         sprintf(buf, "X%"PRIX32"", p->id1);
1221         break;
1222     case FT_EXTREL:
1223         sprintf(buf, "X%"PRIX32",P,-,%"PRIX32",-", p->id1, size);
1224         break;
1225     case FT_EXTSEG:
1226         /* We needed a non-ieee hack here.
1227          * We introduce the Y variable, which is the low
1228          * limit of the native segment the extern resides in
1229          */
1230         sprintf(buf, "Y%"PRIX32",10,/", p->id1);
1231         break;
1232     case FT_EXTWRT:
1233         if (p->id2 < 0)
1234             sprintf(buf, "X%"PRIX32",Y%"PRIX32",+,%"PRIX32",-", p->id2, p->id2,
1235                     -p->id1 * 16);
1236         else
1237             sprintf(buf, "X%"PRIX32",Y%"PRIX32",+,L%"PRIX32",-", p->id2, p->id2, p->id1);
1238         break;
1239     }
1240     ieee_putascii("LR(%s,%"PRIX32").\r\n", buf, size);
1241
1242     return (size);
1243 }
1244
1245 /* Dump all segment data (text and fixups )*/
1246
1247 static void ieee_unqualified_name(char *dest, char *source)
1248 {
1249     if (ieee_uppercase) {
1250         while (*source)
1251             *dest++ = toupper(*source++);
1252         *dest = 0;
1253     } else
1254         strcpy(dest, source);
1255 }
1256 void dbgls_init(struct ofmt *of, void *id, FILE * fp, efunc error)
1257 {
1258     int tempint;
1259     (void)of;
1260     (void)id;
1261     (void)fp;
1262     (void)error;
1263
1264     fnhead = NULL;
1265     fntail = &fnhead;
1266     arrindex = ARRAY_BOT;
1267     arrhead = NULL;
1268     arrtail = &arrhead;
1269     ieee_segment("??LINE", 2, &tempint);
1270     any_segs = false;
1271 }
1272 static void dbgls_cleanup(void)
1273 {
1274     struct ieeeSection *segtmp;
1275     while (fnhead) {
1276         struct FileName *fntemp = fnhead;
1277         fnhead = fnhead->next;
1278         nasm_free(fntemp->name);
1279         nasm_free(fntemp);
1280     }
1281     for (segtmp = seghead; segtmp; segtmp = segtmp->next) {
1282         while (segtmp->lochead) {
1283             struct ieeePublic *loctmp = segtmp->lochead;
1284             segtmp->lochead = loctmp->next;
1285             nasm_free(loctmp->name);
1286             nasm_free(loctmp);
1287         }
1288     }
1289     while (arrhead) {
1290         struct Array *arrtmp = arrhead;
1291         arrhead = arrhead->next;
1292         nasm_free(arrtmp);
1293     }
1294 }
1295
1296 /*
1297  * because this routine is not bracketed in
1298  * the main program, this routine will be called even if there
1299  * is no request for debug info
1300  * so, we have to make sure the ??LINE segment is avaialbe
1301  * as the first segment when this debug format is selected
1302  */
1303 static void dbgls_linnum(const char *lnfname, int32_t lineno, int32_t segto)
1304 {
1305     struct FileName *fn;
1306     struct ieeeSection *seg;
1307     int i = 0;
1308     if (segto == NO_SEG)
1309         return;
1310
1311     /*
1312      * If `any_segs' is still false, we must define a default
1313      * segment.
1314      */
1315     if (!any_segs) {
1316         int tempint;            /* ignored */
1317         if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint))
1318             error(ERR_PANIC, "strange segment conditions in OBJ driver");
1319     }
1320
1321     /*
1322      * Find the segment we are targetting.
1323      */
1324     for (seg = seghead; seg; seg = seg->next)
1325         if (seg->index == segto)
1326             break;
1327     if (!seg)
1328         error(ERR_PANIC, "lineno directed to nonexistent segment?");
1329
1330     for (fn = fnhead; fn; fn = fn->next) {
1331         if (!nasm_stricmp(lnfname, fn->name))
1332             break;
1333         i++;
1334     }
1335     if (!fn) {
1336         fn = nasm_malloc(sizeof(*fn));
1337         fn->name = nasm_malloc(strlen(lnfname) + 1);
1338         fn->index = i;
1339         strcpy(fn->name, lnfname);
1340         fn->next = NULL;
1341         *fntail = fn;
1342         fntail = &fn->next;
1343     }
1344     ieee_write_byte(seghead, fn->index);
1345     ieee_write_word(seghead, lineno);
1346     ieee_write_fixup(segto, NO_SEG, seghead, 4, OUT_ADDRESS,
1347                      seg->currentpos);
1348
1349 }
1350 static void dbgls_deflabel(char *name, int32_t segment,
1351                            int64_t offset, int is_global, char *special)
1352 {
1353     struct ieeeSection *seg;
1354
1355     /* Keep compiler from warning about special */
1356     (void)special;
1357
1358     /*
1359      * If it's a special-retry from pass two, discard it.
1360      */
1361     if (is_global == 3)
1362         return;
1363
1364     /*
1365      * First check for the double-period, signifying something
1366      * unusual.
1367      */
1368     if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
1369         return;
1370     }
1371
1372     /*
1373      * Case (i):
1374      */
1375     if (ieee_seg_needs_update)
1376         return;
1377     if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
1378         return;
1379
1380     if (segment >= SEG_ABS || segment == NO_SEG) {
1381         return;
1382     }
1383
1384     /*
1385      * If `any_segs' is still false, we might need to define a
1386      * default segment, if they're trying to declare a label in
1387      * `first_seg'.  But the label should exist due to a prior
1388      * call to ieee_deflabel so we can skip that.
1389      */
1390
1391     for (seg = seghead; seg; seg = seg->next)
1392         if (seg->index == segment) {
1393             struct ieeePublic *loc;
1394             /*
1395              * Case (ii). Maybe MODPUB someday?
1396              */
1397             if (!is_global) {
1398                 last_defined = loc = nasm_malloc(sizeof(*loc));
1399                 *seg->loctail = loc;
1400                 seg->loctail = &loc->next;
1401                 loc->next = NULL;
1402                 loc->name = nasm_strdup(name);
1403                 loc->offset = offset;
1404                 loc->segment = -1;
1405                 loc->index = seg->ieee_index;
1406             }
1407         }
1408 }
1409 static void dbgls_typevalue(int32_t type)
1410 {
1411     int elem = TYM_ELEMENTS(type);
1412     type = TYM_TYPE(type);
1413
1414     if (!last_defined)
1415         return;
1416
1417     switch (type) {
1418     case TY_BYTE:
1419         last_defined->type = 1; /* uint8_t */
1420         break;
1421     case TY_WORD:
1422         last_defined->type = 3; /* unsigned word */
1423         break;
1424     case TY_DWORD:
1425         last_defined->type = 5; /* unsigned dword */
1426         break;
1427     case TY_FLOAT:
1428         last_defined->type = 9; /* float */
1429         break;
1430     case TY_QWORD:
1431         last_defined->type = 10;        /* qword */
1432         break;
1433     case TY_TBYTE:
1434         last_defined->type = 11;        /* TBYTE */
1435         break;
1436     default:
1437         last_defined->type = 0x10;      /* near label */
1438         break;
1439     }
1440
1441     if (elem > 1) {
1442         struct Array *arrtmp = nasm_malloc(sizeof(*arrtmp));
1443         int vtype = last_defined->type;
1444         arrtmp->size = elem;
1445         arrtmp->basetype = vtype;
1446         arrtmp->next = NULL;
1447         last_defined->type = arrindex++ + 0x100;
1448         *arrtail = arrtmp;
1449         arrtail = &(arrtmp->next);
1450     }
1451     last_defined = NULL;
1452 }
1453 static void dbgls_output(int output_type, void *param)
1454 {
1455     (void)output_type;
1456     (void)param;
1457 }
1458 static struct dfmt ladsoft_debug_form = {
1459     "LADsoft Debug Records",
1460     "ladsoft",
1461     dbgls_init,
1462     dbgls_linnum,
1463     dbgls_deflabel,
1464     null_debug_routine,
1465     dbgls_typevalue,
1466     dbgls_output,
1467     dbgls_cleanup,
1468 };
1469 static struct dfmt *ladsoft_debug_arr[3] = {
1470     &ladsoft_debug_form,
1471     &null_debug_form,
1472     NULL
1473 };
1474 struct ofmt of_ieee = {
1475     "IEEE-695 (LADsoft variant) object file format",
1476     "ieee",
1477     NULL,
1478     ladsoft_debug_arr,
1479     &null_debug_form,
1480     NULL,
1481     ieee_init,
1482     ieee_set_info,
1483     ieee_out,
1484     ieee_deflabel,
1485     ieee_segment,
1486     ieee_segbase,
1487     ieee_directive,
1488     ieee_filename,
1489     ieee_cleanup
1490 };
1491
1492 #endif                          /* OF_IEEE */