NASM 0.96
[nasm.git] / outobj.c
blob0a64c6aeb40685db1b50417cb83bba9b99bc7086
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 % 2 && size == 4) {
604 * This is a 4-byte segment-base relocation such as
605 * `MOV EAX,SEG foo'. OBJ format can't actually handle
606 * these, but if the constant term has the 16 low bits
607 * zero, we can just apply a 2-byte segment-base
608 * relocation to the low word instead.
610 rsize = 2;
611 if (ldata & 0xFFFF)
612 error(ERR_NONFATAL, "OBJ format cannot handle complex"
613 " dword-size segment base references");
615 if (segment != NO_SEG)
616 obj_write_fixup (datacurr, rsize,
617 (realtype == OUT_REL2ADR ||
618 realtype == OUT_REL4ADR ? 0 : 0x4000),
619 segment, wrt,
620 (seg->currentpos - datacurr->startpos));
621 seg->currentpos += size;
622 } else if (realtype == OUT_RESERVE) {
623 obj_ledata_commit();
624 seg->currentpos += size;
628 static long obj_ledata_space(struct Segment *segto) {
629 if (datacurr && datacurr->seg == segto)
630 return datacurr->ledata + LEDATA_MAX - datacurr->lptr;
631 else
632 return 0;
635 static int obj_fixup_free(struct Segment *segto) {
636 if (datacurr && datacurr->seg == segto)
637 return (datacurr->fixupp + RECORD_MAX - datacurr->fptr) > 8;
638 else
639 return 0;
642 static void obj_ledata_new(struct Segment *segto) {
643 datacurr = *datatail = nasm_malloc(sizeof(*datacurr));
644 datacurr->next = NULL;
645 datatail = &datacurr->next;
646 datacurr->nonempty = FALSE;
647 datacurr->lptr = datacurr->ledata;
648 datacurr->fptr = datacurr->fixupp;
649 datacurr->seg = segto;
650 if (segto->use32)
651 datacurr->letype = LEDATA+1;
652 else
653 datacurr->letype = LEDATA;
654 datacurr->startpos = segto->currentpos;
655 datacurr->ftype = FIXUPP;
657 datacurr->lptr = obj_write_index (datacurr->lptr, segto->obj_index);
658 if (datacurr->letype == LEDATA)
659 datacurr->lptr = obj_write_word (datacurr->lptr, segto->currentpos);
660 else
661 datacurr->lptr = obj_write_dword (datacurr->lptr, segto->currentpos);
664 static void obj_ledata_commit(void) {
665 datacurr = NULL;
668 static void obj_write_fixup (struct ObjData *data, int bytes,
669 int segrel, long seg, long wrt,
670 long offset) {
671 int locat, method;
672 int base;
673 long tidx, fidx;
674 struct Segment *s = NULL;
675 struct Group *g = NULL;
676 struct External *e = NULL;
678 if (bytes == 1) {
679 error(ERR_NONFATAL, "`obj' output driver does not support"
680 " one-byte relocations");
681 return;
684 locat = 0x8000 | segrel | offset;
685 if (seg % 2) {
686 base = TRUE;
687 locat |= 0x800;
688 seg--;
689 if (bytes != 2)
690 error(ERR_PANIC, "OBJ: 4-byte segment base fixup got"
691 " through sanity check");
692 } else {
693 base = FALSE;
694 if (bytes == 2)
695 locat |= 0x400;
696 else {
697 locat |= 0x2400;
698 data->ftype = FIXUPP+1; /* need new-style FIXUPP record */
701 data->fptr = obj_write_rword (data->fptr, locat);
703 tidx = fidx = -1, method = 0; /* placate optimisers */
706 * See if we can find the segment ID in our segment list. If
707 * so, we have a T4 (LSEG) target.
709 for (s = seghead; s; s = s->next)
710 if (s->index == seg)
711 break;
712 if (s)
713 method = 4, tidx = s->obj_index;
714 else {
715 for (g = grphead; g; g = g->next)
716 if (g->index == seg)
717 break;
718 if (g)
719 method = 5, tidx = g->obj_index;
720 else {
721 long i = seg/2;
722 struct ExtBack *eb = ebhead;
723 while (i > EXT_BLKSIZ) {
724 if (eb)
725 eb = eb->next;
726 else
727 break;
728 i -= EXT_BLKSIZ;
730 if (eb)
731 method = 6, e = eb->exts[i], tidx = e->index;
732 else
733 error(ERR_PANIC,
734 "unrecognised segment value in obj_write_fixup");
739 * If no WRT given, assume the natural default, which is method
740 * F5 unless:
742 * - we are doing an OFFSET fixup for a grouped segment, in
743 * which case we require F1 (group).
745 * - we are doing an OFFSET fixup for an external with a
746 * default WRT, in which case we must honour the default WRT.
748 if (wrt == NO_SEG) {
749 if (!base && s && s->grp)
750 method |= 0x10, fidx = s->grp->obj_index;
751 else if (!base && e && e->defwrt_type != DEFWRT_NONE) {
752 if (e->defwrt_type == DEFWRT_SEGMENT)
753 method |= 0x00, fidx = e->defwrt_ptr.seg->obj_index;
754 else if (e->defwrt_type == DEFWRT_GROUP)
755 method |= 0x10, fidx = e->defwrt_ptr.grp->obj_index;
756 else {
757 error(ERR_NONFATAL, "default WRT specification for"
758 " external `%s' unresolved", e->name);
759 method |= 0x50, fidx = -1; /* got to do _something_ */
761 } else
762 method |= 0x50, fidx = -1;
763 } else {
765 * See if we can find the WRT-segment ID in our segment
766 * list. If so, we have a F0 (LSEG) frame.
768 for (s = seghead; s; s = s->next)
769 if (s->index == wrt-1)
770 break;
771 if (s)
772 method |= 0x00, fidx = s->obj_index;
773 else {
774 for (g = grphead; g; g = g->next)
775 if (g->index == wrt-1)
776 break;
777 if (g)
778 method |= 0x10, fidx = g->obj_index;
779 else {
780 long i = wrt/2;
781 struct ExtBack *eb = ebhead;
782 while (i > EXT_BLKSIZ) {
783 if (eb)
784 eb = eb->next;
785 else
786 break;
787 i -= EXT_BLKSIZ;
789 if (eb)
790 method |= 0x20, fidx = eb->exts[i]->index;
791 else
792 error(ERR_PANIC,
793 "unrecognised WRT value in obj_write_fixup");
798 data->fptr = obj_write_byte (data->fptr, method);
799 if (fidx != -1)
800 data->fptr = obj_write_index (data->fptr, fidx);
801 data->fptr = obj_write_index (data->fptr, tidx);
804 static long obj_segment (char *name, int pass, int *bits) {
806 * We call the label manager here to define a name for the new
807 * segment, and when our _own_ label-definition stub gets
808 * called in return, it should register the new segment name
809 * using the pointer it gets passed. That way we save memory,
810 * by sponging off the label manager.
812 if (!name) {
813 *bits = 16;
814 return first_seg;
815 } else {
816 struct Segment *seg;
817 struct Group *grp;
818 struct External **extp;
819 int obj_idx, i, attrs, rn_error;
820 char *p;
823 * Look for segment attributes.
825 attrs = 0;
826 while (*name == '.')
827 name++; /* hack, but a documented one */
828 p = name;
829 while (*p && !isspace(*p))
830 p++;
831 if (*p) {
832 *p++ = '\0';
833 while (*p && isspace(*p))
834 *p++ = '\0';
836 while (*p) {
837 while (*p && !isspace(*p))
838 p++;
839 if (*p) {
840 *p++ = '\0';
841 while (*p && isspace(*p))
842 *p++ = '\0';
845 attrs++;
848 obj_idx = 1;
849 for (seg = seghead; seg; seg = seg->next) {
850 obj_idx++;
851 if (!strcmp(seg->name, name)) {
852 if (attrs > 0 && pass == 1)
853 error(ERR_WARNING, "segment attributes specified on"
854 " redeclaration of segment: ignoring");
855 if (seg->use32)
856 *bits = 32;
857 else
858 *bits = 16;
859 return seg->index;
863 *segtail = seg = nasm_malloc(sizeof(*seg));
864 seg->next = NULL;
865 segtail = &seg->next;
866 seg->index = (any_segs ? seg_alloc() : first_seg);
867 seg->obj_index = obj_idx;
868 seg->grp = NULL;
869 any_segs = TRUE;
870 seg->name = NULL;
871 seg->currentpos = 0;
872 seg->align = 1; /* default */
873 seg->use32 = FALSE; /* default */
874 seg->combine = CMB_PUBLIC; /* default */
875 seg->segclass = seg->overlay = NULL;
876 seg->pubhead = NULL;
877 seg->pubtail = &seg->pubhead;
880 * Process the segment attributes.
882 p = name;
883 while (attrs--) {
884 p += strlen(p);
885 while (!*p) p++;
888 * `p' contains a segment attribute.
890 if (!nasm_stricmp(p, "private"))
891 seg->combine = CMB_PRIVATE;
892 else if (!nasm_stricmp(p, "public"))
893 seg->combine = CMB_PUBLIC;
894 else if (!nasm_stricmp(p, "common"))
895 seg->combine = CMB_COMMON;
896 else if (!nasm_stricmp(p, "stack"))
897 seg->combine = CMB_STACK;
898 else if (!nasm_stricmp(p, "use16"))
899 seg->use32 = FALSE;
900 else if (!nasm_stricmp(p, "use32"))
901 seg->use32 = TRUE;
902 else if (!nasm_stricmp(p, "flat")) {
904 * This segment is an OS/2 FLAT segment. That means
905 * that its default group is group FLAT, even if
906 * the group FLAT does not explicitly _contain_ the
907 * segment.
909 * When we see this, we must create the group
910 * `FLAT', containing no segments, if it does not
911 * already exist; then we must set the default
912 * group of this segment to be the FLAT group.
914 struct Group *grp;
915 for (grp = grphead; grp; grp = grp->next)
916 if (!strcmp(grp->name, "FLAT"))
917 break;
918 if (!grp) {
919 obj_directive ("group", "FLAT", 1);
920 for (grp = grphead; grp; grp = grp->next)
921 if (!strcmp(grp->name, "FLAT"))
922 break;
923 if (!grp)
924 error (ERR_PANIC, "failure to define FLAT?!");
926 seg->grp = grp;
927 } else if (!nasm_strnicmp(p, "class=", 6))
928 seg->segclass = nasm_strdup(p+6);
929 else if (!nasm_strnicmp(p, "overlay=", 8))
930 seg->overlay = nasm_strdup(p+8);
931 else if (!nasm_strnicmp(p, "align=", 6)) {
932 seg->align = readnum(p+6, &rn_error);
933 if (rn_error) {
934 seg->align = 1;
935 error (ERR_NONFATAL, "segment alignment should be"
936 " numeric");
938 switch ((int) seg->align) {
939 case 1: /* BYTE */
940 case 2: /* WORD */
941 case 4: /* DWORD */
942 case 16: /* PARA */
943 case 256: /* PAGE */
944 case 4096: /* PharLap extension */
945 break;
946 case 8:
947 error(ERR_WARNING, "OBJ format does not support alignment"
948 " of 8: rounding up to 16");
949 seg->align = 16;
950 break;
951 case 32:
952 case 64:
953 case 128:
954 error(ERR_WARNING, "OBJ format does not support alignment"
955 " of %d: rounding up to 256", seg->align);
956 seg->align = 256;
957 break;
958 case 512:
959 case 1024:
960 case 2048:
961 error(ERR_WARNING, "OBJ format does not support alignment"
962 " of %d: rounding up to 4096", seg->align);
963 seg->align = 4096;
964 break;
965 default:
966 error(ERR_NONFATAL, "invalid alignment value %d",
967 seg->align);
968 seg->align = 1;
969 break;
971 } else if (!nasm_strnicmp(p, "absolute=", 9)) {
972 seg->align = SEG_ABS + readnum(p+9, &rn_error);
973 if (rn_error)
974 error (ERR_NONFATAL, "argument to `absolute' segment"
975 " attribute should be numeric");
979 obj_seg_needs_update = seg;
980 if (seg->align >= SEG_ABS)
981 deflabel (name, NO_SEG, seg->align - SEG_ABS,
982 NULL, FALSE, FALSE, &of_obj, error);
983 else
984 deflabel (name, seg->index+1, 0L,
985 NULL, FALSE, FALSE, &of_obj, error);
986 obj_seg_needs_update = NULL;
989 * See if this segment is defined in any groups.
991 for (grp = grphead; grp; grp = grp->next) {
992 for (i = grp->nindices; i < grp->nentries; i++) {
993 if (!strcmp(grp->segs[i].name, seg->name)) {
994 nasm_free (grp->segs[i].name);
995 grp->segs[i] = grp->segs[grp->nindices];
996 grp->segs[grp->nindices++].index = seg->obj_index;
997 if (seg->grp)
998 error(ERR_WARNING, "segment `%s' is already part of"
999 " a group: first one takes precedence",
1000 seg->name);
1001 else
1002 seg->grp = grp;
1008 * Walk through the list of externals with unresolved
1009 * default-WRT clauses, and resolve any that point at this
1010 * segment.
1012 extp = &dws;
1013 while (*extp) {
1014 if ((*extp)->defwrt_type == DEFWRT_STRING &&
1015 !strcmp((*extp)->defwrt_ptr.string, seg->name)) {
1016 (*extp)->defwrt_type = DEFWRT_SEGMENT;
1017 (*extp)->defwrt_ptr.seg = seg;
1018 *extp = (*extp)->next_dws;
1019 } else
1020 extp = &(*extp)->next_dws;
1023 if (seg->use32)
1024 *bits = 32;
1025 else
1026 *bits = 16;
1027 return seg->index;
1031 static int obj_directive (char *directive, char *value, int pass) {
1032 if (!strcmp(directive, "group")) {
1033 char *p, *q, *v;
1034 if (pass == 1) {
1035 struct Group *grp;
1036 struct Segment *seg;
1037 struct External **extp;
1038 int obj_idx;
1040 q = value;
1041 while (*q == '.')
1042 q++; /* hack, but a documented one */
1043 v = q;
1044 while (*q && !isspace(*q))
1045 q++;
1046 if (isspace(*q)) {
1047 *q++ = '\0';
1048 while (*q && isspace(*q))
1049 q++;
1052 * Here we used to sanity-check the group directive to
1053 * ensure nobody tried to declare a group containing no
1054 * segments. However, OS/2 does this as standard
1055 * practice, so the sanity check has been removed.
1057 * if (!*q) {
1058 * error(ERR_NONFATAL,"GROUP directive contains no segments");
1059 * return 1;
1063 obj_idx = 1;
1064 for (grp = grphead; grp; grp = grp->next) {
1065 obj_idx++;
1066 if (!strcmp(grp->name, v)) {
1067 error(ERR_NONFATAL, "group `%s' defined twice", v);
1068 return 1;
1072 *grptail = grp = nasm_malloc(sizeof(*grp));
1073 grp->next = NULL;
1074 grptail = &grp->next;
1075 grp->index = seg_alloc();
1076 grp->obj_index = obj_idx;
1077 grp->nindices = grp->nentries = 0;
1078 grp->name = NULL;
1080 obj_grp_needs_update = grp;
1081 deflabel (v, grp->index+1, 0L,
1082 NULL, FALSE, FALSE, &of_obj, error);
1083 obj_grp_needs_update = NULL;
1085 while (*q) {
1086 p = q;
1087 while (*q && !isspace(*q))
1088 q++;
1089 if (isspace(*q)) {
1090 *q++ = '\0';
1091 while (*q && isspace(*q))
1092 q++;
1095 * Now p contains a segment name. Find it.
1097 for (seg = seghead; seg; seg = seg->next)
1098 if (!strcmp(seg->name, p))
1099 break;
1100 if (seg) {
1102 * We have a segment index. Shift a name entry
1103 * to the end of the array to make room.
1105 grp->segs[grp->nentries++] = grp->segs[grp->nindices];
1106 grp->segs[grp->nindices++].index = seg->obj_index;
1107 if (seg->grp)
1108 error(ERR_WARNING, "segment `%s' is already part of"
1109 " a group: first one takes precedence",
1110 seg->name);
1111 else
1112 seg->grp = grp;
1113 } else {
1115 * We have an as-yet undefined segment.
1116 * Remember its name, for later.
1118 grp->segs[grp->nentries++].name = nasm_strdup(p);
1123 * Walk through the list of externals with unresolved
1124 * default-WRT clauses, and resolve any that point at
1125 * this group.
1127 extp = &dws;
1128 while (*extp) {
1129 if ((*extp)->defwrt_type == DEFWRT_STRING &&
1130 !strcmp((*extp)->defwrt_ptr.string, grp->name)) {
1131 (*extp)->defwrt_type = DEFWRT_GROUP;
1132 (*extp)->defwrt_ptr.grp = grp;
1133 *extp = (*extp)->next_dws;
1134 } else
1135 extp = &(*extp)->next_dws;
1138 return 1;
1140 if (!strcmp(directive, "uppercase")) {
1141 obj_uppercase = TRUE;
1142 return 1;
1144 if (!strcmp(directive, "import")) {
1145 char *q, *extname, *libname, *impname;
1147 if (pass == 2)
1148 return 1; /* ignore in pass two */
1149 extname = q = value;
1150 while (*q && !isspace(*q))
1151 q++;
1152 if (isspace(*q)) {
1153 *q++ = '\0';
1154 while (*q && isspace(*q))
1155 q++;
1158 libname = q;
1159 while (*q && !isspace(*q))
1160 q++;
1161 if (isspace(*q)) {
1162 *q++ = '\0';
1163 while (*q && isspace(*q))
1164 q++;
1167 impname = q;
1169 if (!*extname || !*libname)
1170 error(ERR_NONFATAL, "`import' directive requires symbol name"
1171 " and library name");
1172 else {
1173 struct ImpDef *imp;
1174 int err = FALSE;
1176 imp = *imptail = nasm_malloc(sizeof(struct ImpDef));
1177 imptail = &imp->next;
1178 imp->next = NULL;
1179 imp->extname = nasm_strdup(extname);
1180 imp->libname = nasm_strdup(libname);
1181 imp->impindex = readnum(impname, &err);
1182 if (!*impname || err)
1183 imp->impname = nasm_strdup(impname);
1184 else
1185 imp->impname = NULL;
1188 return 1;
1190 if (!strcmp(directive, "export")) {
1191 char *q, *extname, *intname, *v;
1192 struct ExpDef *export;
1193 int flags = 0;
1194 unsigned int ordinal = 0;
1196 if (pass == 2)
1197 return 1; /* ignore in pass two */
1198 intname = q = value;
1199 while (*q && !isspace(*q))
1200 q++;
1201 if (isspace(*q)) {
1202 *q++ = '\0';
1203 while (*q && isspace(*q))
1204 q++;
1207 extname = q;
1208 while (*q && !isspace(*q))
1209 q++;
1210 if (isspace(*q)) {
1211 *q++ = '\0';
1212 while (*q && isspace(*q))
1213 q++;
1216 if (!*intname) {
1217 error(ERR_NONFATAL, "`export' directive requires export name");
1218 return 1;
1220 if (!*extname) {
1221 extname = intname;
1222 intname = "";
1224 while (*q) {
1225 v = q;
1226 while (*q && !isspace(*q))
1227 q++;
1228 if (isspace(*q)) {
1229 *q++ = '\0';
1230 while (*q && isspace(*q))
1231 q++;
1233 if (!nasm_stricmp(v, "resident"))
1234 flags |= EXPDEF_FLAG_RESIDENT;
1235 else if (!nasm_stricmp(v, "nodata"))
1236 flags |= EXPDEF_FLAG_NODATA;
1237 else if (!nasm_strnicmp(v, "parm=", 5)) {
1238 int err = FALSE;
1239 flags |= EXPDEF_MASK_PARMCNT & readnum(v+5, &err);
1240 if (err) {
1241 error(ERR_NONFATAL,
1242 "value `%s' for `parm' is non-numeric", v+5);
1243 return 1;
1245 } else {
1246 int err = FALSE;
1247 ordinal = readnum(v, &err);
1248 if (err) {
1249 error(ERR_NONFATAL, "unrecognised export qualifier `%s'",
1251 return 1;
1253 flags |= EXPDEF_FLAG_ORDINAL;
1257 export = *exptail = nasm_malloc(sizeof(struct ExpDef));
1258 exptail = &export->next;
1259 export->next = NULL;
1260 export->extname = nasm_strdup(extname);
1261 export->intname = nasm_strdup(intname);
1262 export->ordinal = ordinal;
1263 export->flags = flags;
1265 return 1;
1267 return 0;
1270 static long obj_segbase (long segment) {
1271 struct Segment *seg;
1274 * Find the segment in our list.
1276 for (seg = seghead; seg; seg = seg->next)
1277 if (seg->index == segment-1)
1278 break;
1280 if (!seg) {
1282 * Might be an external with a default WRT.
1284 long i = segment/2;
1285 struct ExtBack *eb = ebhead;
1286 struct External *e;
1288 while (i > EXT_BLKSIZ) {
1289 if (eb)
1290 eb = eb->next;
1291 else
1292 break;
1293 i -= EXT_BLKSIZ;
1295 if (eb) {
1296 e = eb->exts[i];
1297 if (e->defwrt_type == DEFWRT_NONE)
1298 return segment; /* fine */
1299 else if (e->defwrt_type == DEFWRT_SEGMENT)
1300 return e->defwrt_ptr.seg->index+1;
1301 else if (e->defwrt_type == DEFWRT_GROUP)
1302 return e->defwrt_ptr.grp->index+1;
1303 else if (e->defwrt_type == DEFWRT_STRING)
1304 return NO_SEG; /* can't tell what it is */
1307 return segment; /* not one of ours - leave it alone */
1310 if (seg->align >= SEG_ABS)
1311 return seg->align; /* absolute segment */
1312 if (seg->grp)
1313 return seg->grp->index+1; /* grouped segment */
1315 return segment; /* no special treatment */
1318 static void obj_filename (char *inname, char *outname, efunc error) {
1319 strcpy(obj_infile, inname);
1320 standard_extension (inname, outname, ".obj", error);
1323 static void obj_write_file (void) {
1324 struct Segment *seg;
1325 struct Group *grp;
1326 struct Public *pub;
1327 struct External *ext;
1328 struct ObjData *data;
1329 struct ImpDef *imp;
1330 struct ExpDef *export;
1331 static char boast[] = "The Netwide Assembler " NASM_VER;
1332 int lname_idx, rectype;
1335 * Write the THEADR module header.
1337 recptr = record;
1338 recptr = obj_write_name (recptr, obj_infile);
1339 obj_record (THEADR, record, recptr);
1342 * Write the NASM boast comment.
1344 recptr = record;
1345 recptr = obj_write_rword (recptr, 0); /* comment type zero */
1346 recptr = obj_write_name (recptr, boast);
1347 obj_record (COMENT, record, recptr);
1350 * Write the IMPDEF records, if any.
1352 for (imp = imphead; imp; imp = imp->next) {
1353 recptr = record;
1354 recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */
1355 recptr = obj_write_byte (recptr, 1); /* subfunction 1: IMPDEF */
1356 if (imp->impname)
1357 recptr = obj_write_byte (recptr, 0); /* import by name */
1358 else
1359 recptr = obj_write_byte (recptr, 1); /* import by ordinal */
1360 recptr = obj_write_name (recptr, imp->extname);
1361 recptr = obj_write_name (recptr, imp->libname);
1362 if (imp->impname)
1363 recptr = obj_write_name (recptr, imp->impname);
1364 else
1365 recptr = obj_write_word (recptr, imp->impindex);
1366 obj_record (COMENT, record, recptr);
1370 * Write the EXPDEF records, if any.
1372 for (export = exphead; export; export = export->next) {
1373 recptr = record;
1374 recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */
1375 recptr = obj_write_byte (recptr, 2); /* subfunction 1: EXPDEF */
1376 recptr = obj_write_byte (recptr, export->flags);
1377 recptr = obj_write_name (recptr, export->extname);
1378 recptr = obj_write_name (recptr, export->intname);
1379 if (export->flags & EXPDEF_FLAG_ORDINAL)
1380 recptr = obj_write_word (recptr, export->ordinal);
1381 obj_record (COMENT, record, recptr);
1385 * Write the first LNAMES record, containing LNAME one, which
1386 * is null. Also initialise the LNAME counter.
1388 recptr = record;
1389 recptr = obj_write_name (recptr, "");
1390 obj_record (LNAMES, record, recptr);
1391 lname_idx = 2;
1394 * Write the SEGDEF records. Each has an associated LNAMES
1395 * record.
1397 for (seg = seghead; seg; seg = seg->next) {
1398 int new_segdef; /* do we use the newer record type? */
1399 int acbp;
1400 int sn, cn, on; /* seg, class, overlay LNAME idx */
1402 if (seg->use32 || seg->currentpos >= 0x10000L)
1403 new_segdef = TRUE;
1404 else
1405 new_segdef = FALSE;
1407 recptr = record;
1408 recptr = obj_write_name (recptr, seg->name);
1409 sn = lname_idx++;
1410 if (seg->segclass) {
1411 recptr = obj_write_name (recptr, seg->segclass);
1412 cn = lname_idx++;
1413 } else
1414 cn = 1;
1415 if (seg->overlay) {
1416 recptr = obj_write_name (recptr, seg->overlay);
1417 on = lname_idx++;
1418 } else
1419 on = 1;
1420 obj_record (LNAMES, record, recptr);
1422 acbp = (seg->combine << 2); /* C field */
1424 if (seg->currentpos >= 0x10000L && !new_segdef)
1425 acbp |= 0x02; /* B bit */
1427 if (seg->use32)
1428 acbp |= 0x01; /* P bit is Use32 flag */
1430 /* A field */
1431 if (seg->align >= SEG_ABS)
1432 acbp |= 0x00;
1433 else if (seg->align >= 4096) {
1434 if (seg->align > 4096)
1435 error(ERR_NONFATAL, "segment `%s' requires more alignment"
1436 " than OBJ format supports", seg->name);
1437 acbp |= 0xC0; /* PharLap extension */
1438 } else if (seg->align >= 256) {
1439 acbp |= 0x80;
1440 } else if (seg->align >= 16) {
1441 acbp |= 0x60;
1442 } else if (seg->align >= 4) {
1443 acbp |= 0xA0;
1444 } else if (seg->align >= 2) {
1445 acbp |= 0x40;
1446 } else
1447 acbp |= 0x20;
1449 recptr = record;
1450 recptr = obj_write_byte (recptr, acbp);
1451 if (seg->align & SEG_ABS) {
1452 recptr = obj_write_word (recptr, seg->align - SEG_ABS);
1453 recptr = obj_write_byte (recptr, 0);
1455 if (new_segdef)
1456 recptr = obj_write_dword (recptr, seg->currentpos);
1457 else
1458 recptr = obj_write_word (recptr, seg->currentpos & 0xFFFF);
1459 recptr = obj_write_index (recptr, sn);
1460 recptr = obj_write_index (recptr, cn);
1461 recptr = obj_write_index (recptr, on);
1462 if (new_segdef)
1463 obj_record (SEGDEF+1, record, recptr);
1464 else
1465 obj_record (SEGDEF, record, recptr);
1469 * Write some LNAMES for the group names. lname_idx is left
1470 * alone here - it will catch up when we write the GRPDEFs.
1472 recptr = record;
1473 for (grp = grphead; grp; grp = grp->next) {
1474 if (recptr - record + strlen(grp->name)+2 > 1024) {
1475 obj_record (LNAMES, record, recptr);
1476 recptr = record;
1478 recptr = obj_write_name (recptr, grp->name);
1480 if (recptr > record)
1481 obj_record (LNAMES, record, recptr);
1484 * Write the GRPDEF records.
1486 for (grp = grphead; grp; grp = grp->next) {
1487 int i;
1489 if (grp->nindices != grp->nentries) {
1490 for (i = grp->nindices; i < grp->nentries; i++) {
1491 error(ERR_NONFATAL, "group `%s' contains undefined segment"
1492 " `%s'", grp->name, grp->segs[i].name);
1493 nasm_free (grp->segs[i].name);
1494 grp->segs[i].name = NULL;
1497 recptr = record;
1498 recptr = obj_write_index (recptr, lname_idx++);
1499 for (i = 0; i < grp->nindices; i++) {
1500 recptr = obj_write_byte (recptr, 0xFF);
1501 recptr = obj_write_index (recptr, grp->segs[i].index);
1503 obj_record (GRPDEF, record, recptr);
1507 * Write the PUBDEF records: first the ones in the segments,
1508 * then the far-absolutes.
1510 for (seg = seghead; seg; seg = seg->next) {
1511 int any;
1513 recptr = record;
1514 recptr = obj_write_index (recptr, seg->grp ? seg->grp->obj_index : 0);
1515 recptr = obj_write_index (recptr, seg->obj_index);
1516 any = FALSE;
1517 if (seg->use32)
1518 rectype = PUBDEF+1;
1519 else
1520 rectype = PUBDEF;
1521 for (pub = seg->pubhead; pub; pub = pub->next) {
1522 if (recptr - record + strlen(pub->name) > 1024) {
1523 if (any)
1524 obj_record (rectype, record, recptr);
1525 recptr = record;
1526 recptr = obj_write_index (recptr, 0);
1527 recptr = obj_write_index (recptr, seg->obj_index);
1529 recptr = obj_write_name (recptr, pub->name);
1530 if (seg->use32)
1531 recptr = obj_write_dword (recptr, pub->offset);
1532 else
1533 recptr = obj_write_word (recptr, pub->offset);
1534 recptr = obj_write_index (recptr, 0);
1535 any = TRUE;
1537 if (any)
1538 obj_record (rectype, record, recptr);
1540 for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */
1541 recptr = record;
1542 recptr = obj_write_index (recptr, 0); /* no group */
1543 recptr = obj_write_index (recptr, 0); /* no segment either */
1544 recptr = obj_write_word (recptr, pub->segment);
1545 recptr = obj_write_name (recptr, pub->name);
1546 recptr = obj_write_word (recptr, pub->offset);
1547 recptr = obj_write_index (recptr, 0);
1548 obj_record (PUBDEF, record, recptr);
1552 * Write the EXTDEF and COMDEF records, in order.
1554 recptr = record;
1555 for (ext = exthead; ext; ext = ext->next) {
1556 if (ext->commonsize == 0) {
1557 /* dj@delorie.com: check for buffer overrun before we overrun it */
1558 if (recptr - record + strlen(ext->name)+2 > RECORD_MAX) {
1559 obj_record (EXTDEF, record, recptr);
1560 recptr = record;
1562 recptr = obj_write_name (recptr, ext->name);
1563 recptr = obj_write_index (recptr, 0);
1564 } else {
1565 if (recptr > record)
1566 obj_record (EXTDEF, record, recptr);
1567 recptr = record;
1568 if (ext->commonsize) {
1569 recptr = obj_write_name (recptr, ext->name);
1570 recptr = obj_write_index (recptr, 0);
1571 if (ext->commonelem) {
1572 recptr = obj_write_byte (recptr, 0x61);/* far communal */
1573 recptr = obj_write_value (recptr, (ext->commonsize /
1574 ext->commonelem));
1575 recptr = obj_write_value (recptr, ext->commonelem);
1576 } else {
1577 recptr = obj_write_byte (recptr, 0x62);/* near communal */
1578 recptr = obj_write_value (recptr, ext->commonsize);
1580 obj_record (COMDEF, record, recptr);
1582 recptr = record;
1585 if (recptr > record)
1586 obj_record (EXTDEF, record, recptr);
1589 * Write a COMENT record stating that the linker's first pass
1590 * may stop processing at this point. Exception is if our
1591 * MODEND record specifies a start point, in which case,
1592 * according to some variants of the documentation, this COMENT
1593 * should be omitted. So we'll omit it just in case.
1595 if (obj_entry_seg == NO_SEG) {
1596 recptr = record;
1597 recptr = obj_write_rword (recptr, 0x40A2);
1598 recptr = obj_write_byte (recptr, 1);
1599 obj_record (COMENT, record, recptr);
1603 * Write the LEDATA/FIXUPP pairs.
1605 for (data = datahead; data; data = data->next) {
1606 if (data->nonempty) {
1607 obj_record (data->letype, data->ledata, data->lptr);
1608 if (data->fptr != data->fixupp)
1609 obj_record (data->ftype, data->fixupp, data->fptr);
1614 * Write the MODEND module end marker.
1616 recptr = record;
1617 rectype = MODEND;
1618 if (obj_entry_seg != NO_SEG) {
1619 recptr = obj_write_byte (recptr, 0xC1);
1621 * Find the segment in the segment list.
1623 for (seg = seghead; seg; seg = seg->next) {
1624 if (seg->index == obj_entry_seg) {
1625 if (seg->grp) {
1626 recptr = obj_write_byte (recptr, 0x10);
1627 recptr = obj_write_index (recptr, seg->grp->obj_index);
1628 } else {
1629 recptr = obj_write_byte (recptr, 0x50);
1631 recptr = obj_write_index (recptr, seg->obj_index);
1632 if (seg->use32) {
1633 rectype = MODEND+1;
1634 recptr = obj_write_dword (recptr, obj_entry_ofs);
1635 } else
1636 recptr = obj_write_word (recptr, obj_entry_ofs);
1637 break;
1640 if (!seg)
1641 error(ERR_NONFATAL, "entry point is not in this module");
1642 } else
1643 recptr = obj_write_byte (recptr, 0);
1644 obj_record (rectype, record, recptr);
1647 static unsigned char *obj_write_data(unsigned char *ptr,
1648 unsigned char *data, int len) {
1649 while (len--)
1650 *ptr++ = *data++;
1651 return ptr;
1654 static unsigned char *obj_write_byte(unsigned char *ptr, int data) {
1655 *ptr++ = data;
1656 return ptr;
1659 static unsigned char *obj_write_word(unsigned char *ptr, int data) {
1660 *ptr++ = data & 0xFF;
1661 *ptr++ = (data >> 8) & 0xFF;
1662 return ptr;
1665 static unsigned char *obj_write_dword(unsigned char *ptr, long data) {
1666 *ptr++ = data & 0xFF;
1667 *ptr++ = (data >> 8) & 0xFF;
1668 *ptr++ = (data >> 16) & 0xFF;
1669 *ptr++ = (data >> 24) & 0xFF;
1670 return ptr;
1673 static unsigned char *obj_write_rword(unsigned char *ptr, int data) {
1674 *ptr++ = (data >> 8) & 0xFF;
1675 *ptr++ = data & 0xFF;
1676 return ptr;
1679 static unsigned char *obj_write_name(unsigned char *ptr, char *data) {
1680 *ptr++ = strlen(data);
1681 if (obj_uppercase) {
1682 while (*data) {
1683 *ptr++ = (unsigned char) toupper(*data);
1684 data++;
1686 } else {
1687 while (*data)
1688 *ptr++ = (unsigned char) *data++;
1690 return ptr;
1693 static unsigned char *obj_write_index(unsigned char *ptr, int data) {
1694 if (data < 128)
1695 *ptr++ = data;
1696 else {
1697 *ptr++ = 0x80 | ((data >> 8) & 0x7F);
1698 *ptr++ = data & 0xFF;
1700 return ptr;
1703 static unsigned char *obj_write_value(unsigned char *ptr,
1704 unsigned long data) {
1705 if (data <= 128)
1706 *ptr++ = data;
1707 else if (data <= 0xFFFF) {
1708 *ptr++ = 129;
1709 *ptr++ = data & 0xFF;
1710 *ptr++ = (data >> 8) & 0xFF;
1711 } else if (data <= 0xFFFFFFL) {
1712 *ptr++ = 132;
1713 *ptr++ = data & 0xFF;
1714 *ptr++ = (data >> 8) & 0xFF;
1715 *ptr++ = (data >> 16) & 0xFF;
1716 } else {
1717 *ptr++ = 136;
1718 *ptr++ = data & 0xFF;
1719 *ptr++ = (data >> 8) & 0xFF;
1720 *ptr++ = (data >> 16) & 0xFF;
1721 *ptr++ = (data >> 24) & 0xFF;
1723 return ptr;
1726 static void obj_record(int type, unsigned char *start, unsigned char *end) {
1727 unsigned long cksum, len;
1729 cksum = type;
1730 fputc (type, ofp);
1731 len = end-start+1;
1732 cksum += (len & 0xFF) + ((len>>8) & 0xFF);
1733 fwriteshort (len, ofp);
1734 fwrite (start, 1, end-start, ofp);
1735 while (start < end)
1736 cksum += *start++;
1737 fputc ( (-(long)cksum) & 0xFF, ofp);
1740 static char *obj_stdmac[] = {
1741 "%define __SECT__ [section .text]",
1742 "%imacro group 1+.nolist",
1743 "[group %1]",
1744 "%endmacro",
1745 "%imacro uppercase 1+.nolist",
1746 "[uppercase %1]",
1747 "%endmacro",
1748 "%imacro export 1+.nolist",
1749 "[export %1]",
1750 "%endmacro",
1751 "%imacro import 1+.nolist",
1752 "[import %1]",
1753 "%endmacro",
1754 NULL
1757 struct ofmt of_obj = {
1758 "Microsoft MS-DOS 16-bit OMF object files",
1759 "obj",
1760 obj_stdmac,
1761 obj_init,
1762 obj_out,
1763 obj_deflabel,
1764 obj_segment,
1765 obj_segbase,
1766 obj_directive,
1767 obj_filename,
1768 obj_cleanup
1770 #endif /* OF_OBJ */