]>
git.saurik.com Git - apple/boot.git/blob - i386/nasm/outobj.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* outobj.c output routines for the Netwide Assembler to produce
26 * Microsoft 16-bit .OBJ object files
28 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
29 * Julian Hall. All rights reserved. The software is
30 * redistributable under the licence given in the file "Licence"
31 * distributed in the NASM archive.
45 static char obj_infile
[FILENAME_MAX
];
46 static int obj_uppercase
;
49 static evalfunc evaluate
;
50 static ldfunc deflabel
;
52 static long first_seg
;
55 #define LEDATA_MAX 1024 /* maximum size of LEDATA record */
56 #define RECORD_MAX 1024 /* maximum size of _any_ record */
57 #define GROUP_MAX 256 /* we won't _realistically_ have more
58 * than this many segs in a group */
59 #define EXT_BLKSIZ 256 /* block size for externals list */
61 static unsigned char record
[RECORD_MAX
], *recptr
;
63 struct Segment
; /* need to know these structs exist */
66 static struct Public
{
70 long segment
; /* only if it's far-absolute */
71 } *fpubhead
, **fpubtail
;
73 static struct External
{
74 struct External
*next
;
77 long commonelem
; /* element size if FAR, else zero */
78 int index
; /* OBJ-file external index */
80 DEFWRT_NONE
, /* no unusual default-WRT */
81 DEFWRT_STRING
, /* a string we don't yet understand */
82 DEFWRT_SEGMENT
, /* a segment */
83 DEFWRT_GROUP
/* a group */
90 struct External
*next_dws
; /* next with DEFWRT_STRING */
91 } *exthead
, **exttail
, *dws
;
95 static struct ExtBack
{
97 struct External
*exts
[EXT_BLKSIZ
];
100 static struct Segment
{
101 struct Segment
*next
;
102 long index
; /* the NASM segment id */
103 long obj_index
; /* the OBJ-file segment index */
104 struct Group
*grp
; /* the group it belongs to */
106 long align
; /* can be SEG_ABS + absolute addr */
113 long use32
; /* is this segment 32-bit? */
114 struct Public
*pubhead
, **pubtail
;
116 char *segclass
, *overlay
; /* `class' is a C++ keyword :-) */
117 } *seghead
, **segtail
, *obj_seg_needs_update
;
119 static struct Group
{
122 long index
; /* NASM segment id */
123 long obj_index
; /* OBJ-file group index */
124 long nentries
; /* number of elements... */
125 long nindices
; /* ...and number of index elts... */
129 } segs
[GROUP_MAX
]; /* ...in this */
130 } *grphead
, **grptail
, *obj_grp_needs_update
;
132 static struct ObjData
{
133 struct ObjData
*next
;
138 unsigned char ledata
[LEDATA_MAX
], *lptr
;
139 unsigned char fixupp
[RECORD_MAX
], *fptr
;
140 } *datahead
, *datacurr
, **datatail
;
142 static struct ImpDef
{
146 unsigned int impindex
;
148 } *imphead
, **imptail
;
150 static struct ExpDef
{
154 unsigned int ordinal
;
156 } *exphead
, **exptail
;
158 #define EXPDEF_FLAG_ORDINAL 0x80
159 #define EXPDEF_FLAG_RESIDENT 0x40
160 #define EXPDEF_FLAG_NODATA 0x20
161 #define EXPDEF_MASK_PARMCNT 0x1F
163 static long obj_entry_seg
, obj_entry_ofs
;
165 enum RecordID
{ /* record ID codes */
167 THEADR
= 0x80, /* module header */
168 COMENT
= 0x88, /* comment record */
170 LNAMES
= 0x96, /* list of names */
172 SEGDEF
= 0x98, /* segment definition */
173 GRPDEF
= 0x9A, /* group definition */
174 EXTDEF
= 0x8C, /* external definition */
175 PUBDEF
= 0x90, /* public definition */
176 COMDEF
= 0xB0, /* common definition */
178 LEDATA
= 0xA0, /* logical enumerated data */
179 FIXUPP
= 0x9C, /* fixups (relocations) */
181 MODEND
= 0x8A /* module end */
184 extern struct ofmt of_obj
;
186 static long obj_ledata_space(struct Segment
*);
187 static int obj_fixup_free(struct Segment
*);
188 static void obj_ledata_new(struct Segment
*);
189 static void obj_ledata_commit(void);
190 static void obj_write_fixup (struct ObjData
*, int, int, long, long, long);
191 static long obj_segment (char *, int, int *);
192 static void obj_write_file(void);
193 static unsigned char *obj_write_data(unsigned char *, unsigned char *, int);
194 static unsigned char *obj_write_byte(unsigned char *, int);
195 static unsigned char *obj_write_word(unsigned char *, int);
196 static unsigned char *obj_write_dword(unsigned char *, long);
197 static unsigned char *obj_write_rword(unsigned char *, int);
198 static unsigned char *obj_write_name(unsigned char *, char *);
199 static unsigned char *obj_write_index(unsigned char *, int);
200 static unsigned char *obj_write_value(unsigned char *, unsigned long);
201 static void obj_record(int, unsigned char *, unsigned char *);
202 static int obj_directive (char *, char *, int);
204 static void obj_init (FILE *fp
, efunc errfunc
, ldfunc ldef
, evalfunc eval
) {
209 first_seg
= seg_alloc();
212 fpubtail
= &fpubhead
;
223 seghead
= obj_seg_needs_update
= NULL
;
225 grphead
= obj_grp_needs_update
= NULL
;
227 datahead
= datacurr
= NULL
;
228 datatail
= &datahead
;
229 obj_entry_seg
= NO_SEG
;
230 obj_uppercase
= FALSE
;
233 static void obj_cleanup (void) {
237 struct Segment
*segtmp
= seghead
;
238 seghead
= seghead
->next
;
239 while (segtmp
->pubhead
) {
240 struct Public
*pubtmp
= segtmp
->pubhead
;
241 segtmp
->pubhead
= pubtmp
->next
;
242 nasm_free (pubtmp
->name
);
248 struct Public
*pubtmp
= fpubhead
;
249 fpubhead
= fpubhead
->next
;
250 nasm_free (pubtmp
->name
);
254 struct External
*exttmp
= exthead
;
255 exthead
= exthead
->next
;
259 struct ImpDef
*imptmp
= imphead
;
260 imphead
= imphead
->next
;
261 nasm_free (imptmp
->extname
);
262 nasm_free (imptmp
->libname
);
263 nasm_free (imptmp
->impname
); /* nasm_free won't mind if it's NULL */
267 struct ExpDef
*exptmp
= exphead
;
268 exphead
= exphead
->next
;
269 nasm_free (exptmp
->extname
);
270 nasm_free (exptmp
->intname
);
274 struct ExtBack
*ebtmp
= ebhead
;
275 ebhead
= ebhead
->next
;
279 struct Group
*grptmp
= grphead
;
280 grphead
= grphead
->next
;
284 struct ObjData
*datatmp
= datahead
;
285 datahead
= datahead
->next
;
290 static void obj_ext_set_defwrt (struct External
*ext
, char *id
) {
294 for (seg
= seghead
; seg
; seg
= seg
->next
)
295 if (!strcmp(seg
->name
, id
)) {
296 ext
->defwrt_type
= DEFWRT_SEGMENT
;
297 ext
->defwrt_ptr
.seg
= seg
;
302 for (grp
= grphead
; grp
; grp
= grp
->next
)
303 if (!strcmp(grp
->name
, id
)) {
304 ext
->defwrt_type
= DEFWRT_GROUP
;
305 ext
->defwrt_ptr
.grp
= grp
;
310 ext
->defwrt_type
= DEFWRT_STRING
;
311 ext
->defwrt_ptr
.string
= id
;
316 static void obj_deflabel (char *name
, long segment
,
317 long offset
, int is_global
, char *special
) {
319 * We have three cases:
321 * (i) `segment' is a segment-base. If so, set the name field
322 * for the segment or group structure it refers to, and then
325 * (ii) `segment' is one of our segments, or a SEG_ABS segment.
326 * Save the label position for later output of a PUBDEF record.
327 * (Or a MODPUB, if we work out how.)
329 * (iii) `segment' is not one of our segments. Save the label
330 * position for later output of an EXTDEF, and also store a
331 * back-reference so that we can map later references to this
332 * segment number to the external index.
334 struct External
*ext
;
338 int used_special
= FALSE
; /* have we used the special text? */
341 * If it's a special-retry from pass two, discard it.
347 * First check for the double-period, signifying something
350 if (name
[0] == '.' && name
[1] == '.' && name
[2] != '@') {
351 if (!strcmp(name
, "..start")) {
352 obj_entry_seg
= segment
;
353 obj_entry_ofs
= offset
;
356 error (ERR_NONFATAL
, "unrecognised special symbol `%s'", name
);
362 if (obj_seg_needs_update
) {
363 obj_seg_needs_update
->name
= name
;
365 } else if (obj_grp_needs_update
) {
366 obj_grp_needs_update
->name
= name
;
369 if (segment
< SEG_ABS
&& segment
!= NO_SEG
&& segment
% 2)
372 if (segment
>= SEG_ABS
|| segment
== NO_SEG
) {
374 * SEG_ABS subcase of (ii).
379 pub
= *fpubtail
= nasm_malloc(sizeof(*pub
));
380 fpubtail
= &pub
->next
;
382 pub
->name
= nasm_strdup(name
);
383 pub
->offset
= offset
;
384 pub
->segment
= (segment
== NO_SEG
? 0 : segment
& ~SEG_ABS
);
387 error(ERR_NONFATAL
, "OBJ supports no special symbol features"
388 " for this symbol type");
393 * If `any_segs' is still FALSE, we might need to define a
394 * default segment, if they're trying to declare a label in
397 if (!any_segs
&& segment
== first_seg
) {
398 int tempint
; /* ignored */
399 if (segment
!= obj_segment("__NASMDEFSEG", 2, &tempint
))
400 error (ERR_PANIC
, "strange segment conditions in OBJ driver");
403 for (seg
= seghead
; seg
; seg
= seg
->next
)
404 if (seg
->index
== segment
) {
406 * Case (ii). Maybe MODPUB someday?
410 pub
= *seg
->pubtail
= nasm_malloc(sizeof(*pub
));
411 seg
->pubtail
= &pub
->next
;
413 pub
->name
= nasm_strdup(name
);
414 pub
->offset
= offset
;
417 error(ERR_NONFATAL
, "OBJ supports no special symbol features"
418 " for this symbol type");
425 ext
= *exttail
= nasm_malloc(sizeof(*ext
));
427 exttail
= &ext
->next
;
429 ext
->defwrt_type
= DEFWRT_NONE
;
430 if (is_global
== 2) {
431 ext
->commonsize
= offset
;
432 ext
->commonelem
= 1; /* default FAR */
437 * Now process the special text, if any, to find default-WRT
438 * specifications and common-variable element-size and near/far
441 while (special
&& *special
) {
445 * We might have a default-WRT specification.
447 if (!nasm_strnicmp(special
, "wrt", 3)) {
451 special
+= strspn(special
, " \t");
452 p
= nasm_strndup(special
, len
= strcspn(special
, ":"));
453 obj_ext_set_defwrt (ext
, p
);
455 if (*special
&& *special
!= ':')
456 error(ERR_NONFATAL
, "`:' expected in special symbol"
457 " text for `%s'", ext
->name
);
458 else if (*special
== ':')
463 * The NEAR or FAR keywords specify nearness or
464 * farness. FAR gives default element size 1.
466 if (!nasm_strnicmp(special
, "far", 3)) {
470 error(ERR_NONFATAL
, "`%s': `far' keyword may only be applied"
471 " to common variables\n", ext
->name
);
473 special
+= strspn(special
, " \t");
474 } else if (!nasm_strnicmp(special
, "near", 4)) {
478 error(ERR_NONFATAL
, "`%s': `far' keyword may only be applied"
479 " to common variables\n", ext
->name
);
481 special
+= strspn(special
, " \t");
485 * If it's a common, and anything else remains on the line
486 * before a further colon, evaluate it as an expression and
487 * use that as the element size. Forward references aren't
493 if (ext
->commonsize
) {
495 struct tokenval tokval
;
498 stdscan_bufptr
= special
;
499 tokval
.t_type
= TOKEN_INVALID
;
500 e
= evaluate(stdscan
, NULL
, &tokval
, NULL
, 1, error
, NULL
);
503 error (ERR_NONFATAL
, "cannot use relocatable"
504 " expression as common-variable element size");
506 ext
->commonelem
= reloc_value(e
);
508 special
= stdscan_bufptr
;
510 error (ERR_NONFATAL
, "`%s': element-size specifications only"
511 " apply to common variables", ext
->name
);
512 while (*special
&& *special
!= ':')
523 eb
= *ebtail
= nasm_malloc(sizeof(*eb
));
527 while (i
> EXT_BLKSIZ
) {
531 eb
= *ebtail
= nasm_malloc(sizeof(*eb
));
538 ext
->index
= ++externals
;
540 if (special
&& !used_special
)
541 error(ERR_NONFATAL
, "OBJ supports no special symbol features"
542 " for this symbol type");
545 static void obj_out (long segto
, void *data
, unsigned long type
,
546 long segment
, long wrt
) {
548 unsigned char *ucdata
;
553 * handle absolute-assembly (structure definitions)
555 if (segto
== NO_SEG
) {
556 if ((type
& OUT_TYPMASK
) != OUT_RESERVE
)
557 error (ERR_NONFATAL
, "attempt to assemble code in [ABSOLUTE]"
563 * If `any_segs' is still FALSE, we must define a default
567 int tempint
; /* ignored */
568 if (segto
!= obj_segment("__NASMDEFSEG", 2, &tempint
))
569 error (ERR_PANIC
, "strange segment conditions in OBJ driver");
573 * Find the segment we are targetting.
575 for (seg
= seghead
; seg
; seg
= seg
->next
)
576 if (seg
->index
== segto
)
579 error (ERR_PANIC
, "code directed to nonexistent segment?");
581 size
= type
& OUT_SIZMASK
;
582 realtype
= type
& OUT_TYPMASK
;
583 if (realtype
== OUT_RAWDATA
) {
586 long len
= obj_ledata_space(seg
);
589 len
= obj_ledata_space(seg
);
593 datacurr
->lptr
= obj_write_data (datacurr
->lptr
, ucdata
, len
);
594 datacurr
->nonempty
= TRUE
;
597 seg
->currentpos
+= len
;
599 } else if (realtype
== OUT_ADDRESS
|| realtype
== OUT_REL2ADR
||
600 realtype
== OUT_REL4ADR
) {
603 if (segment
== NO_SEG
&& realtype
!= OUT_ADDRESS
)
604 error(ERR_NONFATAL
, "relative call to absolute address not"
605 " supported by OBJ format");
606 if (segment
>= SEG_ABS
)
607 error(ERR_NONFATAL
, "far-absolute relocations not supported"
609 ldata
= *(long *)data
;
610 if (realtype
== OUT_REL2ADR
) {
614 if (realtype
== OUT_REL4ADR
) {
618 if (obj_ledata_space(seg
) < 4 || !obj_fixup_free(seg
))
621 datacurr
->lptr
= obj_write_word (datacurr
->lptr
, ldata
);
623 datacurr
->lptr
= obj_write_dword (datacurr
->lptr
, ldata
);
624 datacurr
->nonempty
= TRUE
;
626 if (segment
< SEG_ABS
&& (segment
!= NO_SEG
&& segment
% 2) &&
629 * This is a 4-byte segment-base relocation such as
630 * `MOV EAX,SEG foo'. OBJ format can't actually handle
631 * these, but if the constant term has the 16 low bits
632 * zero, we can just apply a 2-byte segment-base
633 * relocation to the low word instead.
637 error(ERR_NONFATAL
, "OBJ format cannot handle complex"
638 " dword-size segment base references");
640 if (segment
!= NO_SEG
)
641 obj_write_fixup (datacurr
, rsize
,
642 (realtype
== OUT_REL2ADR
||
643 realtype
== OUT_REL4ADR
? 0 : 0x4000),
645 (seg
->currentpos
- datacurr
->startpos
));
646 seg
->currentpos
+= size
;
647 } else if (realtype
== OUT_RESERVE
) {
649 seg
->currentpos
+= size
;
653 static long obj_ledata_space(struct Segment
*segto
) {
654 if (datacurr
&& datacurr
->seg
== segto
)
655 return datacurr
->ledata
+ LEDATA_MAX
- datacurr
->lptr
;
660 static int obj_fixup_free(struct Segment
*segto
) {
661 if (datacurr
&& datacurr
->seg
== segto
)
662 return (datacurr
->fixupp
+ RECORD_MAX
- datacurr
->fptr
) > 8;
667 static void obj_ledata_new(struct Segment
*segto
) {
668 datacurr
= *datatail
= nasm_malloc(sizeof(*datacurr
));
669 datacurr
->next
= NULL
;
670 datatail
= &datacurr
->next
;
671 datacurr
->nonempty
= FALSE
;
672 datacurr
->lptr
= datacurr
->ledata
;
673 datacurr
->fptr
= datacurr
->fixupp
;
674 datacurr
->seg
= segto
;
676 datacurr
->letype
= LEDATA
+1;
678 datacurr
->letype
= LEDATA
;
679 datacurr
->startpos
= segto
->currentpos
;
680 datacurr
->ftype
= FIXUPP
;
682 datacurr
->lptr
= obj_write_index (datacurr
->lptr
, segto
->obj_index
);
683 if (datacurr
->letype
== LEDATA
)
684 datacurr
->lptr
= obj_write_word (datacurr
->lptr
, segto
->currentpos
);
686 datacurr
->lptr
= obj_write_dword (datacurr
->lptr
, segto
->currentpos
);
689 static void obj_ledata_commit(void) {
693 static void obj_write_fixup (struct ObjData
*data
, int bytes
,
694 int segrel
, long seg
, long wrt
,
699 struct Segment
*s
= NULL
;
700 struct Group
*g
= NULL
;
701 struct External
*e
= NULL
;
704 error(ERR_NONFATAL
, "`obj' output driver does not support"
705 " one-byte relocations");
709 locat
= 0x8000 | segrel
| offset
;
715 error(ERR_PANIC
, "OBJ: 4-byte segment base fixup got"
716 " through sanity check");
723 data
->ftype
= FIXUPP
+1; /* need new-style FIXUPP record */
726 data
->fptr
= obj_write_rword (data
->fptr
, locat
);
728 tidx
= fidx
= -1, method
= 0; /* placate optimisers */
731 * See if we can find the segment ID in our segment list. If
732 * so, we have a T4 (LSEG) target.
734 for (s
= seghead
; s
; s
= s
->next
)
738 method
= 4, tidx
= s
->obj_index
;
740 for (g
= grphead
; g
; g
= g
->next
)
744 method
= 5, tidx
= g
->obj_index
;
747 struct ExtBack
*eb
= ebhead
;
748 while (i
> EXT_BLKSIZ
) {
756 method
= 6, e
= eb
->exts
[i
], tidx
= e
->index
;
759 "unrecognised segment value in obj_write_fixup");
764 * If no WRT given, assume the natural default, which is method
767 * - we are doing an OFFSET fixup for a grouped segment, in
768 * which case we require F1 (group).
770 * - we are doing an OFFSET fixup for an external with a
771 * default WRT, in which case we must honour the default WRT.
774 if (!base
&& s
&& s
->grp
)
775 method
|= 0x10, fidx
= s
->grp
->obj_index
;
776 else if (!base
&& e
&& e
->defwrt_type
!= DEFWRT_NONE
) {
777 if (e
->defwrt_type
== DEFWRT_SEGMENT
)
778 method
|= 0x00, fidx
= e
->defwrt_ptr
.seg
->obj_index
;
779 else if (e
->defwrt_type
== DEFWRT_GROUP
)
780 method
|= 0x10, fidx
= e
->defwrt_ptr
.grp
->obj_index
;
782 error(ERR_NONFATAL
, "default WRT specification for"
783 " external `%s' unresolved", e
->name
);
784 method
|= 0x50, fidx
= -1; /* got to do _something_ */
787 method
|= 0x50, fidx
= -1;
790 * See if we can find the WRT-segment ID in our segment
791 * list. If so, we have a F0 (LSEG) frame.
793 for (s
= seghead
; s
; s
= s
->next
)
794 if (s
->index
== wrt
-1)
797 method
|= 0x00, fidx
= s
->obj_index
;
799 for (g
= grphead
; g
; g
= g
->next
)
800 if (g
->index
== wrt
-1)
803 method
|= 0x10, fidx
= g
->obj_index
;
806 struct ExtBack
*eb
= ebhead
;
807 while (i
> EXT_BLKSIZ
) {
815 method
|= 0x20, fidx
= eb
->exts
[i
]->index
;
818 "unrecognised WRT value in obj_write_fixup");
823 data
->fptr
= obj_write_byte (data
->fptr
, method
);
825 data
->fptr
= obj_write_index (data
->fptr
, fidx
);
826 data
->fptr
= obj_write_index (data
->fptr
, tidx
);
829 static long obj_segment (char *name
, int pass
, int *bits
) {
831 * We call the label manager here to define a name for the new
832 * segment, and when our _own_ label-definition stub gets
833 * called in return, it should register the new segment name
834 * using the pointer it gets passed. That way we save memory,
835 * by sponging off the label manager.
843 struct External
**extp
;
844 int obj_idx
, i
, attrs
, rn_error
;
848 * Look for segment attributes.
852 name
++; /* hack, but a documented one */
854 while (*p
&& !isspace(*p
))
858 while (*p
&& isspace(*p
))
862 while (*p
&& !isspace(*p
))
866 while (*p
&& isspace(*p
))
874 for (seg
= seghead
; seg
; seg
= seg
->next
) {
876 if (!strcmp(seg
->name
, name
)) {
877 if (attrs
> 0 && pass
== 1)
878 error(ERR_WARNING
, "segment attributes specified on"
879 " redeclaration of segment: ignoring");
888 *segtail
= seg
= nasm_malloc(sizeof(*seg
));
890 segtail
= &seg
->next
;
891 seg
->index
= (any_segs
? seg_alloc() : first_seg
);
892 seg
->obj_index
= obj_idx
;
897 seg
->align
= 1; /* default */
898 seg
->use32
= FALSE
; /* default */
899 seg
->combine
= CMB_PUBLIC
; /* default */
900 seg
->segclass
= seg
->overlay
= NULL
;
902 seg
->pubtail
= &seg
->pubhead
;
905 * Process the segment attributes.
913 * `p' contains a segment attribute.
915 if (!nasm_stricmp(p
, "private"))
916 seg
->combine
= CMB_PRIVATE
;
917 else if (!nasm_stricmp(p
, "public"))
918 seg
->combine
= CMB_PUBLIC
;
919 else if (!nasm_stricmp(p
, "common"))
920 seg
->combine
= CMB_COMMON
;
921 else if (!nasm_stricmp(p
, "stack"))
922 seg
->combine
= CMB_STACK
;
923 else if (!nasm_stricmp(p
, "use16"))
925 else if (!nasm_stricmp(p
, "use32"))
927 else if (!nasm_stricmp(p
, "flat")) {
929 * This segment is an OS/2 FLAT segment. That means
930 * that its default group is group FLAT, even if
931 * the group FLAT does not explicitly _contain_ the
934 * When we see this, we must create the group
935 * `FLAT', containing no segments, if it does not
936 * already exist; then we must set the default
937 * group of this segment to be the FLAT group.
940 for (grp
= grphead
; grp
; grp
= grp
->next
)
941 if (!strcmp(grp
->name
, "FLAT"))
944 obj_directive ("group", "FLAT", 1);
945 for (grp
= grphead
; grp
; grp
= grp
->next
)
946 if (!strcmp(grp
->name
, "FLAT"))
949 error (ERR_PANIC
, "failure to define FLAT?!");
952 } else if (!nasm_strnicmp(p
, "class=", 6))
953 seg
->segclass
= nasm_strdup(p
+6);
954 else if (!nasm_strnicmp(p
, "overlay=", 8))
955 seg
->overlay
= nasm_strdup(p
+8);
956 else if (!nasm_strnicmp(p
, "align=", 6)) {
957 seg
->align
= readnum(p
+6, &rn_error
);
960 error (ERR_NONFATAL
, "segment alignment should be"
963 switch ((int) seg
->align
) {
969 case 4096: /* PharLap extension */
972 error(ERR_WARNING
, "OBJ format does not support alignment"
973 " of 8: rounding up to 16");
979 error(ERR_WARNING
, "OBJ format does not support alignment"
980 " of %d: rounding up to 256", seg
->align
);
986 error(ERR_WARNING
, "OBJ format does not support alignment"
987 " of %d: rounding up to 4096", seg
->align
);
991 error(ERR_NONFATAL
, "invalid alignment value %d",
996 } else if (!nasm_strnicmp(p
, "absolute=", 9)) {
997 seg
->align
= SEG_ABS
+ readnum(p
+9, &rn_error
);
999 error (ERR_NONFATAL
, "argument to `absolute' segment"
1000 " attribute should be numeric");
1004 obj_seg_needs_update
= seg
;
1005 if (seg
->align
>= SEG_ABS
)
1006 deflabel (name
, NO_SEG
, seg
->align
- SEG_ABS
,
1007 NULL
, FALSE
, FALSE
, &of_obj
, error
);
1009 deflabel (name
, seg
->index
+1, 0L,
1010 NULL
, FALSE
, FALSE
, &of_obj
, error
);
1011 obj_seg_needs_update
= NULL
;
1014 * See if this segment is defined in any groups.
1016 for (grp
= grphead
; grp
; grp
= grp
->next
) {
1017 for (i
= grp
->nindices
; i
< grp
->nentries
; i
++) {
1018 if (!strcmp(grp
->segs
[i
].name
, seg
->name
)) {
1019 nasm_free (grp
->segs
[i
].name
);
1020 grp
->segs
[i
] = grp
->segs
[grp
->nindices
];
1021 grp
->segs
[grp
->nindices
++].index
= seg
->obj_index
;
1023 error(ERR_WARNING
, "segment `%s' is already part of"
1024 " a group: first one takes precedence",
1033 * Walk through the list of externals with unresolved
1034 * default-WRT clauses, and resolve any that point at this
1039 if ((*extp
)->defwrt_type
== DEFWRT_STRING
&&
1040 !strcmp((*extp
)->defwrt_ptr
.string
, seg
->name
)) {
1041 (*extp
)->defwrt_type
= DEFWRT_SEGMENT
;
1042 (*extp
)->defwrt_ptr
.seg
= seg
;
1043 *extp
= (*extp
)->next_dws
;
1045 extp
= &(*extp
)->next_dws
;
1056 static int obj_directive (char *directive
, char *value
, int pass
) {
1057 if (!strcmp(directive
, "group")) {
1061 struct Segment
*seg
;
1062 struct External
**extp
;
1067 q
++; /* hack, but a documented one */
1069 while (*q
&& !isspace(*q
))
1073 while (*q
&& isspace(*q
))
1077 * Here we used to sanity-check the group directive to
1078 * ensure nobody tried to declare a group containing no
1079 * segments. However, OS/2 does this as standard
1080 * practice, so the sanity check has been removed.
1083 * error(ERR_NONFATAL,"GROUP directive contains no segments");
1089 for (grp
= grphead
; grp
; grp
= grp
->next
) {
1091 if (!strcmp(grp
->name
, v
)) {
1092 error(ERR_NONFATAL
, "group `%s' defined twice", v
);
1097 *grptail
= grp
= nasm_malloc(sizeof(*grp
));
1099 grptail
= &grp
->next
;
1100 grp
->index
= seg_alloc();
1101 grp
->obj_index
= obj_idx
;
1102 grp
->nindices
= grp
->nentries
= 0;
1105 obj_grp_needs_update
= grp
;
1106 deflabel (v
, grp
->index
+1, 0L,
1107 NULL
, FALSE
, FALSE
, &of_obj
, error
);
1108 obj_grp_needs_update
= NULL
;
1112 while (*q
&& !isspace(*q
))
1116 while (*q
&& isspace(*q
))
1120 * Now p contains a segment name. Find it.
1122 for (seg
= seghead
; seg
; seg
= seg
->next
)
1123 if (!strcmp(seg
->name
, p
))
1127 * We have a segment index. Shift a name entry
1128 * to the end of the array to make room.
1130 grp
->segs
[grp
->nentries
++] = grp
->segs
[grp
->nindices
];
1131 grp
->segs
[grp
->nindices
++].index
= seg
->obj_index
;
1133 error(ERR_WARNING
, "segment `%s' is already part of"
1134 " a group: first one takes precedence",
1140 * We have an as-yet undefined segment.
1141 * Remember its name, for later.
1143 grp
->segs
[grp
->nentries
++].name
= nasm_strdup(p
);
1148 * Walk through the list of externals with unresolved
1149 * default-WRT clauses, and resolve any that point at
1154 if ((*extp
)->defwrt_type
== DEFWRT_STRING
&&
1155 !strcmp((*extp
)->defwrt_ptr
.string
, grp
->name
)) {
1156 (*extp
)->defwrt_type
= DEFWRT_GROUP
;
1157 (*extp
)->defwrt_ptr
.grp
= grp
;
1158 *extp
= (*extp
)->next_dws
;
1160 extp
= &(*extp
)->next_dws
;
1165 if (!strcmp(directive
, "uppercase")) {
1166 obj_uppercase
= TRUE
;
1169 if (!strcmp(directive
, "import")) {
1170 char *q
, *extname
, *libname
, *impname
;
1173 return 1; /* ignore in pass two */
1174 extname
= q
= value
;
1175 while (*q
&& !isspace(*q
))
1179 while (*q
&& isspace(*q
))
1184 while (*q
&& !isspace(*q
))
1188 while (*q
&& isspace(*q
))
1194 if (!*extname
|| !*libname
)
1195 error(ERR_NONFATAL
, "`import' directive requires symbol name"
1196 " and library name");
1201 imp
= *imptail
= nasm_malloc(sizeof(struct ImpDef
));
1202 imptail
= &imp
->next
;
1204 imp
->extname
= nasm_strdup(extname
);
1205 imp
->libname
= nasm_strdup(libname
);
1206 imp
->impindex
= readnum(impname
, &err
);
1207 if (!*impname
|| err
)
1208 imp
->impname
= nasm_strdup(impname
);
1210 imp
->impname
= NULL
;
1215 if (!strcmp(directive
, "export")) {
1216 char *q
, *extname
, *intname
, *v
;
1217 struct ExpDef
*export
;
1219 unsigned int ordinal
= 0;
1222 return 1; /* ignore in pass two */
1223 intname
= q
= value
;
1224 while (*q
&& !isspace(*q
))
1228 while (*q
&& isspace(*q
))
1233 while (*q
&& !isspace(*q
))
1237 while (*q
&& isspace(*q
))
1242 error(ERR_NONFATAL
, "`export' directive requires export name");
1251 while (*q
&& !isspace(*q
))
1255 while (*q
&& isspace(*q
))
1258 if (!nasm_stricmp(v
, "resident"))
1259 flags
|= EXPDEF_FLAG_RESIDENT
;
1260 else if (!nasm_stricmp(v
, "nodata"))
1261 flags
|= EXPDEF_FLAG_NODATA
;
1262 else if (!nasm_strnicmp(v
, "parm=", 5)) {
1264 flags
|= EXPDEF_MASK_PARMCNT
& readnum(v
+5, &err
);
1267 "value `%s' for `parm' is non-numeric", v
+5);
1272 ordinal
= readnum(v
, &err
);
1274 error(ERR_NONFATAL
, "unrecognised export qualifier `%s'",
1278 flags
|= EXPDEF_FLAG_ORDINAL
;
1282 export
= *exptail
= nasm_malloc(sizeof(struct ExpDef
));
1283 exptail
= &export
->next
;
1284 export
->next
= NULL
;
1285 export
->extname
= nasm_strdup(extname
);
1286 export
->intname
= nasm_strdup(intname
);
1287 export
->ordinal
= ordinal
;
1288 export
->flags
= flags
;
1295 static long obj_segbase (long segment
) {
1296 struct Segment
*seg
;
1299 * Find the segment in our list.
1301 for (seg
= seghead
; seg
; seg
= seg
->next
)
1302 if (seg
->index
== segment
-1)
1307 * Might be an external with a default WRT.
1310 struct ExtBack
*eb
= ebhead
;
1313 while (i
> EXT_BLKSIZ
) {
1322 if (e
->defwrt_type
== DEFWRT_NONE
)
1323 return segment
; /* fine */
1324 else if (e
->defwrt_type
== DEFWRT_SEGMENT
)
1325 return e
->defwrt_ptr
.seg
->index
+1;
1326 else if (e
->defwrt_type
== DEFWRT_GROUP
)
1327 return e
->defwrt_ptr
.grp
->index
+1;
1328 else if (e
->defwrt_type
== DEFWRT_STRING
)
1329 return NO_SEG
; /* can't tell what it is */
1332 return segment
; /* not one of ours - leave it alone */
1335 if (seg
->align
>= SEG_ABS
)
1336 return seg
->align
; /* absolute segment */
1338 return seg
->grp
->index
+1; /* grouped segment */
1340 return segment
; /* no special treatment */
1343 static void obj_filename (char *inname
, char *outname
, efunc error
) {
1344 strcpy(obj_infile
, inname
);
1345 standard_extension (inname
, outname
, ".obj", error
);
1348 static void obj_write_file (void) {
1349 struct Segment
*seg
;
1352 struct External
*ext
;
1353 struct ObjData
*data
;
1355 struct ExpDef
*export
;
1356 static char boast
[] = "The Netwide Assembler " NASM_VER
;
1357 int lname_idx
, rectype
;
1360 * Write the THEADR module header.
1363 recptr
= obj_write_name (recptr
, obj_infile
);
1364 obj_record (THEADR
, record
, recptr
);
1367 * Write the NASM boast comment.
1370 recptr
= obj_write_rword (recptr
, 0); /* comment type zero */
1371 recptr
= obj_write_name (recptr
, boast
);
1372 obj_record (COMENT
, record
, recptr
);
1375 * Write the IMPDEF records, if any.
1377 for (imp
= imphead
; imp
; imp
= imp
->next
) {
1379 recptr
= obj_write_rword (recptr
, 0xA0); /* comment class A0 */
1380 recptr
= obj_write_byte (recptr
, 1); /* subfunction 1: IMPDEF */
1382 recptr
= obj_write_byte (recptr
, 0); /* import by name */
1384 recptr
= obj_write_byte (recptr
, 1); /* import by ordinal */
1385 recptr
= obj_write_name (recptr
, imp
->extname
);
1386 recptr
= obj_write_name (recptr
, imp
->libname
);
1388 recptr
= obj_write_name (recptr
, imp
->impname
);
1390 recptr
= obj_write_word (recptr
, imp
->impindex
);
1391 obj_record (COMENT
, record
, recptr
);
1395 * Write the EXPDEF records, if any.
1397 for (export
= exphead
; export
; export
= export
->next
) {
1399 recptr
= obj_write_rword (recptr
, 0xA0); /* comment class A0 */
1400 recptr
= obj_write_byte (recptr
, 2); /* subfunction 1: EXPDEF */
1401 recptr
= obj_write_byte (recptr
, export
->flags
);
1402 recptr
= obj_write_name (recptr
, export
->extname
);
1403 recptr
= obj_write_name (recptr
, export
->intname
);
1404 if (export
->flags
& EXPDEF_FLAG_ORDINAL
)
1405 recptr
= obj_write_word (recptr
, export
->ordinal
);
1406 obj_record (COMENT
, record
, recptr
);
1410 * Write the first LNAMES record, containing LNAME one, which
1411 * is null. Also initialise the LNAME counter.
1414 recptr
= obj_write_name (recptr
, "");
1415 obj_record (LNAMES
, record
, recptr
);
1419 * Write the SEGDEF records. Each has an associated LNAMES
1422 for (seg
= seghead
; seg
; seg
= seg
->next
) {
1423 int new_segdef
; /* do we use the newer record type? */
1425 int sn
, cn
, on
; /* seg, class, overlay LNAME idx */
1427 if (seg
->use32
|| seg
->currentpos
>= 0x10000L
)
1433 recptr
= obj_write_name (recptr
, seg
->name
);
1435 if (seg
->segclass
) {
1436 recptr
= obj_write_name (recptr
, seg
->segclass
);
1441 recptr
= obj_write_name (recptr
, seg
->overlay
);
1445 obj_record (LNAMES
, record
, recptr
);
1447 acbp
= (seg
->combine
<< 2); /* C field */
1449 if (seg
->currentpos
>= 0x10000L
&& !new_segdef
)
1450 acbp
|= 0x02; /* B bit */
1453 acbp
|= 0x01; /* P bit is Use32 flag */
1456 if (seg
->align
>= SEG_ABS
)
1458 else if (seg
->align
>= 4096) {
1459 if (seg
->align
> 4096)
1460 error(ERR_NONFATAL
, "segment `%s' requires more alignment"
1461 " than OBJ format supports", seg
->name
);
1462 acbp
|= 0xC0; /* PharLap extension */
1463 } else if (seg
->align
>= 256) {
1465 } else if (seg
->align
>= 16) {
1467 } else if (seg
->align
>= 4) {
1469 } else if (seg
->align
>= 2) {
1475 recptr
= obj_write_byte (recptr
, acbp
);
1476 if (seg
->align
& SEG_ABS
) {
1477 recptr
= obj_write_word (recptr
, seg
->align
- SEG_ABS
);
1478 recptr
= obj_write_byte (recptr
, 0);
1481 recptr
= obj_write_dword (recptr
, seg
->currentpos
);
1483 recptr
= obj_write_word (recptr
, seg
->currentpos
& 0xFFFF);
1484 recptr
= obj_write_index (recptr
, sn
);
1485 recptr
= obj_write_index (recptr
, cn
);
1486 recptr
= obj_write_index (recptr
, on
);
1488 obj_record (SEGDEF
+1, record
, recptr
);
1490 obj_record (SEGDEF
, record
, recptr
);
1494 * Write some LNAMES for the group names. lname_idx is left
1495 * alone here - it will catch up when we write the GRPDEFs.
1498 for (grp
= grphead
; grp
; grp
= grp
->next
) {
1499 if (recptr
- record
+ strlen(grp
->name
)+2 > 1024) {
1500 obj_record (LNAMES
, record
, recptr
);
1503 recptr
= obj_write_name (recptr
, grp
->name
);
1505 if (recptr
> record
)
1506 obj_record (LNAMES
, record
, recptr
);
1509 * Write the GRPDEF records.
1511 for (grp
= grphead
; grp
; grp
= grp
->next
) {
1514 if (grp
->nindices
!= grp
->nentries
) {
1515 for (i
= grp
->nindices
; i
< grp
->nentries
; i
++) {
1516 error(ERR_NONFATAL
, "group `%s' contains undefined segment"
1517 " `%s'", grp
->name
, grp
->segs
[i
].name
);
1518 nasm_free (grp
->segs
[i
].name
);
1519 grp
->segs
[i
].name
= NULL
;
1523 recptr
= obj_write_index (recptr
, lname_idx
++);
1524 for (i
= 0; i
< grp
->nindices
; i
++) {
1525 recptr
= obj_write_byte (recptr
, 0xFF);
1526 recptr
= obj_write_index (recptr
, grp
->segs
[i
].index
);
1528 obj_record (GRPDEF
, record
, recptr
);
1532 * Write the PUBDEF records: first the ones in the segments,
1533 * then the far-absolutes.
1535 for (seg
= seghead
; seg
; seg
= seg
->next
) {
1539 recptr
= obj_write_index (recptr
, seg
->grp
? seg
->grp
->obj_index
: 0);
1540 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1546 for (pub
= seg
->pubhead
; pub
; pub
= pub
->next
) {
1547 if (recptr
- record
+ strlen(pub
->name
) + 7 > 1024) {
1549 obj_record (rectype
, record
, recptr
);
1551 recptr
= obj_write_index (recptr
, 0);
1552 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1554 recptr
= obj_write_name (recptr
, pub
->name
);
1556 recptr
= obj_write_dword (recptr
, pub
->offset
);
1558 recptr
= obj_write_word (recptr
, pub
->offset
);
1559 recptr
= obj_write_index (recptr
, 0);
1563 obj_record (rectype
, record
, recptr
);
1565 for (pub
= fpubhead
; pub
; pub
= pub
->next
) { /* pub-crawl :-) */
1567 recptr
= obj_write_index (recptr
, 0); /* no group */
1568 recptr
= obj_write_index (recptr
, 0); /* no segment either */
1569 recptr
= obj_write_word (recptr
, pub
->segment
);
1570 recptr
= obj_write_name (recptr
, pub
->name
);
1571 recptr
= obj_write_word (recptr
, pub
->offset
);
1572 recptr
= obj_write_index (recptr
, 0);
1573 obj_record (PUBDEF
, record
, recptr
);
1577 * Write the EXTDEF and COMDEF records, in order.
1580 for (ext
= exthead
; ext
; ext
= ext
->next
) {
1581 if (ext
->commonsize
== 0) {
1582 /* dj@delorie.com: check for buffer overrun before we overrun it */
1583 if (recptr
- record
+ strlen(ext
->name
)+2 > RECORD_MAX
) {
1584 obj_record (EXTDEF
, record
, recptr
);
1587 recptr
= obj_write_name (recptr
, ext
->name
);
1588 recptr
= obj_write_index (recptr
, 0);
1590 if (recptr
> record
)
1591 obj_record (EXTDEF
, record
, recptr
);
1593 if (ext
->commonsize
) {
1594 recptr
= obj_write_name (recptr
, ext
->name
);
1595 recptr
= obj_write_index (recptr
, 0);
1596 if (ext
->commonelem
) {
1597 recptr
= obj_write_byte (recptr
, 0x61);/* far communal */
1598 recptr
= obj_write_value (recptr
, (ext
->commonsize
/
1600 recptr
= obj_write_value (recptr
, ext
->commonelem
);
1602 recptr
= obj_write_byte (recptr
, 0x62);/* near communal */
1603 recptr
= obj_write_value (recptr
, ext
->commonsize
);
1605 obj_record (COMDEF
, record
, recptr
);
1610 if (recptr
> record
)
1611 obj_record (EXTDEF
, record
, recptr
);
1614 * Write a COMENT record stating that the linker's first pass
1615 * may stop processing at this point. Exception is if our
1616 * MODEND record specifies a start point, in which case,
1617 * according to some variants of the documentation, this COMENT
1618 * should be omitted. So we'll omit it just in case.
1620 if (obj_entry_seg
== NO_SEG
) {
1622 recptr
= obj_write_rword (recptr
, 0x40A2);
1623 recptr
= obj_write_byte (recptr
, 1);
1624 obj_record (COMENT
, record
, recptr
);
1628 * Write the LEDATA/FIXUPP pairs.
1630 for (data
= datahead
; data
; data
= data
->next
) {
1631 if (data
->nonempty
) {
1632 obj_record (data
->letype
, data
->ledata
, data
->lptr
);
1633 if (data
->fptr
!= data
->fixupp
)
1634 obj_record (data
->ftype
, data
->fixupp
, data
->fptr
);
1639 * Write the MODEND module end marker.
1643 if (obj_entry_seg
!= NO_SEG
) {
1644 recptr
= obj_write_byte (recptr
, 0xC1);
1646 * Find the segment in the segment list.
1648 for (seg
= seghead
; seg
; seg
= seg
->next
) {
1649 if (seg
->index
== obj_entry_seg
) {
1651 recptr
= obj_write_byte (recptr
, 0x10);
1652 recptr
= obj_write_index (recptr
, seg
->grp
->obj_index
);
1654 recptr
= obj_write_byte (recptr
, 0x50);
1656 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1659 recptr
= obj_write_dword (recptr
, obj_entry_ofs
);
1661 recptr
= obj_write_word (recptr
, obj_entry_ofs
);
1666 error(ERR_NONFATAL
, "entry point is not in this module");
1668 recptr
= obj_write_byte (recptr
, 0);
1669 obj_record (rectype
, record
, recptr
);
1672 static unsigned char *obj_write_data(unsigned char *ptr
,
1673 unsigned char *data
, int len
) {
1679 static unsigned char *obj_write_byte(unsigned char *ptr
, int data
) {
1684 static unsigned char *obj_write_word(unsigned char *ptr
, int data
) {
1685 *ptr
++ = data
& 0xFF;
1686 *ptr
++ = (data
>> 8) & 0xFF;
1690 static unsigned char *obj_write_dword(unsigned char *ptr
, long data
) {
1691 *ptr
++ = data
& 0xFF;
1692 *ptr
++ = (data
>> 8) & 0xFF;
1693 *ptr
++ = (data
>> 16) & 0xFF;
1694 *ptr
++ = (data
>> 24) & 0xFF;
1698 static unsigned char *obj_write_rword(unsigned char *ptr
, int data
) {
1699 *ptr
++ = (data
>> 8) & 0xFF;
1700 *ptr
++ = data
& 0xFF;
1704 static unsigned char *obj_write_name(unsigned char *ptr
, char *data
) {
1705 *ptr
++ = strlen(data
);
1706 if (obj_uppercase
) {
1708 *ptr
++ = (unsigned char) toupper(*data
);
1713 *ptr
++ = (unsigned char) *data
++;
1718 static unsigned char *obj_write_index(unsigned char *ptr
, int data
) {
1722 *ptr
++ = 0x80 | ((data
>> 8) & 0x7F);
1723 *ptr
++ = data
& 0xFF;
1728 static unsigned char *obj_write_value(unsigned char *ptr
,
1729 unsigned long data
) {
1732 else if (data
<= 0xFFFF) {
1734 *ptr
++ = data
& 0xFF;
1735 *ptr
++ = (data
>> 8) & 0xFF;
1736 } else if (data
<= 0xFFFFFFL
) {
1738 *ptr
++ = data
& 0xFF;
1739 *ptr
++ = (data
>> 8) & 0xFF;
1740 *ptr
++ = (data
>> 16) & 0xFF;
1743 *ptr
++ = data
& 0xFF;
1744 *ptr
++ = (data
>> 8) & 0xFF;
1745 *ptr
++ = (data
>> 16) & 0xFF;
1746 *ptr
++ = (data
>> 24) & 0xFF;
1751 static void obj_record(int type
, unsigned char *start
, unsigned char *end
) {
1752 unsigned long cksum
, len
;
1757 cksum
+= (len
& 0xFF) + ((len
>>8) & 0xFF);
1758 fwriteshort (len
, ofp
);
1759 fwrite (start
, 1, end
-start
, ofp
);
1762 fputc ( (-(long)cksum
) & 0xFF, ofp
);
1765 static char *obj_stdmac
[] = {
1766 "%define __SECT__ [section .text]",
1767 "%imacro group 1+.nolist",
1770 "%imacro uppercase 1+.nolist",
1773 "%imacro export 1+.nolist",
1776 "%imacro import 1+.nolist",
1782 struct ofmt of_obj
= {
1783 "Microsoft MS-DOS 16-bit OMF object files",