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