NASM 0.91
[nasm/avx512.git] / outobj.c
blobb33b72de09fb74b46b8e99fa350cbbce8d4acd25
1 /* outobj.c output routines for the Netwide Assembler to produce
2 * Microsoft 16-bit .OBJ object files
4 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
5 * Julian Hall. All rights reserved. The software is
6 * redistributable under the licence given in the file "Licence"
7 * distributed in the NASM archive.
8 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
15 #include "nasm.h"
16 #include "nasmlib.h"
17 #include "outform.h"
19 #ifdef OF_OBJ
21 static char obj_infile[FILENAME_MAX];
22 static int obj_uppercase;
24 static efunc error;
25 static ldfunc deflabel;
26 static FILE *ofp;
27 static long first_seg;
28 static int any_segs;
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 */
36 static unsigned char record[RECORD_MAX], *recptr;
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;
45 static struct External {
46 struct External *next;
47 char *name;
48 long commonsize;
49 } *exthead, **exttail;
51 static int externals;
53 static struct ExtBack {
54 struct ExtBack *next;
55 int index[EXT_BLKSIZ];
56 } *ebhead, **ebtail;
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;
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;
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;
100 static long obj_entry_seg, obj_entry_ofs;
102 enum RecordID { /* record ID codes */
104 THEADR = 0x80, /* module header */
105 COMENT = 0x88, /* comment record */
107 LNAMES = 0x96, /* list of names */
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 */
115 LEDATA = 0xA0, /* logical enumerated data */
116 FIXUPP = 0x9C, /* fixups (relocations) */
118 MODEND = 0x8A /* module end */
121 extern struct ofmt of_obj;
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 *);
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;
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);
174 nasm_free (segtmp);
176 while (fpubhead) {
177 struct Public *pubtmp = fpubhead;
178 fpubhead = fpubhead->next;
179 nasm_free (pubtmp);
181 while (exthead) {
182 struct External *exttmp = exthead;
183 exthead = exthead->next;
184 nasm_free (exttmp);
186 while (ebhead) {
187 struct ExtBack *ebtmp = ebhead;
188 ebhead = ebhead->next;
189 nasm_free (ebtmp);
191 while (grphead) {
192 struct Group *grptmp = grphead;
193 grphead = grphead->next;
194 nasm_free (grptmp);
196 while (datahead) {
197 struct ObjData *datatmp = datahead;
198 datahead = datahead->next;
199 nasm_free (datatmp);
203 static void obj_deflabel (char *name, long segment,
204 long offset, int is_global) {
206 * We have three cases:
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.
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.)
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.
221 struct External *ext;
222 struct ExtBack *eb;
223 struct Segment *seg;
224 int i;
227 * First check for the double-period, signifying something
228 * unusual.
230 if (name[0] == '.' && name[1] == '.') {
231 if (!strcmp(name, "..start")) {
232 obj_entry_seg = segment;
233 obj_entry_ofs = offset;
235 return;
239 * Case (i):
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;
248 if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
249 return;
251 if (segment >= SEG_ABS) {
253 * SEG_ABS subcase of (ii).
255 if (is_global) {
256 struct Public *pub;
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;
265 return;
268 for (seg = seghead; seg; seg = seg->next)
269 if (seg->index == segment) {
271 * Case (ii). Maybe MODPUB someday?
273 if (is_global) {
274 struct Public *pub;
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;
282 return;
286 * Case (iii).
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;
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;
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;
312 i -= EXT_BLKSIZ;
314 eb->index[i] = ++externals;
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;
325 * handle absolute-assembly (structure definitions)
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;
335 * If `any_segs' is still FALSE, we must define a default
336 * segment.
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");
345 * Find the segment we are targetting.
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?");
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);
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;
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;
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;
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;
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;
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);
439 static void obj_ledata_commit(void) {
440 datacurr = NULL;
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;
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 */
469 data->fptr = obj_write_rword (data->fptr, locat);
471 tidx = fidx = -1, method = 0; /* placate optimisers */
474 * See if we can find the segment ID in our segment list. If
475 * so, we have a T4 (LSEG) target.
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;
498 if (eb)
499 method = 6, tidx = eb->index[i];
500 else
501 error(ERR_PANIC,
502 "unrecognised segment value in obj_write_fixup");
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).
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 {
518 * See if we can find the WRT-segment ID in our segment
519 * list. If so, we have a F0 (LSEG) frame.
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;
542 if (eb)
543 method |= 0x20, fidx = eb->index[i];
544 else
545 error(ERR_PANIC,
546 "unrecognised WRT value in obj_write_fixup");
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);
557 static long obj_segment (char *name, int pass, int *bits) {
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.
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;
575 * Look for segment attributes.
577 attrs = 0;
578 p = name;
579 while (*p && !isspace(*p))
580 p++;
581 if (*p) {
582 *p++ = '\0';
583 while (*p && isspace(*p))
584 *p++ = '\0';
586 while (*p) {
587 while (*p && !isspace(*p))
588 p++;
589 if (*p) {
590 *p++ = '\0';
591 while (*p && isspace(*p))
592 *p++ = '\0';
595 attrs++;
598 obj_idx = 1;
599 for (seg = seghead; seg; seg = seg->next) {
600 obj_idx++;
601 if (!strcmp(seg->name, name)) {
602 if (attrs > 0 && pass == 1)
603 error(ERR_WARNING, "segment attributes specified on"
604 " redeclaration of segment: ignoring");
605 if (seg->use32)
606 *bits = 32;
607 else
608 *bits = 16;
609 return seg->index;
613 *segtail = seg = nasm_malloc(sizeof(*seg));
614 seg->next = NULL;
615 segtail = &seg->next;
616 seg->index = (any_segs ? seg_alloc() : first_seg);
617 seg->obj_index = obj_idx;
618 seg->grp = NULL;
619 any_segs = TRUE;
620 seg->name = NULL;
621 seg->currentpos = 0;
622 seg->align = 1; /* default */
623 seg->use32 = FALSE; /* default */
624 seg->combine = CMB_PUBLIC; /* default */
625 seg->segclass = seg->overlay = NULL;
626 seg->pubhead = NULL;
627 seg->pubtail = &seg->pubhead;
630 * Process the segment attributes.
632 p = name;
633 while (attrs--) {
634 p += strlen(p);
635 while (!*p) p++;
638 * `p' contains a segment attribute.
640 if (!nasm_stricmp(p, "private"))
641 seg->combine = CMB_PRIVATE;
642 else if (!nasm_stricmp(p, "public"))
643 seg->combine = CMB_PUBLIC;
644 else if (!nasm_stricmp(p, "common"))
645 seg->combine = CMB_COMMON;
646 else if (!nasm_stricmp(p, "stack"))
647 seg->combine = CMB_STACK;
648 else if (!nasm_stricmp(p, "use16"))
649 seg->use32 = FALSE;
650 else if (!nasm_stricmp(p, "use32"))
651 seg->use32 = TRUE;
652 else if (!nasm_strnicmp(p, "class=", 6))
653 seg->segclass = nasm_strdup(p+6);
654 else if (!nasm_strnicmp(p, "overlay=", 8))
655 seg->overlay = nasm_strdup(p+8);
656 else if (!nasm_strnicmp(p, "align=", 6)) {
657 seg->align = readnum(p+6, &rn_error);
658 if (rn_error) {
659 seg->align = 1;
660 error (ERR_NONFATAL, "segment alignment should be"
661 " numeric");
663 switch ((int) seg->align) {
664 case 1: /* BYTE */
665 case 2: /* WORD */
666 case 4: /* DWORD */
667 case 16: /* PARA */
668 case 256: /* PAGE */
669 break;
670 case 8:
671 error(ERR_WARNING, "OBJ format does not support alignment"
672 " of 8: rounding up to 16");
673 seg->align = 16;
674 break;
675 case 32:
676 case 64:
677 case 128:
678 error(ERR_WARNING, "OBJ format does not support alignment"
679 " of %d: rounding up to 256", seg->align);
680 seg->align = 256;
681 break;
682 default:
683 error(ERR_NONFATAL, "invalid alignment value %d",
684 seg->align);
685 seg->align = 1;
686 break;
688 } else if (!nasm_strnicmp(p, "absolute=", 9)) {
689 seg->align = SEG_ABS + readnum(p+9, &rn_error);
690 if (rn_error)
691 error (ERR_NONFATAL, "argument to `absolute' segment"
692 " attribute should be numeric");
696 obj_seg_needs_update = seg;
697 if (seg->align >= SEG_ABS)
698 deflabel (name, NO_SEG, seg->align - SEG_ABS, &of_obj, error);
699 else
700 deflabel (name, seg->index+1, 0L, &of_obj, error);
701 obj_seg_needs_update = NULL;
704 * See if this segment is defined in any groups.
706 for (grp = grphead; grp; grp = grp->next) {
707 for (i = grp->nindices; i < grp->nentries; i++) {
708 if (!strcmp(grp->segs[i].name, seg->name)) {
709 nasm_free (grp->segs[i].name);
710 grp->segs[i] = grp->segs[grp->nindices];
711 grp->segs[grp->nindices++].index = seg->obj_index;
712 if (seg->grp)
713 error(ERR_WARNING, "segment `%s' is already part of"
714 " a group: first one takes precedence",
715 seg->name);
716 else
717 seg->grp = grp;
722 if (seg->use32)
723 *bits = 32;
724 else
725 *bits = 16;
726 return seg->index;
730 static int obj_directive (char *directive, char *value, int pass) {
731 if (!strcmp(directive, "group")) {
732 char *p, *q;
733 if (pass == 1) {
734 struct Group *grp;
735 struct Segment *seg;
736 int obj_idx;
738 q = value;
739 while (*q && !isspace(*q))
740 q++;
741 if (isspace(*q)) {
742 *q++ = '\0';
743 while (*q && isspace(*q))
744 q++;
746 if (!*q) {
747 error(ERR_NONFATAL, "GROUP directive contains no segments");
748 return 1;
751 obj_idx = 1;
752 for (grp = grphead; grp; grp = grp->next) {
753 obj_idx++;
754 if (!strcmp(grp->name, value)) {
755 error(ERR_NONFATAL, "group `%s' defined twice", value);
756 return 1;
760 *grptail = grp = nasm_malloc(sizeof(*grp));
761 grp->next = NULL;
762 grptail = &grp->next;
763 grp->index = seg_alloc();
764 grp->obj_index = obj_idx;
765 grp->nindices = grp->nentries = 0;
766 grp->name = NULL;
768 obj_grp_needs_update = grp;
769 deflabel (value, grp->index+1, 0L, &of_obj, error);
770 obj_grp_needs_update = NULL;
772 while (*q) {
773 p = q;
774 while (*q && !isspace(*q))
775 q++;
776 if (isspace(*q)) {
777 *q++ = '\0';
778 while (*q && isspace(*q))
779 q++;
782 * Now p contains a segment name. Find it.
784 for (seg = seghead; seg; seg = seg->next)
785 if (!strcmp(seg->name, p))
786 break;
787 if (seg) {
789 * We have a segment index. Shift a name entry
790 * to the end of the array to make room.
792 grp->segs[grp->nentries++] = grp->segs[grp->nindices];
793 grp->segs[grp->nindices++].index = seg->obj_index;
794 if (seg->grp)
795 error(ERR_WARNING, "segment `%s' is already part of"
796 " a group: first one takes precedence",
797 seg->name);
798 else
799 seg->grp = grp;
800 } else {
802 * We have an as-yet undefined segment.
803 * Remember its name, for later.
805 grp->segs[grp->nentries++].name = nasm_strdup(p);
809 return 1;
811 if (!strcmp(directive, "uppercase")) {
812 obj_uppercase = TRUE;
813 return 1;
815 return 0;
818 static long obj_segbase (long segment) {
819 struct Segment *seg;
822 * Find the segment in our list.
824 for (seg = seghead; seg; seg = seg->next)
825 if (seg->index == segment-1)
826 break;
828 if (!seg)
829 return segment; /* not one of ours - leave it alone */
831 if (seg->align >= SEG_ABS)
832 return seg->align; /* absolute segment */
833 if (seg->grp)
834 return seg->grp->index+1; /* grouped segment */
836 return segment; /* no special treatment */
839 static void obj_filename (char *inname, char *outname, efunc error) {
840 strcpy(obj_infile, inname);
841 standard_extension (inname, outname, ".obj", error);
844 static void obj_write_file (void) {
845 struct Segment *seg;
846 struct Group *grp;
847 struct Public *pub;
848 struct External *ext;
849 struct ObjData *data;
850 static unsigned char boast[] = "The Netwide Assembler " NASM_VER;
851 int lname_idx, rectype;
854 * Write the THEADR module header.
856 recptr = record;
857 recptr = obj_write_name (recptr, obj_infile);
858 obj_record (THEADR, record, recptr);
861 * Write the NASM boast comment.
863 recptr = record;
864 recptr = obj_write_rword (recptr, 0); /* comment type zero */
865 recptr = obj_write_data (recptr, boast, sizeof(boast)-1);
866 obj_record (COMENT, record, recptr);
869 * Write the first LNAMES record, containing LNAME one, which
870 * is null. Also initialise the LNAME counter.
872 recptr = record;
873 recptr = obj_write_name (recptr, "");
874 obj_record (LNAMES, record, recptr);
875 lname_idx = 2;
878 * Write the SEGDEF records. Each has an associated LNAMES
879 * record.
881 for (seg = seghead; seg; seg = seg->next) {
882 int new_segdef; /* do we use the newer record type? */
883 int acbp;
884 int sn, cn, on; /* seg, class, overlay LNAME idx */
886 if (seg->use32 || seg->currentpos >= 0x10000)
887 new_segdef = TRUE;
888 else
889 new_segdef = FALSE;
891 recptr = record;
892 recptr = obj_write_name (recptr, seg->name);
893 sn = lname_idx++;
894 if (seg->segclass) {
895 recptr = obj_write_name (recptr, seg->segclass);
896 cn = lname_idx++;
897 } else
898 cn = 1;
899 if (seg->overlay) {
900 recptr = obj_write_name (recptr, seg->overlay);
901 on = lname_idx++;
902 } else
903 on = 1;
904 obj_record (LNAMES, record, recptr);
906 acbp = (seg->combine << 2); /* C field */
908 if (seg->currentpos >= 0x10000 && !new_segdef)
909 acbp |= 0x02; /* B bit */
911 if (seg->use32)
912 acbp |= 0x01; /* P bit is Use32 flag */
914 /* A field */
915 if (seg->align >= SEG_ABS)
916 acbp |= 0x00;
917 else if (seg->align >= 256) {
918 if (seg->align > 256)
919 error(ERR_NONFATAL, "segment `%s' requires more alignment"
920 " than OBJ format supports", seg->name);
921 acbp |= 0x80;
922 } else if (seg->align >= 16) {
923 acbp |= 0x60;
924 } else if (seg->align >= 4) {
925 acbp |= 0xA0;
926 } else if (seg->align >= 2) {
927 acbp |= 0x40;
928 } else
929 acbp |= 0x20;
931 recptr = record;
932 recptr = obj_write_byte (recptr, acbp);
933 if (seg->align & SEG_ABS) {
934 recptr = obj_write_word (recptr, seg->align - SEG_ABS);
935 recptr = obj_write_byte (recptr, 0);
937 if (new_segdef)
938 recptr = obj_write_dword (recptr, seg->currentpos);
939 else
940 recptr = obj_write_word (recptr, seg->currentpos & 0xFFFF);
941 recptr = obj_write_index (recptr, sn);
942 recptr = obj_write_index (recptr, cn);
943 recptr = obj_write_index (recptr, on);
944 if (new_segdef)
945 obj_record (SEGDEF+1, record, recptr);
946 else
947 obj_record (SEGDEF, record, recptr);
951 * Write some LNAMES for the group names. lname_idx is left
952 * alone here - it will catch up when we write the GRPDEFs.
954 recptr = record;
955 for (grp = grphead; grp; grp = grp->next) {
956 recptr = obj_write_name (recptr, grp->name);
957 if (recptr - record > 1024) {
958 obj_record (LNAMES, record, recptr);
959 recptr = record;
962 if (recptr > record)
963 obj_record (LNAMES, record, recptr);
966 * Write the GRPDEF records.
968 for (grp = grphead; grp; grp = grp->next) {
969 int i;
971 if (grp->nindices != grp->nentries) {
972 for (i = grp->nindices; i < grp->nentries; i++) {
973 error(ERR_NONFATAL, "group `%s' contains undefined segment"
974 " `%s'", grp->name, grp->segs[i].name);
975 nasm_free (grp->segs[i].name);
976 grp->segs[i].name = NULL;
979 recptr = record;
980 recptr = obj_write_index (recptr, lname_idx++);
981 for (i = 0; i < grp->nindices; i++) {
982 recptr = obj_write_byte (recptr, 0xFF);
983 recptr = obj_write_index (recptr, grp->segs[i].index);
985 obj_record (GRPDEF, record, recptr);
989 * Write the PUBDEF records: first the ones in the segments,
990 * then the far-absolutes.
992 for (seg = seghead; seg; seg = seg->next) {
993 int any;
995 recptr = record;
996 recptr = obj_write_index (recptr, seg->grp ? seg->grp->obj_index : 0);
997 recptr = obj_write_index (recptr, seg->obj_index);
998 any = FALSE;
999 if (seg->use32)
1000 rectype = PUBDEF+1;
1001 else
1002 rectype = PUBDEF;
1003 for (pub = seg->pubhead; pub; pub = pub->next) {
1004 if (recptr - record + strlen(pub->name) > 1024) {
1005 if (any)
1006 obj_record (rectype, record, recptr);
1007 recptr = record;
1008 recptr = obj_write_index (recptr, 0);
1009 recptr = obj_write_index (recptr, seg->obj_index);
1011 recptr = obj_write_name (recptr, pub->name);
1012 if (seg->use32)
1013 recptr = obj_write_dword (recptr, pub->offset);
1014 else
1015 recptr = obj_write_word (recptr, pub->offset);
1016 recptr = obj_write_index (recptr, 0);
1017 any = TRUE;
1019 if (any)
1020 obj_record (rectype, record, recptr);
1022 for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */
1023 recptr = record;
1024 recptr = obj_write_index (recptr, 0); /* no group */
1025 recptr = obj_write_index (recptr, 0); /* no segment either */
1026 recptr = obj_write_word (recptr, pub->segment);
1027 recptr = obj_write_name (recptr, pub->name);
1028 recptr = obj_write_word (recptr, pub->offset);
1029 recptr = obj_write_index (recptr, 0);
1030 obj_record (PUBDEF, record, recptr);
1034 * Write the EXTDEF and COMDEF records, in order.
1036 recptr = record;
1037 for (ext = exthead; ext; ext = ext->next) {
1038 if (ext->commonsize == 0) {
1039 recptr = obj_write_name (recptr, ext->name);
1040 recptr = obj_write_index (recptr, 0);
1041 if (recptr - record > 1024) {
1042 obj_record (EXTDEF, record, recptr);
1043 recptr = record;
1045 } else {
1046 if (recptr > record)
1047 obj_record (EXTDEF, record, recptr);
1048 recptr = record;
1049 if (ext->commonsize > 0) {
1050 recptr = obj_write_name (recptr, ext->name);
1051 recptr = obj_write_index (recptr, 0);
1052 recptr = obj_write_byte (recptr, 0x61);/* far communal */
1053 recptr = obj_write_value (recptr, 1L);
1054 recptr = obj_write_value (recptr, ext->commonsize);
1055 obj_record (COMDEF, record, recptr);
1056 } else if (ext->commonsize < 0) {
1057 recptr = obj_write_name (recptr, ext->name);
1058 recptr = obj_write_index (recptr, 0);
1059 recptr = obj_write_byte (recptr, 0x62);/* near communal */
1060 recptr = obj_write_value (recptr, ext->commonsize);
1061 obj_record (COMDEF, record, recptr);
1063 recptr = record;
1066 if (recptr > record)
1067 obj_record (EXTDEF, record, recptr);
1070 * Write a COMENT record stating that the linker's first pass
1071 * may stop processing at this point.
1073 recptr = record;
1074 recptr = obj_write_rword (recptr, 0x40A2);
1075 recptr = obj_write_byte (recptr, 1);
1076 obj_record (COMENT, record, recptr);
1079 * Write the LEDATA/FIXUPP pairs.
1081 for (data = datahead; data; data = data->next) {
1082 if (data->nonempty) {
1083 obj_record (data->letype, data->ledata, data->lptr);
1084 if (data->fptr != data->fixupp)
1085 obj_record (FIXUPP, data->fixupp, data->fptr);
1090 * Write the MODEND module end marker.
1092 recptr = record;
1093 rectype = MODEND;
1094 if (obj_entry_seg != NO_SEG) {
1095 recptr = obj_write_byte (recptr, 0xC1);
1097 * Find the segment in the segment list.
1099 for (seg = seghead; seg; seg = seg->next) {
1100 if (seg->index == obj_entry_seg) {
1101 if (seg->grp) {
1102 recptr = obj_write_byte (recptr, 0x10);
1103 recptr = obj_write_index (recptr, seg->grp->obj_index);
1104 } else {
1105 recptr = obj_write_byte (recptr, 0x50);
1107 recptr = obj_write_index (recptr, seg->obj_index);
1108 if (seg->use32) {
1109 rectype = MODEND+1;
1110 recptr = obj_write_dword (recptr, obj_entry_ofs);
1111 } else
1112 recptr = obj_write_word (recptr, obj_entry_ofs);
1113 break;
1116 if (!seg)
1117 error(ERR_NONFATAL, "entry point is not in this module");
1118 } else
1119 recptr = obj_write_byte (recptr, 0);
1120 obj_record (rectype, record, recptr);
1123 static unsigned char *obj_write_data(unsigned char *ptr,
1124 unsigned char *data, int len) {
1125 while (len--)
1126 *ptr++ = *data++;
1127 return ptr;
1130 static unsigned char *obj_write_byte(unsigned char *ptr, int data) {
1131 *ptr++ = data;
1132 return ptr;
1135 static unsigned char *obj_write_word(unsigned char *ptr, int data) {
1136 *ptr++ = data & 0xFF;
1137 *ptr++ = (data >> 8) & 0xFF;
1138 return ptr;
1141 static unsigned char *obj_write_dword(unsigned char *ptr, long data) {
1142 *ptr++ = data & 0xFF;
1143 *ptr++ = (data >> 8) & 0xFF;
1144 *ptr++ = (data >> 16) & 0xFF;
1145 *ptr++ = (data >> 24) & 0xFF;
1146 return ptr;
1149 static unsigned char *obj_write_rword(unsigned char *ptr, int data) {
1150 *ptr++ = (data >> 8) & 0xFF;
1151 *ptr++ = data & 0xFF;
1152 return ptr;
1155 static unsigned char *obj_write_name(unsigned char *ptr, char *data) {
1156 *ptr++ = strlen(data);
1157 if (obj_uppercase) {
1158 while (*data) {
1159 *ptr++ = (unsigned char) toupper(*data);
1160 data++;
1162 } else {
1163 while (*data)
1164 *ptr++ = (unsigned char) *data++;
1166 return ptr;
1169 static unsigned char *obj_write_index(unsigned char *ptr, int data) {
1170 if (data < 128)
1171 *ptr++ = data;
1172 else {
1173 *ptr++ = 0x80 | ((data >> 8) & 0x7F);
1174 *ptr++ = data & 0xFF;
1176 return ptr;
1179 static unsigned char *obj_write_value(unsigned char *ptr,
1180 unsigned long data) {
1181 if (data <= 128)
1182 *ptr++ = data;
1183 else if (data <= 0xFFFF) {
1184 *ptr++ = 129;
1185 *ptr++ = data & 0xFF;
1186 *ptr++ = (data >> 8) & 0xFF;
1187 } else if (data <= 0xFFFFFF) {
1188 *ptr++ = 132;
1189 *ptr++ = data & 0xFF;
1190 *ptr++ = (data >> 8) & 0xFF;
1191 *ptr++ = (data >> 16) & 0xFF;
1192 } else {
1193 *ptr++ = 136;
1194 *ptr++ = data & 0xFF;
1195 *ptr++ = (data >> 8) & 0xFF;
1196 *ptr++ = (data >> 16) & 0xFF;
1197 *ptr++ = (data >> 24) & 0xFF;
1199 return ptr;
1202 static void obj_record(int type, unsigned char *start, unsigned char *end) {
1203 unsigned long cksum, len;
1205 cksum = type;
1206 fputc (type, ofp);
1207 len = end-start+1;
1208 cksum += (len & 0xFF) + ((len>>8) & 0xFF);
1209 fwriteshort (len, ofp);
1210 fwrite (start, 1, end-start, ofp);
1211 while (start < end)
1212 cksum += *start++;
1213 fputc ( (-cksum) & 0xFF, ofp);
1216 struct ofmt of_obj = {
1217 "Microsoft MS-DOS 16-bit object files",
1218 "obj",
1219 obj_init,
1220 obj_out,
1221 obj_deflabel,
1222 obj_segment,
1223 obj_segbase,
1224 obj_directive,
1225 obj_filename,
1226 obj_cleanup
1229 #endif /* OF_OBJ */