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
|| segment
== NO_SEG
) {
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
== NO_SEG
? 0 : 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
>= 0x10000L
)
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
>= 0x10000L
&& !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
<= 0xFFFFFFL
) {
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",