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 while (*p
&& !isspace(*p
))
583 while (*p
&& isspace(*p
))
587 while (*p
&& !isspace(*p
))
591 while (*p
&& isspace(*p
))
599 for (seg
= seghead
; seg
; seg
= seg
->next
) {
601 if (!strcmp(seg
->name
, name
)) {
602 if (attrs
> 0 && pass
== 1)
603 error(ERR_WARNING
, "segment attributes specified on"
604 " redeclaration of segment: ignoring");
613 *segtail
= seg
= nasm_malloc(sizeof(*seg
));
615 segtail
= &seg
->next
;
616 seg
->index
= (any_segs
? seg_alloc() : first_seg
);
617 seg
->obj_index
= obj_idx
;
622 seg
->align
= 1; /* default */
623 seg
->use32
= FALSE
; /* default */
624 seg
->combine
= CMB_PUBLIC
; /* default */
625 seg
->segclass
= seg
->overlay
= NULL
;
627 seg
->pubtail
= &seg
->pubhead
;
630 * Process the segment attributes.
638 * `p' contains a segment attribute.
640 if (!nasm_stricmp(p
, "private"))
641 seg
->combine
= CMB_PRIVATE
;
642 else if (!nasm_stricmp(p
, "public"))
643 seg
->combine
= CMB_PUBLIC
;
644 else if (!nasm_stricmp(p
, "common"))
645 seg
->combine
= CMB_COMMON
;
646 else if (!nasm_stricmp(p
, "stack"))
647 seg
->combine
= CMB_STACK
;
648 else if (!nasm_stricmp(p
, "use16"))
650 else if (!nasm_stricmp(p
, "use32"))
652 else if (!nasm_strnicmp(p
, "class=", 6))
653 seg
->segclass
= nasm_strdup(p
+6);
654 else if (!nasm_strnicmp(p
, "overlay=", 8))
655 seg
->overlay
= nasm_strdup(p
+8);
656 else if (!nasm_strnicmp(p
, "align=", 6)) {
657 seg
->align
= readnum(p
+6, &rn_error
);
660 error (ERR_NONFATAL
, "segment alignment should be"
663 switch ((int) seg
->align
) {
671 error(ERR_WARNING
, "OBJ format does not support alignment"
672 " of 8: rounding up to 16");
678 error(ERR_WARNING
, "OBJ format does not support alignment"
679 " of %d: rounding up to 256", seg
->align
);
683 error(ERR_NONFATAL
, "invalid alignment value %d",
688 } else if (!nasm_strnicmp(p
, "absolute=", 9)) {
689 seg
->align
= SEG_ABS
+ readnum(p
+9, &rn_error
);
691 error (ERR_NONFATAL
, "argument to `absolute' segment"
692 " attribute should be numeric");
696 obj_seg_needs_update
= seg
;
697 if (seg
->align
>= SEG_ABS
)
698 deflabel (name
, NO_SEG
, seg
->align
- SEG_ABS
, &of_obj
, error
);
700 deflabel (name
, seg
->index
+1, 0L, &of_obj
, error
);
701 obj_seg_needs_update
= NULL
;
704 * See if this segment is defined in any groups.
706 for (grp
= grphead
; grp
; grp
= grp
->next
) {
707 for (i
= grp
->nindices
; i
< grp
->nentries
; i
++) {
708 if (!strcmp(grp
->segs
[i
].name
, seg
->name
)) {
709 nasm_free (grp
->segs
[i
].name
);
710 grp
->segs
[i
] = grp
->segs
[grp
->nindices
];
711 grp
->segs
[grp
->nindices
++].index
= seg
->obj_index
;
713 error(ERR_WARNING
, "segment `%s' is already part of"
714 " a group: first one takes precedence",
730 static int obj_directive (char *directive
, char *value
, int pass
) {
731 if (!strcmp(directive
, "group")) {
739 while (*q
&& !isspace(*q
))
743 while (*q
&& isspace(*q
))
747 error(ERR_NONFATAL
, "GROUP directive contains no segments");
752 for (grp
= grphead
; grp
; grp
= grp
->next
) {
754 if (!strcmp(grp
->name
, value
)) {
755 error(ERR_NONFATAL
, "group `%s' defined twice", value
);
760 *grptail
= grp
= nasm_malloc(sizeof(*grp
));
762 grptail
= &grp
->next
;
763 grp
->index
= seg_alloc();
764 grp
->obj_index
= obj_idx
;
765 grp
->nindices
= grp
->nentries
= 0;
768 obj_grp_needs_update
= grp
;
769 deflabel (value
, grp
->index
+1, 0L, &of_obj
, error
);
770 obj_grp_needs_update
= NULL
;
774 while (*q
&& !isspace(*q
))
778 while (*q
&& isspace(*q
))
782 * Now p contains a segment name. Find it.
784 for (seg
= seghead
; seg
; seg
= seg
->next
)
785 if (!strcmp(seg
->name
, p
))
789 * We have a segment index. Shift a name entry
790 * to the end of the array to make room.
792 grp
->segs
[grp
->nentries
++] = grp
->segs
[grp
->nindices
];
793 grp
->segs
[grp
->nindices
++].index
= seg
->obj_index
;
795 error(ERR_WARNING
, "segment `%s' is already part of"
796 " a group: first one takes precedence",
802 * We have an as-yet undefined segment.
803 * Remember its name, for later.
805 grp
->segs
[grp
->nentries
++].name
= nasm_strdup(p
);
811 if (!strcmp(directive
, "uppercase")) {
812 obj_uppercase
= TRUE
;
818 static long obj_segbase (long segment
) {
822 * Find the segment in our list.
824 for (seg
= seghead
; seg
; seg
= seg
->next
)
825 if (seg
->index
== segment
-1)
829 return segment
; /* not one of ours - leave it alone */
831 if (seg
->align
>= SEG_ABS
)
832 return seg
->align
; /* absolute segment */
834 return seg
->grp
->index
+1; /* grouped segment */
836 return segment
; /* no special treatment */
839 static void obj_filename (char *inname
, char *outname
, efunc error
) {
840 strcpy(obj_infile
, inname
);
841 standard_extension (inname
, outname
, ".obj", error
);
844 static void obj_write_file (void) {
848 struct External
*ext
;
849 struct ObjData
*data
;
850 static unsigned char boast
[] = "The Netwide Assembler " NASM_VER
;
851 int lname_idx
, rectype
;
854 * Write the THEADR module header.
857 recptr
= obj_write_name (recptr
, obj_infile
);
858 obj_record (THEADR
, record
, recptr
);
861 * Write the NASM boast comment.
864 recptr
= obj_write_rword (recptr
, 0); /* comment type zero */
865 recptr
= obj_write_data (recptr
, boast
, sizeof(boast
)-1);
866 obj_record (COMENT
, record
, recptr
);
869 * Write the first LNAMES record, containing LNAME one, which
870 * is null. Also initialise the LNAME counter.
873 recptr
= obj_write_name (recptr
, "");
874 obj_record (LNAMES
, record
, recptr
);
878 * Write the SEGDEF records. Each has an associated LNAMES
881 for (seg
= seghead
; seg
; seg
= seg
->next
) {
882 int new_segdef
; /* do we use the newer record type? */
884 int sn
, cn
, on
; /* seg, class, overlay LNAME idx */
886 if (seg
->use32
|| seg
->currentpos
>= 0x10000)
892 recptr
= obj_write_name (recptr
, seg
->name
);
895 recptr
= obj_write_name (recptr
, seg
->segclass
);
900 recptr
= obj_write_name (recptr
, seg
->overlay
);
904 obj_record (LNAMES
, record
, recptr
);
906 acbp
= (seg
->combine
<< 2); /* C field */
908 if (seg
->currentpos
>= 0x10000 && !new_segdef
)
909 acbp
|= 0x02; /* B bit */
912 acbp
|= 0x01; /* P bit is Use32 flag */
915 if (seg
->align
>= SEG_ABS
)
917 else if (seg
->align
>= 256) {
918 if (seg
->align
> 256)
919 error(ERR_NONFATAL
, "segment `%s' requires more alignment"
920 " than OBJ format supports", seg
->name
);
922 } else if (seg
->align
>= 16) {
924 } else if (seg
->align
>= 4) {
926 } else if (seg
->align
>= 2) {
932 recptr
= obj_write_byte (recptr
, acbp
);
933 if (seg
->align
& SEG_ABS
) {
934 recptr
= obj_write_word (recptr
, seg
->align
- SEG_ABS
);
935 recptr
= obj_write_byte (recptr
, 0);
938 recptr
= obj_write_dword (recptr
, seg
->currentpos
);
940 recptr
= obj_write_word (recptr
, seg
->currentpos
& 0xFFFF);
941 recptr
= obj_write_index (recptr
, sn
);
942 recptr
= obj_write_index (recptr
, cn
);
943 recptr
= obj_write_index (recptr
, on
);
945 obj_record (SEGDEF
+1, record
, recptr
);
947 obj_record (SEGDEF
, record
, recptr
);
951 * Write some LNAMES for the group names. lname_idx is left
952 * alone here - it will catch up when we write the GRPDEFs.
955 for (grp
= grphead
; grp
; grp
= grp
->next
) {
956 recptr
= obj_write_name (recptr
, grp
->name
);
957 if (recptr
- record
> 1024) {
958 obj_record (LNAMES
, record
, recptr
);
963 obj_record (LNAMES
, record
, recptr
);
966 * Write the GRPDEF records.
968 for (grp
= grphead
; grp
; grp
= grp
->next
) {
971 if (grp
->nindices
!= grp
->nentries
) {
972 for (i
= grp
->nindices
; i
< grp
->nentries
; i
++) {
973 error(ERR_NONFATAL
, "group `%s' contains undefined segment"
974 " `%s'", grp
->name
, grp
->segs
[i
].name
);
975 nasm_free (grp
->segs
[i
].name
);
976 grp
->segs
[i
].name
= NULL
;
980 recptr
= obj_write_index (recptr
, lname_idx
++);
981 for (i
= 0; i
< grp
->nindices
; i
++) {
982 recptr
= obj_write_byte (recptr
, 0xFF);
983 recptr
= obj_write_index (recptr
, grp
->segs
[i
].index
);
985 obj_record (GRPDEF
, record
, recptr
);
989 * Write the PUBDEF records: first the ones in the segments,
990 * then the far-absolutes.
992 for (seg
= seghead
; seg
; seg
= seg
->next
) {
996 recptr
= obj_write_index (recptr
, seg
->grp
? seg
->grp
->obj_index
: 0);
997 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1003 for (pub
= seg
->pubhead
; pub
; pub
= pub
->next
) {
1004 if (recptr
- record
+ strlen(pub
->name
) > 1024) {
1006 obj_record (rectype
, record
, recptr
);
1008 recptr
= obj_write_index (recptr
, 0);
1009 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1011 recptr
= obj_write_name (recptr
, pub
->name
);
1013 recptr
= obj_write_dword (recptr
, pub
->offset
);
1015 recptr
= obj_write_word (recptr
, pub
->offset
);
1016 recptr
= obj_write_index (recptr
, 0);
1020 obj_record (rectype
, record
, recptr
);
1022 for (pub
= fpubhead
; pub
; pub
= pub
->next
) { /* pub-crawl :-) */
1024 recptr
= obj_write_index (recptr
, 0); /* no group */
1025 recptr
= obj_write_index (recptr
, 0); /* no segment either */
1026 recptr
= obj_write_word (recptr
, pub
->segment
);
1027 recptr
= obj_write_name (recptr
, pub
->name
);
1028 recptr
= obj_write_word (recptr
, pub
->offset
);
1029 recptr
= obj_write_index (recptr
, 0);
1030 obj_record (PUBDEF
, record
, recptr
);
1034 * Write the EXTDEF and COMDEF records, in order.
1037 for (ext
= exthead
; ext
; ext
= ext
->next
) {
1038 if (ext
->commonsize
== 0) {
1039 recptr
= obj_write_name (recptr
, ext
->name
);
1040 recptr
= obj_write_index (recptr
, 0);
1041 if (recptr
- record
> 1024) {
1042 obj_record (EXTDEF
, record
, recptr
);
1046 if (recptr
> record
)
1047 obj_record (EXTDEF
, record
, recptr
);
1049 if (ext
->commonsize
> 0) {
1050 recptr
= obj_write_name (recptr
, ext
->name
);
1051 recptr
= obj_write_index (recptr
, 0);
1052 recptr
= obj_write_byte (recptr
, 0x61);/* far communal */
1053 recptr
= obj_write_value (recptr
, 1L);
1054 recptr
= obj_write_value (recptr
, ext
->commonsize
);
1055 obj_record (COMDEF
, record
, recptr
);
1056 } else if (ext
->commonsize
< 0) {
1057 recptr
= obj_write_name (recptr
, ext
->name
);
1058 recptr
= obj_write_index (recptr
, 0);
1059 recptr
= obj_write_byte (recptr
, 0x62);/* near communal */
1060 recptr
= obj_write_value (recptr
, ext
->commonsize
);
1061 obj_record (COMDEF
, record
, recptr
);
1066 if (recptr
> record
)
1067 obj_record (EXTDEF
, record
, recptr
);
1070 * Write a COMENT record stating that the linker's first pass
1071 * may stop processing at this point.
1074 recptr
= obj_write_rword (recptr
, 0x40A2);
1075 recptr
= obj_write_byte (recptr
, 1);
1076 obj_record (COMENT
, record
, recptr
);
1079 * Write the LEDATA/FIXUPP pairs.
1081 for (data
= datahead
; data
; data
= data
->next
) {
1082 if (data
->nonempty
) {
1083 obj_record (data
->letype
, data
->ledata
, data
->lptr
);
1084 if (data
->fptr
!= data
->fixupp
)
1085 obj_record (FIXUPP
, data
->fixupp
, data
->fptr
);
1090 * Write the MODEND module end marker.
1094 if (obj_entry_seg
!= NO_SEG
) {
1095 recptr
= obj_write_byte (recptr
, 0xC1);
1097 * Find the segment in the segment list.
1099 for (seg
= seghead
; seg
; seg
= seg
->next
) {
1100 if (seg
->index
== obj_entry_seg
) {
1102 recptr
= obj_write_byte (recptr
, 0x10);
1103 recptr
= obj_write_index (recptr
, seg
->grp
->obj_index
);
1105 recptr
= obj_write_byte (recptr
, 0x50);
1107 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1110 recptr
= obj_write_dword (recptr
, obj_entry_ofs
);
1112 recptr
= obj_write_word (recptr
, obj_entry_ofs
);
1117 error(ERR_NONFATAL
, "entry point is not in this module");
1119 recptr
= obj_write_byte (recptr
, 0);
1120 obj_record (rectype
, record
, recptr
);
1123 static unsigned char *obj_write_data(unsigned char *ptr
,
1124 unsigned char *data
, int len
) {
1130 static unsigned char *obj_write_byte(unsigned char *ptr
, int data
) {
1135 static unsigned char *obj_write_word(unsigned char *ptr
, int data
) {
1136 *ptr
++ = data
& 0xFF;
1137 *ptr
++ = (data
>> 8) & 0xFF;
1141 static unsigned char *obj_write_dword(unsigned char *ptr
, long data
) {
1142 *ptr
++ = data
& 0xFF;
1143 *ptr
++ = (data
>> 8) & 0xFF;
1144 *ptr
++ = (data
>> 16) & 0xFF;
1145 *ptr
++ = (data
>> 24) & 0xFF;
1149 static unsigned char *obj_write_rword(unsigned char *ptr
, int data
) {
1150 *ptr
++ = (data
>> 8) & 0xFF;
1151 *ptr
++ = data
& 0xFF;
1155 static unsigned char *obj_write_name(unsigned char *ptr
, char *data
) {
1156 *ptr
++ = strlen(data
);
1157 if (obj_uppercase
) {
1159 *ptr
++ = (unsigned char) toupper(*data
);
1164 *ptr
++ = (unsigned char) *data
++;
1169 static unsigned char *obj_write_index(unsigned char *ptr
, int data
) {
1173 *ptr
++ = 0x80 | ((data
>> 8) & 0x7F);
1174 *ptr
++ = data
& 0xFF;
1179 static unsigned char *obj_write_value(unsigned char *ptr
,
1180 unsigned long data
) {
1183 else if (data
<= 0xFFFF) {
1185 *ptr
++ = data
& 0xFF;
1186 *ptr
++ = (data
>> 8) & 0xFF;
1187 } else if (data
<= 0xFFFFFF) {
1189 *ptr
++ = data
& 0xFF;
1190 *ptr
++ = (data
>> 8) & 0xFF;
1191 *ptr
++ = (data
>> 16) & 0xFF;
1194 *ptr
++ = data
& 0xFF;
1195 *ptr
++ = (data
>> 8) & 0xFF;
1196 *ptr
++ = (data
>> 16) & 0xFF;
1197 *ptr
++ = (data
>> 24) & 0xFF;
1202 static void obj_record(int type
, unsigned char *start
, unsigned char *end
) {
1203 unsigned long cksum
, len
;
1208 cksum
+= (len
& 0xFF) + ((len
>>8) & 0xFF);
1209 fwriteshort (len
, ofp
);
1210 fwrite (start
, 1, end
-start
, ofp
);
1213 fputc ( (-cksum
) & 0xFF, ofp
);
1216 struct ofmt of_obj
= {
1217 "Microsoft MS-DOS 16-bit object files",