NASM 0.95
[nasm/avx512.git] / outobj.c
blob544ec66342984079658867588c192924c3728cd8
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, *defgrp;
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 static int os2;
104 enum RecordID { /* record ID codes */
106 THEADR = 0x80, /* module header */
107 COMENT = 0x88, /* comment record */
109 LNAMES = 0x96, /* list of names */
111 SEGDEF = 0x98, /* segment definition */
112 GRPDEF = 0x9A, /* group definition */
113 EXTDEF = 0x8C, /* external definition */
114 PUBDEF = 0x90, /* public definition */
115 COMDEF = 0xB0, /* common definition */
117 LEDATA = 0xA0, /* logical enumerated data */
118 FIXUPP = 0x9C, /* fixups (relocations) */
120 MODEND = 0x8A /* module end */
123 extern struct ofmt of_obj;
125 static long obj_ledata_space(struct Segment *);
126 static int obj_fixup_free(struct Segment *);
127 static void obj_ledata_new(struct Segment *);
128 static void obj_ledata_commit(void);
129 static void obj_write_fixup (struct ObjData *, int, int, long, long, long);
130 static long obj_segment (char *, int, int *);
131 static void obj_write_file(void);
132 static unsigned char *obj_write_data(unsigned char *, unsigned char *, int);
133 static unsigned char *obj_write_byte(unsigned char *, int);
134 static unsigned char *obj_write_word(unsigned char *, int);
135 static unsigned char *obj_write_dword(unsigned char *, long);
136 static unsigned char *obj_write_rword(unsigned char *, int);
137 static unsigned char *obj_write_name(unsigned char *, char *);
138 static unsigned char *obj_write_index(unsigned char *, int);
139 static unsigned char *obj_write_value(unsigned char *, unsigned long);
140 static void obj_record(int, unsigned char *, unsigned char *);
141 static int obj_directive (char *, char *, int);
143 static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef) {
144 ofp = fp;
145 error = errfunc;
146 deflabel = ldef;
147 first_seg = seg_alloc();
148 any_segs = FALSE;
149 fpubhead = NULL;
150 fpubtail = &fpubhead;
151 exthead = NULL;
152 exttail = &exthead;
153 externals = 0;
154 ebhead = NULL;
155 ebtail = &ebhead;
156 seghead = obj_seg_needs_update = NULL;
157 segtail = &seghead;
158 grphead = obj_grp_needs_update = NULL;
159 grptail = &grphead;
160 datahead = datacurr = NULL;
161 datatail = &datahead;
162 obj_entry_seg = NO_SEG;
163 obj_uppercase = FALSE;
165 if (os2) {
166 obj_directive ("group", "FLAT", 1);
167 defgrp = grphead;
168 } else
169 defgrp = NULL;
172 static void dos_init (FILE *fp, efunc errfunc, ldfunc ldef) {
173 os2 = FALSE;
174 obj_init (fp, errfunc, ldef);
177 static void os2_init (FILE *fp, efunc errfunc, ldfunc ldef) {
178 os2 = TRUE;
179 obj_init (fp, errfunc, ldef);
182 static void obj_cleanup (void) {
183 obj_write_file();
184 fclose (ofp);
185 while (seghead) {
186 struct Segment *segtmp = seghead;
187 seghead = seghead->next;
188 while (segtmp->pubhead) {
189 struct Public *pubtmp = segtmp->pubhead;
190 segtmp->pubhead = pubtmp->next;
191 nasm_free (pubtmp);
193 nasm_free (segtmp);
195 while (fpubhead) {
196 struct Public *pubtmp = fpubhead;
197 fpubhead = fpubhead->next;
198 nasm_free (pubtmp);
200 while (exthead) {
201 struct External *exttmp = exthead;
202 exthead = exthead->next;
203 nasm_free (exttmp);
205 while (ebhead) {
206 struct ExtBack *ebtmp = ebhead;
207 ebhead = ebhead->next;
208 nasm_free (ebtmp);
210 while (grphead) {
211 struct Group *grptmp = grphead;
212 grphead = grphead->next;
213 nasm_free (grptmp);
215 while (datahead) {
216 struct ObjData *datatmp = datahead;
217 datahead = datahead->next;
218 nasm_free (datatmp);
222 static void obj_deflabel (char *name, long segment,
223 long offset, int is_global) {
225 * We have three cases:
227 * (i) `segment' is a segment-base. If so, set the name field
228 * for the segment or group structure it refers to, and then
229 * return.
231 * (ii) `segment' is one of our segments, or a SEG_ABS segment.
232 * Save the label position for later output of a PUBDEF record.
233 * (Or a MODPUB, if we work out how.)
235 * (iii) `segment' is not one of our segments. Save the label
236 * position for later output of an EXTDEF, and also store a
237 * back-reference so that we can map later references to this
238 * segment number to the external index.
240 struct External *ext;
241 struct ExtBack *eb;
242 struct Segment *seg;
243 int i;
246 * First check for the double-period, signifying something
247 * unusual.
249 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
250 if (!strcmp(name, "..start")) {
251 obj_entry_seg = segment;
252 obj_entry_ofs = offset;
253 return;
255 error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
259 * Case (i):
261 if (obj_seg_needs_update) {
262 obj_seg_needs_update->name = name;
263 return;
264 } else if (obj_grp_needs_update) {
265 obj_grp_needs_update->name = name;
266 return;
268 if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
269 return;
271 if (segment >= SEG_ABS || segment == NO_SEG) {
273 * SEG_ABS subcase of (ii).
275 if (is_global) {
276 struct Public *pub;
278 pub = *fpubtail = nasm_malloc(sizeof(*pub));
279 fpubtail = &pub->next;
280 pub->next = NULL;
281 pub->name = name;
282 pub->offset = offset;
283 pub->segment = (segment == NO_SEG ? 0 : segment & ~SEG_ABS);
285 return;
289 * If `any_segs' is still FALSE, we might need to define a
290 * default segment, if they're trying to declare a label in
291 * `first_seg'.
293 if (!any_segs && segment == first_seg) {
294 int tempint; /* ignored */
295 if (segment != obj_segment("__NASMDEFSEG", 2, &tempint))
296 error (ERR_PANIC, "strange segment conditions in OBJ driver");
299 for (seg = seghead; seg; seg = seg->next)
300 if (seg->index == segment) {
302 * Case (ii). Maybe MODPUB someday?
304 if (is_global) {
305 struct Public *pub;
306 pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
307 seg->pubtail = &pub->next;
308 pub->next = NULL;
309 pub->name = name;
310 pub->offset = offset;
312 return;
316 * Case (iii).
318 ext = *exttail = nasm_malloc(sizeof(*ext));
319 ext->next = NULL;
320 exttail = &ext->next;
321 ext->name = name;
322 if (is_global == 2)
323 ext->commonsize = offset;
324 else
325 ext->commonsize = 0;
327 i = segment/2;
328 eb = ebhead;
329 if (!eb) {
330 eb = *ebtail = nasm_malloc(sizeof(*eb));
331 eb->next = NULL;
332 ebtail = &eb->next;
334 while (i > EXT_BLKSIZ) {
335 if (eb && eb->next)
336 eb = eb->next;
337 else {
338 eb = *ebtail = nasm_malloc(sizeof(*eb));
339 eb->next = NULL;
340 ebtail = &eb->next;
342 i -= EXT_BLKSIZ;
344 eb->index[i] = ++externals;
347 static void obj_out (long segto, void *data, unsigned long type,
348 long segment, long wrt) {
349 long size, realtype;
350 unsigned char *ucdata;
351 long ldata;
352 struct Segment *seg;
355 * handle absolute-assembly (structure definitions)
357 if (segto == NO_SEG) {
358 if ((type & OUT_TYPMASK) != OUT_RESERVE)
359 error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
360 " space");
361 return;
365 * If `any_segs' is still FALSE, we must define a default
366 * segment.
368 if (!any_segs) {
369 int tempint; /* ignored */
370 if (segto != obj_segment("__NASMDEFSEG", 2, &tempint))
371 error (ERR_PANIC, "strange segment conditions in OBJ driver");
375 * Find the segment we are targetting.
377 for (seg = seghead; seg; seg = seg->next)
378 if (seg->index == segto)
379 break;
380 if (!seg)
381 error (ERR_PANIC, "code directed to nonexistent segment?");
383 size = type & OUT_SIZMASK;
384 realtype = type & OUT_TYPMASK;
385 if (realtype == OUT_RAWDATA) {
386 ucdata = data;
387 while (size > 0) {
388 long len = obj_ledata_space(seg);
389 if (len == 0) {
390 obj_ledata_new(seg);
391 len = obj_ledata_space(seg);
393 if (len > size)
394 len = size;
395 datacurr->lptr = obj_write_data (datacurr->lptr, ucdata, len);
396 datacurr->nonempty = TRUE;
397 ucdata += len;
398 size -= len;
399 seg->currentpos += len;
401 } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
402 realtype == OUT_REL4ADR) {
403 if (segment == NO_SEG && realtype != OUT_ADDRESS)
404 error(ERR_NONFATAL, "relative call to absolute address not"
405 " supported by OBJ format");
406 if (segment >= SEG_ABS)
407 error(ERR_NONFATAL, "far-absolute relocations not supported"
408 " by OBJ format");
409 ldata = *(long *)data;
410 if (realtype == OUT_REL2ADR)
411 ldata += (size-2);
412 if (realtype == OUT_REL4ADR)
413 ldata += (size-4);
414 if (obj_ledata_space(seg) < 4 || !obj_fixup_free(seg))
415 obj_ledata_new(seg);
416 if (size == 2)
417 datacurr->lptr = obj_write_word (datacurr->lptr, ldata);
418 else
419 datacurr->lptr = obj_write_dword (datacurr->lptr, ldata);
420 datacurr->nonempty = TRUE;
421 if (segment != NO_SEG)
422 obj_write_fixup (datacurr, size,
423 (realtype == OUT_REL2ADR ||
424 realtype == OUT_REL4ADR ? 0 : 0x4000),
425 segment, wrt,
426 (seg->currentpos - datacurr->startpos));
427 seg->currentpos += size;
428 } else if (realtype == OUT_RESERVE) {
429 obj_ledata_commit();
430 seg->currentpos += size;
434 static long obj_ledata_space(struct Segment *segto) {
435 if (datacurr && datacurr->seg == segto)
436 return datacurr->ledata + LEDATA_MAX - datacurr->lptr;
437 else
438 return 0;
441 static int obj_fixup_free(struct Segment *segto) {
442 if (datacurr && datacurr->seg == segto)
443 return (datacurr->fixupp + RECORD_MAX - datacurr->fptr) > 8;
444 else
445 return 0;
448 static void obj_ledata_new(struct Segment *segto) {
449 datacurr = *datatail = nasm_malloc(sizeof(*datacurr));
450 datacurr->next = NULL;
451 datatail = &datacurr->next;
452 datacurr->nonempty = FALSE;
453 datacurr->lptr = datacurr->ledata;
454 datacurr->fptr = datacurr->fixupp;
455 datacurr->seg = segto;
456 if (segto->use32)
457 datacurr->letype = LEDATA+1;
458 else
459 datacurr->letype = LEDATA;
460 datacurr->startpos = segto->currentpos;
461 datacurr->ftype = FIXUPP;
463 datacurr->lptr = obj_write_index (datacurr->lptr, segto->obj_index);
464 if (datacurr->letype == LEDATA)
465 datacurr->lptr = obj_write_word (datacurr->lptr, segto->currentpos);
466 else
467 datacurr->lptr = obj_write_dword (datacurr->lptr, segto->currentpos);
470 static void obj_ledata_commit(void) {
471 datacurr = NULL;
474 static void obj_write_fixup (struct ObjData *data, int bytes,
475 int segrel, long seg, long wrt,
476 long offset) {
477 int locat, method;
478 int base;
479 long tidx, fidx;
480 struct Segment *s = NULL;
481 struct Group *g = NULL;
483 locat = 0x8000 | segrel | offset;
484 if (seg % 2) {
485 base = TRUE;
486 locat |= 0x800;
487 seg--;
488 if (bytes != 2)
489 error(ERR_NONFATAL, "OBJ format can only handle 2-byte"
490 " segment base references");
491 } else {
492 base = FALSE;
493 if (bytes == 2)
494 locat |= 0x400;
495 else {
496 locat |= 0x2400;
497 data->ftype = FIXUPP+1; /* need new-style FIXUPP record */
500 data->fptr = obj_write_rword (data->fptr, locat);
502 tidx = fidx = -1, method = 0; /* placate optimisers */
505 * See if we can find the segment ID in our segment list. If
506 * so, we have a T4 (LSEG) target.
508 for (s = seghead; s; s = s->next)
509 if (s->index == seg)
510 break;
511 if (s)
512 method = 4, tidx = s->obj_index;
513 else {
514 for (g = grphead; g; g = g->next)
515 if (g->index == seg)
516 break;
517 if (g)
518 method = 5, tidx = g->obj_index;
519 else {
520 long i = seg/2;
521 struct ExtBack *eb = ebhead;
522 while (i > EXT_BLKSIZ) {
523 if (eb)
524 eb = eb->next;
525 else
526 break;
527 i -= EXT_BLKSIZ;
529 if (eb)
530 method = 6, tidx = eb->index[i];
531 else
532 error(ERR_PANIC,
533 "unrecognised segment value in obj_write_fixup");
538 * If no WRT given, assume the natural default, which is method
539 * F5 unless we are doing an OFFSET fixup for a grouped
540 * segment, in which case we require F1 (group). Oh, and in
541 * OS/2 mode we're in F1 (group) on `defgrp' _always_, by
542 * default.
544 if (wrt == NO_SEG) {
545 if (os2)
546 method |= 0x10, fidx = defgrp->obj_index;
547 else if (!base && s && s->grp)
548 method |= 0x10, fidx = s->grp->obj_index;
549 else
550 method |= 0x50, fidx = -1;
551 } else {
553 * See if we can find the WRT-segment ID in our segment
554 * list. If so, we have a F0 (LSEG) frame.
556 for (s = seghead; s; s = s->next)
557 if (s->index == wrt-1)
558 break;
559 if (s)
560 method |= 0x00, fidx = s->obj_index;
561 else {
562 for (g = grphead; g; g = g->next)
563 if (g->index == wrt-1)
564 break;
565 if (g)
566 method |= 0x10, fidx = g->obj_index;
567 else {
568 long i = wrt/2;
569 struct ExtBack *eb = ebhead;
570 while (i > EXT_BLKSIZ) {
571 if (eb)
572 eb = eb->next;
573 else
574 break;
575 i -= EXT_BLKSIZ;
577 if (eb)
578 method |= 0x20, fidx = eb->index[i];
579 else
580 error(ERR_PANIC,
581 "unrecognised WRT value in obj_write_fixup");
586 data->fptr = obj_write_byte (data->fptr, method);
587 if (fidx != -1)
588 data->fptr = obj_write_index (data->fptr, fidx);
589 data->fptr = obj_write_index (data->fptr, tidx);
592 static long obj_segment (char *name, int pass, int *bits) {
594 * We call the label manager here to define a name for the new
595 * segment, and when our _own_ label-definition stub gets
596 * called in return, it should register the new segment name
597 * using the pointer it gets passed. That way we save memory,
598 * by sponging off the label manager.
600 if (!name) {
601 *bits = 16;
602 return first_seg;
603 } else {
604 struct Segment *seg;
605 struct Group *grp;
606 int obj_idx, i, attrs, rn_error;
607 char *p;
610 * Look for segment attributes.
612 attrs = 0;
613 while (*name == '.')
614 name++; /* hack, but a documented one */
615 p = name;
616 while (*p && !isspace(*p))
617 p++;
618 if (*p) {
619 *p++ = '\0';
620 while (*p && isspace(*p))
621 *p++ = '\0';
623 while (*p) {
624 while (*p && !isspace(*p))
625 p++;
626 if (*p) {
627 *p++ = '\0';
628 while (*p && isspace(*p))
629 *p++ = '\0';
632 attrs++;
635 obj_idx = 1;
636 for (seg = seghead; seg; seg = seg->next) {
637 obj_idx++;
638 if (!strcmp(seg->name, name)) {
639 if (attrs > 0 && pass == 1)
640 error(ERR_WARNING, "segment attributes specified on"
641 " redeclaration of segment: ignoring");
642 if (seg->use32)
643 *bits = 32;
644 else
645 *bits = 16;
646 return seg->index;
650 *segtail = seg = nasm_malloc(sizeof(*seg));
651 seg->next = NULL;
652 segtail = &seg->next;
653 seg->index = (any_segs ? seg_alloc() : first_seg);
654 seg->obj_index = obj_idx;
655 seg->grp = NULL;
656 any_segs = TRUE;
657 seg->name = NULL;
658 seg->currentpos = 0;
659 seg->align = 1; /* default */
660 seg->use32 = FALSE; /* default */
661 seg->combine = CMB_PUBLIC; /* default */
662 seg->segclass = seg->overlay = NULL;
663 seg->pubhead = NULL;
664 seg->pubtail = &seg->pubhead;
667 * Process the segment attributes.
669 p = name;
670 while (attrs--) {
671 p += strlen(p);
672 while (!*p) p++;
675 * `p' contains a segment attribute.
677 if (!nasm_stricmp(p, "private"))
678 seg->combine = CMB_PRIVATE;
679 else if (!nasm_stricmp(p, "public"))
680 seg->combine = CMB_PUBLIC;
681 else if (!nasm_stricmp(p, "common"))
682 seg->combine = CMB_COMMON;
683 else if (!nasm_stricmp(p, "stack"))
684 seg->combine = CMB_STACK;
685 else if (!nasm_stricmp(p, "use16"))
686 seg->use32 = FALSE;
687 else if (!nasm_stricmp(p, "use32"))
688 seg->use32 = TRUE;
689 else if (!nasm_strnicmp(p, "class=", 6))
690 seg->segclass = nasm_strdup(p+6);
691 else if (!nasm_strnicmp(p, "overlay=", 8))
692 seg->overlay = nasm_strdup(p+8);
693 else if (!nasm_strnicmp(p, "align=", 6)) {
694 seg->align = readnum(p+6, &rn_error);
695 if (rn_error) {
696 seg->align = 1;
697 error (ERR_NONFATAL, "segment alignment should be"
698 " numeric");
700 switch ((int) seg->align) {
701 case 1: /* BYTE */
702 case 2: /* WORD */
703 case 4: /* DWORD */
704 case 16: /* PARA */
705 case 256: /* PAGE */
706 break;
707 case 8:
708 error(ERR_WARNING, "OBJ format does not support alignment"
709 " of 8: rounding up to 16");
710 seg->align = 16;
711 break;
712 case 32:
713 case 64:
714 case 128:
715 error(ERR_WARNING, "OBJ format does not support alignment"
716 " of %d: rounding up to 256", seg->align);
717 seg->align = 256;
718 break;
719 default:
720 error(ERR_NONFATAL, "invalid alignment value %d",
721 seg->align);
722 seg->align = 1;
723 break;
725 } else if (!nasm_strnicmp(p, "absolute=", 9)) {
726 seg->align = SEG_ABS + readnum(p+9, &rn_error);
727 if (rn_error)
728 error (ERR_NONFATAL, "argument to `absolute' segment"
729 " attribute should be numeric");
733 obj_seg_needs_update = seg;
734 if (seg->align >= SEG_ABS)
735 deflabel (name, NO_SEG, seg->align - SEG_ABS, &of_obj, error);
736 else
737 deflabel (name, seg->index+1, 0L, &of_obj, error);
738 obj_seg_needs_update = NULL;
741 * See if this segment is defined in any groups.
743 for (grp = grphead; grp; grp = grp->next) {
744 for (i = grp->nindices; i < grp->nentries; i++) {
745 if (!strcmp(grp->segs[i].name, seg->name)) {
746 nasm_free (grp->segs[i].name);
747 grp->segs[i] = grp->segs[grp->nindices];
748 grp->segs[grp->nindices++].index = seg->obj_index;
749 if (seg->grp)
750 error(ERR_WARNING, "segment `%s' is already part of"
751 " a group: first one takes precedence",
752 seg->name);
753 else
754 seg->grp = grp;
759 if (seg->use32)
760 *bits = 32;
761 else
762 *bits = 16;
763 return seg->index;
767 static int obj_directive (char *directive, char *value, int pass) {
768 if (!strcmp(directive, "group")) {
769 char *p, *q, *v;
770 if (pass == 1) {
771 struct Group *grp;
772 struct Segment *seg;
773 int obj_idx;
775 q = value;
776 while (*q == '.')
777 q++; /* hack, but a documented one */
778 v = q;
779 while (*q && !isspace(*q))
780 q++;
781 if (isspace(*q)) {
782 *q++ = '\0';
783 while (*q && isspace(*q))
784 q++;
787 * Here we used to sanity-check the group directive to
788 * ensure nobody tried to declare a group containing no
789 * segments. However, OS/2 does this as standard
790 * practice, so the sanity check has been removed.
792 * if (!*q) {
793 * error(ERR_NONFATAL,"GROUP directive contains no segments");
794 * return 1;
798 obj_idx = 1;
799 for (grp = grphead; grp; grp = grp->next) {
800 obj_idx++;
801 if (!strcmp(grp->name, v)) {
802 error(ERR_NONFATAL, "group `%s' defined twice", v);
803 return 1;
807 *grptail = grp = nasm_malloc(sizeof(*grp));
808 grp->next = NULL;
809 grptail = &grp->next;
810 grp->index = seg_alloc();
811 grp->obj_index = obj_idx;
812 grp->nindices = grp->nentries = 0;
813 grp->name = NULL;
815 obj_grp_needs_update = grp;
816 deflabel (v, grp->index+1, 0L, &of_obj, error);
817 obj_grp_needs_update = NULL;
819 while (*q) {
820 p = q;
821 while (*q && !isspace(*q))
822 q++;
823 if (isspace(*q)) {
824 *q++ = '\0';
825 while (*q && isspace(*q))
826 q++;
829 * Now p contains a segment name. Find it.
831 for (seg = seghead; seg; seg = seg->next)
832 if (!strcmp(seg->name, p))
833 break;
834 if (seg) {
836 * We have a segment index. Shift a name entry
837 * to the end of the array to make room.
839 grp->segs[grp->nentries++] = grp->segs[grp->nindices];
840 grp->segs[grp->nindices++].index = seg->obj_index;
841 if (seg->grp)
842 error(ERR_WARNING, "segment `%s' is already part of"
843 " a group: first one takes precedence",
844 seg->name);
845 else
846 seg->grp = grp;
847 } else {
849 * We have an as-yet undefined segment.
850 * Remember its name, for later.
852 grp->segs[grp->nentries++].name = nasm_strdup(p);
856 return 1;
858 if (!strcmp(directive, "uppercase")) {
859 obj_uppercase = TRUE;
860 return 1;
862 return 0;
865 static long obj_segbase (long segment) {
866 struct Segment *seg;
869 * Find the segment in our list.
871 for (seg = seghead; seg; seg = seg->next)
872 if (seg->index == segment-1)
873 break;
875 if (!seg)
876 return segment; /* not one of ours - leave it alone */
878 if (seg->align >= SEG_ABS)
879 return seg->align; /* absolute segment */
880 if (seg->grp)
881 return seg->grp->index+1; /* grouped segment */
883 return segment; /* no special treatment */
886 static void obj_filename (char *inname, char *outname, efunc error) {
887 strcpy(obj_infile, inname);
888 standard_extension (inname, outname, ".obj", error);
891 static void obj_write_file (void) {
892 struct Segment *seg;
893 struct Group *grp;
894 struct Public *pub;
895 struct External *ext;
896 struct ObjData *data;
897 static char boast[] = "The Netwide Assembler " NASM_VER;
898 int lname_idx, rectype;
901 * Write the THEADR module header.
903 recptr = record;
904 recptr = obj_write_name (recptr, obj_infile);
905 obj_record (THEADR, record, recptr);
908 * Write the NASM boast comment.
910 recptr = record;
911 recptr = obj_write_rword (recptr, 0); /* comment type zero */
912 recptr = obj_write_name (recptr, boast);
913 obj_record (COMENT, record, recptr);
916 * Write the first LNAMES record, containing LNAME one, which
917 * is null. Also initialise the LNAME counter.
919 recptr = record;
920 recptr = obj_write_name (recptr, "");
921 obj_record (LNAMES, record, recptr);
922 lname_idx = 2;
925 * Write the SEGDEF records. Each has an associated LNAMES
926 * record.
928 for (seg = seghead; seg; seg = seg->next) {
929 int new_segdef; /* do we use the newer record type? */
930 int acbp;
931 int sn, cn, on; /* seg, class, overlay LNAME idx */
933 if (seg->use32 || seg->currentpos >= 0x10000L)
934 new_segdef = TRUE;
935 else
936 new_segdef = FALSE;
938 recptr = record;
939 recptr = obj_write_name (recptr, seg->name);
940 sn = lname_idx++;
941 if (seg->segclass) {
942 recptr = obj_write_name (recptr, seg->segclass);
943 cn = lname_idx++;
944 } else
945 cn = 1;
946 if (seg->overlay) {
947 recptr = obj_write_name (recptr, seg->overlay);
948 on = lname_idx++;
949 } else
950 on = 1;
951 obj_record (LNAMES, record, recptr);
953 acbp = (seg->combine << 2); /* C field */
955 if (seg->currentpos >= 0x10000L && !new_segdef)
956 acbp |= 0x02; /* B bit */
958 if (seg->use32)
959 acbp |= 0x01; /* P bit is Use32 flag */
961 /* A field */
962 if (seg->align >= SEG_ABS)
963 acbp |= 0x00;
964 else if (seg->align >= 256) {
965 if (seg->align > 256)
966 error(ERR_NONFATAL, "segment `%s' requires more alignment"
967 " than OBJ format supports", seg->name);
968 acbp |= 0x80;
969 } else if (seg->align >= 16) {
970 acbp |= 0x60;
971 } else if (seg->align >= 4) {
972 acbp |= 0xA0;
973 } else if (seg->align >= 2) {
974 acbp |= 0x40;
975 } else
976 acbp |= 0x20;
978 recptr = record;
979 recptr = obj_write_byte (recptr, acbp);
980 if (seg->align & SEG_ABS) {
981 recptr = obj_write_word (recptr, seg->align - SEG_ABS);
982 recptr = obj_write_byte (recptr, 0);
984 if (new_segdef)
985 recptr = obj_write_dword (recptr, seg->currentpos);
986 else
987 recptr = obj_write_word (recptr, seg->currentpos & 0xFFFF);
988 recptr = obj_write_index (recptr, sn);
989 recptr = obj_write_index (recptr, cn);
990 recptr = obj_write_index (recptr, on);
991 if (new_segdef)
992 obj_record (SEGDEF+1, record, recptr);
993 else
994 obj_record (SEGDEF, record, recptr);
998 * Write some LNAMES for the group names. lname_idx is left
999 * alone here - it will catch up when we write the GRPDEFs.
1001 recptr = record;
1002 for (grp = grphead; grp; grp = grp->next) {
1003 recptr = obj_write_name (recptr, grp->name);
1004 if (recptr - record > 1024) {
1005 obj_record (LNAMES, record, recptr);
1006 recptr = record;
1009 if (recptr > record)
1010 obj_record (LNAMES, record, recptr);
1013 * Write the GRPDEF records.
1015 for (grp = grphead; grp; grp = grp->next) {
1016 int i;
1018 if (grp->nindices != grp->nentries) {
1019 for (i = grp->nindices; i < grp->nentries; i++) {
1020 error(ERR_NONFATAL, "group `%s' contains undefined segment"
1021 " `%s'", grp->name, grp->segs[i].name);
1022 nasm_free (grp->segs[i].name);
1023 grp->segs[i].name = NULL;
1026 recptr = record;
1027 recptr = obj_write_index (recptr, lname_idx++);
1028 for (i = 0; i < grp->nindices; i++) {
1029 recptr = obj_write_byte (recptr, 0xFF);
1030 recptr = obj_write_index (recptr, grp->segs[i].index);
1032 obj_record (GRPDEF, record, recptr);
1036 * Write the PUBDEF records: first the ones in the segments,
1037 * then the far-absolutes.
1039 for (seg = seghead; seg; seg = seg->next) {
1040 int any;
1042 recptr = record;
1043 recptr = obj_write_index (recptr, seg->grp ? seg->grp->obj_index : 0);
1044 recptr = obj_write_index (recptr, seg->obj_index);
1045 any = FALSE;
1046 if (seg->use32)
1047 rectype = PUBDEF+1;
1048 else
1049 rectype = PUBDEF;
1050 for (pub = seg->pubhead; pub; pub = pub->next) {
1051 if (recptr - record + strlen(pub->name) > 1024) {
1052 if (any)
1053 obj_record (rectype, record, recptr);
1054 recptr = record;
1055 recptr = obj_write_index (recptr, 0);
1056 recptr = obj_write_index (recptr, seg->obj_index);
1058 recptr = obj_write_name (recptr, pub->name);
1059 if (seg->use32)
1060 recptr = obj_write_dword (recptr, pub->offset);
1061 else
1062 recptr = obj_write_word (recptr, pub->offset);
1063 recptr = obj_write_index (recptr, 0);
1064 any = TRUE;
1066 if (any)
1067 obj_record (rectype, record, recptr);
1069 for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */
1070 recptr = record;
1071 recptr = obj_write_index (recptr, 0); /* no group */
1072 recptr = obj_write_index (recptr, 0); /* no segment either */
1073 recptr = obj_write_word (recptr, pub->segment);
1074 recptr = obj_write_name (recptr, pub->name);
1075 recptr = obj_write_word (recptr, pub->offset);
1076 recptr = obj_write_index (recptr, 0);
1077 obj_record (PUBDEF, record, recptr);
1081 * Write the EXTDEF and COMDEF records, in order.
1083 recptr = record;
1084 for (ext = exthead; ext; ext = ext->next) {
1085 if (ext->commonsize == 0) {
1086 recptr = obj_write_name (recptr, ext->name);
1087 recptr = obj_write_index (recptr, 0);
1088 if (recptr - record > 1024) {
1089 obj_record (EXTDEF, record, recptr);
1090 recptr = record;
1092 } else {
1093 if (recptr > record)
1094 obj_record (EXTDEF, record, recptr);
1095 recptr = record;
1096 if (ext->commonsize > 0) {
1097 recptr = obj_write_name (recptr, ext->name);
1098 recptr = obj_write_index (recptr, 0);
1099 recptr = obj_write_byte (recptr, 0x61);/* far communal */
1100 recptr = obj_write_value (recptr, 1L);
1101 recptr = obj_write_value (recptr, ext->commonsize);
1102 obj_record (COMDEF, record, recptr);
1103 } else if (ext->commonsize < 0) {
1104 recptr = obj_write_name (recptr, ext->name);
1105 recptr = obj_write_index (recptr, 0);
1106 recptr = obj_write_byte (recptr, 0x62);/* near communal */
1107 recptr = obj_write_value (recptr, ext->commonsize);
1108 obj_record (COMDEF, record, recptr);
1110 recptr = record;
1113 if (recptr > record)
1114 obj_record (EXTDEF, record, recptr);
1117 * Write a COMENT record stating that the linker's first pass
1118 * may stop processing at this point. Exception is if we're in
1119 * OS/2 mode and our MODEND record specifies a start point, in
1120 * which case, according to the OS/2 documentation, this COMENT
1121 * should be omitted.
1123 if (!os2 || obj_entry_seg == NO_SEG) {
1124 recptr = record;
1125 recptr = obj_write_rword (recptr, 0x40A2);
1126 recptr = obj_write_byte (recptr, 1);
1127 obj_record (COMENT, record, recptr);
1131 * Write the LEDATA/FIXUPP pairs.
1133 for (data = datahead; data; data = data->next) {
1134 if (data->nonempty) {
1135 obj_record (data->letype, data->ledata, data->lptr);
1136 if (data->fptr != data->fixupp)
1137 obj_record (data->ftype, data->fixupp, data->fptr);
1142 * Write the MODEND module end marker.
1144 recptr = record;
1145 rectype = MODEND;
1146 if (obj_entry_seg != NO_SEG) {
1147 recptr = obj_write_byte (recptr, 0xC1);
1149 * Find the segment in the segment list.
1151 for (seg = seghead; seg; seg = seg->next) {
1152 if (seg->index == obj_entry_seg) {
1153 if (seg->grp) {
1154 recptr = obj_write_byte (recptr, 0x10);
1155 recptr = obj_write_index (recptr, seg->grp->obj_index);
1156 } else {
1157 recptr = obj_write_byte (recptr, 0x50);
1159 recptr = obj_write_index (recptr, seg->obj_index);
1160 if (seg->use32) {
1161 rectype = MODEND+1;
1162 recptr = obj_write_dword (recptr, obj_entry_ofs);
1163 } else
1164 recptr = obj_write_word (recptr, obj_entry_ofs);
1165 break;
1168 if (!seg)
1169 error(ERR_NONFATAL, "entry point is not in this module");
1170 } else
1171 recptr = obj_write_byte (recptr, 0);
1172 obj_record (rectype, record, recptr);
1175 static unsigned char *obj_write_data(unsigned char *ptr,
1176 unsigned char *data, int len) {
1177 while (len--)
1178 *ptr++ = *data++;
1179 return ptr;
1182 static unsigned char *obj_write_byte(unsigned char *ptr, int data) {
1183 *ptr++ = data;
1184 return ptr;
1187 static unsigned char *obj_write_word(unsigned char *ptr, int data) {
1188 *ptr++ = data & 0xFF;
1189 *ptr++ = (data >> 8) & 0xFF;
1190 return ptr;
1193 static unsigned char *obj_write_dword(unsigned char *ptr, long data) {
1194 *ptr++ = data & 0xFF;
1195 *ptr++ = (data >> 8) & 0xFF;
1196 *ptr++ = (data >> 16) & 0xFF;
1197 *ptr++ = (data >> 24) & 0xFF;
1198 return ptr;
1201 static unsigned char *obj_write_rword(unsigned char *ptr, int data) {
1202 *ptr++ = (data >> 8) & 0xFF;
1203 *ptr++ = data & 0xFF;
1204 return ptr;
1207 static unsigned char *obj_write_name(unsigned char *ptr, char *data) {
1208 *ptr++ = strlen(data);
1209 if (obj_uppercase) {
1210 while (*data) {
1211 *ptr++ = (unsigned char) toupper(*data);
1212 data++;
1214 } else {
1215 while (*data)
1216 *ptr++ = (unsigned char) *data++;
1218 return ptr;
1221 static unsigned char *obj_write_index(unsigned char *ptr, int data) {
1222 if (data < 128)
1223 *ptr++ = data;
1224 else {
1225 *ptr++ = 0x80 | ((data >> 8) & 0x7F);
1226 *ptr++ = data & 0xFF;
1228 return ptr;
1231 static unsigned char *obj_write_value(unsigned char *ptr,
1232 unsigned long data) {
1233 if (data <= 128)
1234 *ptr++ = data;
1235 else if (data <= 0xFFFF) {
1236 *ptr++ = 129;
1237 *ptr++ = data & 0xFF;
1238 *ptr++ = (data >> 8) & 0xFF;
1239 } else if (data <= 0xFFFFFFL) {
1240 *ptr++ = 132;
1241 *ptr++ = data & 0xFF;
1242 *ptr++ = (data >> 8) & 0xFF;
1243 *ptr++ = (data >> 16) & 0xFF;
1244 } else {
1245 *ptr++ = 136;
1246 *ptr++ = data & 0xFF;
1247 *ptr++ = (data >> 8) & 0xFF;
1248 *ptr++ = (data >> 16) & 0xFF;
1249 *ptr++ = (data >> 24) & 0xFF;
1251 return ptr;
1254 static void obj_record(int type, unsigned char *start, unsigned char *end) {
1255 unsigned long cksum, len;
1257 cksum = type;
1258 fputc (type, ofp);
1259 len = end-start+1;
1260 cksum += (len & 0xFF) + ((len>>8) & 0xFF);
1261 fwriteshort (len, ofp);
1262 fwrite (start, 1, end-start, ofp);
1263 while (start < end)
1264 cksum += *start++;
1265 fputc ( (-cksum) & 0xFF, ofp);
1268 struct ofmt of_obj = {
1269 "Microsoft MS-DOS 16-bit OMF object files",
1270 "obj",
1271 dos_init,
1272 obj_out,
1273 obj_deflabel,
1274 obj_segment,
1275 obj_segbase,
1276 obj_directive,
1277 obj_filename,
1278 obj_cleanup
1281 struct ofmt of_os2 = {
1282 "OS/2 object files (variant of OMF)",
1283 "os2",
1284 os2_init,
1285 obj_out,
1286 obj_deflabel,
1287 obj_segment,
1288 obj_segbase,
1289 obj_directive,
1290 obj_filename,
1291 obj_cleanup
1294 #endif /* OF_OBJ */