NASM 0.93
[platform/upstream/nasm.git] / outobj.c
1 /* outobj.c     output routines for the Netwide Assembler to produce
2  *              Microsoft 16-bit .OBJ 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 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14
15 #include "nasm.h"
16 #include "nasmlib.h"
17 #include "outform.h"
18
19 #ifdef OF_OBJ
20
21 static char obj_infile[FILENAME_MAX];
22 static int obj_uppercase;
23
24 static efunc error;
25 static ldfunc deflabel;
26 static FILE *ofp;
27 static long first_seg;
28 static int any_segs;
29
30 #define LEDATA_MAX 1024                /* maximum size of LEDATA record */
31 #define RECORD_MAX 1024                /* maximum size of _any_ record */
32 #define GROUP_MAX 256                  /* we won't _realistically_ have more
33                                         * than this many segs in a group */
34 #define EXT_BLKSIZ 256                 /* block size for externals list */
35
36 static unsigned char record[RECORD_MAX], *recptr;
37
38 static struct Public {
39     struct Public *next;
40     char *name;
41     long offset;
42     long segment;                      /* only if it's far-absolute */
43 } *fpubhead, **fpubtail;
44
45 static struct External {
46     struct External *next;
47     char *name;
48     long commonsize;
49 } *exthead, **exttail;
50
51 static int externals;
52
53 static struct ExtBack {
54     struct ExtBack *next;
55     int index[EXT_BLKSIZ];
56 } *ebhead, **ebtail;
57
58 static struct Segment {
59     struct Segment *next;
60     long index;                        /* the NASM segment id */
61     long obj_index;                    /* the OBJ-file segment index */
62     struct Group *grp;                 /* the group it belongs to */
63     long currentpos;
64     long align;                        /* can be SEG_ABS + absolute addr */
65     enum {
66         CMB_PRIVATE = 0,
67         CMB_PUBLIC = 2,
68         CMB_STACK = 5,
69         CMB_COMMON = 6
70     } combine;
71     long use32;                        /* is this segment 32-bit? */
72     struct Public *pubhead, **pubtail;
73     char *name;
74     char *segclass, *overlay;          /* `class' is a C++ keyword :-) */
75 } *seghead, **segtail, *obj_seg_needs_update;
76
77 static struct Group {
78     struct Group *next;
79     char *name;
80     long index;                        /* NASM segment id */
81     long obj_index;                    /* OBJ-file group index */
82     long nentries;                     /* number of elements... */
83     long nindices;                     /* ...and number of index elts... */
84     union {
85         long index;
86         char *name;
87     } segs[GROUP_MAX];                 /* ...in this */
88 } *grphead, **grptail, *obj_grp_needs_update;
89
90 static struct ObjData {
91     struct ObjData *next;
92     int nonempty;
93     struct Segment *seg;
94     long startpos;
95     int letype, ftype;
96     unsigned char ledata[LEDATA_MAX], *lptr;
97     unsigned char fixupp[RECORD_MAX], *fptr;
98 } *datahead, *datacurr, **datatail;
99
100 static long obj_entry_seg, obj_entry_ofs;
101
102 enum RecordID {                        /* record ID codes */
103
104     THEADR = 0x80,                     /* module header */
105     COMENT = 0x88,                     /* comment record */
106
107     LNAMES = 0x96,                     /* list of names */
108
109     SEGDEF = 0x98,                     /* segment definition */
110     GRPDEF = 0x9A,                     /* group definition */
111     EXTDEF = 0x8C,                     /* external definition */
112     PUBDEF = 0x90,                     /* public definition */
113     COMDEF = 0xB0,                     /* common definition */
114
115     LEDATA = 0xA0,                     /* logical enumerated data */
116     FIXUPP = 0x9C,                     /* fixups (relocations) */
117
118     MODEND = 0x8A                      /* module end */
119 };
120
121 extern struct ofmt of_obj;
122
123 static long obj_ledata_space(struct Segment *);
124 static int obj_fixup_free(struct Segment *);
125 static void obj_ledata_new(struct Segment *);
126 static void obj_ledata_commit(void);
127 static void obj_write_fixup (struct ObjData *, int, int, long, long, long);
128 static long obj_segment (char *, int, int *);
129 static void obj_write_file(void);
130 static unsigned char *obj_write_data(unsigned char *, unsigned char *, int);
131 static unsigned char *obj_write_byte(unsigned char *, int);
132 static unsigned char *obj_write_word(unsigned char *, int);
133 static unsigned char *obj_write_dword(unsigned char *, long);
134 static unsigned char *obj_write_rword(unsigned char *, int);
135 static unsigned char *obj_write_name(unsigned char *, char *);
136 static unsigned char *obj_write_index(unsigned char *, int);
137 static unsigned char *obj_write_value(unsigned char *, unsigned long);
138 static void obj_record(int, unsigned char *, unsigned char *);
139
140 static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef) {
141     ofp = fp;
142     error = errfunc;
143     deflabel = ldef;
144     first_seg = seg_alloc();
145     any_segs = FALSE;
146     fpubhead = NULL;
147     fpubtail = &fpubhead;
148     exthead = NULL;
149     exttail = &exthead;
150     externals = 0;
151     ebhead = NULL;
152     ebtail = &ebhead;
153     seghead = obj_seg_needs_update = NULL;
154     segtail = &seghead;
155     grphead = obj_grp_needs_update = NULL;
156     grptail = &grphead;
157     datahead = datacurr = NULL;
158     datatail = &datahead;
159     obj_entry_seg = NO_SEG;
160     obj_uppercase = FALSE;
161 }
162
163 static void obj_cleanup (void) {
164     obj_write_file();
165     fclose (ofp);
166     while (seghead) {
167         struct Segment *segtmp = seghead;
168         seghead = seghead->next;
169         while (segtmp->pubhead) {
170             struct Public *pubtmp = segtmp->pubhead;
171             segtmp->pubhead = pubtmp->next;
172             nasm_free (pubtmp);
173         }
174         nasm_free (segtmp);
175     }
176     while (fpubhead) {
177         struct Public *pubtmp = fpubhead;
178         fpubhead = fpubhead->next;
179         nasm_free (pubtmp);
180     }
181     while (exthead) {
182         struct External *exttmp = exthead;
183         exthead = exthead->next;
184         nasm_free (exttmp);
185     }
186     while (ebhead) {
187         struct ExtBack *ebtmp = ebhead;
188         ebhead = ebhead->next;
189         nasm_free (ebtmp);
190     }
191     while (grphead) {
192         struct Group *grptmp = grphead;
193         grphead = grphead->next;
194         nasm_free (grptmp);
195     }
196     while (datahead) {
197         struct ObjData *datatmp = datahead;
198         datahead = datahead->next;
199         nasm_free (datatmp);
200     }
201 }
202
203 static void obj_deflabel (char *name, long segment,
204                           long offset, int is_global) {
205     /*
206      * We have three cases:
207      *
208      * (i) `segment' is a segment-base. If so, set the name field
209      * for the segment or group structure it refers to, and then
210      * return.
211      *
212      * (ii) `segment' is one of our segments, or a SEG_ABS segment.
213      * Save the label position for later output of a PUBDEF record.
214      * (Or a MODPUB, if we work out how.)
215      *
216      * (iii) `segment' is not one of our segments. Save the label
217      * position for later output of an EXTDEF, and also store a
218      * back-reference so that we can map later references to this
219      * segment number to the external index.
220      */
221     struct External *ext;
222     struct ExtBack *eb;
223     struct Segment *seg;
224     int i;
225
226     /*
227      * First check for the double-period, signifying something
228      * unusual.
229      */
230     if (name[0] == '.' && name[1] == '.') {
231         if (!strcmp(name, "..start")) {
232             obj_entry_seg = segment;
233             obj_entry_ofs = offset;
234         }
235         return;
236     }
237
238     /*
239      * Case (i):
240      */
241     if (obj_seg_needs_update) {
242         obj_seg_needs_update->name = name;
243         return;
244     } else if (obj_grp_needs_update) {
245         obj_grp_needs_update->name = name;
246         return;
247     }
248     if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
249         return;
250
251     if (segment >= SEG_ABS) {
252         /*
253          * SEG_ABS subcase of (ii).
254          */
255         if (is_global) {
256             struct Public *pub;
257
258             pub = *fpubtail = nasm_malloc(sizeof(*pub));
259             fpubtail = &pub->next;
260             pub->next = NULL;
261             pub->name = name;
262             pub->offset = offset;
263             pub->segment = segment & ~SEG_ABS;
264         }
265         return;
266     }
267
268     for (seg = seghead; seg; seg = seg->next)
269         if (seg->index == segment) {
270             /*
271              * Case (ii). Maybe MODPUB someday?
272              */
273             if (is_global) {
274                 struct Public *pub;
275
276                 pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
277                 seg->pubtail = &pub->next;
278                 pub->next = NULL;
279                 pub->name = name;
280                 pub->offset = offset;
281             }
282             return;
283         }
284
285     /*
286      * Case (iii).
287      */
288     ext = *exttail = nasm_malloc(sizeof(*ext));
289     ext->next = NULL;
290     exttail = &ext->next;
291     ext->name = name;
292     if (is_global == 2)
293         ext->commonsize = offset;
294     else
295         ext->commonsize = 0;
296
297     i = segment/2;
298     eb = ebhead;
299     if (!eb) {
300         eb = *ebtail = nasm_malloc(sizeof(*eb));
301         eb->next = NULL;
302         ebtail = &eb->next;
303     }
304     while (i > EXT_BLKSIZ) {
305         if (eb && eb->next)
306             eb = eb->next;
307         else {
308             eb = *ebtail = nasm_malloc(sizeof(*eb));
309             eb->next = NULL;
310             ebtail = &eb->next;
311         }
312         i -= EXT_BLKSIZ;
313     }
314     eb->index[i] = ++externals;
315 }
316
317 static void obj_out (long segto, void *data, unsigned long type,
318                      long segment, long wrt) {
319     long size, realtype;
320     unsigned char *ucdata;
321     long ldata;
322     struct Segment *seg;
323
324     /*
325      * handle absolute-assembly (structure definitions)
326      */
327     if (segto == NO_SEG) {
328         if ((type & OUT_TYPMASK) != OUT_RESERVE)
329             error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
330                    " space");
331         return;
332     }
333
334     /*
335      * If `any_segs' is still FALSE, we must define a default
336      * segment.
337      */
338     if (!any_segs) {
339         int tempint;                   /* ignored */
340         if (segto != obj_segment("__NASMDEFSEG", 2, &tempint))
341             error (ERR_PANIC, "strange segment conditions in OBJ driver");
342     }
343
344     /*
345      * Find the segment we are targetting.
346      */
347     for (seg = seghead; seg; seg = seg->next)
348         if (seg->index == segto)
349             break;
350     if (!seg)
351         error (ERR_PANIC, "code directed to nonexistent segment?");
352
353     size = type & OUT_SIZMASK;
354     realtype = type & OUT_TYPMASK;
355     if (realtype == OUT_RAWDATA) {
356         ucdata = data;
357         while (size > 0) {
358             long len = obj_ledata_space(seg);
359             if (len == 0) {
360                 obj_ledata_new(seg);
361                 len = obj_ledata_space(seg);
362             }
363             if (len > size)
364                 len = size;
365             datacurr->lptr = obj_write_data (datacurr->lptr, ucdata, len);
366             datacurr->nonempty = TRUE;
367             ucdata += len;
368             size -= len;
369             seg->currentpos += len;
370         }
371     } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
372                realtype == OUT_REL4ADR) {
373         if (segment == NO_SEG && realtype != OUT_ADDRESS)
374             error(ERR_NONFATAL, "relative call to absolute address not"
375                   " supported by OBJ format");
376         if (segment >= SEG_ABS)
377             error(ERR_NONFATAL, "far-absolute relocations not supported"
378                   " by OBJ format");
379         ldata = *(long *)data;
380         if (realtype == OUT_REL2ADR)
381             ldata += (size-2);
382         if (realtype == OUT_REL4ADR)
383             ldata += (size-4);
384         if (obj_ledata_space(seg) < 4 || !obj_fixup_free(seg))
385             obj_ledata_new(seg);
386         if (size == 2)
387             datacurr->lptr = obj_write_word (datacurr->lptr, ldata);
388         else
389             datacurr->lptr = obj_write_dword (datacurr->lptr, ldata);
390         datacurr->nonempty = TRUE;
391         if (segment != NO_SEG)
392             obj_write_fixup (datacurr, size,
393                              (realtype == OUT_REL2ADR ? 0 : 0x4000),
394                              segment, wrt,
395                              (seg->currentpos - datacurr->startpos));
396         seg->currentpos += size;
397     } else if (realtype == OUT_RESERVE) {
398         obj_ledata_commit();
399         seg->currentpos += size;
400     }
401 }
402
403 static long obj_ledata_space(struct Segment *segto) {
404     if (datacurr && datacurr->seg == segto)
405         return datacurr->ledata + LEDATA_MAX - datacurr->lptr;
406     else
407         return 0;
408 }
409
410 static int obj_fixup_free(struct Segment *segto) {
411     if (datacurr && datacurr->seg == segto)
412         return (datacurr->fixupp + RECORD_MAX - datacurr->fptr) > 8;
413     else
414         return 0;
415 }
416
417 static void obj_ledata_new(struct Segment *segto) {
418     datacurr = *datatail = nasm_malloc(sizeof(*datacurr));
419     datacurr->next = NULL;
420     datatail = &datacurr->next;
421     datacurr->nonempty = FALSE;
422     datacurr->lptr = datacurr->ledata;
423     datacurr->fptr = datacurr->fixupp;
424     datacurr->seg = segto;
425     if (segto->use32)
426         datacurr->letype = LEDATA+1;
427     else
428         datacurr->letype = LEDATA;
429     datacurr->startpos = segto->currentpos;
430     datacurr->ftype = FIXUPP;
431
432     datacurr->lptr = obj_write_index (datacurr->lptr, segto->obj_index);
433     if (datacurr->letype == LEDATA)
434         datacurr->lptr = obj_write_word (datacurr->lptr, segto->currentpos);
435     else
436         datacurr->lptr = obj_write_dword (datacurr->lptr, segto->currentpos);
437 }
438
439 static void obj_ledata_commit(void) {
440     datacurr = NULL;
441 }
442
443 static void obj_write_fixup (struct ObjData *data, int bytes,
444                              int segrel, long seg, long wrt,
445                              long offset) {
446     int locat, method;
447     int base;
448     long tidx, fidx;
449     struct Segment *s = NULL;
450     struct Group *g = NULL;
451
452     locat = 0x8000 | segrel | offset;
453     if (seg % 2) {
454         base = TRUE;
455         locat |= 0x800;
456         seg--;
457         if (bytes != 2)
458             error(ERR_NONFATAL, "OBJ format can only handle 2-byte"
459                   " segment base references");
460     } else {
461         base = FALSE;
462         if (bytes == 2)
463             locat |= 0x400;
464         else {
465             locat |= 0x2400;
466             data->ftype = FIXUPP+1;    /* need new-style FIXUPP record */
467         }
468     }
469     data->fptr = obj_write_rword (data->fptr, locat);
470
471     tidx = fidx = -1, method = 0;      /* placate optimisers */
472
473     /*
474      * See if we can find the segment ID in our segment list. If
475      * so, we have a T4 (LSEG) target.
476      */
477     for (s = seghead; s; s = s->next)
478         if (s->index == seg)
479             break;
480     if (s)
481         method = 4, tidx = s->obj_index;
482     else {
483         for (g = grphead; g; g = g->next)
484             if (g->index == seg)
485                 break;
486         if (g)
487             method = 5, tidx = g->obj_index;
488         else {
489             long i = seg/2;
490             struct ExtBack *eb = ebhead;
491             while (i > EXT_BLKSIZ) {
492                 if (eb)
493                     eb = eb->next;
494                 else
495                     break;
496                 i -= EXT_BLKSIZ;
497             }
498             if (eb)
499                 method = 6, tidx = eb->index[i];
500             else
501                 error(ERR_PANIC,
502                       "unrecognised segment value in obj_write_fixup");
503         }
504     }
505
506     /*
507      * If no WRT given, assume the natural default, which is method
508      * F5 unless we are doing an OFFSET fixup for a grouped
509      * segment, in which case we require F1 (group).
510      */
511     if (wrt == NO_SEG) {
512         if (!base && s && s->grp)
513             method |= 0x10, fidx = s->grp->obj_index;
514         else
515             method |= 0x50, fidx = -1;
516     } else {
517         /*
518          * See if we can find the WRT-segment ID in our segment
519          * list. If so, we have a F0 (LSEG) frame.
520          */
521         for (s = seghead; s; s = s->next)
522             if (s->index == wrt-1)
523                 break;
524         if (s)
525             method |= 0x00, fidx = s->obj_index;
526         else {
527             for (g = grphead; g; g = g->next)
528                 if (g->index == wrt-1)
529                     break;
530             if (g)
531                 method |= 0x10, fidx = g->obj_index;
532             else {
533                 long i = wrt/2;
534                 struct ExtBack *eb = ebhead;
535                 while (i > EXT_BLKSIZ) {
536                     if (eb)
537                         eb = eb->next;
538                     else
539                         break;
540                     i -= EXT_BLKSIZ;
541                 }
542                 if (eb)
543                     method |= 0x20, fidx = eb->index[i];
544                 else
545                     error(ERR_PANIC,
546                           "unrecognised WRT value in obj_write_fixup");
547             }
548         }
549     }
550
551     data->fptr = obj_write_byte (data->fptr, method);
552     if (fidx != -1)
553         data->fptr = obj_write_index (data->fptr, fidx);
554     data->fptr = obj_write_index (data->fptr, tidx);
555 }
556
557 static long obj_segment (char *name, int pass, int *bits) {
558     /*
559      * We call the label manager here to define a name for the new
560      * segment, and when our _own_ label-definition stub gets
561      * called in return, it should register the new segment name
562      * using the pointer it gets passed. That way we save memory,
563      * by sponging off the label manager.
564      */
565     if (!name) {
566         *bits = 16;
567         return first_seg;
568     } else {
569         struct Segment *seg;
570         struct Group *grp;
571         int obj_idx, i, attrs, rn_error;
572         char *p;
573
574         /*
575          * Look for segment attributes.
576          */
577         attrs = 0;
578         while (*name == '.')
579             name++;                    /* hack, but a documented one */
580         p = name;
581         while (*p && !isspace(*p))
582             p++;
583         if (*p) {
584             *p++ = '\0';
585             while (*p && isspace(*p))
586                 *p++ = '\0';
587         }
588         while (*p) {
589             while (*p && !isspace(*p))
590                 p++;
591             if (*p) {
592                 *p++ = '\0';
593                 while (*p && isspace(*p))
594                     *p++ = '\0';
595             }
596
597             attrs++;
598         }
599
600         obj_idx = 1;
601         for (seg = seghead; seg; seg = seg->next) {
602             obj_idx++;
603             if (!strcmp(seg->name, name)) {
604                 if (attrs > 0 && pass == 1)
605                     error(ERR_WARNING, "segment attributes specified on"
606                           " redeclaration of segment: ignoring");
607                 if (seg->use32)
608                     *bits = 32;
609                 else
610                     *bits = 16;
611                 return seg->index;
612             }
613         }
614
615         *segtail = seg = nasm_malloc(sizeof(*seg));
616         seg->next = NULL;
617         segtail = &seg->next;
618         seg->index = (any_segs ? seg_alloc() : first_seg);
619         seg->obj_index = obj_idx;
620         seg->grp = NULL;
621         any_segs = TRUE;
622         seg->name = NULL;
623         seg->currentpos = 0;
624         seg->align = 1;                /* default */
625         seg->use32 = FALSE;            /* default */
626         seg->combine = CMB_PUBLIC;     /* default */
627         seg->segclass = seg->overlay = NULL;
628         seg->pubhead = NULL;
629         seg->pubtail = &seg->pubhead;
630
631         /*
632          * Process the segment attributes.
633          */
634         p = name;
635         while (attrs--) {
636             p += strlen(p);
637             while (!*p) p++;
638
639             /*
640              * `p' contains a segment attribute.
641              */
642             if (!nasm_stricmp(p, "private"))
643                 seg->combine = CMB_PRIVATE;
644             else if (!nasm_stricmp(p, "public"))
645                 seg->combine = CMB_PUBLIC;
646             else if (!nasm_stricmp(p, "common"))
647                 seg->combine = CMB_COMMON;
648             else if (!nasm_stricmp(p, "stack"))
649                 seg->combine = CMB_STACK;
650             else if (!nasm_stricmp(p, "use16"))
651                 seg->use32 = FALSE;
652             else if (!nasm_stricmp(p, "use32"))
653                 seg->use32 = TRUE;
654             else if (!nasm_strnicmp(p, "class=", 6))
655                 seg->segclass = nasm_strdup(p+6);
656             else if (!nasm_strnicmp(p, "overlay=", 8))
657                 seg->overlay = nasm_strdup(p+8);
658             else if (!nasm_strnicmp(p, "align=", 6)) {
659                 seg->align = readnum(p+6, &rn_error);
660                 if (rn_error) {
661                     seg->align = 1;
662                     error (ERR_NONFATAL, "segment alignment should be"
663                            " numeric");
664                 }
665                 switch ((int) seg->align) {
666                   case 1:              /* BYTE */
667                   case 2:              /* WORD */
668                   case 4:              /* DWORD */
669                   case 16:             /* PARA */
670                   case 256:            /* PAGE */
671                     break;
672                   case 8:
673                     error(ERR_WARNING, "OBJ format does not support alignment"
674                           " of 8: rounding up to 16");
675                     seg->align = 16;
676                     break;
677                   case 32:
678                   case 64:
679                   case 128:
680                     error(ERR_WARNING, "OBJ format does not support alignment"
681                           " of %d: rounding up to 256", seg->align);
682                     seg->align = 256;
683                     break;
684                   default:
685                     error(ERR_NONFATAL, "invalid alignment value %d",
686                           seg->align);
687                     seg->align = 1;
688                     break;
689                 }
690             } else if (!nasm_strnicmp(p, "absolute=", 9)) {
691                 seg->align = SEG_ABS + readnum(p+9, &rn_error);
692                 if (rn_error)
693                     error (ERR_NONFATAL, "argument to `absolute' segment"
694                            " attribute should be numeric");
695             }
696         }
697
698         obj_seg_needs_update = seg;
699         if (seg->align >= SEG_ABS)
700             deflabel (name, NO_SEG, seg->align - SEG_ABS, &of_obj, error);
701         else
702             deflabel (name, seg->index+1, 0L, &of_obj, error);
703         obj_seg_needs_update = NULL;
704
705         /*
706          * See if this segment is defined in any groups.
707          */
708         for (grp = grphead; grp; grp = grp->next) {
709             for (i = grp->nindices; i < grp->nentries; i++) {
710                 if (!strcmp(grp->segs[i].name, seg->name)) {
711                     nasm_free (grp->segs[i].name);
712                     grp->segs[i] = grp->segs[grp->nindices];
713                     grp->segs[grp->nindices++].index = seg->obj_index;
714                     if (seg->grp)
715                         error(ERR_WARNING, "segment `%s' is already part of"
716                               " a group: first one takes precedence",
717                               seg->name);
718                     else
719                         seg->grp = grp;
720                 }
721             }
722         }
723
724         if (seg->use32)
725             *bits = 32;
726         else
727             *bits = 16;
728         return seg->index;
729     }
730 }
731
732 static int obj_directive (char *directive, char *value, int pass) {
733     if (!strcmp(directive, "group")) {
734         char *p, *q;
735         if (pass == 1) {
736             struct Group *grp;
737             struct Segment *seg;
738             int obj_idx;
739
740             q = value;
741             while (*q == '.')
742                 q++;                   /* hack, but a documented one */
743             while (*q && !isspace(*q))
744                 q++;
745             if (isspace(*q)) {
746                 *q++ = '\0';
747                 while (*q && isspace(*q))
748                     q++;
749             }
750             if (!*q) {
751                 error(ERR_NONFATAL, "GROUP directive contains no segments");
752                 return 1;
753             }
754
755             obj_idx = 1;
756             for (grp = grphead; grp; grp = grp->next) {
757                 obj_idx++;
758                 if (!strcmp(grp->name, value)) {
759                     error(ERR_NONFATAL, "group `%s' defined twice", value);
760                     return 1;
761                 }
762             }
763
764             *grptail = grp = nasm_malloc(sizeof(*grp));
765             grp->next = NULL;
766             grptail = &grp->next;
767             grp->index = seg_alloc();
768             grp->obj_index = obj_idx;
769             grp->nindices = grp->nentries = 0;
770             grp->name = NULL;
771
772             obj_grp_needs_update = grp;
773             deflabel (value, grp->index+1, 0L, &of_obj, error);
774             obj_grp_needs_update = NULL;
775
776             while (*q) {
777                 p = q;
778                 while (*q && !isspace(*q))
779                     q++;
780                 if (isspace(*q)) {
781                     *q++ = '\0';
782                     while (*q && isspace(*q))
783                         q++;
784                 }
785                 /*
786                  * Now p contains a segment name. Find it.
787                  */
788                 for (seg = seghead; seg; seg = seg->next)
789                     if (!strcmp(seg->name, p))
790                         break;
791                 if (seg) {
792                     /*
793                      * We have a segment index. Shift a name entry
794                      * to the end of the array to make room.
795                      */
796                     grp->segs[grp->nentries++] = grp->segs[grp->nindices];
797                     grp->segs[grp->nindices++].index = seg->obj_index;
798                     if (seg->grp)
799                         error(ERR_WARNING, "segment `%s' is already part of"
800                               " a group: first one takes precedence",
801                               seg->name);
802                     else
803                         seg->grp = grp;
804                 } else {
805                     /*
806                      * We have an as-yet undefined segment.
807                      * Remember its name, for later.
808                      */
809                     grp->segs[grp->nentries++].name = nasm_strdup(p);
810                 }
811             }
812         }
813         return 1;
814     }
815     if (!strcmp(directive, "uppercase")) {
816         obj_uppercase = TRUE;
817         return 1;
818     }
819     return 0;
820 }
821
822 static long obj_segbase (long segment) {
823     struct Segment *seg;
824
825     /*
826      * Find the segment in our list.
827      */
828     for (seg = seghead; seg; seg = seg->next)
829         if (seg->index == segment-1)
830             break;
831
832     if (!seg)
833         return segment;                /* not one of ours - leave it alone */
834
835     if (seg->align >= SEG_ABS)
836         return seg->align;             /* absolute segment */
837     if (seg->grp)
838         return seg->grp->index+1;      /* grouped segment */
839
840     return segment;                    /* no special treatment */
841 }
842
843 static void obj_filename (char *inname, char *outname, efunc error) {
844     strcpy(obj_infile, inname);
845     standard_extension (inname, outname, ".obj", error);
846 }
847
848 static void obj_write_file (void) {
849     struct Segment *seg;
850     struct Group *grp;
851     struct Public *pub;
852     struct External *ext;
853     struct ObjData *data;
854     static char boast[] = "The Netwide Assembler " NASM_VER;
855     int lname_idx, rectype;
856
857     /*
858      * Write the THEADR module header.
859      */
860     recptr = record;
861     recptr = obj_write_name (recptr, obj_infile);
862     obj_record (THEADR, record, recptr);
863
864     /*
865      * Write the NASM boast comment.
866      */
867     recptr = record;
868     recptr = obj_write_rword (recptr, 0);   /* comment type zero */
869     recptr = obj_write_name (recptr, boast);
870     obj_record (COMENT, record, recptr);
871
872     /*
873      * Write the first LNAMES record, containing LNAME one, which
874      * is null. Also initialise the LNAME counter.
875      */
876     recptr = record;
877     recptr = obj_write_name (recptr, "");
878     obj_record (LNAMES, record, recptr);
879     lname_idx = 2;
880
881     /*
882      * Write the SEGDEF records. Each has an associated LNAMES
883      * record.
884      */
885     for (seg = seghead; seg; seg = seg->next) {
886         int new_segdef;                /* do we use the newer record type? */
887         int acbp;
888         int sn, cn, on;                /* seg, class, overlay LNAME idx */
889
890         if (seg->use32 || seg->currentpos >= 0x10000)
891             new_segdef = TRUE;
892         else
893             new_segdef = FALSE;
894
895         recptr = record;
896         recptr = obj_write_name (recptr, seg->name);
897         sn = lname_idx++;
898         if (seg->segclass) {
899             recptr = obj_write_name (recptr, seg->segclass);
900             cn = lname_idx++;
901         } else
902             cn = 1;
903         if (seg->overlay) {
904             recptr = obj_write_name (recptr, seg->overlay);
905             on = lname_idx++;
906         } else
907             on = 1;
908         obj_record (LNAMES, record, recptr);
909
910         acbp = (seg->combine << 2);    /* C field */
911
912         if (seg->currentpos >= 0x10000 && !new_segdef)
913             acbp |= 0x02;              /* B bit */
914
915         if (seg->use32)
916             acbp |= 0x01;              /* P bit is Use32 flag */
917
918         /* A field */
919         if (seg->align >= SEG_ABS)
920             acbp |= 0x00;
921         else if (seg->align >= 256) {
922             if (seg->align > 256)
923                 error(ERR_NONFATAL, "segment `%s' requires more alignment"
924                       " than OBJ format supports", seg->name);
925             acbp |= 0x80;
926         } else if (seg->align >= 16) {
927             acbp |= 0x60;
928         } else if (seg->align >= 4) {
929             acbp |= 0xA0;
930         } else if (seg->align >= 2) {
931             acbp |= 0x40;
932         } else
933             acbp |= 0x20;
934
935         recptr = record;
936         recptr = obj_write_byte (recptr, acbp);
937         if (seg->align & SEG_ABS) {
938             recptr = obj_write_word (recptr, seg->align - SEG_ABS);
939             recptr = obj_write_byte (recptr, 0);
940         }
941         if (new_segdef)
942             recptr = obj_write_dword (recptr, seg->currentpos);
943         else
944             recptr = obj_write_word (recptr, seg->currentpos & 0xFFFF);
945         recptr = obj_write_index (recptr, sn);
946         recptr = obj_write_index (recptr, cn);
947         recptr = obj_write_index (recptr, on);
948         if (new_segdef)
949             obj_record (SEGDEF+1, record, recptr);
950         else
951             obj_record (SEGDEF, record, recptr);
952     }
953
954     /*
955      * Write some LNAMES for the group names. lname_idx is left
956      * alone here - it will catch up when we write the GRPDEFs.
957      */
958     recptr = record;
959     for (grp = grphead; grp; grp = grp->next) {
960         recptr = obj_write_name (recptr, grp->name);
961         if (recptr - record > 1024) {
962             obj_record (LNAMES, record, recptr);
963             recptr = record;
964         }
965     }
966     if (recptr > record)
967         obj_record (LNAMES, record, recptr);
968
969     /*
970      * Write the GRPDEF records.
971      */
972     for (grp = grphead; grp; grp = grp->next) {
973         int i;
974
975         if (grp->nindices != grp->nentries) {
976             for (i = grp->nindices; i < grp->nentries; i++) {
977                 error(ERR_NONFATAL, "group `%s' contains undefined segment"
978                       " `%s'", grp->name, grp->segs[i].name);
979                 nasm_free (grp->segs[i].name);
980                 grp->segs[i].name = NULL;
981             }
982         }
983         recptr = record;
984         recptr = obj_write_index (recptr, lname_idx++);
985         for (i = 0; i < grp->nindices; i++) {
986             recptr = obj_write_byte (recptr, 0xFF);
987             recptr = obj_write_index (recptr, grp->segs[i].index);
988         }
989         obj_record (GRPDEF, record, recptr);
990     }
991
992     /*
993      * Write the PUBDEF records: first the ones in the segments,
994      * then the far-absolutes.
995      */
996     for (seg = seghead; seg; seg = seg->next) {
997         int any;
998
999         recptr = record;
1000         recptr = obj_write_index (recptr, seg->grp ? seg->grp->obj_index : 0);
1001         recptr = obj_write_index (recptr, seg->obj_index);
1002         any = FALSE;
1003         if (seg->use32)
1004             rectype = PUBDEF+1;
1005         else
1006             rectype = PUBDEF;
1007         for (pub = seg->pubhead; pub; pub = pub->next) {
1008             if (recptr - record + strlen(pub->name) > 1024) {
1009                 if (any)
1010                     obj_record (rectype, record, recptr);
1011                 recptr = record;
1012                 recptr = obj_write_index (recptr, 0);
1013                 recptr = obj_write_index (recptr, seg->obj_index);
1014             }
1015             recptr = obj_write_name (recptr, pub->name);
1016             if (seg->use32)
1017                 recptr = obj_write_dword (recptr, pub->offset);
1018             else
1019                 recptr = obj_write_word (recptr, pub->offset);
1020             recptr = obj_write_index (recptr, 0);
1021             any = TRUE;
1022         }
1023         if (any)
1024             obj_record (rectype, record, recptr);
1025     }
1026     for (pub = fpubhead; pub; pub = pub->next) {   /* pub-crawl :-) */
1027         recptr = record;
1028         recptr = obj_write_index (recptr, 0);   /* no group */
1029         recptr = obj_write_index (recptr, 0);   /* no segment either */
1030         recptr = obj_write_word (recptr, pub->segment);
1031         recptr = obj_write_name (recptr, pub->name);
1032         recptr = obj_write_word (recptr, pub->offset);
1033         recptr = obj_write_index (recptr, 0);
1034         obj_record (PUBDEF, record, recptr);
1035     }
1036
1037     /*
1038      * Write the EXTDEF and COMDEF records, in order.
1039      */
1040     recptr = record;
1041     for (ext = exthead; ext; ext = ext->next) {
1042         if (ext->commonsize == 0) {
1043             recptr = obj_write_name (recptr, ext->name);
1044             recptr = obj_write_index (recptr, 0);
1045             if (recptr - record > 1024) {
1046                 obj_record (EXTDEF, record, recptr);
1047                 recptr = record;
1048             }
1049         } else {
1050             if (recptr > record)
1051                 obj_record (EXTDEF, record, recptr);
1052             recptr = record;
1053             if (ext->commonsize > 0) {
1054                 recptr = obj_write_name (recptr, ext->name);
1055                 recptr = obj_write_index (recptr, 0);
1056                 recptr = obj_write_byte (recptr, 0x61);/* far communal */
1057                 recptr = obj_write_value (recptr, 1L);
1058                 recptr = obj_write_value (recptr, ext->commonsize);
1059                 obj_record (COMDEF, record, recptr);
1060             } else if (ext->commonsize < 0) {
1061                 recptr = obj_write_name (recptr, ext->name);
1062                 recptr = obj_write_index (recptr, 0);
1063                 recptr = obj_write_byte (recptr, 0x62);/* near communal */
1064                 recptr = obj_write_value (recptr, ext->commonsize);
1065                 obj_record (COMDEF, record, recptr);
1066             }
1067             recptr = record;
1068         }
1069     }
1070     if (recptr > record)
1071         obj_record (EXTDEF, record, recptr);
1072
1073     /*
1074      * Write a COMENT record stating that the linker's first pass
1075      * may stop processing at this point.
1076      */
1077     recptr = record;
1078     recptr = obj_write_rword (recptr, 0x40A2);
1079     recptr = obj_write_byte (recptr, 1);
1080     obj_record (COMENT, record, recptr);
1081
1082     /*
1083      * Write the LEDATA/FIXUPP pairs.
1084      */
1085     for (data = datahead; data; data = data->next) {
1086         if (data->nonempty) {
1087             obj_record (data->letype, data->ledata, data->lptr);
1088             if (data->fptr != data->fixupp)
1089                 obj_record (FIXUPP, data->fixupp, data->fptr);
1090         }
1091     }
1092
1093     /*
1094      * Write the MODEND module end marker.
1095      */
1096     recptr = record;
1097     rectype = MODEND;
1098     if (obj_entry_seg != NO_SEG) {
1099         recptr = obj_write_byte (recptr, 0xC1);
1100         /*
1101          * Find the segment in the segment list.
1102          */
1103         for (seg = seghead; seg; seg = seg->next) {
1104             if (seg->index == obj_entry_seg) {
1105                 if (seg->grp) {
1106                     recptr = obj_write_byte (recptr, 0x10);
1107                     recptr = obj_write_index (recptr, seg->grp->obj_index);
1108                 } else {
1109                     recptr = obj_write_byte (recptr, 0x50);
1110                 }
1111                 recptr = obj_write_index (recptr, seg->obj_index);
1112                 if (seg->use32) {
1113                     rectype = MODEND+1;
1114                     recptr = obj_write_dword (recptr, obj_entry_ofs);
1115                 } else
1116                     recptr = obj_write_word (recptr, obj_entry_ofs);
1117                 break;
1118             }
1119         }
1120         if (!seg)
1121             error(ERR_NONFATAL, "entry point is not in this module");
1122     } else
1123         recptr = obj_write_byte (recptr, 0);
1124     obj_record (rectype, record, recptr);
1125 }
1126
1127 static unsigned char *obj_write_data(unsigned char *ptr,
1128                                      unsigned char *data, int len) {
1129     while (len--)
1130         *ptr++ = *data++;
1131     return ptr;
1132 }
1133
1134 static unsigned char *obj_write_byte(unsigned char *ptr, int data) {
1135     *ptr++ = data;
1136     return ptr;
1137 }
1138
1139 static unsigned char *obj_write_word(unsigned char *ptr, int data) {
1140     *ptr++ = data & 0xFF;
1141     *ptr++ = (data >> 8) & 0xFF;
1142     return ptr;
1143 }
1144
1145 static unsigned char *obj_write_dword(unsigned char *ptr, long data) {
1146     *ptr++ = data & 0xFF;
1147     *ptr++ = (data >> 8) & 0xFF;
1148     *ptr++ = (data >> 16) & 0xFF;
1149     *ptr++ = (data >> 24) & 0xFF;
1150     return ptr;
1151 }
1152
1153 static unsigned char *obj_write_rword(unsigned char *ptr, int data) {
1154     *ptr++ = (data >> 8) & 0xFF;
1155     *ptr++ = data & 0xFF;
1156     return ptr;
1157 }
1158
1159 static unsigned char *obj_write_name(unsigned char *ptr, char *data) {
1160     *ptr++ = strlen(data);
1161     if (obj_uppercase) {
1162         while (*data) {
1163             *ptr++ = (unsigned char) toupper(*data);
1164             data++;
1165         }
1166     } else {
1167         while (*data)
1168             *ptr++ = (unsigned char) *data++;
1169     }
1170     return ptr;
1171 }
1172
1173 static unsigned char *obj_write_index(unsigned char *ptr, int data) {
1174     if (data < 128)
1175         *ptr++ = data;
1176     else {
1177         *ptr++ = 0x80 | ((data >> 8) & 0x7F);
1178         *ptr++ = data & 0xFF;
1179     }
1180     return ptr;
1181 }
1182
1183 static unsigned char *obj_write_value(unsigned char *ptr,
1184                                       unsigned long data) {
1185     if (data <= 128)
1186         *ptr++ = data;
1187     else if (data <= 0xFFFF) {
1188         *ptr++ = 129;
1189         *ptr++ = data & 0xFF;
1190         *ptr++ = (data >> 8) & 0xFF;
1191     } else if (data <= 0xFFFFFF) {
1192         *ptr++ = 132;
1193         *ptr++ = data & 0xFF;
1194         *ptr++ = (data >> 8) & 0xFF;
1195         *ptr++ = (data >> 16) & 0xFF;
1196     } else {
1197         *ptr++ = 136;
1198         *ptr++ = data & 0xFF;
1199         *ptr++ = (data >> 8) & 0xFF;
1200         *ptr++ = (data >> 16) & 0xFF;
1201         *ptr++ = (data >> 24) & 0xFF;
1202     }
1203     return ptr;
1204 }
1205
1206 static void obj_record(int type, unsigned char *start, unsigned char *end) {
1207     unsigned long cksum, len;
1208
1209     cksum = type;
1210     fputc (type, ofp);
1211     len = end-start+1;
1212     cksum += (len & 0xFF) + ((len>>8) & 0xFF);
1213     fwriteshort (len, ofp);
1214     fwrite (start, 1, end-start, ofp);
1215     while (start < end)
1216         cksum += *start++;
1217     fputc ( (-cksum) & 0xFF, ofp);
1218 }
1219
1220 struct ofmt of_obj = {
1221     "Microsoft MS-DOS 16-bit object files",
1222     "obj",
1223     obj_init,
1224     obj_out,
1225     obj_deflabel,
1226     obj_segment,
1227     obj_segbase,
1228     obj_directive,
1229     obj_filename,
1230     obj_cleanup
1231 };
1232
1233 #endif /* OF_OBJ */