]> git.saurik.com Git - apple/boot.git/blob - i386/nasm/outobj.c
boot-111.1.tar.gz
[apple/boot.git] / i386 / nasm / outobj.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
12 * this file.
13 *
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
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /* outobj.c output routines for the Netwide Assembler to produce
25 * Microsoft 16-bit .OBJ object files
26 *
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.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 #include "nasm.h"
39 #include "nasmlib.h"
40 #include "outform.h"
41
42 #ifdef OF_OBJ
43
44 static char obj_infile[FILENAME_MAX];
45 static int obj_uppercase;
46
47 static efunc error;
48 static evalfunc evaluate;
49 static ldfunc deflabel;
50 static FILE *ofp;
51 static long first_seg;
52 static int any_segs;
53
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 */
59
60 static unsigned char record[RECORD_MAX], *recptr;
61
62 struct Segment; /* need to know these structs exist */
63 struct Group;
64
65 static struct Public {
66 struct Public *next;
67 char *name;
68 long offset;
69 long segment; /* only if it's far-absolute */
70 } *fpubhead, **fpubtail;
71
72 static struct External {
73 struct External *next;
74 char *name;
75 long commonsize;
76 long commonelem; /* element size if FAR, else zero */
77 int index; /* OBJ-file external index */
78 enum {
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 */
83 } defwrt_type;
84 union {
85 char *string;
86 struct Segment *seg;
87 struct Group *grp;
88 } defwrt_ptr;
89 struct External *next_dws; /* next with DEFWRT_STRING */
90 } *exthead, **exttail, *dws;
91
92 static int externals;
93
94 static struct ExtBack {
95 struct ExtBack *next;
96 struct External *exts[EXT_BLKSIZ];
97 } *ebhead, **ebtail;
98
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 */
104 long currentpos;
105 long align; /* can be SEG_ABS + absolute addr */
106 enum {
107 CMB_PRIVATE = 0,
108 CMB_PUBLIC = 2,
109 CMB_STACK = 5,
110 CMB_COMMON = 6
111 } combine;
112 long use32; /* is this segment 32-bit? */
113 struct Public *pubhead, **pubtail;
114 char *name;
115 char *segclass, *overlay; /* `class' is a C++ keyword :-) */
116 } *seghead, **segtail, *obj_seg_needs_update;
117
118 static struct Group {
119 struct Group *next;
120 char *name;
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... */
125 union {
126 long index;
127 char *name;
128 } segs[GROUP_MAX]; /* ...in this */
129 } *grphead, **grptail, *obj_grp_needs_update;
130
131 static struct ObjData {
132 struct ObjData *next;
133 int nonempty;
134 struct Segment *seg;
135 long startpos;
136 int letype, ftype;
137 unsigned char ledata[LEDATA_MAX], *lptr;
138 unsigned char fixupp[RECORD_MAX], *fptr;
139 } *datahead, *datacurr, **datatail;
140
141 static struct ImpDef {
142 struct ImpDef *next;
143 char *extname;
144 char *libname;
145 unsigned int impindex;
146 char *impname;
147 } *imphead, **imptail;
148
149 static struct ExpDef {
150 struct ExpDef *next;
151 char *intname;
152 char *extname;
153 unsigned int ordinal;
154 int flags;
155 } *exphead, **exptail;
156
157 #define EXPDEF_FLAG_ORDINAL 0x80
158 #define EXPDEF_FLAG_RESIDENT 0x40
159 #define EXPDEF_FLAG_NODATA 0x20
160 #define EXPDEF_MASK_PARMCNT 0x1F
161
162 static long obj_entry_seg, obj_entry_ofs;
163
164 enum RecordID { /* record ID codes */
165
166 THEADR = 0x80, /* module header */
167 COMENT = 0x88, /* comment record */
168
169 LNAMES = 0x96, /* list of names */
170
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 */
176
177 LEDATA = 0xA0, /* logical enumerated data */
178 FIXUPP = 0x9C, /* fixups (relocations) */
179
180 MODEND = 0x8A /* module end */
181 };
182
183 extern struct ofmt of_obj;
184
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);
202
203 static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
204 ofp = fp;
205 error = errfunc;
206 evaluate = eval;
207 deflabel = ldef;
208 first_seg = seg_alloc();
209 any_segs = FALSE;
210 fpubhead = NULL;
211 fpubtail = &fpubhead;
212 exthead = NULL;
213 exttail = &exthead;
214 imphead = NULL;
215 imptail = &imphead;
216 exphead = NULL;
217 exptail = &exphead;
218 dws = NULL;
219 externals = 0;
220 ebhead = NULL;
221 ebtail = &ebhead;
222 seghead = obj_seg_needs_update = NULL;
223 segtail = &seghead;
224 grphead = obj_grp_needs_update = NULL;
225 grptail = &grphead;
226 datahead = datacurr = NULL;
227 datatail = &datahead;
228 obj_entry_seg = NO_SEG;
229 obj_uppercase = FALSE;
230 }
231
232 static void obj_cleanup (void) {
233 obj_write_file();
234 fclose (ofp);
235 while (seghead) {
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);
242 nasm_free (pubtmp);
243 }
244 nasm_free (segtmp);
245 }
246 while (fpubhead) {
247 struct Public *pubtmp = fpubhead;
248 fpubhead = fpubhead->next;
249 nasm_free (pubtmp->name);
250 nasm_free (pubtmp);
251 }
252 while (exthead) {
253 struct External *exttmp = exthead;
254 exthead = exthead->next;
255 nasm_free (exttmp);
256 }
257 while (imphead) {
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 */
263 nasm_free (imptmp);
264 }
265 while (exphead) {
266 struct ExpDef *exptmp = exphead;
267 exphead = exphead->next;
268 nasm_free (exptmp->extname);
269 nasm_free (exptmp->intname);
270 nasm_free (exptmp);
271 }
272 while (ebhead) {
273 struct ExtBack *ebtmp = ebhead;
274 ebhead = ebhead->next;
275 nasm_free (ebtmp);
276 }
277 while (grphead) {
278 struct Group *grptmp = grphead;
279 grphead = grphead->next;
280 nasm_free (grptmp);
281 }
282 while (datahead) {
283 struct ObjData *datatmp = datahead;
284 datahead = datahead->next;
285 nasm_free (datatmp);
286 }
287 }
288
289 static void obj_ext_set_defwrt (struct External *ext, char *id) {
290 struct Segment *seg;
291 struct Group *grp;
292
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;
297 nasm_free (id);
298 return;
299 }
300
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;
305 nasm_free (id);
306 return;
307 }
308
309 ext->defwrt_type = DEFWRT_STRING;
310 ext->defwrt_ptr.string = id;
311 ext->next_dws = dws;
312 dws = ext;
313 }
314
315 static void obj_deflabel (char *name, long segment,
316 long offset, int is_global, char *special) {
317 /*
318 * We have three cases:
319 *
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
322 * return.
323 *
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.)
327 *
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.
332 */
333 struct External *ext;
334 struct ExtBack *eb;
335 struct Segment *seg;
336 int i;
337 int used_special = FALSE; /* have we used the special text? */
338
339 /*
340 * If it's a special-retry from pass two, discard it.
341 */
342 if (is_global == 3)
343 return;
344
345 /*
346 * First check for the double-period, signifying something
347 * unusual.
348 */
349 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
350 if (!strcmp(name, "..start")) {
351 obj_entry_seg = segment;
352 obj_entry_ofs = offset;
353 return;
354 }
355 error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
356 }
357
358 /*
359 * Case (i):
360 */
361 if (obj_seg_needs_update) {
362 obj_seg_needs_update->name = name;
363 return;
364 } else if (obj_grp_needs_update) {
365 obj_grp_needs_update->name = name;
366 return;
367 }
368 if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
369 return;
370
371 if (segment >= SEG_ABS || segment == NO_SEG) {
372 /*
373 * SEG_ABS subcase of (ii).
374 */
375 if (is_global) {
376 struct Public *pub;
377
378 pub = *fpubtail = nasm_malloc(sizeof(*pub));
379 fpubtail = &pub->next;
380 pub->next = NULL;
381 pub->name = nasm_strdup(name);
382 pub->offset = offset;
383 pub->segment = (segment == NO_SEG ? 0 : segment & ~SEG_ABS);
384 }
385 if (special)
386 error(ERR_NONFATAL, "OBJ supports no special symbol features"
387 " for this symbol type");
388 return;
389 }
390
391 /*
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
394 * `first_seg'.
395 */
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");
400 }
401
402 for (seg = seghead; seg; seg = seg->next)
403 if (seg->index == segment) {
404 /*
405 * Case (ii). Maybe MODPUB someday?
406 */
407 if (is_global) {
408 struct Public *pub;
409 pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
410 seg->pubtail = &pub->next;
411 pub->next = NULL;
412 pub->name = nasm_strdup(name);
413 pub->offset = offset;
414 }
415 if (special)
416 error(ERR_NONFATAL, "OBJ supports no special symbol features"
417 " for this symbol type");
418 return;
419 }
420
421 /*
422 * Case (iii).
423 */
424 ext = *exttail = nasm_malloc(sizeof(*ext));
425 ext->next = NULL;
426 exttail = &ext->next;
427 ext->name = name;
428 ext->defwrt_type = DEFWRT_NONE;
429 if (is_global == 2) {
430 ext->commonsize = offset;
431 ext->commonelem = 1; /* default FAR */
432 } else
433 ext->commonsize = 0;
434
435 /*
436 * Now process the special text, if any, to find default-WRT
437 * specifications and common-variable element-size and near/far
438 * specifications.
439 */
440 while (special && *special) {
441 used_special = TRUE;
442
443 /*
444 * We might have a default-WRT specification.
445 */
446 if (!nasm_strnicmp(special, "wrt", 3)) {
447 char *p;
448 int len;
449 special += 3;
450 special += strspn(special, " \t");
451 p = nasm_strndup(special, len = strcspn(special, ":"));
452 obj_ext_set_defwrt (ext, p);
453 special += len;
454 if (*special && *special != ':')
455 error(ERR_NONFATAL, "`:' expected in special symbol"
456 " text for `%s'", ext->name);
457 else if (*special == ':')
458 special++;
459 }
460
461 /*
462 * The NEAR or FAR keywords specify nearness or
463 * farness. FAR gives default element size 1.
464 */
465 if (!nasm_strnicmp(special, "far", 3)) {
466 if (ext->commonsize)
467 ext->commonelem = 1;
468 else
469 error(ERR_NONFATAL, "`%s': `far' keyword may only be applied"
470 " to common variables\n", ext->name);
471 special += 3;
472 special += strspn(special, " \t");
473 } else if (!nasm_strnicmp(special, "near", 4)) {
474 if (ext->commonsize)
475 ext->commonelem = 0;
476 else
477 error(ERR_NONFATAL, "`%s': `far' keyword may only be applied"
478 " to common variables\n", ext->name);
479 special += 4;
480 special += strspn(special, " \t");
481 }
482
483 /*
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
487 * allowed.
488 */
489 if (*special == ':')
490 special++;
491 else if (*special) {
492 if (ext->commonsize) {
493 expr *e;
494 struct tokenval tokval;
495
496 stdscan_reset();
497 stdscan_bufptr = special;
498 tokval.t_type = TOKEN_INVALID;
499 e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL);
500 if (e) {
501 if (!is_simple(e))
502 error (ERR_NONFATAL, "cannot use relocatable"
503 " expression as common-variable element size");
504 else
505 ext->commonelem = reloc_value(e);
506 }
507 special = stdscan_bufptr;
508 } else {
509 error (ERR_NONFATAL, "`%s': element-size specifications only"
510 " apply to common variables", ext->name);
511 while (*special && *special != ':')
512 special++;
513 if (*special == ':')
514 special++;
515 }
516 }
517 }
518
519 i = segment/2;
520 eb = ebhead;
521 if (!eb) {
522 eb = *ebtail = nasm_malloc(sizeof(*eb));
523 eb->next = NULL;
524 ebtail = &eb->next;
525 }
526 while (i > EXT_BLKSIZ) {
527 if (eb && eb->next)
528 eb = eb->next;
529 else {
530 eb = *ebtail = nasm_malloc(sizeof(*eb));
531 eb->next = NULL;
532 ebtail = &eb->next;
533 }
534 i -= EXT_BLKSIZ;
535 }
536 eb->exts[i] = ext;
537 ext->index = ++externals;
538
539 if (special && !used_special)
540 error(ERR_NONFATAL, "OBJ supports no special symbol features"
541 " for this symbol type");
542 }
543
544 static void obj_out (long segto, void *data, unsigned long type,
545 long segment, long wrt) {
546 long size, realtype;
547 unsigned char *ucdata;
548 long ldata;
549 struct Segment *seg;
550
551 /*
552 * handle absolute-assembly (structure definitions)
553 */
554 if (segto == NO_SEG) {
555 if ((type & OUT_TYPMASK) != OUT_RESERVE)
556 error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
557 " space");
558 return;
559 }
560
561 /*
562 * If `any_segs' is still FALSE, we must define a default
563 * segment.
564 */
565 if (!any_segs) {
566 int tempint; /* ignored */
567 if (segto != obj_segment("__NASMDEFSEG", 2, &tempint))
568 error (ERR_PANIC, "strange segment conditions in OBJ driver");
569 }
570
571 /*
572 * Find the segment we are targetting.
573 */
574 for (seg = seghead; seg; seg = seg->next)
575 if (seg->index == segto)
576 break;
577 if (!seg)
578 error (ERR_PANIC, "code directed to nonexistent segment?");
579
580 size = type & OUT_SIZMASK;
581 realtype = type & OUT_TYPMASK;
582 if (realtype == OUT_RAWDATA) {
583 ucdata = data;
584 while (size > 0) {
585 long len = obj_ledata_space(seg);
586 if (len == 0) {
587 obj_ledata_new(seg);
588 len = obj_ledata_space(seg);
589 }
590 if (len > size)
591 len = size;
592 datacurr->lptr = obj_write_data (datacurr->lptr, ucdata, len);
593 datacurr->nonempty = TRUE;
594 ucdata += len;
595 size -= len;
596 seg->currentpos += len;
597 }
598 } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
599 realtype == OUT_REL4ADR) {
600 int rsize;
601
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"
607 " by OBJ format");
608 ldata = *(long *)data;
609 if (realtype == OUT_REL2ADR) {
610 ldata += (size-2);
611 size = 2;
612 }
613 if (realtype == OUT_REL4ADR) {
614 ldata += (size-4);
615 size = 4;
616 }
617 if (obj_ledata_space(seg) < 4 || !obj_fixup_free(seg))
618 obj_ledata_new(seg);
619 if (size == 2)
620 datacurr->lptr = obj_write_word (datacurr->lptr, ldata);
621 else
622 datacurr->lptr = obj_write_dword (datacurr->lptr, ldata);
623 datacurr->nonempty = TRUE;
624 rsize = size;
625 if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) &&
626 size == 4) {
627 /*
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.
633 */
634 rsize = 2;
635 if (ldata & 0xFFFF)
636 error(ERR_NONFATAL, "OBJ format cannot handle complex"
637 " dword-size segment base references");
638 }
639 if (segment != NO_SEG)
640 obj_write_fixup (datacurr, rsize,
641 (realtype == OUT_REL2ADR ||
642 realtype == OUT_REL4ADR ? 0 : 0x4000),
643 segment, wrt,
644 (seg->currentpos - datacurr->startpos));
645 seg->currentpos += size;
646 } else if (realtype == OUT_RESERVE) {
647 obj_ledata_commit();
648 seg->currentpos += size;
649 }
650 }
651
652 static long obj_ledata_space(struct Segment *segto) {
653 if (datacurr && datacurr->seg == segto)
654 return datacurr->ledata + LEDATA_MAX - datacurr->lptr;
655 else
656 return 0;
657 }
658
659 static int obj_fixup_free(struct Segment *segto) {
660 if (datacurr && datacurr->seg == segto)
661 return (datacurr->fixupp + RECORD_MAX - datacurr->fptr) > 8;
662 else
663 return 0;
664 }
665
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;
674 if (segto->use32)
675 datacurr->letype = LEDATA+1;
676 else
677 datacurr->letype = LEDATA;
678 datacurr->startpos = segto->currentpos;
679 datacurr->ftype = FIXUPP;
680
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);
684 else
685 datacurr->lptr = obj_write_dword (datacurr->lptr, segto->currentpos);
686 }
687
688 static void obj_ledata_commit(void) {
689 datacurr = NULL;
690 }
691
692 static void obj_write_fixup (struct ObjData *data, int bytes,
693 int segrel, long seg, long wrt,
694 long offset) {
695 int locat, method;
696 int base;
697 long tidx, fidx;
698 struct Segment *s = NULL;
699 struct Group *g = NULL;
700 struct External *e = NULL;
701
702 if (bytes == 1) {
703 error(ERR_NONFATAL, "`obj' output driver does not support"
704 " one-byte relocations");
705 return;
706 }
707
708 locat = 0x8000 | segrel | offset;
709 if (seg % 2) {
710 base = TRUE;
711 locat |= 0x800;
712 seg--;
713 if (bytes != 2)
714 error(ERR_PANIC, "OBJ: 4-byte segment base fixup got"
715 " through sanity check");
716 } else {
717 base = FALSE;
718 if (bytes == 2)
719 locat |= 0x400;
720 else {
721 locat |= 0x2400;
722 data->ftype = FIXUPP+1; /* need new-style FIXUPP record */
723 }
724 }
725 data->fptr = obj_write_rword (data->fptr, locat);
726
727 tidx = fidx = -1, method = 0; /* placate optimisers */
728
729 /*
730 * See if we can find the segment ID in our segment list. If
731 * so, we have a T4 (LSEG) target.
732 */
733 for (s = seghead; s; s = s->next)
734 if (s->index == seg)
735 break;
736 if (s)
737 method = 4, tidx = s->obj_index;
738 else {
739 for (g = grphead; g; g = g->next)
740 if (g->index == seg)
741 break;
742 if (g)
743 method = 5, tidx = g->obj_index;
744 else {
745 long i = seg/2;
746 struct ExtBack *eb = ebhead;
747 while (i > EXT_BLKSIZ) {
748 if (eb)
749 eb = eb->next;
750 else
751 break;
752 i -= EXT_BLKSIZ;
753 }
754 if (eb)
755 method = 6, e = eb->exts[i], tidx = e->index;
756 else
757 error(ERR_PANIC,
758 "unrecognised segment value in obj_write_fixup");
759 }
760 }
761
762 /*
763 * If no WRT given, assume the natural default, which is method
764 * F5 unless:
765 *
766 * - we are doing an OFFSET fixup for a grouped segment, in
767 * which case we require F1 (group).
768 *
769 * - we are doing an OFFSET fixup for an external with a
770 * default WRT, in which case we must honour the default WRT.
771 */
772 if (wrt == NO_SEG) {
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;
780 else {
781 error(ERR_NONFATAL, "default WRT specification for"
782 " external `%s' unresolved", e->name);
783 method |= 0x50, fidx = -1; /* got to do _something_ */
784 }
785 } else
786 method |= 0x50, fidx = -1;
787 } else {
788 /*
789 * See if we can find the WRT-segment ID in our segment
790 * list. If so, we have a F0 (LSEG) frame.
791 */
792 for (s = seghead; s; s = s->next)
793 if (s->index == wrt-1)
794 break;
795 if (s)
796 method |= 0x00, fidx = s->obj_index;
797 else {
798 for (g = grphead; g; g = g->next)
799 if (g->index == wrt-1)
800 break;
801 if (g)
802 method |= 0x10, fidx = g->obj_index;
803 else {
804 long i = wrt/2;
805 struct ExtBack *eb = ebhead;
806 while (i > EXT_BLKSIZ) {
807 if (eb)
808 eb = eb->next;
809 else
810 break;
811 i -= EXT_BLKSIZ;
812 }
813 if (eb)
814 method |= 0x20, fidx = eb->exts[i]->index;
815 else
816 error(ERR_PANIC,
817 "unrecognised WRT value in obj_write_fixup");
818 }
819 }
820 }
821
822 data->fptr = obj_write_byte (data->fptr, method);
823 if (fidx != -1)
824 data->fptr = obj_write_index (data->fptr, fidx);
825 data->fptr = obj_write_index (data->fptr, tidx);
826 }
827
828 static long obj_segment (char *name, int pass, int *bits) {
829 /*
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.
835 */
836 if (!name) {
837 *bits = 16;
838 return first_seg;
839 } else {
840 struct Segment *seg;
841 struct Group *grp;
842 struct External **extp;
843 int obj_idx, i, attrs, rn_error;
844 char *p;
845
846 /*
847 * Look for segment attributes.
848 */
849 attrs = 0;
850 while (*name == '.')
851 name++; /* hack, but a documented one */
852 p = name;
853 while (*p && !isspace(*p))
854 p++;
855 if (*p) {
856 *p++ = '\0';
857 while (*p && isspace(*p))
858 *p++ = '\0';
859 }
860 while (*p) {
861 while (*p && !isspace(*p))
862 p++;
863 if (*p) {
864 *p++ = '\0';
865 while (*p && isspace(*p))
866 *p++ = '\0';
867 }
868
869 attrs++;
870 }
871
872 obj_idx = 1;
873 for (seg = seghead; seg; seg = seg->next) {
874 obj_idx++;
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");
879 if (seg->use32)
880 *bits = 32;
881 else
882 *bits = 16;
883 return seg->index;
884 }
885 }
886
887 *segtail = seg = nasm_malloc(sizeof(*seg));
888 seg->next = NULL;
889 segtail = &seg->next;
890 seg->index = (any_segs ? seg_alloc() : first_seg);
891 seg->obj_index = obj_idx;
892 seg->grp = NULL;
893 any_segs = TRUE;
894 seg->name = NULL;
895 seg->currentpos = 0;
896 seg->align = 1; /* default */
897 seg->use32 = FALSE; /* default */
898 seg->combine = CMB_PUBLIC; /* default */
899 seg->segclass = seg->overlay = NULL;
900 seg->pubhead = NULL;
901 seg->pubtail = &seg->pubhead;
902
903 /*
904 * Process the segment attributes.
905 */
906 p = name;
907 while (attrs--) {
908 p += strlen(p);
909 while (!*p) p++;
910
911 /*
912 * `p' contains a segment attribute.
913 */
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"))
923 seg->use32 = FALSE;
924 else if (!nasm_stricmp(p, "use32"))
925 seg->use32 = TRUE;
926 else if (!nasm_stricmp(p, "flat")) {
927 /*
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
931 * segment.
932 *
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.
937 */
938 struct Group *grp;
939 for (grp = grphead; grp; grp = grp->next)
940 if (!strcmp(grp->name, "FLAT"))
941 break;
942 if (!grp) {
943 obj_directive ("group", "FLAT", 1);
944 for (grp = grphead; grp; grp = grp->next)
945 if (!strcmp(grp->name, "FLAT"))
946 break;
947 if (!grp)
948 error (ERR_PANIC, "failure to define FLAT?!");
949 }
950 seg->grp = grp;
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);
957 if (rn_error) {
958 seg->align = 1;
959 error (ERR_NONFATAL, "segment alignment should be"
960 " numeric");
961 }
962 switch ((int) seg->align) {
963 case 1: /* BYTE */
964 case 2: /* WORD */
965 case 4: /* DWORD */
966 case 16: /* PARA */
967 case 256: /* PAGE */
968 case 4096: /* PharLap extension */
969 break;
970 case 8:
971 error(ERR_WARNING, "OBJ format does not support alignment"
972 " of 8: rounding up to 16");
973 seg->align = 16;
974 break;
975 case 32:
976 case 64:
977 case 128:
978 error(ERR_WARNING, "OBJ format does not support alignment"
979 " of %d: rounding up to 256", seg->align);
980 seg->align = 256;
981 break;
982 case 512:
983 case 1024:
984 case 2048:
985 error(ERR_WARNING, "OBJ format does not support alignment"
986 " of %d: rounding up to 4096", seg->align);
987 seg->align = 4096;
988 break;
989 default:
990 error(ERR_NONFATAL, "invalid alignment value %d",
991 seg->align);
992 seg->align = 1;
993 break;
994 }
995 } else if (!nasm_strnicmp(p, "absolute=", 9)) {
996 seg->align = SEG_ABS + readnum(p+9, &rn_error);
997 if (rn_error)
998 error (ERR_NONFATAL, "argument to `absolute' segment"
999 " attribute should be numeric");
1000 }
1001 }
1002
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);
1007 else
1008 deflabel (name, seg->index+1, 0L,
1009 NULL, FALSE, FALSE, &of_obj, error);
1010 obj_seg_needs_update = NULL;
1011
1012 /*
1013 * See if this segment is defined in any groups.
1014 */
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;
1021 if (seg->grp)
1022 error(ERR_WARNING, "segment `%s' is already part of"
1023 " a group: first one takes precedence",
1024 seg->name);
1025 else
1026 seg->grp = grp;
1027 }
1028 }
1029 }
1030
1031 /*
1032 * Walk through the list of externals with unresolved
1033 * default-WRT clauses, and resolve any that point at this
1034 * segment.
1035 */
1036 extp = &dws;
1037 while (*extp) {
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;
1043 } else
1044 extp = &(*extp)->next_dws;
1045 }
1046
1047 if (seg->use32)
1048 *bits = 32;
1049 else
1050 *bits = 16;
1051 return seg->index;
1052 }
1053 }
1054
1055 static int obj_directive (char *directive, char *value, int pass) {
1056 if (!strcmp(directive, "group")) {
1057 char *p, *q, *v;
1058 if (pass == 1) {
1059 struct Group *grp;
1060 struct Segment *seg;
1061 struct External **extp;
1062 int obj_idx;
1063
1064 q = value;
1065 while (*q == '.')
1066 q++; /* hack, but a documented one */
1067 v = q;
1068 while (*q && !isspace(*q))
1069 q++;
1070 if (isspace(*q)) {
1071 *q++ = '\0';
1072 while (*q && isspace(*q))
1073 q++;
1074 }
1075 /*
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.
1080 *
1081 * if (!*q) {
1082 * error(ERR_NONFATAL,"GROUP directive contains no segments");
1083 * return 1;
1084 * }
1085 */
1086
1087 obj_idx = 1;
1088 for (grp = grphead; grp; grp = grp->next) {
1089 obj_idx++;
1090 if (!strcmp(grp->name, v)) {
1091 error(ERR_NONFATAL, "group `%s' defined twice", v);
1092 return 1;
1093 }
1094 }
1095
1096 *grptail = grp = nasm_malloc(sizeof(*grp));
1097 grp->next = NULL;
1098 grptail = &grp->next;
1099 grp->index = seg_alloc();
1100 grp->obj_index = obj_idx;
1101 grp->nindices = grp->nentries = 0;
1102 grp->name = NULL;
1103
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;
1108
1109 while (*q) {
1110 p = q;
1111 while (*q && !isspace(*q))
1112 q++;
1113 if (isspace(*q)) {
1114 *q++ = '\0';
1115 while (*q && isspace(*q))
1116 q++;
1117 }
1118 /*
1119 * Now p contains a segment name. Find it.
1120 */
1121 for (seg = seghead; seg; seg = seg->next)
1122 if (!strcmp(seg->name, p))
1123 break;
1124 if (seg) {
1125 /*
1126 * We have a segment index. Shift a name entry
1127 * to the end of the array to make room.
1128 */
1129 grp->segs[grp->nentries++] = grp->segs[grp->nindices];
1130 grp->segs[grp->nindices++].index = seg->obj_index;
1131 if (seg->grp)
1132 error(ERR_WARNING, "segment `%s' is already part of"
1133 " a group: first one takes precedence",
1134 seg->name);
1135 else
1136 seg->grp = grp;
1137 } else {
1138 /*
1139 * We have an as-yet undefined segment.
1140 * Remember its name, for later.
1141 */
1142 grp->segs[grp->nentries++].name = nasm_strdup(p);
1143 }
1144 }
1145
1146 /*
1147 * Walk through the list of externals with unresolved
1148 * default-WRT clauses, and resolve any that point at
1149 * this group.
1150 */
1151 extp = &dws;
1152 while (*extp) {
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;
1158 } else
1159 extp = &(*extp)->next_dws;
1160 }
1161 }
1162 return 1;
1163 }
1164 if (!strcmp(directive, "uppercase")) {
1165 obj_uppercase = TRUE;
1166 return 1;
1167 }
1168 if (!strcmp(directive, "import")) {
1169 char *q, *extname, *libname, *impname;
1170
1171 if (pass == 2)
1172 return 1; /* ignore in pass two */
1173 extname = q = value;
1174 while (*q && !isspace(*q))
1175 q++;
1176 if (isspace(*q)) {
1177 *q++ = '\0';
1178 while (*q && isspace(*q))
1179 q++;
1180 }
1181
1182 libname = q;
1183 while (*q && !isspace(*q))
1184 q++;
1185 if (isspace(*q)) {
1186 *q++ = '\0';
1187 while (*q && isspace(*q))
1188 q++;
1189 }
1190
1191 impname = q;
1192
1193 if (!*extname || !*libname)
1194 error(ERR_NONFATAL, "`import' directive requires symbol name"
1195 " and library name");
1196 else {
1197 struct ImpDef *imp;
1198 int err = FALSE;
1199
1200 imp = *imptail = nasm_malloc(sizeof(struct ImpDef));
1201 imptail = &imp->next;
1202 imp->next = NULL;
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);
1208 else
1209 imp->impname = NULL;
1210 }
1211
1212 return 1;
1213 }
1214 if (!strcmp(directive, "export")) {
1215 char *q, *extname, *intname, *v;
1216 struct ExpDef *export;
1217 int flags = 0;
1218 unsigned int ordinal = 0;
1219
1220 if (pass == 2)
1221 return 1; /* ignore in pass two */
1222 intname = q = value;
1223 while (*q && !isspace(*q))
1224 q++;
1225 if (isspace(*q)) {
1226 *q++ = '\0';
1227 while (*q && isspace(*q))
1228 q++;
1229 }
1230
1231 extname = q;
1232 while (*q && !isspace(*q))
1233 q++;
1234 if (isspace(*q)) {
1235 *q++ = '\0';
1236 while (*q && isspace(*q))
1237 q++;
1238 }
1239
1240 if (!*intname) {
1241 error(ERR_NONFATAL, "`export' directive requires export name");
1242 return 1;
1243 }
1244 if (!*extname) {
1245 extname = intname;
1246 intname = "";
1247 }
1248 while (*q) {
1249 v = q;
1250 while (*q && !isspace(*q))
1251 q++;
1252 if (isspace(*q)) {
1253 *q++ = '\0';
1254 while (*q && isspace(*q))
1255 q++;
1256 }
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)) {
1262 int err = FALSE;
1263 flags |= EXPDEF_MASK_PARMCNT & readnum(v+5, &err);
1264 if (err) {
1265 error(ERR_NONFATAL,
1266 "value `%s' for `parm' is non-numeric", v+5);
1267 return 1;
1268 }
1269 } else {
1270 int err = FALSE;
1271 ordinal = readnum(v, &err);
1272 if (err) {
1273 error(ERR_NONFATAL, "unrecognised export qualifier `%s'",
1274 v);
1275 return 1;
1276 }
1277 flags |= EXPDEF_FLAG_ORDINAL;
1278 }
1279 }
1280
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;
1288
1289 return 1;
1290 }
1291 return 0;
1292 }
1293
1294 static long obj_segbase (long segment) {
1295 struct Segment *seg;
1296
1297 /*
1298 * Find the segment in our list.
1299 */
1300 for (seg = seghead; seg; seg = seg->next)
1301 if (seg->index == segment-1)
1302 break;
1303
1304 if (!seg) {
1305 /*
1306 * Might be an external with a default WRT.
1307 */
1308 long i = segment/2;
1309 struct ExtBack *eb = ebhead;
1310 struct External *e;
1311
1312 while (i > EXT_BLKSIZ) {
1313 if (eb)
1314 eb = eb->next;
1315 else
1316 break;
1317 i -= EXT_BLKSIZ;
1318 }
1319 if (eb) {
1320 e = eb->exts[i];
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 */
1329 }
1330
1331 return segment; /* not one of ours - leave it alone */
1332 }
1333
1334 if (seg->align >= SEG_ABS)
1335 return seg->align; /* absolute segment */
1336 if (seg->grp)
1337 return seg->grp->index+1; /* grouped segment */
1338
1339 return segment; /* no special treatment */
1340 }
1341
1342 static void obj_filename (char *inname, char *outname, efunc error) {
1343 strcpy(obj_infile, inname);
1344 standard_extension (inname, outname, ".obj", error);
1345 }
1346
1347 static void obj_write_file (void) {
1348 struct Segment *seg;
1349 struct Group *grp;
1350 struct Public *pub;
1351 struct External *ext;
1352 struct ObjData *data;
1353 struct ImpDef *imp;
1354 struct ExpDef *export;
1355 static char boast[] = "The Netwide Assembler " NASM_VER;
1356 int lname_idx, rectype;
1357
1358 /*
1359 * Write the THEADR module header.
1360 */
1361 recptr = record;
1362 recptr = obj_write_name (recptr, obj_infile);
1363 obj_record (THEADR, record, recptr);
1364
1365 /*
1366 * Write the NASM boast comment.
1367 */
1368 recptr = record;
1369 recptr = obj_write_rword (recptr, 0); /* comment type zero */
1370 recptr = obj_write_name (recptr, boast);
1371 obj_record (COMENT, record, recptr);
1372
1373 /*
1374 * Write the IMPDEF records, if any.
1375 */
1376 for (imp = imphead; imp; imp = imp->next) {
1377 recptr = record;
1378 recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */
1379 recptr = obj_write_byte (recptr, 1); /* subfunction 1: IMPDEF */
1380 if (imp->impname)
1381 recptr = obj_write_byte (recptr, 0); /* import by name */
1382 else
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);
1386 if (imp->impname)
1387 recptr = obj_write_name (recptr, imp->impname);
1388 else
1389 recptr = obj_write_word (recptr, imp->impindex);
1390 obj_record (COMENT, record, recptr);
1391 }
1392
1393 /*
1394 * Write the EXPDEF records, if any.
1395 */
1396 for (export = exphead; export; export = export->next) {
1397 recptr = record;
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);
1406 }
1407
1408 /*
1409 * Write the first LNAMES record, containing LNAME one, which
1410 * is null. Also initialise the LNAME counter.
1411 */
1412 recptr = record;
1413 recptr = obj_write_name (recptr, "");
1414 obj_record (LNAMES, record, recptr);
1415 lname_idx = 2;
1416
1417 /*
1418 * Write the SEGDEF records. Each has an associated LNAMES
1419 * record.
1420 */
1421 for (seg = seghead; seg; seg = seg->next) {
1422 int new_segdef; /* do we use the newer record type? */
1423 int acbp;
1424 int sn, cn, on; /* seg, class, overlay LNAME idx */
1425
1426 if (seg->use32 || seg->currentpos >= 0x10000L)
1427 new_segdef = TRUE;
1428 else
1429 new_segdef = FALSE;
1430
1431 recptr = record;
1432 recptr = obj_write_name (recptr, seg->name);
1433 sn = lname_idx++;
1434 if (seg->segclass) {
1435 recptr = obj_write_name (recptr, seg->segclass);
1436 cn = lname_idx++;
1437 } else
1438 cn = 1;
1439 if (seg->overlay) {
1440 recptr = obj_write_name (recptr, seg->overlay);
1441 on = lname_idx++;
1442 } else
1443 on = 1;
1444 obj_record (LNAMES, record, recptr);
1445
1446 acbp = (seg->combine << 2); /* C field */
1447
1448 if (seg->currentpos >= 0x10000L && !new_segdef)
1449 acbp |= 0x02; /* B bit */
1450
1451 if (seg->use32)
1452 acbp |= 0x01; /* P bit is Use32 flag */
1453
1454 /* A field */
1455 if (seg->align >= SEG_ABS)
1456 acbp |= 0x00;
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) {
1463 acbp |= 0x80;
1464 } else if (seg->align >= 16) {
1465 acbp |= 0x60;
1466 } else if (seg->align >= 4) {
1467 acbp |= 0xA0;
1468 } else if (seg->align >= 2) {
1469 acbp |= 0x40;
1470 } else
1471 acbp |= 0x20;
1472
1473 recptr = record;
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);
1478 }
1479 if (new_segdef)
1480 recptr = obj_write_dword (recptr, seg->currentpos);
1481 else
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);
1486 if (new_segdef)
1487 obj_record (SEGDEF+1, record, recptr);
1488 else
1489 obj_record (SEGDEF, record, recptr);
1490 }
1491
1492 /*
1493 * Write some LNAMES for the group names. lname_idx is left
1494 * alone here - it will catch up when we write the GRPDEFs.
1495 */
1496 recptr = record;
1497 for (grp = grphead; grp; grp = grp->next) {
1498 if (recptr - record + strlen(grp->name)+2 > 1024) {
1499 obj_record (LNAMES, record, recptr);
1500 recptr = record;
1501 }
1502 recptr = obj_write_name (recptr, grp->name);
1503 }
1504 if (recptr > record)
1505 obj_record (LNAMES, record, recptr);
1506
1507 /*
1508 * Write the GRPDEF records.
1509 */
1510 for (grp = grphead; grp; grp = grp->next) {
1511 int i;
1512
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;
1519 }
1520 }
1521 recptr = record;
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);
1526 }
1527 obj_record (GRPDEF, record, recptr);
1528 }
1529
1530 /*
1531 * Write the PUBDEF records: first the ones in the segments,
1532 * then the far-absolutes.
1533 */
1534 for (seg = seghead; seg; seg = seg->next) {
1535 int any;
1536
1537 recptr = record;
1538 recptr = obj_write_index (recptr, seg->grp ? seg->grp->obj_index : 0);
1539 recptr = obj_write_index (recptr, seg->obj_index);
1540 any = FALSE;
1541 if (seg->use32)
1542 rectype = PUBDEF+1;
1543 else
1544 rectype = PUBDEF;
1545 for (pub = seg->pubhead; pub; pub = pub->next) {
1546 if (recptr - record + strlen(pub->name) + 7 > 1024) {
1547 if (any)
1548 obj_record (rectype, record, recptr);
1549 recptr = record;
1550 recptr = obj_write_index (recptr, 0);
1551 recptr = obj_write_index (recptr, seg->obj_index);
1552 }
1553 recptr = obj_write_name (recptr, pub->name);
1554 if (seg->use32)
1555 recptr = obj_write_dword (recptr, pub->offset);
1556 else
1557 recptr = obj_write_word (recptr, pub->offset);
1558 recptr = obj_write_index (recptr, 0);
1559 any = TRUE;
1560 }
1561 if (any)
1562 obj_record (rectype, record, recptr);
1563 }
1564 for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */
1565 recptr = record;
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);
1573 }
1574
1575 /*
1576 * Write the EXTDEF and COMDEF records, in order.
1577 */
1578 recptr = record;
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);
1584 recptr = record;
1585 }
1586 recptr = obj_write_name (recptr, ext->name);
1587 recptr = obj_write_index (recptr, 0);
1588 } else {
1589 if (recptr > record)
1590 obj_record (EXTDEF, record, recptr);
1591 recptr = record;
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 /
1598 ext->commonelem));
1599 recptr = obj_write_value (recptr, ext->commonelem);
1600 } else {
1601 recptr = obj_write_byte (recptr, 0x62);/* near communal */
1602 recptr = obj_write_value (recptr, ext->commonsize);
1603 }
1604 obj_record (COMDEF, record, recptr);
1605 }
1606 recptr = record;
1607 }
1608 }
1609 if (recptr > record)
1610 obj_record (EXTDEF, record, recptr);
1611
1612 /*
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.
1618 */
1619 if (obj_entry_seg == NO_SEG) {
1620 recptr = record;
1621 recptr = obj_write_rword (recptr, 0x40A2);
1622 recptr = obj_write_byte (recptr, 1);
1623 obj_record (COMENT, record, recptr);
1624 }
1625
1626 /*
1627 * Write the LEDATA/FIXUPP pairs.
1628 */
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);
1634 }
1635 }
1636
1637 /*
1638 * Write the MODEND module end marker.
1639 */
1640 recptr = record;
1641 rectype = MODEND;
1642 if (obj_entry_seg != NO_SEG) {
1643 recptr = obj_write_byte (recptr, 0xC1);
1644 /*
1645 * Find the segment in the segment list.
1646 */
1647 for (seg = seghead; seg; seg = seg->next) {
1648 if (seg->index == obj_entry_seg) {
1649 if (seg->grp) {
1650 recptr = obj_write_byte (recptr, 0x10);
1651 recptr = obj_write_index (recptr, seg->grp->obj_index);
1652 } else {
1653 recptr = obj_write_byte (recptr, 0x50);
1654 }
1655 recptr = obj_write_index (recptr, seg->obj_index);
1656 if (seg->use32) {
1657 rectype = MODEND+1;
1658 recptr = obj_write_dword (recptr, obj_entry_ofs);
1659 } else
1660 recptr = obj_write_word (recptr, obj_entry_ofs);
1661 break;
1662 }
1663 }
1664 if (!seg)
1665 error(ERR_NONFATAL, "entry point is not in this module");
1666 } else
1667 recptr = obj_write_byte (recptr, 0);
1668 obj_record (rectype, record, recptr);
1669 }
1670
1671 static unsigned char *obj_write_data(unsigned char *ptr,
1672 unsigned char *data, int len) {
1673 while (len--)
1674 *ptr++ = *data++;
1675 return ptr;
1676 }
1677
1678 static unsigned char *obj_write_byte(unsigned char *ptr, int data) {
1679 *ptr++ = data;
1680 return ptr;
1681 }
1682
1683 static unsigned char *obj_write_word(unsigned char *ptr, int data) {
1684 *ptr++ = data & 0xFF;
1685 *ptr++ = (data >> 8) & 0xFF;
1686 return ptr;
1687 }
1688
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;
1694 return ptr;
1695 }
1696
1697 static unsigned char *obj_write_rword(unsigned char *ptr, int data) {
1698 *ptr++ = (data >> 8) & 0xFF;
1699 *ptr++ = data & 0xFF;
1700 return ptr;
1701 }
1702
1703 static unsigned char *obj_write_name(unsigned char *ptr, char *data) {
1704 *ptr++ = strlen(data);
1705 if (obj_uppercase) {
1706 while (*data) {
1707 *ptr++ = (unsigned char) toupper(*data);
1708 data++;
1709 }
1710 } else {
1711 while (*data)
1712 *ptr++ = (unsigned char) *data++;
1713 }
1714 return ptr;
1715 }
1716
1717 static unsigned char *obj_write_index(unsigned char *ptr, int data) {
1718 if (data < 128)
1719 *ptr++ = data;
1720 else {
1721 *ptr++ = 0x80 | ((data >> 8) & 0x7F);
1722 *ptr++ = data & 0xFF;
1723 }
1724 return ptr;
1725 }
1726
1727 static unsigned char *obj_write_value(unsigned char *ptr,
1728 unsigned long data) {
1729 if (data <= 128)
1730 *ptr++ = data;
1731 else if (data <= 0xFFFF) {
1732 *ptr++ = 129;
1733 *ptr++ = data & 0xFF;
1734 *ptr++ = (data >> 8) & 0xFF;
1735 } else if (data <= 0xFFFFFFL) {
1736 *ptr++ = 132;
1737 *ptr++ = data & 0xFF;
1738 *ptr++ = (data >> 8) & 0xFF;
1739 *ptr++ = (data >> 16) & 0xFF;
1740 } else {
1741 *ptr++ = 136;
1742 *ptr++ = data & 0xFF;
1743 *ptr++ = (data >> 8) & 0xFF;
1744 *ptr++ = (data >> 16) & 0xFF;
1745 *ptr++ = (data >> 24) & 0xFF;
1746 }
1747 return ptr;
1748 }
1749
1750 static void obj_record(int type, unsigned char *start, unsigned char *end) {
1751 unsigned long cksum, len;
1752
1753 cksum = type;
1754 fputc (type, ofp);
1755 len = end-start+1;
1756 cksum += (len & 0xFF) + ((len>>8) & 0xFF);
1757 fwriteshort (len, ofp);
1758 fwrite (start, 1, end-start, ofp);
1759 while (start < end)
1760 cksum += *start++;
1761 fputc ( (-(long)cksum) & 0xFF, ofp);
1762 }
1763
1764 static char *obj_stdmac[] = {
1765 "%define __SECT__ [section .text]",
1766 "%imacro group 1+.nolist",
1767 "[group %1]",
1768 "%endmacro",
1769 "%imacro uppercase 1+.nolist",
1770 "[uppercase %1]",
1771 "%endmacro",
1772 "%imacro export 1+.nolist",
1773 "[export %1]",
1774 "%endmacro",
1775 "%imacro import 1+.nolist",
1776 "[import %1]",
1777 "%endmacro",
1778 NULL
1779 };
1780
1781 struct ofmt of_obj = {
1782 "Microsoft MS-DOS 16-bit OMF object files",
1783 "obj",
1784 obj_stdmac,
1785 obj_init,
1786 obj_out,
1787 obj_deflabel,
1788 obj_segment,
1789 obj_segbase,
1790 obj_directive,
1791 obj_filename,
1792 obj_cleanup
1793 };
1794 #endif /* OF_OBJ */