home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / nasm097s.zip / OUTOBJ.C < prev    next >
C/C++ Source or Header  |  1997-12-06  |  49KB  |  1,772 lines

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