NASM 0.97
[nasm/avx512.git] / outobj.c
blobf54d29763914494a936fc13fd1cf1d98f1a43041
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 evalfunc evaluate;
26 static ldfunc deflabel;
27 static FILE *ofp;
28 static long first_seg;
29 static int any_segs;
31 #define LEDATA_MAX 1024 /* maximum size of LEDATA record */
32 #define RECORD_MAX 1024 /* maximum size of _any_ record */
33 #define GROUP_MAX 256 /* we won't _realistically_ have more
34 * than this many segs in a group */
35 #define EXT_BLKSIZ 256 /* block size for externals list */
37 static unsigned char record[RECORD_MAX], *recptr;
39 struct Segment; /* need to know these structs exist */
40 struct Group;
42 static struct Public {
43 struct Public *next;
44 char *name;
45 long offset;
46 long segment; /* only if it's far-absolute */
47 } *fpubhead, **fpubtail;
49 static struct External {
50 struct External *next;
51 char *name;
52 long commonsize;
53 long commonelem; /* element size if FAR, else zero */
54 int index; /* OBJ-file external index */
55 enum {
56 DEFWRT_NONE, /* no unusual default-WRT */
57 DEFWRT_STRING, /* a string we don't yet understand */
58 DEFWRT_SEGMENT, /* a segment */
59 DEFWRT_GROUP /* a group */
60 } defwrt_type;
61 union {
62 char *string;
63 struct Segment *seg;
64 struct Group *grp;
65 } defwrt_ptr;
66 struct External *next_dws; /* next with DEFWRT_STRING */
67 } *exthead, **exttail, *dws;
69 static int externals;
71 static struct ExtBack {
72 struct ExtBack *next;
73 struct External *exts[EXT_BLKSIZ];
74 } *ebhead, **ebtail;
76 static struct Segment {
77 struct Segment *next;
78 long index; /* the NASM segment id */
79 long obj_index; /* the OBJ-file segment index */
80 struct Group *grp; /* the group it belongs to */
81 long currentpos;
82 long align; /* can be SEG_ABS + absolute addr */
83 enum {
84 CMB_PRIVATE = 0,
85 CMB_PUBLIC = 2,
86 CMB_STACK = 5,
87 CMB_COMMON = 6
88 } combine;
89 long use32; /* is this segment 32-bit? */
90 struct Public *pubhead, **pubtail;
91 char *name;
92 char *segclass, *overlay; /* `class' is a C++ keyword :-) */
93 } *seghead, **segtail, *obj_seg_needs_update;
95 static struct Group {
96 struct Group *next;
97 char *name;
98 long index; /* NASM segment id */
99 long obj_index; /* OBJ-file group index */
100 long nentries; /* number of elements... */
101 long nindices; /* ...and number of index elts... */
102 union {
103 long index;
104 char *name;
105 } segs[GROUP_MAX]; /* ...in this */
106 } *grphead, **grptail, *obj_grp_needs_update;
108 static struct ObjData {
109 struct ObjData *next;
110 int nonempty;
111 struct Segment *seg;
112 long startpos;
113 int letype, ftype;
114 unsigned char ledata[LEDATA_MAX], *lptr;
115 unsigned char fixupp[RECORD_MAX], *fptr;
116 } *datahead, *datacurr, **datatail;
118 static struct ImpDef {
119 struct ImpDef *next;
120 char *extname;
121 char *libname;
122 unsigned int impindex;
123 char *impname;
124 } *imphead, **imptail;
126 static struct ExpDef {
127 struct ExpDef *next;
128 char *intname;
129 char *extname;
130 unsigned int ordinal;
131 int flags;
132 } *exphead, **exptail;
134 #define EXPDEF_FLAG_ORDINAL 0x80
135 #define EXPDEF_FLAG_RESIDENT 0x40
136 #define EXPDEF_FLAG_NODATA 0x20
137 #define EXPDEF_MASK_PARMCNT 0x1F
139 static long obj_entry_seg, obj_entry_ofs;
141 enum RecordID { /* record ID codes */
143 THEADR = 0x80, /* module header */
144 COMENT = 0x88, /* comment record */
146 LNAMES = 0x96, /* list of names */
148 SEGDEF = 0x98, /* segment definition */
149 GRPDEF = 0x9A, /* group definition */
150 EXTDEF = 0x8C, /* external definition */
151 PUBDEF = 0x90, /* public definition */
152 COMDEF = 0xB0, /* common definition */
154 LEDATA = 0xA0, /* logical enumerated data */
155 FIXUPP = 0x9C, /* fixups (relocations) */
157 MODEND = 0x8A /* module end */
160 extern struct ofmt of_obj;
162 static long obj_ledata_space(struct Segment *);
163 static int obj_fixup_free(struct Segment *);
164 static void obj_ledata_new(struct Segment *);
165 static void obj_ledata_commit(void);
166 static void obj_write_fixup (struct ObjData *, int, int, long, long, long);
167 static long obj_segment (char *, int, int *);
168 static void obj_write_file(void);
169 static unsigned char *obj_write_data(unsigned char *, unsigned char *, int);
170 static unsigned char *obj_write_byte(unsigned char *, int);
171 static unsigned char *obj_write_word(unsigned char *, int);
172 static unsigned char *obj_write_dword(unsigned char *, long);
173 static unsigned char *obj_write_rword(unsigned char *, int);
174 static unsigned char *obj_write_name(unsigned char *, char *);
175 static unsigned char *obj_write_index(unsigned char *, int);
176 static unsigned char *obj_write_value(unsigned char *, unsigned long);
177 static void obj_record(int, unsigned char *, unsigned char *);
178 static int obj_directive (char *, char *, int);
180 static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
181 ofp = fp;
182 error = errfunc;
183 evaluate = eval;
184 deflabel = ldef;
185 first_seg = seg_alloc();
186 any_segs = FALSE;
187 fpubhead = NULL;
188 fpubtail = &fpubhead;
189 exthead = NULL;
190 exttail = &exthead;
191 imphead = NULL;
192 imptail = &imphead;
193 exphead = NULL;
194 exptail = &exphead;
195 dws = NULL;
196 externals = 0;
197 ebhead = NULL;
198 ebtail = &ebhead;
199 seghead = obj_seg_needs_update = NULL;
200 segtail = &seghead;
201 grphead = obj_grp_needs_update = NULL;
202 grptail = &grphead;
203 datahead = datacurr = NULL;
204 datatail = &datahead;
205 obj_entry_seg = NO_SEG;
206 obj_uppercase = FALSE;
209 static void obj_cleanup (void) {
210 obj_write_file();
211 fclose (ofp);
212 while (seghead) {
213 struct Segment *segtmp = seghead;
214 seghead = seghead->next;
215 while (segtmp->pubhead) {
216 struct Public *pubtmp = segtmp->pubhead;
217 segtmp->pubhead = pubtmp->next;
218 nasm_free (pubtmp->name);
219 nasm_free (pubtmp);
221 nasm_free (segtmp);
223 while (fpubhead) {
224 struct Public *pubtmp = fpubhead;
225 fpubhead = fpubhead->next;
226 nasm_free (pubtmp->name);
227 nasm_free (pubtmp);
229 while (exthead) {
230 struct External *exttmp = exthead;
231 exthead = exthead->next;
232 nasm_free (exttmp);
234 while (imphead) {
235 struct ImpDef *imptmp = imphead;
236 imphead = imphead->next;
237 nasm_free (imptmp->extname);
238 nasm_free (imptmp->libname);
239 nasm_free (imptmp->impname); /* nasm_free won't mind if it's NULL */
240 nasm_free (imptmp);
242 while (exphead) {
243 struct ExpDef *exptmp = exphead;
244 exphead = exphead->next;
245 nasm_free (exptmp->extname);
246 nasm_free (exptmp->intname);
247 nasm_free (exptmp);
249 while (ebhead) {
250 struct ExtBack *ebtmp = ebhead;
251 ebhead = ebhead->next;
252 nasm_free (ebtmp);
254 while (grphead) {
255 struct Group *grptmp = grphead;
256 grphead = grphead->next;
257 nasm_free (grptmp);
259 while (datahead) {
260 struct ObjData *datatmp = datahead;
261 datahead = datahead->next;
262 nasm_free (datatmp);
266 static void obj_ext_set_defwrt (struct External *ext, char *id) {
267 struct Segment *seg;
268 struct Group *grp;
270 for (seg = seghead; seg; seg = seg->next)
271 if (!strcmp(seg->name, id)) {
272 ext->defwrt_type = DEFWRT_SEGMENT;
273 ext->defwrt_ptr.seg = seg;
274 nasm_free (id);
275 return;
278 for (grp = grphead; grp; grp = grp->next)
279 if (!strcmp(grp->name, id)) {
280 ext->defwrt_type = DEFWRT_GROUP;
281 ext->defwrt_ptr.grp = grp;
282 nasm_free (id);
283 return;
286 ext->defwrt_type = DEFWRT_STRING;
287 ext->defwrt_ptr.string = id;
288 ext->next_dws = dws;
289 dws = ext;
292 static void obj_deflabel (char *name, long segment,
293 long offset, int is_global, char *special) {
295 * We have three cases:
297 * (i) `segment' is a segment-base. If so, set the name field
298 * for the segment or group structure it refers to, and then
299 * return.
301 * (ii) `segment' is one of our segments, or a SEG_ABS segment.
302 * Save the label position for later output of a PUBDEF record.
303 * (Or a MODPUB, if we work out how.)
305 * (iii) `segment' is not one of our segments. Save the label
306 * position for later output of an EXTDEF, and also store a
307 * back-reference so that we can map later references to this
308 * segment number to the external index.
310 struct External *ext;
311 struct ExtBack *eb;
312 struct Segment *seg;
313 int i;
314 int used_special = FALSE; /* have we used the special text? */
317 * If it's a special-retry from pass two, discard it.
319 if (is_global == 3)
320 return;
323 * First check for the double-period, signifying something
324 * unusual.
326 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
327 if (!strcmp(name, "..start")) {
328 obj_entry_seg = segment;
329 obj_entry_ofs = offset;
330 return;
332 error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
336 * Case (i):
338 if (obj_seg_needs_update) {
339 obj_seg_needs_update->name = name;
340 return;
341 } else if (obj_grp_needs_update) {
342 obj_grp_needs_update->name = name;
343 return;
345 if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
346 return;
348 if (segment >= SEG_ABS || segment == NO_SEG) {
350 * SEG_ABS subcase of (ii).
352 if (is_global) {
353 struct Public *pub;
355 pub = *fpubtail = nasm_malloc(sizeof(*pub));
356 fpubtail = &pub->next;
357 pub->next = NULL;
358 pub->name = nasm_strdup(name);
359 pub->offset = offset;
360 pub->segment = (segment == NO_SEG ? 0 : segment & ~SEG_ABS);
362 if (special)
363 error(ERR_NONFATAL, "OBJ supports no special symbol features"
364 " for this symbol type");
365 return;
369 * If `any_segs' is still FALSE, we might need to define a
370 * default segment, if they're trying to declare a label in
371 * `first_seg'.
373 if (!any_segs && segment == first_seg) {
374 int tempint; /* ignored */
375 if (segment != obj_segment("__NASMDEFSEG", 2, &tempint))
376 error (ERR_PANIC, "strange segment conditions in OBJ driver");
379 for (seg = seghead; seg; seg = seg->next)
380 if (seg->index == segment) {
382 * Case (ii). Maybe MODPUB someday?
384 if (is_global) {
385 struct Public *pub;
386 pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
387 seg->pubtail = &pub->next;
388 pub->next = NULL;
389 pub->name = nasm_strdup(name);
390 pub->offset = offset;
392 if (special)
393 error(ERR_NONFATAL, "OBJ supports no special symbol features"
394 " for this symbol type");
395 return;
399 * Case (iii).
401 ext = *exttail = nasm_malloc(sizeof(*ext));
402 ext->next = NULL;
403 exttail = &ext->next;
404 ext->name = name;
405 ext->defwrt_type = DEFWRT_NONE;
406 if (is_global == 2) {
407 ext->commonsize = offset;
408 ext->commonelem = 1; /* default FAR */
409 } else
410 ext->commonsize = 0;
413 * Now process the special text, if any, to find default-WRT
414 * specifications and common-variable element-size and near/far
415 * specifications.
417 while (special && *special) {
418 used_special = TRUE;
421 * We might have a default-WRT specification.
423 if (!nasm_strnicmp(special, "wrt", 3)) {
424 char *p;
425 int len;
426 special += 3;
427 special += strspn(special, " \t");
428 p = nasm_strndup(special, len = strcspn(special, ":"));
429 obj_ext_set_defwrt (ext, p);
430 special += len;
431 if (*special && *special != ':')
432 error(ERR_NONFATAL, "`:' expected in special symbol"
433 " text for `%s'", ext->name);
434 else if (*special == ':')
435 special++;
439 * The NEAR or FAR keywords specify nearness or
440 * farness. FAR gives default element size 1.
442 if (!nasm_strnicmp(special, "far", 3)) {
443 if (ext->commonsize)
444 ext->commonelem = 1;
445 else
446 error(ERR_NONFATAL, "`%s': `far' keyword may only be applied"
447 " to common variables\n", ext->name);
448 special += 3;
449 special += strspn(special, " \t");
450 } else if (!nasm_strnicmp(special, "near", 4)) {
451 if (ext->commonsize)
452 ext->commonelem = 0;
453 else
454 error(ERR_NONFATAL, "`%s': `far' keyword may only be applied"
455 " to common variables\n", ext->name);
456 special += 4;
457 special += strspn(special, " \t");
461 * If it's a common, and anything else remains on the line
462 * before a further colon, evaluate it as an expression and
463 * use that as the element size. Forward references aren't
464 * allowed.
466 if (*special == ':')
467 special++;
468 else if (*special) {
469 if (ext->commonsize) {
470 expr *e;
471 struct tokenval tokval;
473 stdscan_reset();
474 stdscan_bufptr = special;
475 tokval.t_type = TOKEN_INVALID;
476 e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL);
477 if (e) {
478 if (!is_simple(e))
479 error (ERR_NONFATAL, "cannot use relocatable"
480 " expression as common-variable element size");
481 else
482 ext->commonelem = reloc_value(e);
484 special = stdscan_bufptr;
485 } else {
486 error (ERR_NONFATAL, "`%s': element-size specifications only"
487 " apply to common variables", ext->name);
488 while (*special && *special != ':')
489 special++;
490 if (*special == ':')
491 special++;
496 i = segment/2;
497 eb = ebhead;
498 if (!eb) {
499 eb = *ebtail = nasm_malloc(sizeof(*eb));
500 eb->next = NULL;
501 ebtail = &eb->next;
503 while (i > EXT_BLKSIZ) {
504 if (eb && eb->next)
505 eb = eb->next;
506 else {
507 eb = *ebtail = nasm_malloc(sizeof(*eb));
508 eb->next = NULL;
509 ebtail = &eb->next;
511 i -= EXT_BLKSIZ;
513 eb->exts[i] = ext;
514 ext->index = ++externals;
516 if (special && !used_special)
517 error(ERR_NONFATAL, "OBJ supports no special symbol features"
518 " for this symbol type");
521 static void obj_out (long segto, void *data, unsigned long type,
522 long segment, long wrt) {
523 long size, realtype;
524 unsigned char *ucdata;
525 long ldata;
526 struct Segment *seg;
529 * handle absolute-assembly (structure definitions)
531 if (segto == NO_SEG) {
532 if ((type & OUT_TYPMASK) != OUT_RESERVE)
533 error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
534 " space");
535 return;
539 * If `any_segs' is still FALSE, we must define a default
540 * segment.
542 if (!any_segs) {
543 int tempint; /* ignored */
544 if (segto != obj_segment("__NASMDEFSEG", 2, &tempint))
545 error (ERR_PANIC, "strange segment conditions in OBJ driver");
549 * Find the segment we are targetting.
551 for (seg = seghead; seg; seg = seg->next)
552 if (seg->index == segto)
553 break;
554 if (!seg)
555 error (ERR_PANIC, "code directed to nonexistent segment?");
557 size = type & OUT_SIZMASK;
558 realtype = type & OUT_TYPMASK;
559 if (realtype == OUT_RAWDATA) {
560 ucdata = data;
561 while (size > 0) {
562 long len = obj_ledata_space(seg);
563 if (len == 0) {
564 obj_ledata_new(seg);
565 len = obj_ledata_space(seg);
567 if (len > size)
568 len = size;
569 datacurr->lptr = obj_write_data (datacurr->lptr, ucdata, len);
570 datacurr->nonempty = TRUE;
571 ucdata += len;
572 size -= len;
573 seg->currentpos += len;
575 } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
576 realtype == OUT_REL4ADR) {
577 int rsize;
579 if (segment == NO_SEG && realtype != OUT_ADDRESS)
580 error(ERR_NONFATAL, "relative call to absolute address not"
581 " supported by OBJ format");
582 if (segment >= SEG_ABS)
583 error(ERR_NONFATAL, "far-absolute relocations not supported"
584 " by OBJ format");
585 ldata = *(long *)data;
586 if (realtype == OUT_REL2ADR) {
587 ldata += (size-2);
588 size = 2;
590 if (realtype == OUT_REL4ADR) {
591 ldata += (size-4);
592 size = 4;
594 if (obj_ledata_space(seg) < 4 || !obj_fixup_free(seg))
595 obj_ledata_new(seg);
596 if (size == 2)
597 datacurr->lptr = obj_write_word (datacurr->lptr, ldata);
598 else
599 datacurr->lptr = obj_write_dword (datacurr->lptr, ldata);
600 datacurr->nonempty = TRUE;
601 rsize = size;
602 if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) &&
603 size == 4) {
605 * This is a 4-byte segment-base relocation such as
606 * `MOV EAX,SEG foo'. OBJ format can't actually handle
607 * these, but if the constant term has the 16 low bits
608 * zero, we can just apply a 2-byte segment-base
609 * relocation to the low word instead.
611 rsize = 2;
612 if (ldata & 0xFFFF)
613 error(ERR_NONFATAL, "OBJ format cannot handle complex"
614 " dword-size segment base references");
616 if (segment != NO_SEG)
617 obj_write_fixup (datacurr, rsize,
618 (realtype == OUT_REL2ADR ||
619 realtype == OUT_REL4ADR ? 0 : 0x4000),
620 segment, wrt,
621 (seg->currentpos - datacurr->startpos));
622 seg->currentpos += size;
623 } else if (realtype == OUT_RESERVE) {
624 obj_ledata_commit();
625 seg->currentpos += size;
629 static long obj_ledata_space(struct Segment *segto) {
630 if (datacurr && datacurr->seg == segto)
631 return datacurr->ledata + LEDATA_MAX - datacurr->lptr;
632 else
633 return 0;
636 static int obj_fixup_free(struct Segment *segto) {
637 if (datacurr && datacurr->seg == segto)
638 return (datacurr->fixupp + RECORD_MAX - datacurr->fptr) > 8;
639 else
640 return 0;
643 static void obj_ledata_new(struct Segment *segto) {
644 datacurr = *datatail = nasm_malloc(sizeof(*datacurr));
645 datacurr->next = NULL;
646 datatail = &datacurr->next;
647 datacurr->nonempty = FALSE;
648 datacurr->lptr = datacurr->ledata;
649 datacurr->fptr = datacurr->fixupp;
650 datacurr->seg = segto;
651 if (segto->use32)
652 datacurr->letype = LEDATA+1;
653 else
654 datacurr->letype = LEDATA;
655 datacurr->startpos = segto->currentpos;
656 datacurr->ftype = FIXUPP;
658 datacurr->lptr = obj_write_index (datacurr->lptr, segto->obj_index);
659 if (datacurr->letype == LEDATA)
660 datacurr->lptr = obj_write_word (datacurr->lptr, segto->currentpos);
661 else
662 datacurr->lptr = obj_write_dword (datacurr->lptr, segto->currentpos);
665 static void obj_ledata_commit(void) {
666 datacurr = NULL;
669 static void obj_write_fixup (struct ObjData *data, int bytes,
670 int segrel, long seg, long wrt,
671 long offset) {
672 int locat, method;
673 int base;
674 long tidx, fidx;
675 struct Segment *s = NULL;
676 struct Group *g = NULL;
677 struct External *e = NULL;
679 if (bytes == 1) {
680 error(ERR_NONFATAL, "`obj' output driver does not support"
681 " one-byte relocations");
682 return;
685 locat = 0x8000 | segrel | offset;
686 if (seg % 2) {
687 base = TRUE;
688 locat |= 0x800;
689 seg--;
690 if (bytes != 2)
691 error(ERR_PANIC, "OBJ: 4-byte segment base fixup got"
692 " through sanity check");
693 } else {
694 base = FALSE;
695 if (bytes == 2)
696 locat |= 0x400;
697 else {
698 locat |= 0x2400;
699 data->ftype = FIXUPP+1; /* need new-style FIXUPP record */
702 data->fptr = obj_write_rword (data->fptr, locat);
704 tidx = fidx = -1, method = 0; /* placate optimisers */
707 * See if we can find the segment ID in our segment list. If
708 * so, we have a T4 (LSEG) target.
710 for (s = seghead; s; s = s->next)
711 if (s->index == seg)
712 break;
713 if (s)
714 method = 4, tidx = s->obj_index;
715 else {
716 for (g = grphead; g; g = g->next)
717 if (g->index == seg)
718 break;
719 if (g)
720 method = 5, tidx = g->obj_index;
721 else {
722 long i = seg/2;
723 struct ExtBack *eb = ebhead;
724 while (i > EXT_BLKSIZ) {
725 if (eb)
726 eb = eb->next;
727 else
728 break;
729 i -= EXT_BLKSIZ;
731 if (eb)
732 method = 6, e = eb->exts[i], tidx = e->index;
733 else
734 error(ERR_PANIC,
735 "unrecognised segment value in obj_write_fixup");
740 * If no WRT given, assume the natural default, which is method
741 * F5 unless:
743 * - we are doing an OFFSET fixup for a grouped segment, in
744 * which case we require F1 (group).
746 * - we are doing an OFFSET fixup for an external with a
747 * default WRT, in which case we must honour the default WRT.
749 if (wrt == NO_SEG) {
750 if (!base && s && s->grp)
751 method |= 0x10, fidx = s->grp->obj_index;
752 else if (!base && e && e->defwrt_type != DEFWRT_NONE) {
753 if (e->defwrt_type == DEFWRT_SEGMENT)
754 method |= 0x00, fidx = e->defwrt_ptr.seg->obj_index;
755 else if (e->defwrt_type == DEFWRT_GROUP)
756 method |= 0x10, fidx = e->defwrt_ptr.grp->obj_index;
757 else {
758 error(ERR_NONFATAL, "default WRT specification for"
759 " external `%s' unresolved", e->name);
760 method |= 0x50, fidx = -1; /* got to do _something_ */
762 } else
763 method |= 0x50, fidx = -1;
764 } else {
766 * See if we can find the WRT-segment ID in our segment
767 * list. If so, we have a F0 (LSEG) frame.
769 for (s = seghead; s; s = s->next)
770 if (s->index == wrt-1)
771 break;
772 if (s)
773 method |= 0x00, fidx = s->obj_index;
774 else {
775 for (g = grphead; g; g = g->next)
776 if (g->index == wrt-1)
777 break;
778 if (g)
779 method |= 0x10, fidx = g->obj_index;
780 else {
781 long i = wrt/2;
782 struct ExtBack *eb = ebhead;
783 while (i > EXT_BLKSIZ) {
784 if (eb)
785 eb = eb->next;
786 else
787 break;
788 i -= EXT_BLKSIZ;
790 if (eb)
791 method |= 0x20, fidx = eb->exts[i]->index;
792 else
793 error(ERR_PANIC,
794 "unrecognised WRT value in obj_write_fixup");
799 data->fptr = obj_write_byte (data->fptr, method);
800 if (fidx != -1)
801 data->fptr = obj_write_index (data->fptr, fidx);
802 data->fptr = obj_write_index (data->fptr, tidx);
805 static long obj_segment (char *name, int pass, int *bits) {
807 * We call the label manager here to define a name for the new
808 * segment, and when our _own_ label-definition stub gets
809 * called in return, it should register the new segment name
810 * using the pointer it gets passed. That way we save memory,
811 * by sponging off the label manager.
813 if (!name) {
814 *bits = 16;
815 return first_seg;
816 } else {
817 struct Segment *seg;
818 struct Group *grp;
819 struct External **extp;
820 int obj_idx, i, attrs, rn_error;
821 char *p;
824 * Look for segment attributes.
826 attrs = 0;
827 while (*name == '.')
828 name++; /* hack, but a documented one */
829 p = name;
830 while (*p && !isspace(*p))
831 p++;
832 if (*p) {
833 *p++ = '\0';
834 while (*p && isspace(*p))
835 *p++ = '\0';
837 while (*p) {
838 while (*p && !isspace(*p))
839 p++;
840 if (*p) {
841 *p++ = '\0';
842 while (*p && isspace(*p))
843 *p++ = '\0';
846 attrs++;
849 obj_idx = 1;
850 for (seg = seghead; seg; seg = seg->next) {
851 obj_idx++;
852 if (!strcmp(seg->name, name)) {
853 if (attrs > 0 && pass == 1)
854 error(ERR_WARNING, "segment attributes specified on"
855 " redeclaration of segment: ignoring");
856 if (seg->use32)
857 *bits = 32;
858 else
859 *bits = 16;
860 return seg->index;
864 *segtail = seg = nasm_malloc(sizeof(*seg));
865 seg->next = NULL;
866 segtail = &seg->next;
867 seg->index = (any_segs ? seg_alloc() : first_seg);
868 seg->obj_index = obj_idx;
869 seg->grp = NULL;
870 any_segs = TRUE;
871 seg->name = NULL;
872 seg->currentpos = 0;
873 seg->align = 1; /* default */
874 seg->use32 = FALSE; /* default */
875 seg->combine = CMB_PUBLIC; /* default */
876 seg->segclass = seg->overlay = NULL;
877 seg->pubhead = NULL;
878 seg->pubtail = &seg->pubhead;
881 * Process the segment attributes.
883 p = name;
884 while (attrs--) {
885 p += strlen(p);
886 while (!*p) p++;
889 * `p' contains a segment attribute.
891 if (!nasm_stricmp(p, "private"))
892 seg->combine = CMB_PRIVATE;
893 else if (!nasm_stricmp(p, "public"))
894 seg->combine = CMB_PUBLIC;
895 else if (!nasm_stricmp(p, "common"))
896 seg->combine = CMB_COMMON;
897 else if (!nasm_stricmp(p, "stack"))
898 seg->combine = CMB_STACK;
899 else if (!nasm_stricmp(p, "use16"))
900 seg->use32 = FALSE;
901 else if (!nasm_stricmp(p, "use32"))
902 seg->use32 = TRUE;
903 else if (!nasm_stricmp(p, "flat")) {
905 * This segment is an OS/2 FLAT segment. That means
906 * that its default group is group FLAT, even if
907 * the group FLAT does not explicitly _contain_ the
908 * segment.
910 * When we see this, we must create the group
911 * `FLAT', containing no segments, if it does not
912 * already exist; then we must set the default
913 * group of this segment to be the FLAT group.
915 struct Group *grp;
916 for (grp = grphead; grp; grp = grp->next)
917 if (!strcmp(grp->name, "FLAT"))
918 break;
919 if (!grp) {
920 obj_directive ("group", "FLAT", 1);
921 for (grp = grphead; grp; grp = grp->next)
922 if (!strcmp(grp->name, "FLAT"))
923 break;
924 if (!grp)
925 error (ERR_PANIC, "failure to define FLAT?!");
927 seg->grp = grp;
928 } else if (!nasm_strnicmp(p, "class=", 6))
929 seg->segclass = nasm_strdup(p+6);
930 else if (!nasm_strnicmp(p, "overlay=", 8))
931 seg->overlay = nasm_strdup(p+8);
932 else if (!nasm_strnicmp(p, "align=", 6)) {
933 seg->align = readnum(p+6, &rn_error);
934 if (rn_error) {
935 seg->align = 1;
936 error (ERR_NONFATAL, "segment alignment should be"
937 " numeric");
939 switch ((int) seg->align) {
940 case 1: /* BYTE */
941 case 2: /* WORD */
942 case 4: /* DWORD */
943 case 16: /* PARA */
944 case 256: /* PAGE */
945 case 4096: /* PharLap extension */
946 break;
947 case 8:
948 error(ERR_WARNING, "OBJ format does not support alignment"
949 " of 8: rounding up to 16");
950 seg->align = 16;
951 break;
952 case 32:
953 case 64:
954 case 128:
955 error(ERR_WARNING, "OBJ format does not support alignment"
956 " of %d: rounding up to 256", seg->align);
957 seg->align = 256;
958 break;
959 case 512:
960 case 1024:
961 case 2048:
962 error(ERR_WARNING, "OBJ format does not support alignment"
963 " of %d: rounding up to 4096", seg->align);
964 seg->align = 4096;
965 break;
966 default:
967 error(ERR_NONFATAL, "invalid alignment value %d",
968 seg->align);
969 seg->align = 1;
970 break;
972 } else if (!nasm_strnicmp(p, "absolute=", 9)) {
973 seg->align = SEG_ABS + readnum(p+9, &rn_error);
974 if (rn_error)
975 error (ERR_NONFATAL, "argument to `absolute' segment"
976 " attribute should be numeric");
980 obj_seg_needs_update = seg;
981 if (seg->align >= SEG_ABS)
982 deflabel (name, NO_SEG, seg->align - SEG_ABS,
983 NULL, FALSE, FALSE, &of_obj, error);
984 else
985 deflabel (name, seg->index+1, 0L,
986 NULL, FALSE, FALSE, &of_obj, error);
987 obj_seg_needs_update = NULL;
990 * See if this segment is defined in any groups.
992 for (grp = grphead; grp; grp = grp->next) {
993 for (i = grp->nindices; i < grp->nentries; i++) {
994 if (!strcmp(grp->segs[i].name, seg->name)) {
995 nasm_free (grp->segs[i].name);
996 grp->segs[i] = grp->segs[grp->nindices];
997 grp->segs[grp->nindices++].index = seg->obj_index;
998 if (seg->grp)
999 error(ERR_WARNING, "segment `%s' is already part of"
1000 " a group: first one takes precedence",
1001 seg->name);
1002 else
1003 seg->grp = grp;
1009 * Walk through the list of externals with unresolved
1010 * default-WRT clauses, and resolve any that point at this
1011 * segment.
1013 extp = &dws;
1014 while (*extp) {
1015 if ((*extp)->defwrt_type == DEFWRT_STRING &&
1016 !strcmp((*extp)->defwrt_ptr.string, seg->name)) {
1017 (*extp)->defwrt_type = DEFWRT_SEGMENT;
1018 (*extp)->defwrt_ptr.seg = seg;
1019 *extp = (*extp)->next_dws;
1020 } else
1021 extp = &(*extp)->next_dws;
1024 if (seg->use32)
1025 *bits = 32;
1026 else
1027 *bits = 16;
1028 return seg->index;
1032 static int obj_directive (char *directive, char *value, int pass) {
1033 if (!strcmp(directive, "group")) {
1034 char *p, *q, *v;
1035 if (pass == 1) {
1036 struct Group *grp;
1037 struct Segment *seg;
1038 struct External **extp;
1039 int obj_idx;
1041 q = value;
1042 while (*q == '.')
1043 q++; /* hack, but a documented one */
1044 v = q;
1045 while (*q && !isspace(*q))
1046 q++;
1047 if (isspace(*q)) {
1048 *q++ = '\0';
1049 while (*q && isspace(*q))
1050 q++;
1053 * Here we used to sanity-check the group directive to
1054 * ensure nobody tried to declare a group containing no
1055 * segments. However, OS/2 does this as standard
1056 * practice, so the sanity check has been removed.
1058 * if (!*q) {
1059 * error(ERR_NONFATAL,"GROUP directive contains no segments");
1060 * return 1;
1064 obj_idx = 1;
1065 for (grp = grphead; grp; grp = grp->next) {
1066 obj_idx++;
1067 if (!strcmp(grp->name, v)) {
1068 error(ERR_NONFATAL, "group `%s' defined twice", v);
1069 return 1;
1073 *grptail = grp = nasm_malloc(sizeof(*grp));
1074 grp->next = NULL;
1075 grptail = &grp->next;
1076 grp->index = seg_alloc();
1077 grp->obj_index = obj_idx;
1078 grp->nindices = grp->nentries = 0;
1079 grp->name = NULL;
1081 obj_grp_needs_update = grp;
1082 deflabel (v, grp->index+1, 0L,
1083 NULL, FALSE, FALSE, &of_obj, error);
1084 obj_grp_needs_update = NULL;
1086 while (*q) {
1087 p = q;
1088 while (*q && !isspace(*q))
1089 q++;
1090 if (isspace(*q)) {
1091 *q++ = '\0';
1092 while (*q && isspace(*q))
1093 q++;
1096 * Now p contains a segment name. Find it.
1098 for (seg = seghead; seg; seg = seg->next)
1099 if (!strcmp(seg->name, p))
1100 break;
1101 if (seg) {
1103 * We have a segment index. Shift a name entry
1104 * to the end of the array to make room.
1106 grp->segs[grp->nentries++] = grp->segs[grp->nindices];
1107 grp->segs[grp->nindices++].index = seg->obj_index;
1108 if (seg->grp)
1109 error(ERR_WARNING, "segment `%s' is already part of"
1110 " a group: first one takes precedence",
1111 seg->name);
1112 else
1113 seg->grp = grp;
1114 } else {
1116 * We have an as-yet undefined segment.
1117 * Remember its name, for later.
1119 grp->segs[grp->nentries++].name = nasm_strdup(p);
1124 * Walk through the list of externals with unresolved
1125 * default-WRT clauses, and resolve any that point at
1126 * this group.
1128 extp = &dws;
1129 while (*extp) {
1130 if ((*extp)->defwrt_type == DEFWRT_STRING &&
1131 !strcmp((*extp)->defwrt_ptr.string, grp->name)) {
1132 (*extp)->defwrt_type = DEFWRT_GROUP;
1133 (*extp)->defwrt_ptr.grp = grp;
1134 *extp = (*extp)->next_dws;
1135 } else
1136 extp = &(*extp)->next_dws;
1139 return 1;
1141 if (!strcmp(directive, "uppercase")) {
1142 obj_uppercase = TRUE;
1143 return 1;
1145 if (!strcmp(directive, "import")) {
1146 char *q, *extname, *libname, *impname;
1148 if (pass == 2)
1149 return 1; /* ignore in pass two */
1150 extname = q = value;
1151 while (*q && !isspace(*q))
1152 q++;
1153 if (isspace(*q)) {
1154 *q++ = '\0';
1155 while (*q && isspace(*q))
1156 q++;
1159 libname = q;
1160 while (*q && !isspace(*q))
1161 q++;
1162 if (isspace(*q)) {
1163 *q++ = '\0';
1164 while (*q && isspace(*q))
1165 q++;
1168 impname = q;
1170 if (!*extname || !*libname)
1171 error(ERR_NONFATAL, "`import' directive requires symbol name"
1172 " and library name");
1173 else {
1174 struct ImpDef *imp;
1175 int err = FALSE;
1177 imp = *imptail = nasm_malloc(sizeof(struct ImpDef));
1178 imptail = &imp->next;
1179 imp->next = NULL;
1180 imp->extname = nasm_strdup(extname);
1181 imp->libname = nasm_strdup(libname);
1182 imp->impindex = readnum(impname, &err);
1183 if (!*impname || err)
1184 imp->impname = nasm_strdup(impname);
1185 else
1186 imp->impname = NULL;
1189 return 1;
1191 if (!strcmp(directive, "export")) {
1192 char *q, *extname, *intname, *v;
1193 struct ExpDef *export;
1194 int flags = 0;
1195 unsigned int ordinal = 0;
1197 if (pass == 2)
1198 return 1; /* ignore in pass two */
1199 intname = q = value;
1200 while (*q && !isspace(*q))
1201 q++;
1202 if (isspace(*q)) {
1203 *q++ = '\0';
1204 while (*q && isspace(*q))
1205 q++;
1208 extname = q;
1209 while (*q && !isspace(*q))
1210 q++;
1211 if (isspace(*q)) {
1212 *q++ = '\0';
1213 while (*q && isspace(*q))
1214 q++;
1217 if (!*intname) {
1218 error(ERR_NONFATAL, "`export' directive requires export name");
1219 return 1;
1221 if (!*extname) {
1222 extname = intname;
1223 intname = "";
1225 while (*q) {
1226 v = q;
1227 while (*q && !isspace(*q))
1228 q++;
1229 if (isspace(*q)) {
1230 *q++ = '\0';
1231 while (*q && isspace(*q))
1232 q++;
1234 if (!nasm_stricmp(v, "resident"))
1235 flags |= EXPDEF_FLAG_RESIDENT;
1236 else if (!nasm_stricmp(v, "nodata"))
1237 flags |= EXPDEF_FLAG_NODATA;
1238 else if (!nasm_strnicmp(v, "parm=", 5)) {
1239 int err = FALSE;
1240 flags |= EXPDEF_MASK_PARMCNT & readnum(v+5, &err);
1241 if (err) {
1242 error(ERR_NONFATAL,
1243 "value `%s' for `parm' is non-numeric", v+5);
1244 return 1;
1246 } else {
1247 int err = FALSE;
1248 ordinal = readnum(v, &err);
1249 if (err) {
1250 error(ERR_NONFATAL, "unrecognised export qualifier `%s'",
1252 return 1;
1254 flags |= EXPDEF_FLAG_ORDINAL;
1258 export = *exptail = nasm_malloc(sizeof(struct ExpDef));
1259 exptail = &export->next;
1260 export->next = NULL;
1261 export->extname = nasm_strdup(extname);
1262 export->intname = nasm_strdup(intname);
1263 export->ordinal = ordinal;
1264 export->flags = flags;
1266 return 1;
1268 return 0;
1271 static long obj_segbase (long segment) {
1272 struct Segment *seg;
1275 * Find the segment in our list.
1277 for (seg = seghead; seg; seg = seg->next)
1278 if (seg->index == segment-1)
1279 break;
1281 if (!seg) {
1283 * Might be an external with a default WRT.
1285 long i = segment/2;
1286 struct ExtBack *eb = ebhead;
1287 struct External *e;
1289 while (i > EXT_BLKSIZ) {
1290 if (eb)
1291 eb = eb->next;
1292 else
1293 break;
1294 i -= EXT_BLKSIZ;
1296 if (eb) {
1297 e = eb->exts[i];
1298 if (e->defwrt_type == DEFWRT_NONE)
1299 return segment; /* fine */
1300 else if (e->defwrt_type == DEFWRT_SEGMENT)
1301 return e->defwrt_ptr.seg->index+1;
1302 else if (e->defwrt_type == DEFWRT_GROUP)
1303 return e->defwrt_ptr.grp->index+1;
1304 else if (e->defwrt_type == DEFWRT_STRING)
1305 return NO_SEG; /* can't tell what it is */
1308 return segment; /* not one of ours - leave it alone */
1311 if (seg->align >= SEG_ABS)
1312 return seg->align; /* absolute segment */
1313 if (seg->grp)
1314 return seg->grp->index+1; /* grouped segment */
1316 return segment; /* no special treatment */
1319 static void obj_filename (char *inname, char *outname, efunc error) {
1320 strcpy(obj_infile, inname);
1321 standard_extension (inname, outname, ".obj", error);
1324 static void obj_write_file (void) {
1325 struct Segment *seg;
1326 struct Group *grp;
1327 struct Public *pub;
1328 struct External *ext;
1329 struct ObjData *data;
1330 struct ImpDef *imp;
1331 struct ExpDef *export;
1332 static char boast[] = "The Netwide Assembler " NASM_VER;
1333 int lname_idx, rectype;
1336 * Write the THEADR module header.
1338 recptr = record;
1339 recptr = obj_write_name (recptr, obj_infile);
1340 obj_record (THEADR, record, recptr);
1343 * Write the NASM boast comment.
1345 recptr = record;
1346 recptr = obj_write_rword (recptr, 0); /* comment type zero */
1347 recptr = obj_write_name (recptr, boast);
1348 obj_record (COMENT, record, recptr);
1351 * Write the IMPDEF records, if any.
1353 for (imp = imphead; imp; imp = imp->next) {
1354 recptr = record;
1355 recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */
1356 recptr = obj_write_byte (recptr, 1); /* subfunction 1: IMPDEF */
1357 if (imp->impname)
1358 recptr = obj_write_byte (recptr, 0); /* import by name */
1359 else
1360 recptr = obj_write_byte (recptr, 1); /* import by ordinal */
1361 recptr = obj_write_name (recptr, imp->extname);
1362 recptr = obj_write_name (recptr, imp->libname);
1363 if (imp->impname)
1364 recptr = obj_write_name (recptr, imp->impname);
1365 else
1366 recptr = obj_write_word (recptr, imp->impindex);
1367 obj_record (COMENT, record, recptr);
1371 * Write the EXPDEF records, if any.
1373 for (export = exphead; export; export = export->next) {
1374 recptr = record;
1375 recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */
1376 recptr = obj_write_byte (recptr, 2); /* subfunction 1: EXPDEF */
1377 recptr = obj_write_byte (recptr, export->flags);
1378 recptr = obj_write_name (recptr, export->extname);
1379 recptr = obj_write_name (recptr, export->intname);
1380 if (export->flags & EXPDEF_FLAG_ORDINAL)
1381 recptr = obj_write_word (recptr, export->ordinal);
1382 obj_record (COMENT, record, recptr);
1386 * Write the first LNAMES record, containing LNAME one, which
1387 * is null. Also initialise the LNAME counter.
1389 recptr = record;
1390 recptr = obj_write_name (recptr, "");
1391 obj_record (LNAMES, record, recptr);
1392 lname_idx = 2;
1395 * Write the SEGDEF records. Each has an associated LNAMES
1396 * record.
1398 for (seg = seghead; seg; seg = seg->next) {
1399 int new_segdef; /* do we use the newer record type? */
1400 int acbp;
1401 int sn, cn, on; /* seg, class, overlay LNAME idx */
1403 if (seg->use32 || seg->currentpos >= 0x10000L)
1404 new_segdef = TRUE;
1405 else
1406 new_segdef = FALSE;
1408 recptr = record;
1409 recptr = obj_write_name (recptr, seg->name);
1410 sn = lname_idx++;
1411 if (seg->segclass) {
1412 recptr = obj_write_name (recptr, seg->segclass);
1413 cn = lname_idx++;
1414 } else
1415 cn = 1;
1416 if (seg->overlay) {
1417 recptr = obj_write_name (recptr, seg->overlay);
1418 on = lname_idx++;
1419 } else
1420 on = 1;
1421 obj_record (LNAMES, record, recptr);
1423 acbp = (seg->combine << 2); /* C field */
1425 if (seg->currentpos >= 0x10000L && !new_segdef)
1426 acbp |= 0x02; /* B bit */
1428 if (seg->use32)
1429 acbp |= 0x01; /* P bit is Use32 flag */
1431 /* A field */
1432 if (seg->align >= SEG_ABS)
1433 acbp |= 0x00;
1434 else if (seg->align >= 4096) {
1435 if (seg->align > 4096)
1436 error(ERR_NONFATAL, "segment `%s' requires more alignment"
1437 " than OBJ format supports", seg->name);
1438 acbp |= 0xC0; /* PharLap extension */
1439 } else if (seg->align >= 256) {
1440 acbp |= 0x80;
1441 } else if (seg->align >= 16) {
1442 acbp |= 0x60;
1443 } else if (seg->align >= 4) {
1444 acbp |= 0xA0;
1445 } else if (seg->align >= 2) {
1446 acbp |= 0x40;
1447 } else
1448 acbp |= 0x20;
1450 recptr = record;
1451 recptr = obj_write_byte (recptr, acbp);
1452 if (seg->align & SEG_ABS) {
1453 recptr = obj_write_word (recptr, seg->align - SEG_ABS);
1454 recptr = obj_write_byte (recptr, 0);
1456 if (new_segdef)
1457 recptr = obj_write_dword (recptr, seg->currentpos);
1458 else
1459 recptr = obj_write_word (recptr, seg->currentpos & 0xFFFF);
1460 recptr = obj_write_index (recptr, sn);
1461 recptr = obj_write_index (recptr, cn);
1462 recptr = obj_write_index (recptr, on);
1463 if (new_segdef)
1464 obj_record (SEGDEF+1, record, recptr);
1465 else
1466 obj_record (SEGDEF, record, recptr);
1470 * Write some LNAMES for the group names. lname_idx is left
1471 * alone here - it will catch up when we write the GRPDEFs.
1473 recptr = record;
1474 for (grp = grphead; grp; grp = grp->next) {
1475 if (recptr - record + strlen(grp->name)+2 > 1024) {
1476 obj_record (LNAMES, record, recptr);
1477 recptr = record;
1479 recptr = obj_write_name (recptr, grp->name);
1481 if (recptr > record)
1482 obj_record (LNAMES, record, recptr);
1485 * Write the GRPDEF records.
1487 for (grp = grphead; grp; grp = grp->next) {
1488 int i;
1490 if (grp->nindices != grp->nentries) {
1491 for (i = grp->nindices; i < grp->nentries; i++) {
1492 error(ERR_NONFATAL, "group `%s' contains undefined segment"
1493 " `%s'", grp->name, grp->segs[i].name);
1494 nasm_free (grp->segs[i].name);
1495 grp->segs[i].name = NULL;
1498 recptr = record;
1499 recptr = obj_write_index (recptr, lname_idx++);
1500 for (i = 0; i < grp->nindices; i++) {
1501 recptr = obj_write_byte (recptr, 0xFF);
1502 recptr = obj_write_index (recptr, grp->segs[i].index);
1504 obj_record (GRPDEF, record, recptr);
1508 * Write the PUBDEF records: first the ones in the segments,
1509 * then the far-absolutes.
1511 for (seg = seghead; seg; seg = seg->next) {
1512 int any;
1514 recptr = record;
1515 recptr = obj_write_index (recptr, seg->grp ? seg->grp->obj_index : 0);
1516 recptr = obj_write_index (recptr, seg->obj_index);
1517 any = FALSE;
1518 if (seg->use32)
1519 rectype = PUBDEF+1;
1520 else
1521 rectype = PUBDEF;
1522 for (pub = seg->pubhead; pub; pub = pub->next) {
1523 if (recptr - record + strlen(pub->name) + 7 > 1024) {
1524 if (any)
1525 obj_record (rectype, record, recptr);
1526 recptr = record;
1527 recptr = obj_write_index (recptr, 0);
1528 recptr = obj_write_index (recptr, seg->obj_index);
1530 recptr = obj_write_name (recptr, pub->name);
1531 if (seg->use32)
1532 recptr = obj_write_dword (recptr, pub->offset);
1533 else
1534 recptr = obj_write_word (recptr, pub->offset);
1535 recptr = obj_write_index (recptr, 0);
1536 any = TRUE;
1538 if (any)
1539 obj_record (rectype, record, recptr);
1541 for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */
1542 recptr = record;
1543 recptr = obj_write_index (recptr, 0); /* no group */
1544 recptr = obj_write_index (recptr, 0); /* no segment either */
1545 recptr = obj_write_word (recptr, pub->segment);
1546 recptr = obj_write_name (recptr, pub->name);
1547 recptr = obj_write_word (recptr, pub->offset);
1548 recptr = obj_write_index (recptr, 0);
1549 obj_record (PUBDEF, record, recptr);
1553 * Write the EXTDEF and COMDEF records, in order.
1555 recptr = record;
1556 for (ext = exthead; ext; ext = ext->next) {
1557 if (ext->commonsize == 0) {
1558 /* dj@delorie.com: check for buffer overrun before we overrun it */
1559 if (recptr - record + strlen(ext->name)+2 > RECORD_MAX) {
1560 obj_record (EXTDEF, record, recptr);
1561 recptr = record;
1563 recptr = obj_write_name (recptr, ext->name);
1564 recptr = obj_write_index (recptr, 0);
1565 } else {
1566 if (recptr > record)
1567 obj_record (EXTDEF, record, recptr);
1568 recptr = record;
1569 if (ext->commonsize) {
1570 recptr = obj_write_name (recptr, ext->name);
1571 recptr = obj_write_index (recptr, 0);
1572 if (ext->commonelem) {
1573 recptr = obj_write_byte (recptr, 0x61);/* far communal */
1574 recptr = obj_write_value (recptr, (ext->commonsize /
1575 ext->commonelem));
1576 recptr = obj_write_value (recptr, ext->commonelem);
1577 } else {
1578 recptr = obj_write_byte (recptr, 0x62);/* near communal */
1579 recptr = obj_write_value (recptr, ext->commonsize);
1581 obj_record (COMDEF, record, recptr);
1583 recptr = record;
1586 if (recptr > record)
1587 obj_record (EXTDEF, record, recptr);
1590 * Write a COMENT record stating that the linker's first pass
1591 * may stop processing at this point. Exception is if our
1592 * MODEND record specifies a start point, in which case,
1593 * according to some variants of the documentation, this COMENT
1594 * should be omitted. So we'll omit it just in case.
1596 if (obj_entry_seg == NO_SEG) {
1597 recptr = record;
1598 recptr = obj_write_rword (recptr, 0x40A2);
1599 recptr = obj_write_byte (recptr, 1);
1600 obj_record (COMENT, record, recptr);
1604 * Write the LEDATA/FIXUPP pairs.
1606 for (data = datahead; data; data = data->next) {
1607 if (data->nonempty) {
1608 obj_record (data->letype, data->ledata, data->lptr);
1609 if (data->fptr != data->fixupp)
1610 obj_record (data->ftype, data->fixupp, data->fptr);
1615 * Write the MODEND module end marker.
1617 recptr = record;
1618 rectype = MODEND;
1619 if (obj_entry_seg != NO_SEG) {
1620 recptr = obj_write_byte (recptr, 0xC1);
1622 * Find the segment in the segment list.
1624 for (seg = seghead; seg; seg = seg->next) {
1625 if (seg->index == obj_entry_seg) {
1626 if (seg->grp) {
1627 recptr = obj_write_byte (recptr, 0x10);
1628 recptr = obj_write_index (recptr, seg->grp->obj_index);
1629 } else {
1630 recptr = obj_write_byte (recptr, 0x50);
1632 recptr = obj_write_index (recptr, seg->obj_index);
1633 if (seg->use32) {
1634 rectype = MODEND+1;
1635 recptr = obj_write_dword (recptr, obj_entry_ofs);
1636 } else
1637 recptr = obj_write_word (recptr, obj_entry_ofs);
1638 break;
1641 if (!seg)
1642 error(ERR_NONFATAL, "entry point is not in this module");
1643 } else
1644 recptr = obj_write_byte (recptr, 0);
1645 obj_record (rectype, record, recptr);
1648 static unsigned char *obj_write_data(unsigned char *ptr,
1649 unsigned char *data, int len) {
1650 while (len--)
1651 *ptr++ = *data++;
1652 return ptr;
1655 static unsigned char *obj_write_byte(unsigned char *ptr, int data) {
1656 *ptr++ = data;
1657 return ptr;
1660 static unsigned char *obj_write_word(unsigned char *ptr, int data) {
1661 *ptr++ = data & 0xFF;
1662 *ptr++ = (data >> 8) & 0xFF;
1663 return ptr;
1666 static unsigned char *obj_write_dword(unsigned char *ptr, long data) {
1667 *ptr++ = data & 0xFF;
1668 *ptr++ = (data >> 8) & 0xFF;
1669 *ptr++ = (data >> 16) & 0xFF;
1670 *ptr++ = (data >> 24) & 0xFF;
1671 return ptr;
1674 static unsigned char *obj_write_rword(unsigned char *ptr, int data) {
1675 *ptr++ = (data >> 8) & 0xFF;
1676 *ptr++ = data & 0xFF;
1677 return ptr;
1680 static unsigned char *obj_write_name(unsigned char *ptr, char *data) {
1681 *ptr++ = strlen(data);
1682 if (obj_uppercase) {
1683 while (*data) {
1684 *ptr++ = (unsigned char) toupper(*data);
1685 data++;
1687 } else {
1688 while (*data)
1689 *ptr++ = (unsigned char) *data++;
1691 return ptr;
1694 static unsigned char *obj_write_index(unsigned char *ptr, int data) {
1695 if (data < 128)
1696 *ptr++ = data;
1697 else {
1698 *ptr++ = 0x80 | ((data >> 8) & 0x7F);
1699 *ptr++ = data & 0xFF;
1701 return ptr;
1704 static unsigned char *obj_write_value(unsigned char *ptr,
1705 unsigned long data) {
1706 if (data <= 128)
1707 *ptr++ = data;
1708 else if (data <= 0xFFFF) {
1709 *ptr++ = 129;
1710 *ptr++ = data & 0xFF;
1711 *ptr++ = (data >> 8) & 0xFF;
1712 } else if (data <= 0xFFFFFFL) {
1713 *ptr++ = 132;
1714 *ptr++ = data & 0xFF;
1715 *ptr++ = (data >> 8) & 0xFF;
1716 *ptr++ = (data >> 16) & 0xFF;
1717 } else {
1718 *ptr++ = 136;
1719 *ptr++ = data & 0xFF;
1720 *ptr++ = (data >> 8) & 0xFF;
1721 *ptr++ = (data >> 16) & 0xFF;
1722 *ptr++ = (data >> 24) & 0xFF;
1724 return ptr;
1727 static void obj_record(int type, unsigned char *start, unsigned char *end) {
1728 unsigned long cksum, len;
1730 cksum = type;
1731 fputc (type, ofp);
1732 len = end-start+1;
1733 cksum += (len & 0xFF) + ((len>>8) & 0xFF);
1734 fwriteshort (len, ofp);
1735 fwrite (start, 1, end-start, ofp);
1736 while (start < end)
1737 cksum += *start++;
1738 fputc ( (-(long)cksum) & 0xFF, ofp);
1741 static char *obj_stdmac[] = {
1742 "%define __SECT__ [section .text]",
1743 "%imacro group 1+.nolist",
1744 "[group %1]",
1745 "%endmacro",
1746 "%imacro uppercase 1+.nolist",
1747 "[uppercase %1]",
1748 "%endmacro",
1749 "%imacro export 1+.nolist",
1750 "[export %1]",
1751 "%endmacro",
1752 "%imacro import 1+.nolist",
1753 "[import %1]",
1754 "%endmacro",
1755 NULL
1758 struct ofmt of_obj = {
1759 "Microsoft MS-DOS 16-bit OMF object files",
1760 "obj",
1761 obj_stdmac,
1762 obj_init,
1763 obj_out,
1764 obj_deflabel,
1765 obj_segment,
1766 obj_segbase,
1767 obj_directive,
1768 obj_filename,
1769 obj_cleanup
1771 #endif /* OF_OBJ */