Home | History | Annotate | Download | only in rdf
      1 /*
      2  * Relocatable Dynamic Object File Format (RDOFF) version 2 format
      3  *
      4  *  Copyright (C) 2006-2007  Peter Johnson
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
     16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
     19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  * POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 #include <util.h>
     28 
     29 #include <libyasm.h>
     30 
     31 
     32 #define REGULAR_OUTBUF_SIZE     1024
     33 
     34 #define RDF_MAGIC       "RDOFF2"
     35 
     36 /* Maximum size of an import/export label (including trailing zero) */
     37 #define EXIM_LABEL_MAX          64
     38 
     39 /* Maximum size of library or module name (including trailing zero) */
     40 #define MODLIB_NAME_MAX         128
     41 
     42 /* Maximum number of segments that we can handle in one file */
     43 #define RDF_MAXSEGS             64
     44 
     45 /* Record types that may present the RDOFF header */
     46 #define RDFREC_GENERIC          0
     47 #define RDFREC_RELOC            1
     48 #define RDFREC_IMPORT           2
     49 #define RDFREC_GLOBAL           3
     50 #define RDFREC_DLL              4
     51 #define RDFREC_BSS              5
     52 #define RDFREC_SEGRELOC         6
     53 #define RDFREC_FARIMPORT        7
     54 #define RDFREC_MODNAME          8
     55 #define RDFREC_COMMON           10
     56 
     57 /* Flags for ExportRec/ImportRec */
     58 #define SYM_DATA        1
     59 #define SYM_FUNCTION    2
     60 
     61 /* Flags for ExportRec */
     62 #define SYM_GLOBAL      4
     63 
     64 /* Flags for ImportRec */
     65 #define SYM_IMPORT      8
     66 #define SYM_FAR         16
     67 
     68 typedef struct rdf_reloc {
     69     yasm_reloc reloc;
     70     enum {
     71         RDF_RELOC_NORM,     /* normal */
     72         RDF_RELOC_REL,      /* relative to current position */
     73         RDF_RELOC_SEG       /* segment containing symbol */
     74     } type;                         /* type of relocation */
     75     unsigned int size;
     76     unsigned int refseg;
     77 } rdf_reloc;
     78 
     79 typedef struct rdf_section_data {
     80     /*@dependent@*/ yasm_symrec *sym;   /* symbol created for this section */
     81     long scnum;             /* section number (0=first section) */
     82     enum {
     83         RDF_SECT_BSS = 0,
     84         RDF_SECT_CODE = 1,
     85         RDF_SECT_DATA = 2,
     86         RDF_SECT_COMMENT = 3,
     87         RDF_SECT_LCOMMENT = 4,
     88         RDF_SECT_PCOMMENT = 5,
     89         RDF_SECT_SYMDEBUG = 6,
     90         RDF_SECT_LINEDEBUG = 7
     91     } type;                 /* section type */
     92     unsigned int reserved;  /* reserved data */
     93     unsigned long size;     /* size of raw data (section data) in bytes */
     94 
     95     unsigned char *raw_data;    /* raw section data, only used during output */
     96 } rdf_section_data;
     97 
     98 typedef struct rdf_symrec_data {
     99     unsigned int segment;               /* assigned RDF "segment" index */
    100 } rdf_symrec_data;
    101 
    102 typedef STAILQ_HEAD(xdf_str_head, xdf_str) xdf_str_head;
    103 typedef struct xdf_str {
    104     STAILQ_ENTRY(xdf_str) link;
    105     /*@owned@*/ char *str;
    106 } xdf_str;
    107 
    108 typedef struct yasm_objfmt_rdf {
    109     yasm_objfmt_base objfmt;                /* base structure */
    110 
    111     long parse_scnum;               /* sect numbering in parser */
    112 
    113     /*@owned@*/ xdf_str_head module_names;
    114     /*@owned@*/ xdf_str_head library_names;
    115 } yasm_objfmt_rdf;
    116 
    117 typedef struct rdf_objfmt_output_info {
    118     yasm_object *object;
    119     yasm_objfmt_rdf *objfmt_rdf;
    120     yasm_errwarns *errwarns;
    121     /*@dependent@*/ FILE *f;
    122     /*@only@*/ unsigned char *buf;
    123     yasm_section *sect;
    124     /*@dependent@*/ rdf_section_data *rsd;
    125 
    126     unsigned long indx;             /* symbol "segment" (extern/common only) */
    127 
    128     unsigned long bss_size;         /* total BSS size */
    129 } rdf_objfmt_output_info;
    130 
    131 static void rdf_section_data_destroy(/*@only@*/ void *d);
    132 static void rdf_section_data_print(void *data, FILE *f, int indent_level);
    133 
    134 static const yasm_assoc_data_callback rdf_section_data_cb = {
    135     rdf_section_data_destroy,
    136     rdf_section_data_print
    137 };
    138 
    139 static void rdf_symrec_data_destroy(/*@only@*/ void *d);
    140 static void rdf_symrec_data_print(void *data, FILE *f, int indent_level);
    141 
    142 static const yasm_assoc_data_callback rdf_symrec_data_cb = {
    143     rdf_symrec_data_destroy,
    144     rdf_symrec_data_print
    145 };
    146 
    147 yasm_objfmt_module yasm_rdf_LTX_objfmt;
    148 
    149 
    150 static /*@dependent@*/ rdf_symrec_data *
    151 rdf_objfmt_sym_set_data(yasm_symrec *sym, unsigned int segment)
    152 {
    153     rdf_symrec_data *rsymd = yasm_xmalloc(sizeof(rdf_symrec_data));
    154 
    155     rsymd->segment = segment;
    156 
    157     yasm_symrec_add_data(sym, &rdf_symrec_data_cb, rsymd);
    158     return rsymd;
    159 }
    160 
    161 static yasm_objfmt *
    162 rdf_objfmt_create(yasm_object *object)
    163 {
    164     yasm_objfmt_rdf *objfmt_rdf = yasm_xmalloc(sizeof(yasm_objfmt_rdf));
    165 
    166     /* We theoretically support all arches, so don't check.
    167      * Really we only support byte-addressable ones.
    168      */
    169 
    170     objfmt_rdf->parse_scnum = 0;    /* section numbering starts at 0 */
    171 
    172     STAILQ_INIT(&objfmt_rdf->module_names);
    173     STAILQ_INIT(&objfmt_rdf->library_names);
    174 
    175     objfmt_rdf->objfmt.module = &yasm_rdf_LTX_objfmt;
    176 
    177     return (yasm_objfmt *)objfmt_rdf;
    178 }
    179 
    180 static int
    181 rdf_objfmt_output_value(yasm_value *value, unsigned char *buf,
    182                         unsigned int destsize, unsigned long offset,
    183                         yasm_bytecode *bc, int warn, /*@null@*/ void *d)
    184 {
    185     /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
    186     yasm_objfmt_rdf *objfmt_rdf;
    187     /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
    188     unsigned long intn_minus;
    189     unsigned long intn_plus;
    190     int retval;
    191     unsigned int valsize = value->size;
    192 
    193     assert(info != NULL);
    194     objfmt_rdf = info->objfmt_rdf;
    195 
    196     if (value->abs)
    197         value->abs = yasm_expr_simplify(value->abs, 1);
    198 
    199     /* Try to output constant and PC-relative section-local first.
    200      * Note this does NOT output any value with a SEG, WRT, external,
    201      * cross-section, or non-PC-relative reference (those are handled below).
    202      */
    203     switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
    204                                     info->object->arch)) {
    205         case -1:
    206             return 1;
    207         case 0:
    208             break;
    209         default:
    210             return 0;
    211     }
    212 
    213     if (value->section_rel) {
    214         yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    215                        N_("rdf: relocation too complex"));
    216         return 1;
    217     }
    218 
    219     if (value->rel && value->wrt) {
    220         yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    221                        N_("rdf: WRT not supported"));
    222         return 1;
    223     }
    224 
    225     intn_minus = 0;
    226     intn_plus = 0;
    227     if (value->rel) {
    228         rdf_reloc *reloc;
    229         /*@null@*/ rdf_symrec_data *rsymd;
    230         /*@dependent@*/ yasm_bytecode *precbc;
    231 
    232         reloc = yasm_xmalloc(sizeof(rdf_reloc));
    233         reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
    234         reloc->reloc.sym = value->rel;
    235         reloc->size = valsize/8;
    236 
    237         if (value->seg_of)
    238             reloc->type = RDF_RELOC_SEG;
    239         else if (value->curpos_rel) {
    240             reloc->type = RDF_RELOC_REL;
    241             /* Adjust to start of section, so subtract out the bytecode
    242              * offset.
    243              */
    244             intn_minus = bc->offset;
    245         } else
    246             reloc->type = RDF_RELOC_NORM;
    247 
    248         if (yasm_symrec_get_label(value->rel, &precbc)) {
    249             /* local, set the value to be the offset, and the refseg to the
    250              * segment number.
    251              */
    252             /*@dependent@*/ /*@null@*/ rdf_section_data *csectd;
    253             /*@dependent@*/ yasm_section *sect;
    254 
    255             sect = yasm_bc_get_section(precbc);
    256             csectd = yasm_section_get_data(sect, &rdf_section_data_cb);
    257             if (!csectd)
    258                 yasm_internal_error(N_("didn't understand section"));
    259             reloc->refseg = csectd->scnum;
    260             intn_plus = yasm_bc_next_offset(precbc);
    261         } else {
    262             /* must be common/external */
    263             rsymd = yasm_symrec_get_data(reloc->reloc.sym,
    264                                          &rdf_symrec_data_cb);
    265             if (!rsymd)
    266                 yasm_internal_error(
    267                     N_("rdf: no symbol data for relocated symbol"));
    268             reloc->refseg = rsymd->segment;
    269         }
    270 
    271         yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
    272     }
    273 
    274     if (intn_minus > 0) {
    275         intn = yasm_intnum_create_uint(intn_minus);
    276         yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
    277     } else
    278         intn = yasm_intnum_create_uint(intn_plus);
    279 
    280     if (value->abs) {
    281         yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
    282         if (!intn2) {
    283             yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    284                            N_("rdf: relocation too complex"));
    285             yasm_intnum_destroy(intn);
    286             return 1;
    287         }
    288         yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
    289     }
    290 
    291     retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
    292                                       valsize, 0, bc, warn);
    293     yasm_intnum_destroy(intn);
    294     return retval;
    295 }
    296 
    297 static int
    298 rdf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
    299 {
    300     /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
    301     /*@null@*/ /*@only@*/ unsigned char *bigbuf;
    302     unsigned long size = REGULAR_OUTBUF_SIZE;
    303     int gap;
    304 
    305     assert(info != NULL);
    306 
    307     bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
    308                              rdf_objfmt_output_value, NULL);
    309 
    310     /* Don't bother doing anything else if size ended up being 0. */
    311     if (size == 0) {
    312         if (bigbuf)
    313             yasm_xfree(bigbuf);
    314         return 0;
    315     }
    316 
    317     /* Warn that gaps are converted to 0 and write out the 0's. */
    318     if (gap) {
    319         yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
    320                       N_("uninitialized space: zeroing"));
    321         /* Write out in chunks */
    322         memset(&info->rsd->raw_data[info->rsd->size], 0, size);
    323     } else {
    324         /* Output buf (or bigbuf if non-NULL) to file */
    325         memcpy(&info->rsd->raw_data[info->rsd->size],
    326                bigbuf ? bigbuf : info->buf, (size_t)size);
    327     }
    328 
    329     info->rsd->size += size;
    330 
    331     /* If bigbuf was allocated, free it */
    332     if (bigbuf)
    333         yasm_xfree(bigbuf);
    334 
    335     return 0;
    336 }
    337 
    338 static int
    339 rdf_objfmt_output_section_mem(yasm_section *sect, /*@null@*/ void *d)
    340 {
    341     /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
    342     /*@dependent@*/ /*@null@*/ rdf_section_data *rsd;
    343     unsigned long size;
    344 
    345     assert(info != NULL);
    346     rsd = yasm_section_get_data(sect, &rdf_section_data_cb);
    347     assert(rsd != NULL);
    348 
    349     size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
    350 
    351     if (rsd->type == RDF_SECT_BSS) {
    352         /* Don't output BSS sections, but remember length
    353          * TODO: Check for non-reserve bytecodes?
    354          */
    355         info->bss_size += size;
    356         return 0;
    357     }
    358 
    359     /* Empty?  Go on to next section */
    360     if (size == 0)
    361         return 0;
    362 
    363     /* See UGH comment in output() for why we're doing this */
    364     rsd->raw_data = yasm_xmalloc(size);
    365     rsd->size = 0;
    366 
    367     info->sect = sect;
    368     info->rsd = rsd;
    369     yasm_section_bcs_traverse(sect, info->errwarns, info,
    370                               rdf_objfmt_output_bytecode);
    371 
    372     /* Sanity check final section size */
    373     if (rsd->size != size)
    374         yasm_internal_error(
    375             N_("rdf: section computed size did not match actual size"));
    376 
    377     return 0;
    378 }
    379 
    380 static int
    381 rdf_objfmt_output_section_reloc(yasm_section *sect, /*@null@*/ void *d)
    382 {
    383     /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
    384     /*@dependent@*/ /*@null@*/ rdf_section_data *rsd;
    385     rdf_reloc *reloc;
    386 
    387     assert(info != NULL);
    388     rsd = yasm_section_get_data(sect, &rdf_section_data_cb);
    389     assert(rsd != NULL);
    390 
    391     if (rsd->type == RDF_SECT_BSS) {
    392         /* Don't output BSS sections. */
    393         return 0;
    394     }
    395 
    396     /* Empty?  Go on to next section */
    397     if (rsd->size == 0)
    398         return 0;
    399 
    400     reloc = (rdf_reloc *)yasm_section_relocs_first(sect);
    401     while (reloc) {
    402         unsigned char *localbuf = info->buf;
    403 
    404         if (reloc->type == RDF_RELOC_SEG)
    405             YASM_WRITE_8(localbuf, RDFREC_SEGRELOC);
    406         else
    407             YASM_WRITE_8(localbuf, RDFREC_RELOC);
    408         YASM_WRITE_8(localbuf, 8);              /* record length */
    409         /* Section number, +0x40 if relative reloc */
    410         YASM_WRITE_8(localbuf, rsd->scnum +
    411                      (reloc->type == RDF_RELOC_REL ? 0x40 : 0));
    412         yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
    413         localbuf += 4;                          /* offset of relocation */
    414         YASM_WRITE_8(localbuf, reloc->size);        /* size of relocation */
    415         YASM_WRITE_16_L(localbuf, reloc->refseg);   /* relocated symbol */
    416         fwrite(info->buf, 10, 1, info->f);
    417 
    418         reloc = (rdf_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
    419     }
    420 
    421     return 0;
    422 }
    423 
    424 static int
    425 rdf_objfmt_output_section_file(yasm_section *sect, /*@null@*/ void *d)
    426 {
    427     /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
    428     /*@dependent@*/ /*@null@*/ rdf_section_data *rsd;
    429     unsigned char *localbuf;
    430 
    431     assert(info != NULL);
    432     rsd = yasm_section_get_data(sect, &rdf_section_data_cb);
    433     assert(rsd != NULL);
    434 
    435     if (rsd->type == RDF_SECT_BSS) {
    436         /* Don't output BSS sections. */
    437         return 0;
    438     }
    439 
    440     /* Empty?  Go on to next section */
    441     if (rsd->size == 0)
    442         return 0;
    443 
    444     /* Section header */
    445     localbuf = info->buf;
    446     YASM_WRITE_16_L(localbuf, rsd->type);       /* type */
    447     YASM_WRITE_16_L(localbuf, rsd->scnum);      /* number */
    448     YASM_WRITE_16_L(localbuf, rsd->reserved);   /* reserved */
    449     YASM_WRITE_32_L(localbuf, rsd->size);       /* length */
    450     fwrite(info->buf, 10, 1, info->f);
    451 
    452     /* Section data */
    453     fwrite(rsd->raw_data, rsd->size, 1, info->f);
    454 
    455     /* Free section data */
    456     yasm_xfree(rsd->raw_data);
    457     rsd->raw_data = NULL;
    458 
    459     return 0;
    460 }
    461 
    462 #define FLAG_EXT    0x1000
    463 #define FLAG_GLOB   0x2000
    464 #define FLAG_SET    0x4000
    465 #define FLAG_CLR    0x8000
    466 #define FLAG_MASK   0x0fff
    467 
    468 static int
    469 rdf_helper_flag(void *obj, yasm_valparam *vp, unsigned long line, void *d,
    470                 uintptr_t flag)
    471 {
    472     yasm_symrec *sym = (yasm_symrec *)obj;
    473     yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
    474     unsigned int *flags = (unsigned int *)d;
    475 
    476     if (((vis & YASM_SYM_GLOBAL) && (flag & FLAG_GLOB)) ||
    477         ((vis & YASM_SYM_EXTERN) && (flag & FLAG_EXT))) {
    478         if (flag & FLAG_SET)
    479             *flags |= flag & FLAG_MASK;
    480         else if (flag & FLAG_CLR)
    481             *flags &= ~(flag & FLAG_MASK);
    482     }
    483     return 0;
    484 }
    485 
    486 static unsigned int
    487 rdf_parse_flags(yasm_symrec *sym)
    488 {
    489     /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams =
    490         yasm_symrec_get_objext_valparams(sym);
    491     unsigned int flags = 0;
    492 
    493     static const yasm_dir_help help[] = {
    494         { "data", 0, rdf_helper_flag, 0,
    495           FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA },
    496         { "object", 0, rdf_helper_flag, 0,
    497           FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_DATA },
    498         { "proc", 0, rdf_helper_flag, 0,
    499           FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION },
    500         { "function", 0, rdf_helper_flag, 0,
    501           FLAG_EXT|FLAG_GLOB|FLAG_SET|SYM_FUNCTION },
    502         { "import", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_IMPORT },
    503         { "export", 0, rdf_helper_flag, 0, FLAG_GLOB|FLAG_SET|SYM_GLOBAL },
    504         { "far", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_SET|SYM_FAR },
    505         { "near", 0, rdf_helper_flag, 0, FLAG_EXT|FLAG_CLR|SYM_FAR }
    506     };
    507 
    508     if (!objext_valparams)
    509         return 0;
    510 
    511     yasm_dir_helper(sym, yasm_vps_first(objext_valparams), 0, help,
    512                     NELEMS(help), &flags, yasm_dir_helper_valparam_warn);
    513 
    514     return flags;
    515 }
    516 
    517 static int
    518 rdf_objfmt_output_sym(yasm_symrec *sym, /*@null@*/ void *d)
    519 {
    520     /*@null@*/ rdf_objfmt_output_info *info = (rdf_objfmt_output_info *)d;
    521     yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
    522     /*@only@*/ char *name;
    523     size_t len;
    524     unsigned long value = 0;
    525     unsigned int scnum = 0;
    526     /*@dependent@*/ /*@null@*/ yasm_section *sect;
    527     /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
    528     unsigned char *localbuf;
    529 
    530     assert(info != NULL);
    531 
    532     if (vis == YASM_SYM_LOCAL || vis == YASM_SYM_DLOCAL)
    533         return 0;   /* skip local syms */
    534 
    535     /* Look at symrec for value/scnum/etc. */
    536     if (yasm_symrec_get_label(sym, &precbc)) {
    537         /*@dependent@*/ /*@null@*/ rdf_section_data *csectd;
    538 
    539         if (precbc)
    540             sect = yasm_bc_get_section(precbc);
    541         else
    542             sect = NULL;
    543         if (!sect)
    544             return 0;
    545 
    546         /* it's a label: get value and offset. */
    547         csectd = yasm_section_get_data(sect, &rdf_section_data_cb);
    548         if (csectd)
    549             scnum = csectd->scnum;
    550         else
    551             yasm_internal_error(N_("didn't understand section"));
    552         value = yasm_bc_next_offset(precbc);
    553     } else if (yasm_symrec_get_equ(sym)) {
    554         yasm_warn_set(YASM_WARN_GENERAL,
    555             N_("rdf does not support exporting EQU/absolute values"));
    556         yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
    557         return 0;
    558     }
    559 
    560     name = yasm_symrec_get_global_name(sym, info->object);
    561     len = strlen(name);
    562 
    563     if (len > EXIM_LABEL_MAX-1) {
    564         yasm_warn_set(YASM_WARN_GENERAL,
    565                       N_("label name too long, truncating to %d bytes"),
    566                       EXIM_LABEL_MAX);
    567         len = EXIM_LABEL_MAX-1;
    568     }
    569 
    570     localbuf = info->buf;
    571     if (vis & YASM_SYM_GLOBAL) {
    572         YASM_WRITE_8(localbuf, RDFREC_GLOBAL);
    573         YASM_WRITE_8(localbuf, 6+len+1);        /* record length */
    574         YASM_WRITE_8(localbuf, rdf_parse_flags(sym));   /* flags */
    575         YASM_WRITE_8(localbuf, scnum);          /* segment referred to */
    576         YASM_WRITE_32_L(localbuf, value);       /* offset */
    577     } else {
    578         /* Save symbol segment in symrec data (for later reloc gen) */
    579         scnum = info->indx++;
    580         rdf_objfmt_sym_set_data(sym, scnum);
    581 
    582         if (vis & YASM_SYM_COMMON) {
    583             /*@dependent@*/ /*@null@*/ yasm_expr **csize_expr;
    584             const yasm_intnum *intn;
    585             /*@dependent@*/ /*@null@*/ yasm_valparamhead *objext_valparams =
    586                 yasm_symrec_get_objext_valparams(sym);
    587             unsigned long addralign = 0;
    588 
    589             YASM_WRITE_8(localbuf, RDFREC_COMMON);
    590             YASM_WRITE_8(localbuf, 8+len+1);    /* record length */
    591             YASM_WRITE_16_L(localbuf, scnum);   /* segment allocated */
    592 
    593             /* size */
    594             csize_expr = yasm_symrec_get_common_size(sym);
    595             assert(csize_expr != NULL);
    596             intn = yasm_expr_get_intnum(csize_expr, 1);
    597             if (!intn) {
    598                 yasm_error_set(YASM_ERROR_NOT_CONSTANT,
    599                     N_("COMMON data size not an integer expression"));
    600             } else
    601                 value = yasm_intnum_get_uint(intn);
    602             YASM_WRITE_32_L(localbuf, value);
    603 
    604             /* alignment */
    605             if (objext_valparams) {
    606                 yasm_valparam *vp = yasm_vps_first(objext_valparams);
    607                 for (; vp; vp = yasm_vps_next(vp)) {
    608                     if (!vp->val) {
    609                         /*@only@*/ /*@null@*/ yasm_expr *align_expr;
    610                         /*@dependent@*/ /*@null@*/
    611                         const yasm_intnum *align_intn;
    612 
    613                         if (!(align_expr = yasm_vp_expr(vp,
    614                                 info->object->symtab,
    615                                 yasm_symrec_get_decl_line(sym))) ||
    616                             !(align_intn = yasm_expr_get_intnum(&align_expr,
    617                                                                 0))) {
    618                             yasm_error_set(YASM_ERROR_VALUE,
    619                                 N_("argument to `%s' is not an integer"),
    620                                 vp->val);
    621                             if (align_expr)
    622                                 yasm_expr_destroy(align_expr);
    623                             continue;
    624                         }
    625                         addralign = yasm_intnum_get_uint(align_intn);
    626                         yasm_expr_destroy(align_expr);
    627 
    628                         /* Alignments must be a power of two. */
    629                         if (!is_exp2(addralign)) {
    630                             yasm_error_set(YASM_ERROR_VALUE,
    631                                 N_("alignment constraint is not a power of two"));
    632                             continue;
    633                         }
    634                     } else
    635                         yasm_warn_set(YASM_WARN_GENERAL,
    636                             N_("Unrecognized qualifier `%s'"), vp->val);
    637                 }
    638             }
    639             YASM_WRITE_16_L(localbuf, addralign);
    640         } else if (vis & YASM_SYM_EXTERN) {
    641             unsigned int flags = rdf_parse_flags(sym);
    642             if (flags & SYM_FAR) {
    643                 YASM_WRITE_8(localbuf, RDFREC_FARIMPORT);
    644                 flags &= ~SYM_FAR;
    645             } else
    646                 YASM_WRITE_8(localbuf, RDFREC_IMPORT);
    647             YASM_WRITE_8(localbuf, 3+len+1);    /* record length */
    648             YASM_WRITE_8(localbuf, flags);      /* flags */
    649             YASM_WRITE_16_L(localbuf, scnum);   /* segment allocated */
    650         }
    651     }
    652 
    653     /* Symbol name */
    654     memcpy(localbuf, name, len);
    655     localbuf += len;
    656     YASM_WRITE_8(localbuf, 0);          /* 0-terminated name */
    657     yasm_xfree(name);
    658 
    659     fwrite(info->buf, (unsigned long)(localbuf-info->buf), 1, info->f);
    660 
    661     yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
    662     return 0;
    663 }
    664 
    665 static void
    666 rdf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
    667                   yasm_errwarns *errwarns)
    668 {
    669     yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt;
    670     rdf_objfmt_output_info info;
    671     unsigned char *localbuf;
    672     long headerlen, filelen;
    673     xdf_str *cur;
    674     size_t len;
    675 
    676     info.object = object;
    677     info.objfmt_rdf = objfmt_rdf;
    678     info.errwarns = errwarns;
    679     info.f = f;
    680     info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
    681     info.bss_size = 0;
    682 
    683     /* Allocate space for file header by seeking forward */
    684     if (fseek(f, (long)strlen(RDF_MAGIC)+8, SEEK_SET) < 0) {
    685         yasm__fatal(N_("could not seek on output file"));
    686         /*@notreached@*/
    687         return;
    688     }
    689 
    690     /* Output custom header records (library and module, etc) */
    691     cur = STAILQ_FIRST(&objfmt_rdf->module_names);
    692     while (cur) {
    693         len = strlen(cur->str)+1;
    694         localbuf = info.buf;
    695         YASM_WRITE_8(localbuf, RDFREC_MODNAME);         /* record type */
    696         YASM_WRITE_8(localbuf, len);                    /* record length */
    697         fwrite(info.buf, 2, 1, f);
    698         fwrite(cur->str, len, 1, f);
    699         cur = STAILQ_NEXT(cur, link);
    700     }
    701 
    702     cur = STAILQ_FIRST(&objfmt_rdf->library_names);
    703     while (cur) {
    704         len = strlen(cur->str)+1;
    705         localbuf = info.buf;
    706         YASM_WRITE_8(localbuf, RDFREC_DLL);             /* record type */
    707         YASM_WRITE_8(localbuf, len);                    /* record length */
    708         fwrite(info.buf, 2, 1, f);
    709         fwrite(cur->str, len, 1, f);
    710         cur = STAILQ_NEXT(cur, link);
    711     }
    712 
    713     /* Output symbol table */
    714     info.indx = objfmt_rdf->parse_scnum;
    715     yasm_symtab_traverse(object->symtab, &info, rdf_objfmt_output_sym);
    716 
    717     /* UGH! Due to the fact the relocs go at the beginning of the file, and
    718      * we only know if we have relocs when we output the sections, we have
    719      * to output the section data before we have output the relocs.  But
    720      * we also don't know how much space to preallocate for relocs, so....
    721      * we output into memory buffers first (thus the UGH).
    722      *
    723      * Stupid object format design, if you ask me (basically all other
    724      * object formats put the relocs *after* the section data to avoid this
    725      * exact problem).
    726      *
    727      * We also calculate the total size of all BSS sections here.
    728      */
    729     if (yasm_object_sections_traverse(object, &info,
    730                                       rdf_objfmt_output_section_mem))
    731         return;
    732 
    733     /* Output all relocs */
    734     if (yasm_object_sections_traverse(object, &info,
    735                                       rdf_objfmt_output_section_reloc))
    736         return;
    737 
    738     /* Output BSS record */
    739     if (info.bss_size > 0) {
    740         localbuf = info.buf;
    741         YASM_WRITE_8(localbuf, RDFREC_BSS);             /* record type */
    742         YASM_WRITE_8(localbuf, 4);                      /* record length */
    743         YASM_WRITE_32_L(localbuf, info.bss_size);       /* total BSS size */
    744         fwrite(info.buf, 6, 1, f);
    745     }
    746 
    747     /* Determine header length */
    748     headerlen = ftell(f);
    749     if (headerlen == -1) {
    750         yasm__fatal(N_("could not get file position on output file"));
    751         /*@notreached@*/
    752         return;
    753     }
    754 
    755     /* Section data (to file) */
    756     if (yasm_object_sections_traverse(object, &info,
    757                                       rdf_objfmt_output_section_file))
    758         return;
    759 
    760     /* NULL section to end file */
    761     memset(info.buf, 0, 10);
    762     fwrite(info.buf, 10, 1, f);
    763 
    764     /* Determine object length */
    765     filelen = ftell(f);
    766     if (filelen == -1) {
    767         yasm__fatal(N_("could not get file position on output file"));
    768         /*@notreached@*/
    769         return;
    770     }
    771 
    772     /* Write file header */
    773     if (fseek(f, 0, SEEK_SET) < 0) {
    774         yasm__fatal(N_("could not seek on output file"));
    775         /*@notreached@*/
    776         return;
    777     }
    778 
    779     fwrite(RDF_MAGIC, strlen(RDF_MAGIC), 1, f);
    780     localbuf = info.buf;
    781     YASM_WRITE_32_L(localbuf, filelen-10);              /* object size */
    782     YASM_WRITE_32_L(localbuf, headerlen-14);            /* header size */
    783     fwrite(info.buf, 8, 1, f);
    784 
    785     yasm_xfree(info.buf);
    786 }
    787 
    788 static void
    789 rdf_objfmt_destroy(yasm_objfmt *objfmt)
    790 {
    791     yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)objfmt;
    792     xdf_str *cur, *next;
    793 
    794     cur = STAILQ_FIRST(&objfmt_rdf->module_names);
    795     while (cur) {
    796         next = STAILQ_NEXT(cur, link);
    797         yasm_xfree(cur->str);
    798         yasm_xfree(cur);
    799         cur = next;
    800     }
    801 
    802     cur = STAILQ_FIRST(&objfmt_rdf->library_names);
    803     while (cur) {
    804         next = STAILQ_NEXT(cur, link);
    805         yasm_xfree(cur->str);
    806         yasm_xfree(cur);
    807         cur = next;
    808     }
    809 
    810     yasm_xfree(objfmt);
    811 }
    812 
    813 static void
    814 rdf_objfmt_init_new_section(yasm_section *sect, unsigned long line)
    815 {
    816     yasm_object *object = yasm_section_get_object(sect);
    817     const char *sectname = yasm_section_get_name(sect);
    818     yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt;
    819     rdf_section_data *data;
    820     yasm_symrec *sym;
    821 
    822     data = yasm_xmalloc(sizeof(rdf_section_data));
    823     data->scnum = objfmt_rdf->parse_scnum++;
    824     data->type = 0;
    825     data->reserved = 0;
    826     data->size = 0;
    827     data->raw_data = NULL;
    828     yasm_section_add_data(sect, &rdf_section_data_cb, data);
    829 
    830     sym = yasm_symtab_define_label(object->symtab, sectname,
    831                                    yasm_section_bcs_first(sect), 1, line);
    832     data->sym = sym;
    833 }
    834 
    835 static yasm_section *
    836 rdf_objfmt_add_default_section(yasm_object *object)
    837 {
    838     yasm_section *retval;
    839     rdf_section_data *rsd;
    840     int isnew;
    841 
    842     retval = yasm_object_get_general(object, ".text", 0, 1, 0, &isnew, 0);
    843     if (isnew) {
    844         rsd = yasm_section_get_data(retval, &rdf_section_data_cb);
    845         rsd->type = RDF_SECT_CODE;
    846         rsd->reserved = 0;
    847         yasm_section_set_default(retval, 1);
    848     }
    849     return retval;
    850 }
    851 
    852 static int
    853 rdf_helper_set_type(void *obj, yasm_valparam *vp, unsigned long line,
    854                     void *d, uintptr_t newtype)
    855 {
    856     unsigned int *type = (unsigned int *)d;
    857     *type = newtype;
    858     return 0;
    859 }
    860 
    861 struct rdf_section_switch_data {
    862     /*@only@*/ /*@null@*/ yasm_intnum *reserved_intn;
    863     unsigned int type;
    864 };
    865 
    866 static int
    867 rdf_helper_set_reserved(void *obj, yasm_valparam *vp, unsigned long line,
    868                         void *d)
    869 {
    870     struct rdf_section_switch_data *data = (struct rdf_section_switch_data *)d;
    871 
    872     if (!vp->val && vp->type == YASM_PARAM_EXPR)
    873         return yasm_dir_helper_intn(obj, vp, line, &data->reserved_intn, 0);
    874     else
    875         return yasm_dir_helper_valparam_warn(obj, vp, line, d);
    876 }
    877 
    878 static /*@observer@*/ /*@null@*/ yasm_section *
    879 rdf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
    880                           /*@unused@*/ /*@null@*/
    881                           yasm_valparamhead *objext_valparams,
    882                           unsigned long line)
    883 {
    884     yasm_valparam *vp = yasm_vps_first(valparams);
    885     yasm_section *retval;
    886     int isnew;
    887     unsigned int reserved = 0;
    888     int flags_override = 0;
    889     const char *sectname;
    890     rdf_section_data *rsd;
    891 
    892     struct rdf_section_switch_data data;
    893 
    894     static const yasm_dir_help help[] = {
    895         { "bss", 0, rdf_helper_set_type,
    896           offsetof(struct rdf_section_switch_data, type), RDF_SECT_BSS },
    897         { "code", 0, rdf_helper_set_type,
    898           offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE },
    899         { "text", 0, rdf_helper_set_type,
    900           offsetof(struct rdf_section_switch_data, type), RDF_SECT_CODE },
    901         { "data", 0, rdf_helper_set_type,
    902           offsetof(struct rdf_section_switch_data, type), RDF_SECT_DATA },
    903         { "comment", 0, rdf_helper_set_type,
    904           offsetof(struct rdf_section_switch_data, type), RDF_SECT_COMMENT },
    905         { "lcomment", 0, rdf_helper_set_type,
    906           offsetof(struct rdf_section_switch_data, type), RDF_SECT_LCOMMENT },
    907         { "pcomment", 0, rdf_helper_set_type,
    908           offsetof(struct rdf_section_switch_data, type), RDF_SECT_PCOMMENT },
    909         { "symdebug", 0, rdf_helper_set_type,
    910           offsetof(struct rdf_section_switch_data, type), RDF_SECT_SYMDEBUG },
    911         { "linedebug", 0, rdf_helper_set_type,
    912           offsetof(struct rdf_section_switch_data, type), RDF_SECT_LINEDEBUG },
    913         { "reserved", 1, yasm_dir_helper_intn,
    914           offsetof(struct rdf_section_switch_data, reserved_intn), 0 }
    915     };
    916 
    917     data.reserved_intn = NULL;
    918     data.type = 0xffff;
    919 
    920     vp = yasm_vps_first(valparams);
    921     sectname = yasm_vp_string(vp);
    922     if (!sectname)
    923         return NULL;
    924     vp = yasm_vps_next(vp);
    925 
    926     if (strcmp(sectname, ".text") == 0)
    927         data.type = RDF_SECT_CODE;
    928     else if (strcmp(sectname, ".data") == 0)
    929         data.type = RDF_SECT_DATA;
    930     else if (strcmp(sectname, ".bss") == 0)
    931         data.type = RDF_SECT_BSS;
    932 
    933     flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
    934                                      &data, rdf_helper_set_reserved);
    935     if (flags_override < 0)
    936         return NULL;    /* error occurred */
    937 
    938     if (data.type == 0xffff) {
    939         yasm_error_set(YASM_ERROR_VALUE,
    940                        N_("new segment declared without type code"));
    941         data.type = RDF_SECT_DATA;
    942     }
    943 
    944     if (data.reserved_intn) {
    945         reserved = yasm_intnum_get_uint(data.reserved_intn);
    946         yasm_intnum_destroy(data.reserved_intn);
    947     }
    948 
    949     retval = yasm_object_get_general(object, sectname, 0, 1,
    950                                      data.type == RDF_SECT_BSS, &isnew, line);
    951 
    952     rsd = yasm_section_get_data(retval, &rdf_section_data_cb);
    953 
    954     if (isnew || yasm_section_is_default(retval)) {
    955         yasm_section_set_default(retval, 0);
    956         rsd->type = data.type;
    957         rsd->reserved = reserved;
    958     } else if (flags_override)
    959         yasm_warn_set(YASM_WARN_GENERAL,
    960                       N_("section flags ignored on section redeclaration"));
    961     return retval;
    962 }
    963 
    964 static /*@observer@*/ /*@null@*/ yasm_symrec *
    965 rdf_objfmt_get_special_sym(yasm_object *object, const char *name,
    966                            const char *parser)
    967 {
    968     return NULL;
    969 }
    970 
    971 static void
    972 rdf_section_data_destroy(void *data)
    973 {
    974     rdf_section_data *rsd = (rdf_section_data *)data;
    975     if (rsd->raw_data)
    976         yasm_xfree(rsd->raw_data);
    977     yasm_xfree(data);
    978 }
    979 
    980 static void
    981 rdf_section_data_print(void *data, FILE *f, int indent_level)
    982 {
    983     rdf_section_data *rsd = (rdf_section_data *)data;
    984 
    985     fprintf(f, "%*ssym=\n", indent_level, "");
    986     yasm_symrec_print(rsd->sym, f, indent_level+1);
    987     fprintf(f, "%*sscnum=%ld\n", indent_level, "", rsd->scnum);
    988     fprintf(f, "%*stype=0x%x\n", indent_level, "", rsd->type);
    989     fprintf(f, "%*sreserved=0x%x\n", indent_level, "", rsd->reserved);
    990     fprintf(f, "%*ssize=%ld\n", indent_level, "", rsd->size);
    991 }
    992 
    993 static void
    994 rdf_symrec_data_destroy(void *data)
    995 {
    996     yasm_xfree(data);
    997 }
    998 
    999 static void
   1000 rdf_symrec_data_print(void *data, FILE *f, int indent_level)
   1001 {
   1002     rdf_symrec_data *rsymd = (rdf_symrec_data *)data;
   1003 
   1004     fprintf(f, "%*ssymtab segment=%u\n", indent_level, "", rsymd->segment);
   1005 }
   1006 
   1007 static void
   1008 rdf_objfmt_add_libmodule(yasm_object *object, char *name, int lib)
   1009 {
   1010     yasm_objfmt_rdf *objfmt_rdf = (yasm_objfmt_rdf *)object->objfmt;
   1011     xdf_str *str;
   1012 
   1013     /* Add to list */
   1014     str = yasm_xmalloc(sizeof(xdf_str));
   1015     str->str = name;
   1016     if (lib)
   1017         STAILQ_INSERT_TAIL(&objfmt_rdf->library_names, str, link);
   1018     else
   1019         STAILQ_INSERT_TAIL(&objfmt_rdf->module_names, str, link);
   1020 
   1021     if (strlen(str->str) > MODLIB_NAME_MAX-1) {
   1022         yasm_warn_set(YASM_WARN_GENERAL,
   1023                       N_("name too long, truncating to %d bytes"),
   1024                       MODLIB_NAME_MAX);
   1025         str->str[MODLIB_NAME_MAX-1] = '\0';
   1026     }
   1027 }
   1028 
   1029 static void
   1030 dir_library(yasm_object *object, yasm_valparamhead *valparams,
   1031             yasm_valparamhead *objext_valparams, unsigned long line)
   1032 {
   1033     yasm_valparam *vp = yasm_vps_first(valparams);
   1034     rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 1);
   1035 }
   1036 
   1037 static void
   1038 dir_module(yasm_object *object, yasm_valparamhead *valparams,
   1039            yasm_valparamhead *objext_valparams, unsigned long line)
   1040 {
   1041     yasm_valparam *vp = yasm_vps_first(valparams);
   1042     rdf_objfmt_add_libmodule(object, yasm__xstrdup(yasm_vp_string(vp)), 0);
   1043 }
   1044 
   1045 /* Define valid debug formats to use with this object format */
   1046 static const char *rdf_objfmt_dbgfmt_keywords[] = {
   1047     "null",
   1048     NULL
   1049 };
   1050 
   1051 static const yasm_directive rdf_objfmt_directives[] = {
   1052     { "library",        "nasm", dir_library,    YASM_DIR_ARG_REQUIRED },
   1053     { "module",         "nasm", dir_module,     YASM_DIR_ARG_REQUIRED },
   1054     { NULL, NULL, NULL, 0 }
   1055 };
   1056 
   1057 static const char *rdf_nasm_stdmac[] = {
   1058     "%imacro library 1+.nolist",
   1059     "[library %1]",
   1060     "%endmacro",
   1061     "%imacro module 1+.nolist",
   1062     "[module %1]",
   1063     "%endmacro",
   1064     NULL
   1065 };
   1066 
   1067 static const yasm_stdmac rdf_objfmt_stdmacs[] = {
   1068     { "nasm", "nasm", rdf_nasm_stdmac },
   1069     { NULL, NULL, NULL }
   1070 };
   1071 
   1072 /* Define objfmt structure -- see objfmt.h for details */
   1073 yasm_objfmt_module yasm_rdf_LTX_objfmt = {
   1074     "Relocatable Dynamic Object File Format (RDOFF) v2.0",
   1075     "rdf",
   1076     "rdf",
   1077     32,
   1078     0,
   1079     rdf_objfmt_dbgfmt_keywords,
   1080     "null",
   1081     rdf_objfmt_directives,
   1082     rdf_objfmt_stdmacs,
   1083     rdf_objfmt_create,
   1084     rdf_objfmt_output,
   1085     rdf_objfmt_destroy,
   1086     rdf_objfmt_add_default_section,
   1087     rdf_objfmt_init_new_section,
   1088     rdf_objfmt_section_switch,
   1089     rdf_objfmt_get_special_sym
   1090 };
   1091