NASM 0.93
[nasm/avx512.git] / outobj.c
blob1bb30de715731539a78a0519f8fd047838b358db
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 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';
588 while (*p) {
589 while (*p && !isspace(*p))
590 p++;
591 if (*p) {
592 *p++ = '\0';
593 while (*p && isspace(*p))
594 *p++ = '\0';
597 attrs++;
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;
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;
632 * Process the segment attributes.
634 p = name;
635 while (attrs--) {
636 p += strlen(p);
637 while (!*p) p++;
640 * `p' contains a segment attribute.
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");
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;
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");
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;
706 * See if this segment is defined in any groups.
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;
724 if (seg->use32)
725 *bits = 32;
726 else
727 *bits = 16;
728 return seg->index;
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;
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++;
750 if (!*q) {
751 error(ERR_NONFATAL, "GROUP directive contains no segments");
752 return 1;
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;
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;
772 obj_grp_needs_update = grp;
773 deflabel (value, grp->index+1, 0L, &of_obj, error);
774 obj_grp_needs_update = NULL;
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++;
786 * Now p contains a segment name. Find it.
788 for (seg = seghead; seg; seg = seg->next)
789 if (!strcmp(seg->name, p))
790 break;
791 if (seg) {
793 * We have a segment index. Shift a name entry
794 * to the end of the array to make room.
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 {
806 * We have an as-yet undefined segment.
807 * Remember its name, for later.
809 grp->segs[grp->nentries++].name = nasm_strdup(p);
813 return 1;
815 if (!strcmp(directive, "uppercase")) {
816 obj_uppercase = TRUE;
817 return 1;
819 return 0;
822 static long obj_segbase (long segment) {
823 struct Segment *seg;
826 * Find the segment in our list.
828 for (seg = seghead; seg; seg = seg->next)
829 if (seg->index == segment-1)
830 break;
832 if (!seg)
833 return segment; /* not one of ours - leave it alone */
835 if (seg->align >= SEG_ABS)
836 return seg->align; /* absolute segment */
837 if (seg->grp)
838 return seg->grp->index+1; /* grouped segment */
840 return segment; /* no special treatment */
843 static void obj_filename (char *inname, char *outname, efunc error) {
844 strcpy(obj_infile, inname);
845 standard_extension (inname, outname, ".obj", error);
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;
858 * Write the THEADR module header.
860 recptr = record;
861 recptr = obj_write_name (recptr, obj_infile);
862 obj_record (THEADR, record, recptr);
865 * Write the NASM boast comment.
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);
873 * Write the first LNAMES record, containing LNAME one, which
874 * is null. Also initialise the LNAME counter.
876 recptr = record;
877 recptr = obj_write_name (recptr, "");
878 obj_record (LNAMES, record, recptr);
879 lname_idx = 2;
882 * Write the SEGDEF records. Each has an associated LNAMES
883 * record.
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 */
890 if (seg->use32 || seg->currentpos >= 0x10000)
891 new_segdef = TRUE;
892 else
893 new_segdef = FALSE;
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);
910 acbp = (seg->combine << 2); /* C field */
912 if (seg->currentpos >= 0x10000 && !new_segdef)
913 acbp |= 0x02; /* B bit */
915 if (seg->use32)
916 acbp |= 0x01; /* P bit is Use32 flag */
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;
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);
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);
955 * Write some LNAMES for the group names. lname_idx is left
956 * alone here - it will catch up when we write the GRPDEFs.
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;
966 if (recptr > record)
967 obj_record (LNAMES, record, recptr);
970 * Write the GRPDEF records.
972 for (grp = grphead; grp; grp = grp->next) {
973 int i;
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;
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);
989 obj_record (GRPDEF, record, recptr);
993 * Write the PUBDEF records: first the ones in the segments,
994 * then the far-absolutes.
996 for (seg = seghead; seg; seg = seg->next) {
997 int any;
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);
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;
1023 if (any)
1024 obj_record (rectype, record, recptr);
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);
1038 * Write the EXTDEF and COMDEF records, in order.
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;
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);
1067 recptr = record;
1070 if (recptr > record)
1071 obj_record (EXTDEF, record, recptr);
1074 * Write a COMENT record stating that the linker's first pass
1075 * may stop processing at this point.
1077 recptr = record;
1078 recptr = obj_write_rword (recptr, 0x40A2);
1079 recptr = obj_write_byte (recptr, 1);
1080 obj_record (COMENT, record, recptr);
1083 * Write the LEDATA/FIXUPP pairs.
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);
1094 * Write the MODEND module end marker.
1096 recptr = record;
1097 rectype = MODEND;
1098 if (obj_entry_seg != NO_SEG) {
1099 recptr = obj_write_byte (recptr, 0xC1);
1101 * Find the segment in the segment list.
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);
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;
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);
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;
1134 static unsigned char *obj_write_byte(unsigned char *ptr, int data) {
1135 *ptr++ = data;
1136 return ptr;
1139 static unsigned char *obj_write_word(unsigned char *ptr, int data) {
1140 *ptr++ = data & 0xFF;
1141 *ptr++ = (data >> 8) & 0xFF;
1142 return ptr;
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;
1153 static unsigned char *obj_write_rword(unsigned char *ptr, int data) {
1154 *ptr++ = (data >> 8) & 0xFF;
1155 *ptr++ = data & 0xFF;
1156 return ptr;
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++;
1166 } else {
1167 while (*data)
1168 *ptr++ = (unsigned char) *data++;
1170 return ptr;
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;
1180 return ptr;
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;
1203 return ptr;
1206 static void obj_record(int type, unsigned char *start, unsigned char *end) {
1207 unsigned long cksum, len;
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);
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
1233 #endif /* OF_OBJ */