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
, *defgrp
;
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
;
104 enum RecordID
{ /* record ID codes */
106 THEADR
= 0x80, /* module header */
107 COMENT
= 0x88, /* comment record */
109 LNAMES
= 0x96, /* list of names */
111 SEGDEF
= 0x98, /* segment definition */
112 GRPDEF
= 0x9A, /* group definition */
113 EXTDEF
= 0x8C, /* external definition */
114 PUBDEF
= 0x90, /* public definition */
115 COMDEF
= 0xB0, /* common definition */
117 LEDATA
= 0xA0, /* logical enumerated data */
118 FIXUPP
= 0x9C, /* fixups (relocations) */
120 MODEND
= 0x8A /* module end */
123 extern struct ofmt of_obj
;
125 static long obj_ledata_space(struct Segment
*);
126 static int obj_fixup_free(struct Segment
*);
127 static void obj_ledata_new(struct Segment
*);
128 static void obj_ledata_commit(void);
129 static void obj_write_fixup (struct ObjData
*, int, int, long, long, long);
130 static long obj_segment (char *, int, int *);
131 static void obj_write_file(void);
132 static unsigned char *obj_write_data(unsigned char *, unsigned char *, int);
133 static unsigned char *obj_write_byte(unsigned char *, int);
134 static unsigned char *obj_write_word(unsigned char *, int);
135 static unsigned char *obj_write_dword(unsigned char *, long);
136 static unsigned char *obj_write_rword(unsigned char *, int);
137 static unsigned char *obj_write_name(unsigned char *, char *);
138 static unsigned char *obj_write_index(unsigned char *, int);
139 static unsigned char *obj_write_value(unsigned char *, unsigned long);
140 static void obj_record(int, unsigned char *, unsigned char *);
141 static int obj_directive (char *, char *, int);
143 static void obj_init (FILE *fp
, efunc errfunc
, ldfunc ldef
) {
147 first_seg
= seg_alloc();
150 fpubtail
= &fpubhead
;
156 seghead
= obj_seg_needs_update
= NULL
;
158 grphead
= obj_grp_needs_update
= NULL
;
160 datahead
= datacurr
= NULL
;
161 datatail
= &datahead
;
162 obj_entry_seg
= NO_SEG
;
163 obj_uppercase
= FALSE
;
166 obj_directive ("group", "FLAT", 1);
172 static void dos_init (FILE *fp
, efunc errfunc
, ldfunc ldef
) {
174 obj_init (fp
, errfunc
, ldef
);
177 static void os2_init (FILE *fp
, efunc errfunc
, ldfunc ldef
) {
179 obj_init (fp
, errfunc
, ldef
);
182 static void obj_cleanup (void) {
186 struct Segment
*segtmp
= seghead
;
187 seghead
= seghead
->next
;
188 while (segtmp
->pubhead
) {
189 struct Public
*pubtmp
= segtmp
->pubhead
;
190 segtmp
->pubhead
= pubtmp
->next
;
196 struct Public
*pubtmp
= fpubhead
;
197 fpubhead
= fpubhead
->next
;
201 struct External
*exttmp
= exthead
;
202 exthead
= exthead
->next
;
206 struct ExtBack
*ebtmp
= ebhead
;
207 ebhead
= ebhead
->next
;
211 struct Group
*grptmp
= grphead
;
212 grphead
= grphead
->next
;
216 struct ObjData
*datatmp
= datahead
;
217 datahead
= datahead
->next
;
222 static void obj_deflabel (char *name
, long segment
,
223 long offset
, int is_global
) {
225 * We have three cases:
227 * (i) `segment' is a segment-base. If so, set the name field
228 * for the segment or group structure it refers to, and then
231 * (ii) `segment' is one of our segments, or a SEG_ABS segment.
232 * Save the label position for later output of a PUBDEF record.
233 * (Or a MODPUB, if we work out how.)
235 * (iii) `segment' is not one of our segments. Save the label
236 * position for later output of an EXTDEF, and also store a
237 * back-reference so that we can map later references to this
238 * segment number to the external index.
240 struct External
*ext
;
246 * First check for the double-period, signifying something
249 if (name
[0] == '.' && name
[1] == '.' && name
[2] != '@') {
250 if (!strcmp(name
, "..start")) {
251 obj_entry_seg
= segment
;
252 obj_entry_ofs
= offset
;
255 error (ERR_NONFATAL
, "unrecognised special symbol `%s'", name
);
261 if (obj_seg_needs_update
) {
262 obj_seg_needs_update
->name
= name
;
264 } else if (obj_grp_needs_update
) {
265 obj_grp_needs_update
->name
= name
;
268 if (segment
< SEG_ABS
&& segment
!= NO_SEG
&& segment
% 2)
271 if (segment
>= SEG_ABS
|| segment
== NO_SEG
) {
273 * SEG_ABS subcase of (ii).
278 pub
= *fpubtail
= nasm_malloc(sizeof(*pub
));
279 fpubtail
= &pub
->next
;
282 pub
->offset
= offset
;
283 pub
->segment
= (segment
== NO_SEG
? 0 : segment
& ~SEG_ABS
);
289 * If `any_segs' is still FALSE, we might need to define a
290 * default segment, if they're trying to declare a label in
293 if (!any_segs
&& segment
== first_seg
) {
294 int tempint
; /* ignored */
295 if (segment
!= obj_segment("__NASMDEFSEG", 2, &tempint
))
296 error (ERR_PANIC
, "strange segment conditions in OBJ driver");
299 for (seg
= seghead
; seg
; seg
= seg
->next
)
300 if (seg
->index
== segment
) {
302 * Case (ii). Maybe MODPUB someday?
306 pub
= *seg
->pubtail
= nasm_malloc(sizeof(*pub
));
307 seg
->pubtail
= &pub
->next
;
310 pub
->offset
= offset
;
318 ext
= *exttail
= nasm_malloc(sizeof(*ext
));
320 exttail
= &ext
->next
;
323 ext
->commonsize
= offset
;
330 eb
= *ebtail
= nasm_malloc(sizeof(*eb
));
334 while (i
> EXT_BLKSIZ
) {
338 eb
= *ebtail
= nasm_malloc(sizeof(*eb
));
344 eb
->index
[i
] = ++externals
;
347 static void obj_out (long segto
, void *data
, unsigned long type
,
348 long segment
, long wrt
) {
350 unsigned char *ucdata
;
355 * handle absolute-assembly (structure definitions)
357 if (segto
== NO_SEG
) {
358 if ((type
& OUT_TYPMASK
) != OUT_RESERVE
)
359 error (ERR_NONFATAL
, "attempt to assemble code in [ABSOLUTE]"
365 * If `any_segs' is still FALSE, we must define a default
369 int tempint
; /* ignored */
370 if (segto
!= obj_segment("__NASMDEFSEG", 2, &tempint
))
371 error (ERR_PANIC
, "strange segment conditions in OBJ driver");
375 * Find the segment we are targetting.
377 for (seg
= seghead
; seg
; seg
= seg
->next
)
378 if (seg
->index
== segto
)
381 error (ERR_PANIC
, "code directed to nonexistent segment?");
383 size
= type
& OUT_SIZMASK
;
384 realtype
= type
& OUT_TYPMASK
;
385 if (realtype
== OUT_RAWDATA
) {
388 long len
= obj_ledata_space(seg
);
391 len
= obj_ledata_space(seg
);
395 datacurr
->lptr
= obj_write_data (datacurr
->lptr
, ucdata
, len
);
396 datacurr
->nonempty
= TRUE
;
399 seg
->currentpos
+= len
;
401 } else if (realtype
== OUT_ADDRESS
|| realtype
== OUT_REL2ADR
||
402 realtype
== OUT_REL4ADR
) {
403 if (segment
== NO_SEG
&& realtype
!= OUT_ADDRESS
)
404 error(ERR_NONFATAL
, "relative call to absolute address not"
405 " supported by OBJ format");
406 if (segment
>= SEG_ABS
)
407 error(ERR_NONFATAL
, "far-absolute relocations not supported"
409 ldata
= *(long *)data
;
410 if (realtype
== OUT_REL2ADR
)
412 if (realtype
== OUT_REL4ADR
)
414 if (obj_ledata_space(seg
) < 4 || !obj_fixup_free(seg
))
417 datacurr
->lptr
= obj_write_word (datacurr
->lptr
, ldata
);
419 datacurr
->lptr
= obj_write_dword (datacurr
->lptr
, ldata
);
420 datacurr
->nonempty
= TRUE
;
421 if (segment
!= NO_SEG
)
422 obj_write_fixup (datacurr
, size
,
423 (realtype
== OUT_REL2ADR
||
424 realtype
== OUT_REL4ADR
? 0 : 0x4000),
426 (seg
->currentpos
- datacurr
->startpos
));
427 seg
->currentpos
+= size
;
428 } else if (realtype
== OUT_RESERVE
) {
430 seg
->currentpos
+= size
;
434 static long obj_ledata_space(struct Segment
*segto
) {
435 if (datacurr
&& datacurr
->seg
== segto
)
436 return datacurr
->ledata
+ LEDATA_MAX
- datacurr
->lptr
;
441 static int obj_fixup_free(struct Segment
*segto
) {
442 if (datacurr
&& datacurr
->seg
== segto
)
443 return (datacurr
->fixupp
+ RECORD_MAX
- datacurr
->fptr
) > 8;
448 static void obj_ledata_new(struct Segment
*segto
) {
449 datacurr
= *datatail
= nasm_malloc(sizeof(*datacurr
));
450 datacurr
->next
= NULL
;
451 datatail
= &datacurr
->next
;
452 datacurr
->nonempty
= FALSE
;
453 datacurr
->lptr
= datacurr
->ledata
;
454 datacurr
->fptr
= datacurr
->fixupp
;
455 datacurr
->seg
= segto
;
457 datacurr
->letype
= LEDATA
+1;
459 datacurr
->letype
= LEDATA
;
460 datacurr
->startpos
= segto
->currentpos
;
461 datacurr
->ftype
= FIXUPP
;
463 datacurr
->lptr
= obj_write_index (datacurr
->lptr
, segto
->obj_index
);
464 if (datacurr
->letype
== LEDATA
)
465 datacurr
->lptr
= obj_write_word (datacurr
->lptr
, segto
->currentpos
);
467 datacurr
->lptr
= obj_write_dword (datacurr
->lptr
, segto
->currentpos
);
470 static void obj_ledata_commit(void) {
474 static void obj_write_fixup (struct ObjData
*data
, int bytes
,
475 int segrel
, long seg
, long wrt
,
480 struct Segment
*s
= NULL
;
481 struct Group
*g
= NULL
;
483 locat
= 0x8000 | segrel
| offset
;
489 error(ERR_NONFATAL
, "OBJ format can only handle 2-byte"
490 " segment base references");
497 data
->ftype
= FIXUPP
+1; /* need new-style FIXUPP record */
500 data
->fptr
= obj_write_rword (data
->fptr
, locat
);
502 tidx
= fidx
= -1, method
= 0; /* placate optimisers */
505 * See if we can find the segment ID in our segment list. If
506 * so, we have a T4 (LSEG) target.
508 for (s
= seghead
; s
; s
= s
->next
)
512 method
= 4, tidx
= s
->obj_index
;
514 for (g
= grphead
; g
; g
= g
->next
)
518 method
= 5, tidx
= g
->obj_index
;
521 struct ExtBack
*eb
= ebhead
;
522 while (i
> EXT_BLKSIZ
) {
530 method
= 6, tidx
= eb
->index
[i
];
533 "unrecognised segment value in obj_write_fixup");
538 * If no WRT given, assume the natural default, which is method
539 * F5 unless we are doing an OFFSET fixup for a grouped
540 * segment, in which case we require F1 (group). Oh, and in
541 * OS/2 mode we're in F1 (group) on `defgrp' _always_, by
546 method
|= 0x10, fidx
= defgrp
->obj_index
;
547 else if (!base
&& s
&& s
->grp
)
548 method
|= 0x10, fidx
= s
->grp
->obj_index
;
550 method
|= 0x50, fidx
= -1;
553 * See if we can find the WRT-segment ID in our segment
554 * list. If so, we have a F0 (LSEG) frame.
556 for (s
= seghead
; s
; s
= s
->next
)
557 if (s
->index
== wrt
-1)
560 method
|= 0x00, fidx
= s
->obj_index
;
562 for (g
= grphead
; g
; g
= g
->next
)
563 if (g
->index
== wrt
-1)
566 method
|= 0x10, fidx
= g
->obj_index
;
569 struct ExtBack
*eb
= ebhead
;
570 while (i
> EXT_BLKSIZ
) {
578 method
|= 0x20, fidx
= eb
->index
[i
];
581 "unrecognised WRT value in obj_write_fixup");
586 data
->fptr
= obj_write_byte (data
->fptr
, method
);
588 data
->fptr
= obj_write_index (data
->fptr
, fidx
);
589 data
->fptr
= obj_write_index (data
->fptr
, tidx
);
592 static long obj_segment (char *name
, int pass
, int *bits
) {
594 * We call the label manager here to define a name for the new
595 * segment, and when our _own_ label-definition stub gets
596 * called in return, it should register the new segment name
597 * using the pointer it gets passed. That way we save memory,
598 * by sponging off the label manager.
606 int obj_idx
, i
, attrs
, rn_error
;
610 * Look for segment attributes.
614 name
++; /* hack, but a documented one */
616 while (*p
&& !isspace(*p
))
620 while (*p
&& isspace(*p
))
624 while (*p
&& !isspace(*p
))
628 while (*p
&& isspace(*p
))
636 for (seg
= seghead
; seg
; seg
= seg
->next
) {
638 if (!strcmp(seg
->name
, name
)) {
639 if (attrs
> 0 && pass
== 1)
640 error(ERR_WARNING
, "segment attributes specified on"
641 " redeclaration of segment: ignoring");
650 *segtail
= seg
= nasm_malloc(sizeof(*seg
));
652 segtail
= &seg
->next
;
653 seg
->index
= (any_segs
? seg_alloc() : first_seg
);
654 seg
->obj_index
= obj_idx
;
659 seg
->align
= 1; /* default */
660 seg
->use32
= FALSE
; /* default */
661 seg
->combine
= CMB_PUBLIC
; /* default */
662 seg
->segclass
= seg
->overlay
= NULL
;
664 seg
->pubtail
= &seg
->pubhead
;
667 * Process the segment attributes.
675 * `p' contains a segment attribute.
677 if (!nasm_stricmp(p
, "private"))
678 seg
->combine
= CMB_PRIVATE
;
679 else if (!nasm_stricmp(p
, "public"))
680 seg
->combine
= CMB_PUBLIC
;
681 else if (!nasm_stricmp(p
, "common"))
682 seg
->combine
= CMB_COMMON
;
683 else if (!nasm_stricmp(p
, "stack"))
684 seg
->combine
= CMB_STACK
;
685 else if (!nasm_stricmp(p
, "use16"))
687 else if (!nasm_stricmp(p
, "use32"))
689 else if (!nasm_strnicmp(p
, "class=", 6))
690 seg
->segclass
= nasm_strdup(p
+6);
691 else if (!nasm_strnicmp(p
, "overlay=", 8))
692 seg
->overlay
= nasm_strdup(p
+8);
693 else if (!nasm_strnicmp(p
, "align=", 6)) {
694 seg
->align
= readnum(p
+6, &rn_error
);
697 error (ERR_NONFATAL
, "segment alignment should be"
700 switch ((int) seg
->align
) {
708 error(ERR_WARNING
, "OBJ format does not support alignment"
709 " of 8: rounding up to 16");
715 error(ERR_WARNING
, "OBJ format does not support alignment"
716 " of %d: rounding up to 256", seg
->align
);
720 error(ERR_NONFATAL
, "invalid alignment value %d",
725 } else if (!nasm_strnicmp(p
, "absolute=", 9)) {
726 seg
->align
= SEG_ABS
+ readnum(p
+9, &rn_error
);
728 error (ERR_NONFATAL
, "argument to `absolute' segment"
729 " attribute should be numeric");
733 obj_seg_needs_update
= seg
;
734 if (seg
->align
>= SEG_ABS
)
735 deflabel (name
, NO_SEG
, seg
->align
- SEG_ABS
, &of_obj
, error
);
737 deflabel (name
, seg
->index
+1, 0L, &of_obj
, error
);
738 obj_seg_needs_update
= NULL
;
741 * See if this segment is defined in any groups.
743 for (grp
= grphead
; grp
; grp
= grp
->next
) {
744 for (i
= grp
->nindices
; i
< grp
->nentries
; i
++) {
745 if (!strcmp(grp
->segs
[i
].name
, seg
->name
)) {
746 nasm_free (grp
->segs
[i
].name
);
747 grp
->segs
[i
] = grp
->segs
[grp
->nindices
];
748 grp
->segs
[grp
->nindices
++].index
= seg
->obj_index
;
750 error(ERR_WARNING
, "segment `%s' is already part of"
751 " a group: first one takes precedence",
767 static int obj_directive (char *directive
, char *value
, int pass
) {
768 if (!strcmp(directive
, "group")) {
777 q
++; /* hack, but a documented one */
779 while (*q
&& !isspace(*q
))
783 while (*q
&& isspace(*q
))
787 * Here we used to sanity-check the group directive to
788 * ensure nobody tried to declare a group containing no
789 * segments. However, OS/2 does this as standard
790 * practice, so the sanity check has been removed.
793 * error(ERR_NONFATAL,"GROUP directive contains no segments");
799 for (grp
= grphead
; grp
; grp
= grp
->next
) {
801 if (!strcmp(grp
->name
, v
)) {
802 error(ERR_NONFATAL
, "group `%s' defined twice", v
);
807 *grptail
= grp
= nasm_malloc(sizeof(*grp
));
809 grptail
= &grp
->next
;
810 grp
->index
= seg_alloc();
811 grp
->obj_index
= obj_idx
;
812 grp
->nindices
= grp
->nentries
= 0;
815 obj_grp_needs_update
= grp
;
816 deflabel (v
, grp
->index
+1, 0L, &of_obj
, error
);
817 obj_grp_needs_update
= NULL
;
821 while (*q
&& !isspace(*q
))
825 while (*q
&& isspace(*q
))
829 * Now p contains a segment name. Find it.
831 for (seg
= seghead
; seg
; seg
= seg
->next
)
832 if (!strcmp(seg
->name
, p
))
836 * We have a segment index. Shift a name entry
837 * to the end of the array to make room.
839 grp
->segs
[grp
->nentries
++] = grp
->segs
[grp
->nindices
];
840 grp
->segs
[grp
->nindices
++].index
= seg
->obj_index
;
842 error(ERR_WARNING
, "segment `%s' is already part of"
843 " a group: first one takes precedence",
849 * We have an as-yet undefined segment.
850 * Remember its name, for later.
852 grp
->segs
[grp
->nentries
++].name
= nasm_strdup(p
);
858 if (!strcmp(directive
, "uppercase")) {
859 obj_uppercase
= TRUE
;
865 static long obj_segbase (long segment
) {
869 * Find the segment in our list.
871 for (seg
= seghead
; seg
; seg
= seg
->next
)
872 if (seg
->index
== segment
-1)
876 return segment
; /* not one of ours - leave it alone */
878 if (seg
->align
>= SEG_ABS
)
879 return seg
->align
; /* absolute segment */
881 return seg
->grp
->index
+1; /* grouped segment */
883 return segment
; /* no special treatment */
886 static void obj_filename (char *inname
, char *outname
, efunc error
) {
887 strcpy(obj_infile
, inname
);
888 standard_extension (inname
, outname
, ".obj", error
);
891 static void obj_write_file (void) {
895 struct External
*ext
;
896 struct ObjData
*data
;
897 static char boast
[] = "The Netwide Assembler " NASM_VER
;
898 int lname_idx
, rectype
;
901 * Write the THEADR module header.
904 recptr
= obj_write_name (recptr
, obj_infile
);
905 obj_record (THEADR
, record
, recptr
);
908 * Write the NASM boast comment.
911 recptr
= obj_write_rword (recptr
, 0); /* comment type zero */
912 recptr
= obj_write_name (recptr
, boast
);
913 obj_record (COMENT
, record
, recptr
);
916 * Write the first LNAMES record, containing LNAME one, which
917 * is null. Also initialise the LNAME counter.
920 recptr
= obj_write_name (recptr
, "");
921 obj_record (LNAMES
, record
, recptr
);
925 * Write the SEGDEF records. Each has an associated LNAMES
928 for (seg
= seghead
; seg
; seg
= seg
->next
) {
929 int new_segdef
; /* do we use the newer record type? */
931 int sn
, cn
, on
; /* seg, class, overlay LNAME idx */
933 if (seg
->use32
|| seg
->currentpos
>= 0x10000L
)
939 recptr
= obj_write_name (recptr
, seg
->name
);
942 recptr
= obj_write_name (recptr
, seg
->segclass
);
947 recptr
= obj_write_name (recptr
, seg
->overlay
);
951 obj_record (LNAMES
, record
, recptr
);
953 acbp
= (seg
->combine
<< 2); /* C field */
955 if (seg
->currentpos
>= 0x10000L
&& !new_segdef
)
956 acbp
|= 0x02; /* B bit */
959 acbp
|= 0x01; /* P bit is Use32 flag */
962 if (seg
->align
>= SEG_ABS
)
964 else if (seg
->align
>= 256) {
965 if (seg
->align
> 256)
966 error(ERR_NONFATAL
, "segment `%s' requires more alignment"
967 " than OBJ format supports", seg
->name
);
969 } else if (seg
->align
>= 16) {
971 } else if (seg
->align
>= 4) {
973 } else if (seg
->align
>= 2) {
979 recptr
= obj_write_byte (recptr
, acbp
);
980 if (seg
->align
& SEG_ABS
) {
981 recptr
= obj_write_word (recptr
, seg
->align
- SEG_ABS
);
982 recptr
= obj_write_byte (recptr
, 0);
985 recptr
= obj_write_dword (recptr
, seg
->currentpos
);
987 recptr
= obj_write_word (recptr
, seg
->currentpos
& 0xFFFF);
988 recptr
= obj_write_index (recptr
, sn
);
989 recptr
= obj_write_index (recptr
, cn
);
990 recptr
= obj_write_index (recptr
, on
);
992 obj_record (SEGDEF
+1, record
, recptr
);
994 obj_record (SEGDEF
, record
, recptr
);
998 * Write some LNAMES for the group names. lname_idx is left
999 * alone here - it will catch up when we write the GRPDEFs.
1002 for (grp
= grphead
; grp
; grp
= grp
->next
) {
1003 recptr
= obj_write_name (recptr
, grp
->name
);
1004 if (recptr
- record
> 1024) {
1005 obj_record (LNAMES
, record
, recptr
);
1009 if (recptr
> record
)
1010 obj_record (LNAMES
, record
, recptr
);
1013 * Write the GRPDEF records.
1015 for (grp
= grphead
; grp
; grp
= grp
->next
) {
1018 if (grp
->nindices
!= grp
->nentries
) {
1019 for (i
= grp
->nindices
; i
< grp
->nentries
; i
++) {
1020 error(ERR_NONFATAL
, "group `%s' contains undefined segment"
1021 " `%s'", grp
->name
, grp
->segs
[i
].name
);
1022 nasm_free (grp
->segs
[i
].name
);
1023 grp
->segs
[i
].name
= NULL
;
1027 recptr
= obj_write_index (recptr
, lname_idx
++);
1028 for (i
= 0; i
< grp
->nindices
; i
++) {
1029 recptr
= obj_write_byte (recptr
, 0xFF);
1030 recptr
= obj_write_index (recptr
, grp
->segs
[i
].index
);
1032 obj_record (GRPDEF
, record
, recptr
);
1036 * Write the PUBDEF records: first the ones in the segments,
1037 * then the far-absolutes.
1039 for (seg
= seghead
; seg
; seg
= seg
->next
) {
1043 recptr
= obj_write_index (recptr
, seg
->grp
? seg
->grp
->obj_index
: 0);
1044 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1050 for (pub
= seg
->pubhead
; pub
; pub
= pub
->next
) {
1051 if (recptr
- record
+ strlen(pub
->name
) > 1024) {
1053 obj_record (rectype
, record
, recptr
);
1055 recptr
= obj_write_index (recptr
, 0);
1056 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1058 recptr
= obj_write_name (recptr
, pub
->name
);
1060 recptr
= obj_write_dword (recptr
, pub
->offset
);
1062 recptr
= obj_write_word (recptr
, pub
->offset
);
1063 recptr
= obj_write_index (recptr
, 0);
1067 obj_record (rectype
, record
, recptr
);
1069 for (pub
= fpubhead
; pub
; pub
= pub
->next
) { /* pub-crawl :-) */
1071 recptr
= obj_write_index (recptr
, 0); /* no group */
1072 recptr
= obj_write_index (recptr
, 0); /* no segment either */
1073 recptr
= obj_write_word (recptr
, pub
->segment
);
1074 recptr
= obj_write_name (recptr
, pub
->name
);
1075 recptr
= obj_write_word (recptr
, pub
->offset
);
1076 recptr
= obj_write_index (recptr
, 0);
1077 obj_record (PUBDEF
, record
, recptr
);
1081 * Write the EXTDEF and COMDEF records, in order.
1084 for (ext
= exthead
; ext
; ext
= ext
->next
) {
1085 if (ext
->commonsize
== 0) {
1086 recptr
= obj_write_name (recptr
, ext
->name
);
1087 recptr
= obj_write_index (recptr
, 0);
1088 if (recptr
- record
> 1024) {
1089 obj_record (EXTDEF
, record
, recptr
);
1093 if (recptr
> record
)
1094 obj_record (EXTDEF
, record
, recptr
);
1096 if (ext
->commonsize
> 0) {
1097 recptr
= obj_write_name (recptr
, ext
->name
);
1098 recptr
= obj_write_index (recptr
, 0);
1099 recptr
= obj_write_byte (recptr
, 0x61);/* far communal */
1100 recptr
= obj_write_value (recptr
, 1L);
1101 recptr
= obj_write_value (recptr
, ext
->commonsize
);
1102 obj_record (COMDEF
, record
, recptr
);
1103 } else if (ext
->commonsize
< 0) {
1104 recptr
= obj_write_name (recptr
, ext
->name
);
1105 recptr
= obj_write_index (recptr
, 0);
1106 recptr
= obj_write_byte (recptr
, 0x62);/* near communal */
1107 recptr
= obj_write_value (recptr
, ext
->commonsize
);
1108 obj_record (COMDEF
, record
, recptr
);
1113 if (recptr
> record
)
1114 obj_record (EXTDEF
, record
, recptr
);
1117 * Write a COMENT record stating that the linker's first pass
1118 * may stop processing at this point. Exception is if we're in
1119 * OS/2 mode and our MODEND record specifies a start point, in
1120 * which case, according to the OS/2 documentation, this COMENT
1121 * should be omitted.
1123 if (!os2
|| obj_entry_seg
== NO_SEG
) {
1125 recptr
= obj_write_rword (recptr
, 0x40A2);
1126 recptr
= obj_write_byte (recptr
, 1);
1127 obj_record (COMENT
, record
, recptr
);
1131 * Write the LEDATA/FIXUPP pairs.
1133 for (data
= datahead
; data
; data
= data
->next
) {
1134 if (data
->nonempty
) {
1135 obj_record (data
->letype
, data
->ledata
, data
->lptr
);
1136 if (data
->fptr
!= data
->fixupp
)
1137 obj_record (data
->ftype
, data
->fixupp
, data
->fptr
);
1142 * Write the MODEND module end marker.
1146 if (obj_entry_seg
!= NO_SEG
) {
1147 recptr
= obj_write_byte (recptr
, 0xC1);
1149 * Find the segment in the segment list.
1151 for (seg
= seghead
; seg
; seg
= seg
->next
) {
1152 if (seg
->index
== obj_entry_seg
) {
1154 recptr
= obj_write_byte (recptr
, 0x10);
1155 recptr
= obj_write_index (recptr
, seg
->grp
->obj_index
);
1157 recptr
= obj_write_byte (recptr
, 0x50);
1159 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1162 recptr
= obj_write_dword (recptr
, obj_entry_ofs
);
1164 recptr
= obj_write_word (recptr
, obj_entry_ofs
);
1169 error(ERR_NONFATAL
, "entry point is not in this module");
1171 recptr
= obj_write_byte (recptr
, 0);
1172 obj_record (rectype
, record
, recptr
);
1175 static unsigned char *obj_write_data(unsigned char *ptr
,
1176 unsigned char *data
, int len
) {
1182 static unsigned char *obj_write_byte(unsigned char *ptr
, int data
) {
1187 static unsigned char *obj_write_word(unsigned char *ptr
, int data
) {
1188 *ptr
++ = data
& 0xFF;
1189 *ptr
++ = (data
>> 8) & 0xFF;
1193 static unsigned char *obj_write_dword(unsigned char *ptr
, long data
) {
1194 *ptr
++ = data
& 0xFF;
1195 *ptr
++ = (data
>> 8) & 0xFF;
1196 *ptr
++ = (data
>> 16) & 0xFF;
1197 *ptr
++ = (data
>> 24) & 0xFF;
1201 static unsigned char *obj_write_rword(unsigned char *ptr
, int data
) {
1202 *ptr
++ = (data
>> 8) & 0xFF;
1203 *ptr
++ = data
& 0xFF;
1207 static unsigned char *obj_write_name(unsigned char *ptr
, char *data
) {
1208 *ptr
++ = strlen(data
);
1209 if (obj_uppercase
) {
1211 *ptr
++ = (unsigned char) toupper(*data
);
1216 *ptr
++ = (unsigned char) *data
++;
1221 static unsigned char *obj_write_index(unsigned char *ptr
, int data
) {
1225 *ptr
++ = 0x80 | ((data
>> 8) & 0x7F);
1226 *ptr
++ = data
& 0xFF;
1231 static unsigned char *obj_write_value(unsigned char *ptr
,
1232 unsigned long data
) {
1235 else if (data
<= 0xFFFF) {
1237 *ptr
++ = data
& 0xFF;
1238 *ptr
++ = (data
>> 8) & 0xFF;
1239 } else if (data
<= 0xFFFFFFL
) {
1241 *ptr
++ = data
& 0xFF;
1242 *ptr
++ = (data
>> 8) & 0xFF;
1243 *ptr
++ = (data
>> 16) & 0xFF;
1246 *ptr
++ = data
& 0xFF;
1247 *ptr
++ = (data
>> 8) & 0xFF;
1248 *ptr
++ = (data
>> 16) & 0xFF;
1249 *ptr
++ = (data
>> 24) & 0xFF;
1254 static void obj_record(int type
, unsigned char *start
, unsigned char *end
) {
1255 unsigned long cksum
, len
;
1260 cksum
+= (len
& 0xFF) + ((len
>>8) & 0xFF);
1261 fwriteshort (len
, ofp
);
1262 fwrite (start
, 1, end
-start
, ofp
);
1265 fputc ( (-cksum
) & 0xFF, ofp
);
1268 struct ofmt of_obj
= {
1269 "Microsoft MS-DOS 16-bit OMF object files",
1281 struct ofmt of_os2
= {
1282 "OS/2 object files (variant of OMF)",