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.
21 static char obj_infile[FILENAME_MAX];
22 static int obj_uppercase;
25 static ldfunc deflabel;
27 static long first_seg;
30 #define LEDATA_MAX 1024 /* maximum size of LEDATA record */
31 #define RECORD_MAX 1024 /* maximum size of _any_ record */
32 #define GROUP_MAX 256 /* we won't _realistically_ have more
33 * than this many segs in a group */
34 #define EXT_BLKSIZ 256 /* block size for externals list */
36 static unsigned char record[RECORD_MAX], *recptr;
38 static struct Public {
42 long segment; /* only if it's far-absolute */
43 } *fpubhead, **fpubtail;
45 static struct External {
46 struct External *next;
49 } *exthead, **exttail;
53 static struct ExtBack {
55 int index[EXT_BLKSIZ];
58 static struct Segment {
60 long index; /* the NASM segment id */
61 long obj_index; /* the OBJ-file segment index */
62 struct Group *grp; /* the group it belongs to */
64 long align; /* can be SEG_ABS + absolute addr */
71 long use32; /* is this segment 32-bit? */
72 struct Public *pubhead, **pubtail;
74 char *segclass, *overlay; /* `class' is a C++ keyword :-) */
75 } *seghead, **segtail, *obj_seg_needs_update;
80 long index; /* NASM segment id */
81 long obj_index; /* OBJ-file group index */
82 long nentries; /* number of elements... */
83 long nindices; /* ...and number of index elts... */
87 } segs[GROUP_MAX]; /* ...in this */
88 } *grphead, **grptail, *obj_grp_needs_update;
90 static struct ObjData {
96 unsigned char ledata[LEDATA_MAX], *lptr;
97 unsigned char fixupp[RECORD_MAX], *fptr;
98 } *datahead, *datacurr, **datatail;
100 static long obj_entry_seg, obj_entry_ofs;
102 enum RecordID { /* record ID codes */
104 THEADR = 0x80, /* module header */
105 COMENT = 0x88, /* comment record */
107 LNAMES = 0x96, /* list of names */
109 SEGDEF = 0x98, /* segment definition */
110 GRPDEF = 0x9A, /* group definition */
111 EXTDEF = 0x8C, /* external definition */
112 PUBDEF = 0x90, /* public definition */
113 COMDEF = 0xB0, /* common definition */
115 LEDATA = 0xA0, /* logical enumerated data */
116 FIXUPP = 0x9C, /* fixups (relocations) */
118 MODEND = 0x8A /* module end */
121 extern struct ofmt of_obj;
123 static long obj_ledata_space(struct Segment *);
124 static int obj_fixup_free(struct Segment *);
125 static void obj_ledata_new(struct Segment *);
126 static void obj_ledata_commit(void);
127 static void obj_write_fixup (struct ObjData *, int, int, long, long, long);
128 static long obj_segment (char *, int, int *);
129 static void obj_write_file(void);
130 static unsigned char *obj_write_data(unsigned char *, unsigned char *, int);
131 static unsigned char *obj_write_byte(unsigned char *, int);
132 static unsigned char *obj_write_word(unsigned char *, int);
133 static unsigned char *obj_write_dword(unsigned char *, long);
134 static unsigned char *obj_write_rword(unsigned char *, int);
135 static unsigned char *obj_write_name(unsigned char *, char *);
136 static unsigned char *obj_write_index(unsigned char *, int);
137 static unsigned char *obj_write_value(unsigned char *, unsigned long);
138 static void obj_record(int, unsigned char *, unsigned char *);
140 static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef) {
144 first_seg = seg_alloc();
147 fpubtail = &fpubhead;
153 seghead = obj_seg_needs_update = NULL;
155 grphead = obj_grp_needs_update = NULL;
157 datahead = datacurr = NULL;
158 datatail = &datahead;
159 obj_entry_seg = NO_SEG;
160 obj_uppercase = FALSE;
163 static void obj_cleanup (void) {
167 struct Segment *segtmp = seghead;
168 seghead = seghead->next;
169 while (segtmp->pubhead) {
170 struct Public *pubtmp = segtmp->pubhead;
171 segtmp->pubhead = pubtmp->next;
177 struct Public *pubtmp = fpubhead;
178 fpubhead = fpubhead->next;
182 struct External *exttmp = exthead;
183 exthead = exthead->next;
187 struct ExtBack *ebtmp = ebhead;
188 ebhead = ebhead->next;
192 struct Group *grptmp = grphead;
193 grphead = grphead->next;
197 struct ObjData *datatmp = datahead;
198 datahead = datahead->next;
203 static void obj_deflabel (char *name, long segment,
204 long offset, int is_global) {
206 * We have three cases:
208 * (i) `segment' is a segment-base. If so, set the name field
209 * for the segment or group structure it refers to, and then
212 * (ii) `segment' is one of our segments, or a SEG_ABS segment.
213 * Save the label position for later output of a PUBDEF record.
214 * (Or a MODPUB, if we work out how.)
216 * (iii) `segment' is not one of our segments. Save the label
217 * position for later output of an EXTDEF, and also store a
218 * back-reference so that we can map later references to this
219 * segment number to the external index.
221 struct External *ext;
227 * First check for the double-period, signifying something
230 if (name[0] == '.' && name[1] == '.') {
231 if (!strcmp(name, "..start")) {
232 obj_entry_seg = segment;
233 obj_entry_ofs = offset;
241 if (obj_seg_needs_update) {
242 obj_seg_needs_update->name = name;
244 } else if (obj_grp_needs_update) {
245 obj_grp_needs_update->name = name;
248 if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
251 if (segment >= SEG_ABS) {
253 * SEG_ABS subcase of (ii).
258 pub = *fpubtail = nasm_malloc(sizeof(*pub));
259 fpubtail = &pub->next;
262 pub->offset = offset;
263 pub->segment = segment & ~SEG_ABS;
268 for (seg = seghead; seg; seg = seg->next)
269 if (seg->index == segment) {
271 * Case (ii). Maybe MODPUB someday?
276 pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
277 seg->pubtail = &pub->next;
280 pub->offset = offset;
288 ext = *exttail = nasm_malloc(sizeof(*ext));
290 exttail = &ext->next;
293 ext->commonsize = offset;
300 eb = *ebtail = nasm_malloc(sizeof(*eb));
304 while (i > EXT_BLKSIZ) {
308 eb = *ebtail = nasm_malloc(sizeof(*eb));
314 eb->index[i] = ++externals;
317 static void obj_out (long segto, void *data, unsigned long type,
318 long segment, long wrt) {
320 unsigned char *ucdata;
325 * handle absolute-assembly (structure definitions)
327 if (segto == NO_SEG) {
328 if ((type & OUT_TYPMASK) != OUT_RESERVE)
329 error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
335 * If `any_segs' is still FALSE, we must define a default
339 int tempint; /* ignored */
340 if (segto != obj_segment("__NASMDEFSEG", 2, &tempint))
341 error (ERR_PANIC, "strange segment conditions in OBJ driver");
345 * Find the segment we are targetting.
347 for (seg = seghead; seg; seg = seg->next)
348 if (seg->index == segto)
351 error (ERR_PANIC, "code directed to nonexistent segment?");
353 size = type & OUT_SIZMASK;
354 realtype = type & OUT_TYPMASK;
355 if (realtype == OUT_RAWDATA) {
358 long len = obj_ledata_space(seg);
361 len = obj_ledata_space(seg);
365 datacurr->lptr = obj_write_data (datacurr->lptr, ucdata, len);
366 datacurr->nonempty = TRUE;
369 seg->currentpos += len;
371 } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
372 realtype == OUT_REL4ADR) {
373 if (segment == NO_SEG && realtype != OUT_ADDRESS)
374 error(ERR_NONFATAL, "relative call to absolute address not"
375 " supported by OBJ format");
376 if (segment >= SEG_ABS)
377 error(ERR_NONFATAL, "far-absolute relocations not supported"
379 ldata = *(long *)data;
380 if (realtype == OUT_REL2ADR)
382 if (realtype == OUT_REL4ADR)
384 if (obj_ledata_space(seg) < 4 || !obj_fixup_free(seg))
387 datacurr->lptr = obj_write_word (datacurr->lptr, ldata);
389 datacurr->lptr = obj_write_dword (datacurr->lptr, ldata);
390 datacurr->nonempty = TRUE;
391 if (segment != NO_SEG)
392 obj_write_fixup (datacurr, size,
393 (realtype == OUT_REL2ADR ? 0 : 0x4000),
395 (seg->currentpos - datacurr->startpos));
396 seg->currentpos += size;
397 } else if (realtype == OUT_RESERVE) {
399 seg->currentpos += size;
403 static long obj_ledata_space(struct Segment *segto) {
404 if (datacurr && datacurr->seg == segto)
405 return datacurr->ledata + LEDATA_MAX - datacurr->lptr;
410 static int obj_fixup_free(struct Segment *segto) {
411 if (datacurr && datacurr->seg == segto)
412 return (datacurr->fixupp + RECORD_MAX - datacurr->fptr) > 8;
417 static void obj_ledata_new(struct Segment *segto) {
418 datacurr = *datatail = nasm_malloc(sizeof(*datacurr));
419 datacurr->next = NULL;
420 datatail = &datacurr->next;
421 datacurr->nonempty = FALSE;
422 datacurr->lptr = datacurr->ledata;
423 datacurr->fptr = datacurr->fixupp;
424 datacurr->seg = segto;
426 datacurr->letype = LEDATA+1;
428 datacurr->letype = LEDATA;
429 datacurr->startpos = segto->currentpos;
430 datacurr->ftype = FIXUPP;
432 datacurr->lptr = obj_write_index (datacurr->lptr, segto->obj_index);
433 if (datacurr->letype == LEDATA)
434 datacurr->lptr = obj_write_word (datacurr->lptr, segto->currentpos);
436 datacurr->lptr = obj_write_dword (datacurr->lptr, segto->currentpos);
439 static void obj_ledata_commit(void) {
443 static void obj_write_fixup (struct ObjData *data, int bytes,
444 int segrel, long seg, long wrt,
449 struct Segment *s = NULL;
450 struct Group *g = NULL;
452 locat = 0x8000 | segrel | offset;
458 error(ERR_NONFATAL, "OBJ format can only handle 2-byte"
459 " segment base references");
466 data->ftype = FIXUPP+1; /* need new-style FIXUPP record */
469 data->fptr = obj_write_rword (data->fptr, locat);
471 tidx = fidx = -1, method = 0; /* placate optimisers */
474 * See if we can find the segment ID in our segment list. If
475 * so, we have a T4 (LSEG) target.
477 for (s = seghead; s; s = s->next)
481 method = 4, tidx = s->obj_index;
483 for (g = grphead; g; g = g->next)
487 method = 5, tidx = g->obj_index;
490 struct ExtBack *eb = ebhead;
491 while (i > EXT_BLKSIZ) {
499 method = 6, tidx = eb->index[i];
502 "unrecognised segment value in obj_write_fixup");
507 * If no WRT given, assume the natural default, which is method
508 * F5 unless we are doing an OFFSET fixup for a grouped
509 * segment, in which case we require F1 (group).
512 if (!base && s && s->grp)
513 method |= 0x10, fidx = s->grp->obj_index;
515 method |= 0x50, fidx = -1;
518 * See if we can find the WRT-segment ID in our segment
519 * list. If so, we have a F0 (LSEG) frame.
521 for (s = seghead; s; s = s->next)
522 if (s->index == wrt-1)
525 method |= 0x00, fidx = s->obj_index;
527 for (g = grphead; g; g = g->next)
528 if (g->index == wrt-1)
531 method |= 0x10, fidx = g->obj_index;
534 struct ExtBack *eb = ebhead;
535 while (i > EXT_BLKSIZ) {
543 method |= 0x20, fidx = eb->index[i];
546 "unrecognised WRT value in obj_write_fixup");
551 data->fptr = obj_write_byte (data->fptr, method);
553 data->fptr = obj_write_index (data->fptr, fidx);
554 data->fptr = obj_write_index (data->fptr, tidx);
557 static long obj_segment (char *name, int pass, int *bits) {
559 * We call the label manager here to define a name for the new
560 * segment, and when our _own_ label-definition stub gets
561 * called in return, it should register the new segment name
562 * using the pointer it gets passed. That way we save memory,
563 * by sponging off the label manager.
571 int obj_idx, i, attrs, rn_error;
575 * Look for segment attributes.
579 name++; /* hack, but a documented one */
581 while (*p && !isspace(*p))
585 while (*p && isspace(*p))
589 while (*p && !isspace(*p))
593 while (*p && isspace(*p))
601 for (seg = seghead; seg; seg = seg->next) {
603 if (!strcmp(seg->name, name)) {
604 if (attrs > 0 && pass == 1)
605 error(ERR_WARNING, "segment attributes specified on"
606 " redeclaration of segment: ignoring");
615 *segtail = seg = nasm_malloc(sizeof(*seg));
617 segtail = &seg->next;
618 seg->index = (any_segs ? seg_alloc() : first_seg);
619 seg->obj_index = obj_idx;
624 seg->align = 1; /* default */
625 seg->use32 = FALSE; /* default */
626 seg->combine = CMB_PUBLIC; /* default */
627 seg->segclass = seg->overlay = NULL;
629 seg->pubtail = &seg->pubhead;
632 * Process the segment attributes.
640 * `p' contains a segment attribute.
642 if (!nasm_stricmp(p, "private"))
643 seg->combine = CMB_PRIVATE;
644 else if (!nasm_stricmp(p, "public"))
645 seg->combine = CMB_PUBLIC;
646 else if (!nasm_stricmp(p, "common"))
647 seg->combine = CMB_COMMON;
648 else if (!nasm_stricmp(p, "stack"))
649 seg->combine = CMB_STACK;
650 else if (!nasm_stricmp(p, "use16"))
652 else if (!nasm_stricmp(p, "use32"))
654 else if (!nasm_strnicmp(p, "class=", 6))
655 seg->segclass = nasm_strdup(p+6);
656 else if (!nasm_strnicmp(p, "overlay=", 8))
657 seg->overlay = nasm_strdup(p+8);
658 else if (!nasm_strnicmp(p, "align=", 6)) {
659 seg->align = readnum(p+6, &rn_error);
662 error (ERR_NONFATAL, "segment alignment should be"
665 switch ((int) seg->align) {
673 error(ERR_WARNING, "OBJ format does not support alignment"
674 " of 8: rounding up to 16");
680 error(ERR_WARNING, "OBJ format does not support alignment"
681 " of %d: rounding up to 256", seg->align);
685 error(ERR_NONFATAL, "invalid alignment value %d",
690 } else if (!nasm_strnicmp(p, "absolute=", 9)) {
691 seg->align = SEG_ABS + readnum(p+9, &rn_error);
693 error (ERR_NONFATAL, "argument to `absolute' segment"
694 " attribute should be numeric");
698 obj_seg_needs_update = seg;
699 if (seg->align >= SEG_ABS)
700 deflabel (name, NO_SEG, seg->align - SEG_ABS, &of_obj, error);
702 deflabel (name, seg->index+1, 0L, &of_obj, error);
703 obj_seg_needs_update = NULL;
706 * See if this segment is defined in any groups.
708 for (grp = grphead; grp; grp = grp->next) {
709 for (i = grp->nindices; i < grp->nentries; i++) {
710 if (!strcmp(grp->segs[i].name, seg->name)) {
711 nasm_free (grp->segs[i].name);
712 grp->segs[i] = grp->segs[grp->nindices];
713 grp->segs[grp->nindices++].index = seg->obj_index;
715 error(ERR_WARNING, "segment `%s' is already part of"
716 " a group: first one takes precedence",
732 static int obj_directive (char *directive, char *value, int pass) {
733 if (!strcmp(directive, "group")) {
742 q++; /* hack, but a documented one */
743 while (*q && !isspace(*q))
747 while (*q && isspace(*q))
751 error(ERR_NONFATAL, "GROUP directive contains no segments");
756 for (grp = grphead; grp; grp = grp->next) {
758 if (!strcmp(grp->name, value)) {
759 error(ERR_NONFATAL, "group `%s' defined twice", value);
764 *grptail = grp = nasm_malloc(sizeof(*grp));
766 grptail = &grp->next;
767 grp->index = seg_alloc();
768 grp->obj_index = obj_idx;
769 grp->nindices = grp->nentries = 0;
772 obj_grp_needs_update = grp;
773 deflabel (value, grp->index+1, 0L, &of_obj, error);
774 obj_grp_needs_update = NULL;
778 while (*q && !isspace(*q))
782 while (*q && isspace(*q))
786 * Now p contains a segment name. Find it.
788 for (seg = seghead; seg; seg = seg->next)
789 if (!strcmp(seg->name, p))
793 * We have a segment index. Shift a name entry
794 * to the end of the array to make room.
796 grp->segs[grp->nentries++] = grp->segs[grp->nindices];
797 grp->segs[grp->nindices++].index = seg->obj_index;
799 error(ERR_WARNING, "segment `%s' is already part of"
800 " a group: first one takes precedence",
806 * We have an as-yet undefined segment.
807 * Remember its name, for later.
809 grp->segs[grp->nentries++].name = nasm_strdup(p);
815 if (!strcmp(directive, "uppercase")) {
816 obj_uppercase = TRUE;
822 static long obj_segbase (long segment) {
826 * Find the segment in our list.
828 for (seg = seghead; seg; seg = seg->next)
829 if (seg->index == segment-1)
833 return segment; /* not one of ours - leave it alone */
835 if (seg->align >= SEG_ABS)
836 return seg->align; /* absolute segment */
838 return seg->grp->index+1; /* grouped segment */
840 return segment; /* no special treatment */
843 static void obj_filename (char *inname, char *outname, efunc error) {
844 strcpy(obj_infile, inname);
845 standard_extension (inname, outname, ".obj", error);
848 static void obj_write_file (void) {
852 struct External *ext;
853 struct ObjData *data;
854 static char boast[] = "The Netwide Assembler " NASM_VER;
855 int lname_idx, rectype;
858 * Write the THEADR module header.
861 recptr = obj_write_name (recptr, obj_infile);
862 obj_record (THEADR, record, recptr);
865 * Write the NASM boast comment.
868 recptr = obj_write_rword (recptr, 0); /* comment type zero */
869 recptr = obj_write_name (recptr, boast);
870 obj_record (COMENT, record, recptr);
873 * Write the first LNAMES record, containing LNAME one, which
874 * is null. Also initialise the LNAME counter.
877 recptr = obj_write_name (recptr, "");
878 obj_record (LNAMES, record, recptr);
882 * Write the SEGDEF records. Each has an associated LNAMES
885 for (seg = seghead; seg; seg = seg->next) {
886 int new_segdef; /* do we use the newer record type? */
888 int sn, cn, on; /* seg, class, overlay LNAME idx */
890 if (seg->use32 || seg->currentpos >= 0x10000)
896 recptr = obj_write_name (recptr, seg->name);
899 recptr = obj_write_name (recptr, seg->segclass);
904 recptr = obj_write_name (recptr, seg->overlay);
908 obj_record (LNAMES, record, recptr);
910 acbp = (seg->combine << 2); /* C field */
912 if (seg->currentpos >= 0x10000 && !new_segdef)
913 acbp |= 0x02; /* B bit */
916 acbp |= 0x01; /* P bit is Use32 flag */
919 if (seg->align >= SEG_ABS)
921 else if (seg->align >= 256) {
922 if (seg->align > 256)
923 error(ERR_NONFATAL, "segment `%s' requires more alignment"
924 " than OBJ format supports", seg->name);
926 } else if (seg->align >= 16) {
928 } else if (seg->align >= 4) {
930 } else if (seg->align >= 2) {
936 recptr = obj_write_byte (recptr, acbp);
937 if (seg->align & SEG_ABS) {
938 recptr = obj_write_word (recptr, seg->align - SEG_ABS);
939 recptr = obj_write_byte (recptr, 0);
942 recptr = obj_write_dword (recptr, seg->currentpos);
944 recptr = obj_write_word (recptr, seg->currentpos & 0xFFFF);
945 recptr = obj_write_index (recptr, sn);
946 recptr = obj_write_index (recptr, cn);
947 recptr = obj_write_index (recptr, on);
949 obj_record (SEGDEF+1, record, recptr);
951 obj_record (SEGDEF, record, recptr);
955 * Write some LNAMES for the group names. lname_idx is left
956 * alone here - it will catch up when we write the GRPDEFs.
959 for (grp = grphead; grp; grp = grp->next) {
960 recptr = obj_write_name (recptr, grp->name);
961 if (recptr - record > 1024) {
962 obj_record (LNAMES, record, recptr);
967 obj_record (LNAMES, record, recptr);
970 * Write the GRPDEF records.
972 for (grp = grphead; grp; grp = grp->next) {
975 if (grp->nindices != grp->nentries) {
976 for (i = grp->nindices; i < grp->nentries; i++) {
977 error(ERR_NONFATAL, "group `%s' contains undefined segment"
978 " `%s'", grp->name, grp->segs[i].name);
979 nasm_free (grp->segs[i].name);
980 grp->segs[i].name = NULL;
984 recptr = obj_write_index (recptr, lname_idx++);
985 for (i = 0; i < grp->nindices; i++) {
986 recptr = obj_write_byte (recptr, 0xFF);
987 recptr = obj_write_index (recptr, grp->segs[i].index);
989 obj_record (GRPDEF, record, recptr);
993 * Write the PUBDEF records: first the ones in the segments,
994 * then the far-absolutes.
996 for (seg = seghead; seg; seg = seg->next) {
1000 recptr = obj_write_index (recptr, seg->grp ? seg->grp->obj_index : 0);
1001 recptr = obj_write_index (recptr, seg->obj_index);
1007 for (pub = seg->pubhead; pub; pub = pub->next) {
1008 if (recptr - record + strlen(pub->name) > 1024) {
1010 obj_record (rectype, record, recptr);
1012 recptr = obj_write_index (recptr, 0);
1013 recptr = obj_write_index (recptr, seg->obj_index);
1015 recptr = obj_write_name (recptr, pub->name);
1017 recptr = obj_write_dword (recptr, pub->offset);
1019 recptr = obj_write_word (recptr, pub->offset);
1020 recptr = obj_write_index (recptr, 0);
1024 obj_record (rectype, record, recptr);
1026 for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */
1028 recptr = obj_write_index (recptr, 0); /* no group */
1029 recptr = obj_write_index (recptr, 0); /* no segment either */
1030 recptr = obj_write_word (recptr, pub->segment);
1031 recptr = obj_write_name (recptr, pub->name);
1032 recptr = obj_write_word (recptr, pub->offset);
1033 recptr = obj_write_index (recptr, 0);
1034 obj_record (PUBDEF, record, recptr);
1038 * Write the EXTDEF and COMDEF records, in order.
1041 for (ext = exthead; ext; ext = ext->next) {
1042 if (ext->commonsize == 0) {
1043 recptr = obj_write_name (recptr, ext->name);
1044 recptr = obj_write_index (recptr, 0);
1045 if (recptr - record > 1024) {
1046 obj_record (EXTDEF, record, recptr);
1050 if (recptr > record)
1051 obj_record (EXTDEF, record, recptr);
1053 if (ext->commonsize > 0) {
1054 recptr = obj_write_name (recptr, ext->name);
1055 recptr = obj_write_index (recptr, 0);
1056 recptr = obj_write_byte (recptr, 0x61);/* far communal */
1057 recptr = obj_write_value (recptr, 1L);
1058 recptr = obj_write_value (recptr, ext->commonsize);
1059 obj_record (COMDEF, record, recptr);
1060 } else if (ext->commonsize < 0) {
1061 recptr = obj_write_name (recptr, ext->name);
1062 recptr = obj_write_index (recptr, 0);
1063 recptr = obj_write_byte (recptr, 0x62);/* near communal */
1064 recptr = obj_write_value (recptr, ext->commonsize);
1065 obj_record (COMDEF, record, recptr);
1070 if (recptr > record)
1071 obj_record (EXTDEF, record, recptr);
1074 * Write a COMENT record stating that the linker's first pass
1075 * may stop processing at this point.
1078 recptr = obj_write_rword (recptr, 0x40A2);
1079 recptr = obj_write_byte (recptr, 1);
1080 obj_record (COMENT, record, recptr);
1083 * Write the LEDATA/FIXUPP pairs.
1085 for (data = datahead; data; data = data->next) {
1086 if (data->nonempty) {
1087 obj_record (data->letype, data->ledata, data->lptr);
1088 if (data->fptr != data->fixupp)
1089 obj_record (FIXUPP, data->fixupp, data->fptr);
1094 * Write the MODEND module end marker.
1098 if (obj_entry_seg != NO_SEG) {
1099 recptr = obj_write_byte (recptr, 0xC1);
1101 * Find the segment in the segment list.
1103 for (seg = seghead; seg; seg = seg->next) {
1104 if (seg->index == obj_entry_seg) {
1106 recptr = obj_write_byte (recptr, 0x10);
1107 recptr = obj_write_index (recptr, seg->grp->obj_index);
1109 recptr = obj_write_byte (recptr, 0x50);
1111 recptr = obj_write_index (recptr, seg->obj_index);
1114 recptr = obj_write_dword (recptr, obj_entry_ofs);
1116 recptr = obj_write_word (recptr, obj_entry_ofs);
1121 error(ERR_NONFATAL, "entry point is not in this module");
1123 recptr = obj_write_byte (recptr, 0);
1124 obj_record (rectype, record, recptr);
1127 static unsigned char *obj_write_data(unsigned char *ptr,
1128 unsigned char *data, int len) {
1134 static unsigned char *obj_write_byte(unsigned char *ptr, int data) {
1139 static unsigned char *obj_write_word(unsigned char *ptr, int data) {
1140 *ptr++ = data & 0xFF;
1141 *ptr++ = (data >> 8) & 0xFF;
1145 static unsigned char *obj_write_dword(unsigned char *ptr, long data) {
1146 *ptr++ = data & 0xFF;
1147 *ptr++ = (data >> 8) & 0xFF;
1148 *ptr++ = (data >> 16) & 0xFF;
1149 *ptr++ = (data >> 24) & 0xFF;
1153 static unsigned char *obj_write_rword(unsigned char *ptr, int data) {
1154 *ptr++ = (data >> 8) & 0xFF;
1155 *ptr++ = data & 0xFF;
1159 static unsigned char *obj_write_name(unsigned char *ptr, char *data) {
1160 *ptr++ = strlen(data);
1161 if (obj_uppercase) {
1163 *ptr++ = (unsigned char) toupper(*data);
1168 *ptr++ = (unsigned char) *data++;
1173 static unsigned char *obj_write_index(unsigned char *ptr, int data) {
1177 *ptr++ = 0x80 | ((data >> 8) & 0x7F);
1178 *ptr++ = data & 0xFF;
1183 static unsigned char *obj_write_value(unsigned char *ptr,
1184 unsigned long data) {
1187 else if (data <= 0xFFFF) {
1189 *ptr++ = data & 0xFF;
1190 *ptr++ = (data >> 8) & 0xFF;
1191 } else if (data <= 0xFFFFFF) {
1193 *ptr++ = data & 0xFF;
1194 *ptr++ = (data >> 8) & 0xFF;
1195 *ptr++ = (data >> 16) & 0xFF;
1198 *ptr++ = data & 0xFF;
1199 *ptr++ = (data >> 8) & 0xFF;
1200 *ptr++ = (data >> 16) & 0xFF;
1201 *ptr++ = (data >> 24) & 0xFF;
1206 static void obj_record(int type, unsigned char *start, unsigned char *end) {
1207 unsigned long cksum, len;
1212 cksum += (len & 0xFF) + ((len>>8) & 0xFF);
1213 fwriteshort (len, ofp);
1214 fwrite (start, 1, end-start, ofp);
1217 fputc ( (-cksum) & 0xFF, ofp);
1220 struct ofmt of_obj = {
1221 "Microsoft MS-DOS 16-bit object files",