]>
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 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
24 /* outobj.c output routines for the Netwide Assembler to produce
25 * Microsoft 16-bit .OBJ object files
27 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
28 * Julian Hall. All rights reserved. The software is
29 * redistributable under the licence given in the file "Licence"
30 * distributed in the NASM archive.
44 static char obj_infile
[FILENAME_MAX
];
45 static int obj_uppercase
;
48 static evalfunc evaluate
;
49 static ldfunc deflabel
;
51 static long first_seg
;
54 #define LEDATA_MAX 1024 /* maximum size of LEDATA record */
55 #define RECORD_MAX 1024 /* maximum size of _any_ record */
56 #define GROUP_MAX 256 /* we won't _realistically_ have more
57 * than this many segs in a group */
58 #define EXT_BLKSIZ 256 /* block size for externals list */
60 static unsigned char record
[RECORD_MAX
], *recptr
;
62 struct Segment
; /* need to know these structs exist */
65 static struct Public
{
69 long segment
; /* only if it's far-absolute */
70 } *fpubhead
, **fpubtail
;
72 static struct External
{
73 struct External
*next
;
76 long commonelem
; /* element size if FAR, else zero */
77 int index
; /* OBJ-file external index */
79 DEFWRT_NONE
, /* no unusual default-WRT */
80 DEFWRT_STRING
, /* a string we don't yet understand */
81 DEFWRT_SEGMENT
, /* a segment */
82 DEFWRT_GROUP
/* a group */
89 struct External
*next_dws
; /* next with DEFWRT_STRING */
90 } *exthead
, **exttail
, *dws
;
94 static struct ExtBack
{
96 struct External
*exts
[EXT_BLKSIZ
];
99 static struct Segment
{
100 struct Segment
*next
;
101 long index
; /* the NASM segment id */
102 long obj_index
; /* the OBJ-file segment index */
103 struct Group
*grp
; /* the group it belongs to */
105 long align
; /* can be SEG_ABS + absolute addr */
112 long use32
; /* is this segment 32-bit? */
113 struct Public
*pubhead
, **pubtail
;
115 char *segclass
, *overlay
; /* `class' is a C++ keyword :-) */
116 } *seghead
, **segtail
, *obj_seg_needs_update
;
118 static struct Group
{
121 long index
; /* NASM segment id */
122 long obj_index
; /* OBJ-file group index */
123 long nentries
; /* number of elements... */
124 long nindices
; /* ...and number of index elts... */
128 } segs
[GROUP_MAX
]; /* ...in this */
129 } *grphead
, **grptail
, *obj_grp_needs_update
;
131 static struct ObjData
{
132 struct ObjData
*next
;
137 unsigned char ledata
[LEDATA_MAX
], *lptr
;
138 unsigned char fixupp
[RECORD_MAX
], *fptr
;
139 } *datahead
, *datacurr
, **datatail
;
141 static struct ImpDef
{
145 unsigned int impindex
;
147 } *imphead
, **imptail
;
149 static struct ExpDef
{
153 unsigned int ordinal
;
155 } *exphead
, **exptail
;
157 #define EXPDEF_FLAG_ORDINAL 0x80
158 #define EXPDEF_FLAG_RESIDENT 0x40
159 #define EXPDEF_FLAG_NODATA 0x20
160 #define EXPDEF_MASK_PARMCNT 0x1F
162 static long obj_entry_seg
, obj_entry_ofs
;
164 enum RecordID
{ /* record ID codes */
166 THEADR
= 0x80, /* module header */
167 COMENT
= 0x88, /* comment record */
169 LNAMES
= 0x96, /* list of names */
171 SEGDEF
= 0x98, /* segment definition */
172 GRPDEF
= 0x9A, /* group definition */
173 EXTDEF
= 0x8C, /* external definition */
174 PUBDEF
= 0x90, /* public definition */
175 COMDEF
= 0xB0, /* common definition */
177 LEDATA
= 0xA0, /* logical enumerated data */
178 FIXUPP
= 0x9C, /* fixups (relocations) */
180 MODEND
= 0x8A /* module end */
183 extern struct ofmt of_obj
;
185 static long obj_ledata_space(struct Segment
*);
186 static int obj_fixup_free(struct Segment
*);
187 static void obj_ledata_new(struct Segment
*);
188 static void obj_ledata_commit(void);
189 static void obj_write_fixup (struct ObjData
*, int, int, long, long, long);
190 static long obj_segment (char *, int, int *);
191 static void obj_write_file(void);
192 static unsigned char *obj_write_data(unsigned char *, unsigned char *, int);
193 static unsigned char *obj_write_byte(unsigned char *, int);
194 static unsigned char *obj_write_word(unsigned char *, int);
195 static unsigned char *obj_write_dword(unsigned char *, long);
196 static unsigned char *obj_write_rword(unsigned char *, int);
197 static unsigned char *obj_write_name(unsigned char *, char *);
198 static unsigned char *obj_write_index(unsigned char *, int);
199 static unsigned char *obj_write_value(unsigned char *, unsigned long);
200 static void obj_record(int, unsigned char *, unsigned char *);
201 static int obj_directive (char *, char *, int);
203 static void obj_init (FILE *fp
, efunc errfunc
, ldfunc ldef
, evalfunc eval
) {
208 first_seg
= seg_alloc();
211 fpubtail
= &fpubhead
;
222 seghead
= obj_seg_needs_update
= NULL
;
224 grphead
= obj_grp_needs_update
= NULL
;
226 datahead
= datacurr
= NULL
;
227 datatail
= &datahead
;
228 obj_entry_seg
= NO_SEG
;
229 obj_uppercase
= FALSE
;
232 static void obj_cleanup (void) {
236 struct Segment
*segtmp
= seghead
;
237 seghead
= seghead
->next
;
238 while (segtmp
->pubhead
) {
239 struct Public
*pubtmp
= segtmp
->pubhead
;
240 segtmp
->pubhead
= pubtmp
->next
;
241 nasm_free (pubtmp
->name
);
247 struct Public
*pubtmp
= fpubhead
;
248 fpubhead
= fpubhead
->next
;
249 nasm_free (pubtmp
->name
);
253 struct External
*exttmp
= exthead
;
254 exthead
= exthead
->next
;
258 struct ImpDef
*imptmp
= imphead
;
259 imphead
= imphead
->next
;
260 nasm_free (imptmp
->extname
);
261 nasm_free (imptmp
->libname
);
262 nasm_free (imptmp
->impname
); /* nasm_free won't mind if it's NULL */
266 struct ExpDef
*exptmp
= exphead
;
267 exphead
= exphead
->next
;
268 nasm_free (exptmp
->extname
);
269 nasm_free (exptmp
->intname
);
273 struct ExtBack
*ebtmp
= ebhead
;
274 ebhead
= ebhead
->next
;
278 struct Group
*grptmp
= grphead
;
279 grphead
= grphead
->next
;
283 struct ObjData
*datatmp
= datahead
;
284 datahead
= datahead
->next
;
289 static void obj_ext_set_defwrt (struct External
*ext
, char *id
) {
293 for (seg
= seghead
; seg
; seg
= seg
->next
)
294 if (!strcmp(seg
->name
, id
)) {
295 ext
->defwrt_type
= DEFWRT_SEGMENT
;
296 ext
->defwrt_ptr
.seg
= seg
;
301 for (grp
= grphead
; grp
; grp
= grp
->next
)
302 if (!strcmp(grp
->name
, id
)) {
303 ext
->defwrt_type
= DEFWRT_GROUP
;
304 ext
->defwrt_ptr
.grp
= grp
;
309 ext
->defwrt_type
= DEFWRT_STRING
;
310 ext
->defwrt_ptr
.string
= id
;
315 static void obj_deflabel (char *name
, long segment
,
316 long offset
, int is_global
, char *special
) {
318 * We have three cases:
320 * (i) `segment' is a segment-base. If so, set the name field
321 * for the segment or group structure it refers to, and then
324 * (ii) `segment' is one of our segments, or a SEG_ABS segment.
325 * Save the label position for later output of a PUBDEF record.
326 * (Or a MODPUB, if we work out how.)
328 * (iii) `segment' is not one of our segments. Save the label
329 * position for later output of an EXTDEF, and also store a
330 * back-reference so that we can map later references to this
331 * segment number to the external index.
333 struct External
*ext
;
337 int used_special
= FALSE
; /* have we used the special text? */
340 * If it's a special-retry from pass two, discard it.
346 * First check for the double-period, signifying something
349 if (name
[0] == '.' && name
[1] == '.' && name
[2] != '@') {
350 if (!strcmp(name
, "..start")) {
351 obj_entry_seg
= segment
;
352 obj_entry_ofs
= offset
;
355 error (ERR_NONFATAL
, "unrecognised special symbol `%s'", name
);
361 if (obj_seg_needs_update
) {
362 obj_seg_needs_update
->name
= name
;
364 } else if (obj_grp_needs_update
) {
365 obj_grp_needs_update
->name
= name
;
368 if (segment
< SEG_ABS
&& segment
!= NO_SEG
&& segment
% 2)
371 if (segment
>= SEG_ABS
|| segment
== NO_SEG
) {
373 * SEG_ABS subcase of (ii).
378 pub
= *fpubtail
= nasm_malloc(sizeof(*pub
));
379 fpubtail
= &pub
->next
;
381 pub
->name
= nasm_strdup(name
);
382 pub
->offset
= offset
;
383 pub
->segment
= (segment
== NO_SEG
? 0 : segment
& ~SEG_ABS
);
386 error(ERR_NONFATAL
, "OBJ supports no special symbol features"
387 " for this symbol type");
392 * If `any_segs' is still FALSE, we might need to define a
393 * default segment, if they're trying to declare a label in
396 if (!any_segs
&& segment
== first_seg
) {
397 int tempint
; /* ignored */
398 if (segment
!= obj_segment("__NASMDEFSEG", 2, &tempint
))
399 error (ERR_PANIC
, "strange segment conditions in OBJ driver");
402 for (seg
= seghead
; seg
; seg
= seg
->next
)
403 if (seg
->index
== segment
) {
405 * Case (ii). Maybe MODPUB someday?
409 pub
= *seg
->pubtail
= nasm_malloc(sizeof(*pub
));
410 seg
->pubtail
= &pub
->next
;
412 pub
->name
= nasm_strdup(name
);
413 pub
->offset
= offset
;
416 error(ERR_NONFATAL
, "OBJ supports no special symbol features"
417 " for this symbol type");
424 ext
= *exttail
= nasm_malloc(sizeof(*ext
));
426 exttail
= &ext
->next
;
428 ext
->defwrt_type
= DEFWRT_NONE
;
429 if (is_global
== 2) {
430 ext
->commonsize
= offset
;
431 ext
->commonelem
= 1; /* default FAR */
436 * Now process the special text, if any, to find default-WRT
437 * specifications and common-variable element-size and near/far
440 while (special
&& *special
) {
444 * We might have a default-WRT specification.
446 if (!nasm_strnicmp(special
, "wrt", 3)) {
450 special
+= strspn(special
, " \t");
451 p
= nasm_strndup(special
, len
= strcspn(special
, ":"));
452 obj_ext_set_defwrt (ext
, p
);
454 if (*special
&& *special
!= ':')
455 error(ERR_NONFATAL
, "`:' expected in special symbol"
456 " text for `%s'", ext
->name
);
457 else if (*special
== ':')
462 * The NEAR or FAR keywords specify nearness or
463 * farness. FAR gives default element size 1.
465 if (!nasm_strnicmp(special
, "far", 3)) {
469 error(ERR_NONFATAL
, "`%s': `far' keyword may only be applied"
470 " to common variables\n", ext
->name
);
472 special
+= strspn(special
, " \t");
473 } else if (!nasm_strnicmp(special
, "near", 4)) {
477 error(ERR_NONFATAL
, "`%s': `far' keyword may only be applied"
478 " to common variables\n", ext
->name
);
480 special
+= strspn(special
, " \t");
484 * If it's a common, and anything else remains on the line
485 * before a further colon, evaluate it as an expression and
486 * use that as the element size. Forward references aren't
492 if (ext
->commonsize
) {
494 struct tokenval tokval
;
497 stdscan_bufptr
= special
;
498 tokval
.t_type
= TOKEN_INVALID
;
499 e
= evaluate(stdscan
, NULL
, &tokval
, NULL
, 1, error
, NULL
);
502 error (ERR_NONFATAL
, "cannot use relocatable"
503 " expression as common-variable element size");
505 ext
->commonelem
= reloc_value(e
);
507 special
= stdscan_bufptr
;
509 error (ERR_NONFATAL
, "`%s': element-size specifications only"
510 " apply to common variables", ext
->name
);
511 while (*special
&& *special
!= ':')
522 eb
= *ebtail
= nasm_malloc(sizeof(*eb
));
526 while (i
> EXT_BLKSIZ
) {
530 eb
= *ebtail
= nasm_malloc(sizeof(*eb
));
537 ext
->index
= ++externals
;
539 if (special
&& !used_special
)
540 error(ERR_NONFATAL
, "OBJ supports no special symbol features"
541 " for this symbol type");
544 static void obj_out (long segto
, void *data
, unsigned long type
,
545 long segment
, long wrt
) {
547 unsigned char *ucdata
;
552 * handle absolute-assembly (structure definitions)
554 if (segto
== NO_SEG
) {
555 if ((type
& OUT_TYPMASK
) != OUT_RESERVE
)
556 error (ERR_NONFATAL
, "attempt to assemble code in [ABSOLUTE]"
562 * If `any_segs' is still FALSE, we must define a default
566 int tempint
; /* ignored */
567 if (segto
!= obj_segment("__NASMDEFSEG", 2, &tempint
))
568 error (ERR_PANIC
, "strange segment conditions in OBJ driver");
572 * Find the segment we are targetting.
574 for (seg
= seghead
; seg
; seg
= seg
->next
)
575 if (seg
->index
== segto
)
578 error (ERR_PANIC
, "code directed to nonexistent segment?");
580 size
= type
& OUT_SIZMASK
;
581 realtype
= type
& OUT_TYPMASK
;
582 if (realtype
== OUT_RAWDATA
) {
585 long len
= obj_ledata_space(seg
);
588 len
= obj_ledata_space(seg
);
592 datacurr
->lptr
= obj_write_data (datacurr
->lptr
, ucdata
, len
);
593 datacurr
->nonempty
= TRUE
;
596 seg
->currentpos
+= len
;
598 } else if (realtype
== OUT_ADDRESS
|| realtype
== OUT_REL2ADR
||
599 realtype
== OUT_REL4ADR
) {
602 if (segment
== NO_SEG
&& realtype
!= OUT_ADDRESS
)
603 error(ERR_NONFATAL
, "relative call to absolute address not"
604 " supported by OBJ format");
605 if (segment
>= SEG_ABS
)
606 error(ERR_NONFATAL
, "far-absolute relocations not supported"
608 ldata
= *(long *)data
;
609 if (realtype
== OUT_REL2ADR
) {
613 if (realtype
== OUT_REL4ADR
) {
617 if (obj_ledata_space(seg
) < 4 || !obj_fixup_free(seg
))
620 datacurr
->lptr
= obj_write_word (datacurr
->lptr
, ldata
);
622 datacurr
->lptr
= obj_write_dword (datacurr
->lptr
, ldata
);
623 datacurr
->nonempty
= TRUE
;
625 if (segment
< SEG_ABS
&& (segment
!= NO_SEG
&& segment
% 2) &&
628 * This is a 4-byte segment-base relocation such as
629 * `MOV EAX,SEG foo'. OBJ format can't actually handle
630 * these, but if the constant term has the 16 low bits
631 * zero, we can just apply a 2-byte segment-base
632 * relocation to the low word instead.
636 error(ERR_NONFATAL
, "OBJ format cannot handle complex"
637 " dword-size segment base references");
639 if (segment
!= NO_SEG
)
640 obj_write_fixup (datacurr
, rsize
,
641 (realtype
== OUT_REL2ADR
||
642 realtype
== OUT_REL4ADR
? 0 : 0x4000),
644 (seg
->currentpos
- datacurr
->startpos
));
645 seg
->currentpos
+= size
;
646 } else if (realtype
== OUT_RESERVE
) {
648 seg
->currentpos
+= size
;
652 static long obj_ledata_space(struct Segment
*segto
) {
653 if (datacurr
&& datacurr
->seg
== segto
)
654 return datacurr
->ledata
+ LEDATA_MAX
- datacurr
->lptr
;
659 static int obj_fixup_free(struct Segment
*segto
) {
660 if (datacurr
&& datacurr
->seg
== segto
)
661 return (datacurr
->fixupp
+ RECORD_MAX
- datacurr
->fptr
) > 8;
666 static void obj_ledata_new(struct Segment
*segto
) {
667 datacurr
= *datatail
= nasm_malloc(sizeof(*datacurr
));
668 datacurr
->next
= NULL
;
669 datatail
= &datacurr
->next
;
670 datacurr
->nonempty
= FALSE
;
671 datacurr
->lptr
= datacurr
->ledata
;
672 datacurr
->fptr
= datacurr
->fixupp
;
673 datacurr
->seg
= segto
;
675 datacurr
->letype
= LEDATA
+1;
677 datacurr
->letype
= LEDATA
;
678 datacurr
->startpos
= segto
->currentpos
;
679 datacurr
->ftype
= FIXUPP
;
681 datacurr
->lptr
= obj_write_index (datacurr
->lptr
, segto
->obj_index
);
682 if (datacurr
->letype
== LEDATA
)
683 datacurr
->lptr
= obj_write_word (datacurr
->lptr
, segto
->currentpos
);
685 datacurr
->lptr
= obj_write_dword (datacurr
->lptr
, segto
->currentpos
);
688 static void obj_ledata_commit(void) {
692 static void obj_write_fixup (struct ObjData
*data
, int bytes
,
693 int segrel
, long seg
, long wrt
,
698 struct Segment
*s
= NULL
;
699 struct Group
*g
= NULL
;
700 struct External
*e
= NULL
;
703 error(ERR_NONFATAL
, "`obj' output driver does not support"
704 " one-byte relocations");
708 locat
= 0x8000 | segrel
| offset
;
714 error(ERR_PANIC
, "OBJ: 4-byte segment base fixup got"
715 " through sanity check");
722 data
->ftype
= FIXUPP
+1; /* need new-style FIXUPP record */
725 data
->fptr
= obj_write_rword (data
->fptr
, locat
);
727 tidx
= fidx
= -1, method
= 0; /* placate optimisers */
730 * See if we can find the segment ID in our segment list. If
731 * so, we have a T4 (LSEG) target.
733 for (s
= seghead
; s
; s
= s
->next
)
737 method
= 4, tidx
= s
->obj_index
;
739 for (g
= grphead
; g
; g
= g
->next
)
743 method
= 5, tidx
= g
->obj_index
;
746 struct ExtBack
*eb
= ebhead
;
747 while (i
> EXT_BLKSIZ
) {
755 method
= 6, e
= eb
->exts
[i
], tidx
= e
->index
;
758 "unrecognised segment value in obj_write_fixup");
763 * If no WRT given, assume the natural default, which is method
766 * - we are doing an OFFSET fixup for a grouped segment, in
767 * which case we require F1 (group).
769 * - we are doing an OFFSET fixup for an external with a
770 * default WRT, in which case we must honour the default WRT.
773 if (!base
&& s
&& s
->grp
)
774 method
|= 0x10, fidx
= s
->grp
->obj_index
;
775 else if (!base
&& e
&& e
->defwrt_type
!= DEFWRT_NONE
) {
776 if (e
->defwrt_type
== DEFWRT_SEGMENT
)
777 method
|= 0x00, fidx
= e
->defwrt_ptr
.seg
->obj_index
;
778 else if (e
->defwrt_type
== DEFWRT_GROUP
)
779 method
|= 0x10, fidx
= e
->defwrt_ptr
.grp
->obj_index
;
781 error(ERR_NONFATAL
, "default WRT specification for"
782 " external `%s' unresolved", e
->name
);
783 method
|= 0x50, fidx
= -1; /* got to do _something_ */
786 method
|= 0x50, fidx
= -1;
789 * See if we can find the WRT-segment ID in our segment
790 * list. If so, we have a F0 (LSEG) frame.
792 for (s
= seghead
; s
; s
= s
->next
)
793 if (s
->index
== wrt
-1)
796 method
|= 0x00, fidx
= s
->obj_index
;
798 for (g
= grphead
; g
; g
= g
->next
)
799 if (g
->index
== wrt
-1)
802 method
|= 0x10, fidx
= g
->obj_index
;
805 struct ExtBack
*eb
= ebhead
;
806 while (i
> EXT_BLKSIZ
) {
814 method
|= 0x20, fidx
= eb
->exts
[i
]->index
;
817 "unrecognised WRT value in obj_write_fixup");
822 data
->fptr
= obj_write_byte (data
->fptr
, method
);
824 data
->fptr
= obj_write_index (data
->fptr
, fidx
);
825 data
->fptr
= obj_write_index (data
->fptr
, tidx
);
828 static long obj_segment (char *name
, int pass
, int *bits
) {
830 * We call the label manager here to define a name for the new
831 * segment, and when our _own_ label-definition stub gets
832 * called in return, it should register the new segment name
833 * using the pointer it gets passed. That way we save memory,
834 * by sponging off the label manager.
842 struct External
**extp
;
843 int obj_idx
, i
, attrs
, rn_error
;
847 * Look for segment attributes.
851 name
++; /* hack, but a documented one */
853 while (*p
&& !isspace(*p
))
857 while (*p
&& isspace(*p
))
861 while (*p
&& !isspace(*p
))
865 while (*p
&& isspace(*p
))
873 for (seg
= seghead
; seg
; seg
= seg
->next
) {
875 if (!strcmp(seg
->name
, name
)) {
876 if (attrs
> 0 && pass
== 1)
877 error(ERR_WARNING
, "segment attributes specified on"
878 " redeclaration of segment: ignoring");
887 *segtail
= seg
= nasm_malloc(sizeof(*seg
));
889 segtail
= &seg
->next
;
890 seg
->index
= (any_segs
? seg_alloc() : first_seg
);
891 seg
->obj_index
= obj_idx
;
896 seg
->align
= 1; /* default */
897 seg
->use32
= FALSE
; /* default */
898 seg
->combine
= CMB_PUBLIC
; /* default */
899 seg
->segclass
= seg
->overlay
= NULL
;
901 seg
->pubtail
= &seg
->pubhead
;
904 * Process the segment attributes.
912 * `p' contains a segment attribute.
914 if (!nasm_stricmp(p
, "private"))
915 seg
->combine
= CMB_PRIVATE
;
916 else if (!nasm_stricmp(p
, "public"))
917 seg
->combine
= CMB_PUBLIC
;
918 else if (!nasm_stricmp(p
, "common"))
919 seg
->combine
= CMB_COMMON
;
920 else if (!nasm_stricmp(p
, "stack"))
921 seg
->combine
= CMB_STACK
;
922 else if (!nasm_stricmp(p
, "use16"))
924 else if (!nasm_stricmp(p
, "use32"))
926 else if (!nasm_stricmp(p
, "flat")) {
928 * This segment is an OS/2 FLAT segment. That means
929 * that its default group is group FLAT, even if
930 * the group FLAT does not explicitly _contain_ the
933 * When we see this, we must create the group
934 * `FLAT', containing no segments, if it does not
935 * already exist; then we must set the default
936 * group of this segment to be the FLAT group.
939 for (grp
= grphead
; grp
; grp
= grp
->next
)
940 if (!strcmp(grp
->name
, "FLAT"))
943 obj_directive ("group", "FLAT", 1);
944 for (grp
= grphead
; grp
; grp
= grp
->next
)
945 if (!strcmp(grp
->name
, "FLAT"))
948 error (ERR_PANIC
, "failure to define FLAT?!");
951 } else if (!nasm_strnicmp(p
, "class=", 6))
952 seg
->segclass
= nasm_strdup(p
+6);
953 else if (!nasm_strnicmp(p
, "overlay=", 8))
954 seg
->overlay
= nasm_strdup(p
+8);
955 else if (!nasm_strnicmp(p
, "align=", 6)) {
956 seg
->align
= readnum(p
+6, &rn_error
);
959 error (ERR_NONFATAL
, "segment alignment should be"
962 switch ((int) seg
->align
) {
968 case 4096: /* PharLap extension */
971 error(ERR_WARNING
, "OBJ format does not support alignment"
972 " of 8: rounding up to 16");
978 error(ERR_WARNING
, "OBJ format does not support alignment"
979 " of %d: rounding up to 256", seg
->align
);
985 error(ERR_WARNING
, "OBJ format does not support alignment"
986 " of %d: rounding up to 4096", seg
->align
);
990 error(ERR_NONFATAL
, "invalid alignment value %d",
995 } else if (!nasm_strnicmp(p
, "absolute=", 9)) {
996 seg
->align
= SEG_ABS
+ readnum(p
+9, &rn_error
);
998 error (ERR_NONFATAL
, "argument to `absolute' segment"
999 " attribute should be numeric");
1003 obj_seg_needs_update
= seg
;
1004 if (seg
->align
>= SEG_ABS
)
1005 deflabel (name
, NO_SEG
, seg
->align
- SEG_ABS
,
1006 NULL
, FALSE
, FALSE
, &of_obj
, error
);
1008 deflabel (name
, seg
->index
+1, 0L,
1009 NULL
, FALSE
, FALSE
, &of_obj
, error
);
1010 obj_seg_needs_update
= NULL
;
1013 * See if this segment is defined in any groups.
1015 for (grp
= grphead
; grp
; grp
= grp
->next
) {
1016 for (i
= grp
->nindices
; i
< grp
->nentries
; i
++) {
1017 if (!strcmp(grp
->segs
[i
].name
, seg
->name
)) {
1018 nasm_free (grp
->segs
[i
].name
);
1019 grp
->segs
[i
] = grp
->segs
[grp
->nindices
];
1020 grp
->segs
[grp
->nindices
++].index
= seg
->obj_index
;
1022 error(ERR_WARNING
, "segment `%s' is already part of"
1023 " a group: first one takes precedence",
1032 * Walk through the list of externals with unresolved
1033 * default-WRT clauses, and resolve any that point at this
1038 if ((*extp
)->defwrt_type
== DEFWRT_STRING
&&
1039 !strcmp((*extp
)->defwrt_ptr
.string
, seg
->name
)) {
1040 (*extp
)->defwrt_type
= DEFWRT_SEGMENT
;
1041 (*extp
)->defwrt_ptr
.seg
= seg
;
1042 *extp
= (*extp
)->next_dws
;
1044 extp
= &(*extp
)->next_dws
;
1055 static int obj_directive (char *directive
, char *value
, int pass
) {
1056 if (!strcmp(directive
, "group")) {
1060 struct Segment
*seg
;
1061 struct External
**extp
;
1066 q
++; /* hack, but a documented one */
1068 while (*q
&& !isspace(*q
))
1072 while (*q
&& isspace(*q
))
1076 * Here we used to sanity-check the group directive to
1077 * ensure nobody tried to declare a group containing no
1078 * segments. However, OS/2 does this as standard
1079 * practice, so the sanity check has been removed.
1082 * error(ERR_NONFATAL,"GROUP directive contains no segments");
1088 for (grp
= grphead
; grp
; grp
= grp
->next
) {
1090 if (!strcmp(grp
->name
, v
)) {
1091 error(ERR_NONFATAL
, "group `%s' defined twice", v
);
1096 *grptail
= grp
= nasm_malloc(sizeof(*grp
));
1098 grptail
= &grp
->next
;
1099 grp
->index
= seg_alloc();
1100 grp
->obj_index
= obj_idx
;
1101 grp
->nindices
= grp
->nentries
= 0;
1104 obj_grp_needs_update
= grp
;
1105 deflabel (v
, grp
->index
+1, 0L,
1106 NULL
, FALSE
, FALSE
, &of_obj
, error
);
1107 obj_grp_needs_update
= NULL
;
1111 while (*q
&& !isspace(*q
))
1115 while (*q
&& isspace(*q
))
1119 * Now p contains a segment name. Find it.
1121 for (seg
= seghead
; seg
; seg
= seg
->next
)
1122 if (!strcmp(seg
->name
, p
))
1126 * We have a segment index. Shift a name entry
1127 * to the end of the array to make room.
1129 grp
->segs
[grp
->nentries
++] = grp
->segs
[grp
->nindices
];
1130 grp
->segs
[grp
->nindices
++].index
= seg
->obj_index
;
1132 error(ERR_WARNING
, "segment `%s' is already part of"
1133 " a group: first one takes precedence",
1139 * We have an as-yet undefined segment.
1140 * Remember its name, for later.
1142 grp
->segs
[grp
->nentries
++].name
= nasm_strdup(p
);
1147 * Walk through the list of externals with unresolved
1148 * default-WRT clauses, and resolve any that point at
1153 if ((*extp
)->defwrt_type
== DEFWRT_STRING
&&
1154 !strcmp((*extp
)->defwrt_ptr
.string
, grp
->name
)) {
1155 (*extp
)->defwrt_type
= DEFWRT_GROUP
;
1156 (*extp
)->defwrt_ptr
.grp
= grp
;
1157 *extp
= (*extp
)->next_dws
;
1159 extp
= &(*extp
)->next_dws
;
1164 if (!strcmp(directive
, "uppercase")) {
1165 obj_uppercase
= TRUE
;
1168 if (!strcmp(directive
, "import")) {
1169 char *q
, *extname
, *libname
, *impname
;
1172 return 1; /* ignore in pass two */
1173 extname
= q
= value
;
1174 while (*q
&& !isspace(*q
))
1178 while (*q
&& isspace(*q
))
1183 while (*q
&& !isspace(*q
))
1187 while (*q
&& isspace(*q
))
1193 if (!*extname
|| !*libname
)
1194 error(ERR_NONFATAL
, "`import' directive requires symbol name"
1195 " and library name");
1200 imp
= *imptail
= nasm_malloc(sizeof(struct ImpDef
));
1201 imptail
= &imp
->next
;
1203 imp
->extname
= nasm_strdup(extname
);
1204 imp
->libname
= nasm_strdup(libname
);
1205 imp
->impindex
= readnum(impname
, &err
);
1206 if (!*impname
|| err
)
1207 imp
->impname
= nasm_strdup(impname
);
1209 imp
->impname
= NULL
;
1214 if (!strcmp(directive
, "export")) {
1215 char *q
, *extname
, *intname
, *v
;
1216 struct ExpDef
*export
;
1218 unsigned int ordinal
= 0;
1221 return 1; /* ignore in pass two */
1222 intname
= q
= value
;
1223 while (*q
&& !isspace(*q
))
1227 while (*q
&& isspace(*q
))
1232 while (*q
&& !isspace(*q
))
1236 while (*q
&& isspace(*q
))
1241 error(ERR_NONFATAL
, "`export' directive requires export name");
1250 while (*q
&& !isspace(*q
))
1254 while (*q
&& isspace(*q
))
1257 if (!nasm_stricmp(v
, "resident"))
1258 flags
|= EXPDEF_FLAG_RESIDENT
;
1259 else if (!nasm_stricmp(v
, "nodata"))
1260 flags
|= EXPDEF_FLAG_NODATA
;
1261 else if (!nasm_strnicmp(v
, "parm=", 5)) {
1263 flags
|= EXPDEF_MASK_PARMCNT
& readnum(v
+5, &err
);
1266 "value `%s' for `parm' is non-numeric", v
+5);
1271 ordinal
= readnum(v
, &err
);
1273 error(ERR_NONFATAL
, "unrecognised export qualifier `%s'",
1277 flags
|= EXPDEF_FLAG_ORDINAL
;
1281 export
= *exptail
= nasm_malloc(sizeof(struct ExpDef
));
1282 exptail
= &export
->next
;
1283 export
->next
= NULL
;
1284 export
->extname
= nasm_strdup(extname
);
1285 export
->intname
= nasm_strdup(intname
);
1286 export
->ordinal
= ordinal
;
1287 export
->flags
= flags
;
1294 static long obj_segbase (long segment
) {
1295 struct Segment
*seg
;
1298 * Find the segment in our list.
1300 for (seg
= seghead
; seg
; seg
= seg
->next
)
1301 if (seg
->index
== segment
-1)
1306 * Might be an external with a default WRT.
1309 struct ExtBack
*eb
= ebhead
;
1312 while (i
> EXT_BLKSIZ
) {
1321 if (e
->defwrt_type
== DEFWRT_NONE
)
1322 return segment
; /* fine */
1323 else if (e
->defwrt_type
== DEFWRT_SEGMENT
)
1324 return e
->defwrt_ptr
.seg
->index
+1;
1325 else if (e
->defwrt_type
== DEFWRT_GROUP
)
1326 return e
->defwrt_ptr
.grp
->index
+1;
1327 else if (e
->defwrt_type
== DEFWRT_STRING
)
1328 return NO_SEG
; /* can't tell what it is */
1331 return segment
; /* not one of ours - leave it alone */
1334 if (seg
->align
>= SEG_ABS
)
1335 return seg
->align
; /* absolute segment */
1337 return seg
->grp
->index
+1; /* grouped segment */
1339 return segment
; /* no special treatment */
1342 static void obj_filename (char *inname
, char *outname
, efunc error
) {
1343 strcpy(obj_infile
, inname
);
1344 standard_extension (inname
, outname
, ".obj", error
);
1347 static void obj_write_file (void) {
1348 struct Segment
*seg
;
1351 struct External
*ext
;
1352 struct ObjData
*data
;
1354 struct ExpDef
*export
;
1355 static char boast
[] = "The Netwide Assembler " NASM_VER
;
1356 int lname_idx
, rectype
;
1359 * Write the THEADR module header.
1362 recptr
= obj_write_name (recptr
, obj_infile
);
1363 obj_record (THEADR
, record
, recptr
);
1366 * Write the NASM boast comment.
1369 recptr
= obj_write_rword (recptr
, 0); /* comment type zero */
1370 recptr
= obj_write_name (recptr
, boast
);
1371 obj_record (COMENT
, record
, recptr
);
1374 * Write the IMPDEF records, if any.
1376 for (imp
= imphead
; imp
; imp
= imp
->next
) {
1378 recptr
= obj_write_rword (recptr
, 0xA0); /* comment class A0 */
1379 recptr
= obj_write_byte (recptr
, 1); /* subfunction 1: IMPDEF */
1381 recptr
= obj_write_byte (recptr
, 0); /* import by name */
1383 recptr
= obj_write_byte (recptr
, 1); /* import by ordinal */
1384 recptr
= obj_write_name (recptr
, imp
->extname
);
1385 recptr
= obj_write_name (recptr
, imp
->libname
);
1387 recptr
= obj_write_name (recptr
, imp
->impname
);
1389 recptr
= obj_write_word (recptr
, imp
->impindex
);
1390 obj_record (COMENT
, record
, recptr
);
1394 * Write the EXPDEF records, if any.
1396 for (export
= exphead
; export
; export
= export
->next
) {
1398 recptr
= obj_write_rword (recptr
, 0xA0); /* comment class A0 */
1399 recptr
= obj_write_byte (recptr
, 2); /* subfunction 1: EXPDEF */
1400 recptr
= obj_write_byte (recptr
, export
->flags
);
1401 recptr
= obj_write_name (recptr
, export
->extname
);
1402 recptr
= obj_write_name (recptr
, export
->intname
);
1403 if (export
->flags
& EXPDEF_FLAG_ORDINAL
)
1404 recptr
= obj_write_word (recptr
, export
->ordinal
);
1405 obj_record (COMENT
, record
, recptr
);
1409 * Write the first LNAMES record, containing LNAME one, which
1410 * is null. Also initialise the LNAME counter.
1413 recptr
= obj_write_name (recptr
, "");
1414 obj_record (LNAMES
, record
, recptr
);
1418 * Write the SEGDEF records. Each has an associated LNAMES
1421 for (seg
= seghead
; seg
; seg
= seg
->next
) {
1422 int new_segdef
; /* do we use the newer record type? */
1424 int sn
, cn
, on
; /* seg, class, overlay LNAME idx */
1426 if (seg
->use32
|| seg
->currentpos
>= 0x10000L
)
1432 recptr
= obj_write_name (recptr
, seg
->name
);
1434 if (seg
->segclass
) {
1435 recptr
= obj_write_name (recptr
, seg
->segclass
);
1440 recptr
= obj_write_name (recptr
, seg
->overlay
);
1444 obj_record (LNAMES
, record
, recptr
);
1446 acbp
= (seg
->combine
<< 2); /* C field */
1448 if (seg
->currentpos
>= 0x10000L
&& !new_segdef
)
1449 acbp
|= 0x02; /* B bit */
1452 acbp
|= 0x01; /* P bit is Use32 flag */
1455 if (seg
->align
>= SEG_ABS
)
1457 else if (seg
->align
>= 4096) {
1458 if (seg
->align
> 4096)
1459 error(ERR_NONFATAL
, "segment `%s' requires more alignment"
1460 " than OBJ format supports", seg
->name
);
1461 acbp
|= 0xC0; /* PharLap extension */
1462 } else if (seg
->align
>= 256) {
1464 } else if (seg
->align
>= 16) {
1466 } else if (seg
->align
>= 4) {
1468 } else if (seg
->align
>= 2) {
1474 recptr
= obj_write_byte (recptr
, acbp
);
1475 if (seg
->align
& SEG_ABS
) {
1476 recptr
= obj_write_word (recptr
, seg
->align
- SEG_ABS
);
1477 recptr
= obj_write_byte (recptr
, 0);
1480 recptr
= obj_write_dword (recptr
, seg
->currentpos
);
1482 recptr
= obj_write_word (recptr
, seg
->currentpos
& 0xFFFF);
1483 recptr
= obj_write_index (recptr
, sn
);
1484 recptr
= obj_write_index (recptr
, cn
);
1485 recptr
= obj_write_index (recptr
, on
);
1487 obj_record (SEGDEF
+1, record
, recptr
);
1489 obj_record (SEGDEF
, record
, recptr
);
1493 * Write some LNAMES for the group names. lname_idx is left
1494 * alone here - it will catch up when we write the GRPDEFs.
1497 for (grp
= grphead
; grp
; grp
= grp
->next
) {
1498 if (recptr
- record
+ strlen(grp
->name
)+2 > 1024) {
1499 obj_record (LNAMES
, record
, recptr
);
1502 recptr
= obj_write_name (recptr
, grp
->name
);
1504 if (recptr
> record
)
1505 obj_record (LNAMES
, record
, recptr
);
1508 * Write the GRPDEF records.
1510 for (grp
= grphead
; grp
; grp
= grp
->next
) {
1513 if (grp
->nindices
!= grp
->nentries
) {
1514 for (i
= grp
->nindices
; i
< grp
->nentries
; i
++) {
1515 error(ERR_NONFATAL
, "group `%s' contains undefined segment"
1516 " `%s'", grp
->name
, grp
->segs
[i
].name
);
1517 nasm_free (grp
->segs
[i
].name
);
1518 grp
->segs
[i
].name
= NULL
;
1522 recptr
= obj_write_index (recptr
, lname_idx
++);
1523 for (i
= 0; i
< grp
->nindices
; i
++) {
1524 recptr
= obj_write_byte (recptr
, 0xFF);
1525 recptr
= obj_write_index (recptr
, grp
->segs
[i
].index
);
1527 obj_record (GRPDEF
, record
, recptr
);
1531 * Write the PUBDEF records: first the ones in the segments,
1532 * then the far-absolutes.
1534 for (seg
= seghead
; seg
; seg
= seg
->next
) {
1538 recptr
= obj_write_index (recptr
, seg
->grp
? seg
->grp
->obj_index
: 0);
1539 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1545 for (pub
= seg
->pubhead
; pub
; pub
= pub
->next
) {
1546 if (recptr
- record
+ strlen(pub
->name
) + 7 > 1024) {
1548 obj_record (rectype
, record
, recptr
);
1550 recptr
= obj_write_index (recptr
, 0);
1551 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1553 recptr
= obj_write_name (recptr
, pub
->name
);
1555 recptr
= obj_write_dword (recptr
, pub
->offset
);
1557 recptr
= obj_write_word (recptr
, pub
->offset
);
1558 recptr
= obj_write_index (recptr
, 0);
1562 obj_record (rectype
, record
, recptr
);
1564 for (pub
= fpubhead
; pub
; pub
= pub
->next
) { /* pub-crawl :-) */
1566 recptr
= obj_write_index (recptr
, 0); /* no group */
1567 recptr
= obj_write_index (recptr
, 0); /* no segment either */
1568 recptr
= obj_write_word (recptr
, pub
->segment
);
1569 recptr
= obj_write_name (recptr
, pub
->name
);
1570 recptr
= obj_write_word (recptr
, pub
->offset
);
1571 recptr
= obj_write_index (recptr
, 0);
1572 obj_record (PUBDEF
, record
, recptr
);
1576 * Write the EXTDEF and COMDEF records, in order.
1579 for (ext
= exthead
; ext
; ext
= ext
->next
) {
1580 if (ext
->commonsize
== 0) {
1581 /* dj@delorie.com: check for buffer overrun before we overrun it */
1582 if (recptr
- record
+ strlen(ext
->name
)+2 > RECORD_MAX
) {
1583 obj_record (EXTDEF
, record
, recptr
);
1586 recptr
= obj_write_name (recptr
, ext
->name
);
1587 recptr
= obj_write_index (recptr
, 0);
1589 if (recptr
> record
)
1590 obj_record (EXTDEF
, record
, recptr
);
1592 if (ext
->commonsize
) {
1593 recptr
= obj_write_name (recptr
, ext
->name
);
1594 recptr
= obj_write_index (recptr
, 0);
1595 if (ext
->commonelem
) {
1596 recptr
= obj_write_byte (recptr
, 0x61);/* far communal */
1597 recptr
= obj_write_value (recptr
, (ext
->commonsize
/
1599 recptr
= obj_write_value (recptr
, ext
->commonelem
);
1601 recptr
= obj_write_byte (recptr
, 0x62);/* near communal */
1602 recptr
= obj_write_value (recptr
, ext
->commonsize
);
1604 obj_record (COMDEF
, record
, recptr
);
1609 if (recptr
> record
)
1610 obj_record (EXTDEF
, record
, recptr
);
1613 * Write a COMENT record stating that the linker's first pass
1614 * may stop processing at this point. Exception is if our
1615 * MODEND record specifies a start point, in which case,
1616 * according to some variants of the documentation, this COMENT
1617 * should be omitted. So we'll omit it just in case.
1619 if (obj_entry_seg
== NO_SEG
) {
1621 recptr
= obj_write_rword (recptr
, 0x40A2);
1622 recptr
= obj_write_byte (recptr
, 1);
1623 obj_record (COMENT
, record
, recptr
);
1627 * Write the LEDATA/FIXUPP pairs.
1629 for (data
= datahead
; data
; data
= data
->next
) {
1630 if (data
->nonempty
) {
1631 obj_record (data
->letype
, data
->ledata
, data
->lptr
);
1632 if (data
->fptr
!= data
->fixupp
)
1633 obj_record (data
->ftype
, data
->fixupp
, data
->fptr
);
1638 * Write the MODEND module end marker.
1642 if (obj_entry_seg
!= NO_SEG
) {
1643 recptr
= obj_write_byte (recptr
, 0xC1);
1645 * Find the segment in the segment list.
1647 for (seg
= seghead
; seg
; seg
= seg
->next
) {
1648 if (seg
->index
== obj_entry_seg
) {
1650 recptr
= obj_write_byte (recptr
, 0x10);
1651 recptr
= obj_write_index (recptr
, seg
->grp
->obj_index
);
1653 recptr
= obj_write_byte (recptr
, 0x50);
1655 recptr
= obj_write_index (recptr
, seg
->obj_index
);
1658 recptr
= obj_write_dword (recptr
, obj_entry_ofs
);
1660 recptr
= obj_write_word (recptr
, obj_entry_ofs
);
1665 error(ERR_NONFATAL
, "entry point is not in this module");
1667 recptr
= obj_write_byte (recptr
, 0);
1668 obj_record (rectype
, record
, recptr
);
1671 static unsigned char *obj_write_data(unsigned char *ptr
,
1672 unsigned char *data
, int len
) {
1678 static unsigned char *obj_write_byte(unsigned char *ptr
, int data
) {
1683 static unsigned char *obj_write_word(unsigned char *ptr
, int data
) {
1684 *ptr
++ = data
& 0xFF;
1685 *ptr
++ = (data
>> 8) & 0xFF;
1689 static unsigned char *obj_write_dword(unsigned char *ptr
, long data
) {
1690 *ptr
++ = data
& 0xFF;
1691 *ptr
++ = (data
>> 8) & 0xFF;
1692 *ptr
++ = (data
>> 16) & 0xFF;
1693 *ptr
++ = (data
>> 24) & 0xFF;
1697 static unsigned char *obj_write_rword(unsigned char *ptr
, int data
) {
1698 *ptr
++ = (data
>> 8) & 0xFF;
1699 *ptr
++ = data
& 0xFF;
1703 static unsigned char *obj_write_name(unsigned char *ptr
, char *data
) {
1704 *ptr
++ = strlen(data
);
1705 if (obj_uppercase
) {
1707 *ptr
++ = (unsigned char) toupper(*data
);
1712 *ptr
++ = (unsigned char) *data
++;
1717 static unsigned char *obj_write_index(unsigned char *ptr
, int data
) {
1721 *ptr
++ = 0x80 | ((data
>> 8) & 0x7F);
1722 *ptr
++ = data
& 0xFF;
1727 static unsigned char *obj_write_value(unsigned char *ptr
,
1728 unsigned long data
) {
1731 else if (data
<= 0xFFFF) {
1733 *ptr
++ = data
& 0xFF;
1734 *ptr
++ = (data
>> 8) & 0xFF;
1735 } else if (data
<= 0xFFFFFFL
) {
1737 *ptr
++ = data
& 0xFF;
1738 *ptr
++ = (data
>> 8) & 0xFF;
1739 *ptr
++ = (data
>> 16) & 0xFF;
1742 *ptr
++ = data
& 0xFF;
1743 *ptr
++ = (data
>> 8) & 0xFF;
1744 *ptr
++ = (data
>> 16) & 0xFF;
1745 *ptr
++ = (data
>> 24) & 0xFF;
1750 static void obj_record(int type
, unsigned char *start
, unsigned char *end
) {
1751 unsigned long cksum
, len
;
1756 cksum
+= (len
& 0xFF) + ((len
>>8) & 0xFF);
1757 fwriteshort (len
, ofp
);
1758 fwrite (start
, 1, end
-start
, ofp
);
1761 fputc ( (-(long)cksum
) & 0xFF, ofp
);
1764 static char *obj_stdmac
[] = {
1765 "%define __SECT__ [section .text]",
1766 "%imacro group 1+.nolist",
1769 "%imacro uppercase 1+.nolist",
1772 "%imacro export 1+.nolist",
1775 "%imacro import 1+.nolist",
1781 struct ofmt of_obj
= {
1782 "Microsoft MS-DOS 16-bit OMF object files",