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