Hash even backend-specific directives, unify null functions
[platform/upstream/nasm.git] / output / outrdf2.c
1 /* ----------------------------------------------------------------------- *
2  *   
3  *   Copyright 1996-2009 The NASM Authors - All Rights Reserved
4  *   See the file AUTHORS included with the NASM distribution for
5  *   the specific copyright holders.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following
9  *   conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *     
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * ----------------------------------------------------------------------- */
33
34 /*
35  * outrdf2.c    output routines for the Netwide Assembler to produce
36  *              RDOFF version 2 format object files, which Julian originally
37  *              planned to use it in his MOSCOW operating system.
38  */
39
40 #include "compiler.h"
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include <assert.h>
47 #include <inttypes.h>
48
49 #include "nasm.h"
50 #include "nasmlib.h"
51 #include "saa.h"
52 #include "output/outform.h"
53 #include "output/outlib.h"
54
55 /* VERBOSE_WARNINGS: define this to add some extra warnings... */
56 #define VERBOSE_WARNINGS
57
58 #ifdef OF_RDF2
59
60 #include "rdoff/rdoff.h"
61
62 /* This signature is written to start of RDOFF files */
63 static const char *RDOFF2Id = RDOFF2_SIGNATURE;
64
65 /* Note that whenever a segment is referred to in the RDOFF file, its number
66  * is always half of the segment number that NASM uses to refer to it; this
67  * is because NASM only allocates even numbered segments, so as to not
68  * waste any of the 16 bits of segment number written to the file - this
69  * allows up to 65533 external labels to be defined; otherwise it would be
70  * 32764. */
71
72 #define COUNT_SEGTYPES 9
73
74 static char *segmenttypes[COUNT_SEGTYPES] = {
75     "null", "text", "code", "data",
76     "comment", "lcomment", "pcomment",
77     "symdebug", "linedebug"
78 };
79
80 static int segmenttypenumbers[COUNT_SEGTYPES] = {
81     0, 1, 1, 2, 3, 4, 5, 6, 7
82 };
83
84 /* code for managing buffers needed to separate code and data into individual
85  * sections until they are ready to be written to the file.
86  * We'd better hope that it all fits in memory else we're buggered... */
87
88 #define BUF_BLOCK_LEN 4088      /* selected to match page size (4096)
89                                  * on 80x86 machines for efficiency */
90
91 /***********************************************************************
92  * Actual code to deal with RDOFF2 ouput format begins here...
93  */
94
95 /* global variables set during the initialisation phase */
96
97 static struct SAA *seg[RDF_MAXSEGS];    /* seg 0 = code, seg 1 = data */
98 static struct SAA *header;      /* relocation/import/export records */
99
100 static FILE *ofile;
101
102 static efunc error;
103
104 static struct seginfo {
105     char *segname;
106     int segnumber;
107     uint16_t segtype;
108     uint16_t segreserved;
109     int32_t seglength;
110 } segments[RDF_MAXSEGS];
111
112 static int nsegments;
113
114 static int32_t bsslength;
115 static int32_t headerlength;
116
117 static void rdf2_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval)
118 {
119     int segtext, segdata, segbss;
120
121     (void)ldef;
122     (void)eval;
123
124     maxbits = 64;
125
126     /* set up the initial segments */
127     segments[0].segname = ".text";
128     segments[0].segnumber = 0;
129     segments[0].segtype = 1;
130     segments[0].segreserved = 0;
131     segments[0].seglength = 0;
132
133     segments[1].segname = ".data";
134     segments[1].segnumber = 1;
135     segments[1].segtype = 2;
136     segments[1].segreserved = 0;
137     segments[1].seglength = 0;
138
139     segments[2].segname = ".bss";
140     segments[2].segnumber = 2;
141     segments[2].segtype = 0xFFFF;       /* reserved - should never be produced */
142     segments[2].segreserved = 0;
143     segments[2].seglength = 0;
144
145     nsegments = 3;
146
147     ofile = fp;
148     error = errfunc;
149
150     seg[0] = saa_init(1L);
151     seg[1] = saa_init(1L);
152     seg[2] = NULL;              /* special case! */
153
154     header = saa_init(1L);
155
156     segtext = seg_alloc();
157     segdata = seg_alloc();
158     segbss = seg_alloc();
159     if (segtext != 0 || segdata != 2 || segbss != 4)
160         error(ERR_PANIC,
161               "rdf segment numbers not allocated as expected (%d,%d,%d)",
162               segtext, segdata, segbss);
163     bsslength = 0;
164     headerlength = 0;
165 }
166
167 static int32_t rdf2_section_names(char *name, int pass, int *bits)
168 {
169     int i;
170     bool err;
171     char *p, *q;
172     int code = -1;
173     int reserved = 0;
174
175     (void)pass;
176
177     /*
178      * Default is 32 bits, in the text segment.
179      */
180     if (!name) {
181         *bits = 32;
182         return 0;
183     }
184
185     /* look for segment type code following segment name */
186     p = name;
187     while (*p && !nasm_isspace(*p))
188         p++;
189     if (*p) {                   /* we're now in whitespace */
190         *p++ = '\0';
191         while (*p && nasm_isspace(80))
192             *p++ = '\0';
193     }
194     if (*p) {                   /* we're now in an attribute value */
195         /*
196          * see if we have an optional ',number' following the type code
197          */
198         if ((q = strchr(p, ','))) {
199             *q++ = '\0';
200
201             reserved = readnum(q, &err);
202             if (err) {
203                 error(ERR_NONFATAL,
204                       "value following comma must be numeric");
205                 reserved = 0;
206             }
207         }
208         /*
209          * check it against the text strings in segmenttypes
210          */
211
212         for (i = 0; i < COUNT_SEGTYPES; i++)
213             if (!nasm_stricmp(p, segmenttypes[i])) {
214                 code = segmenttypenumbers[i];
215                 break;
216             }
217         if (code == -1) {       /* didn't find anything */
218             code = readnum(p, &err);
219             if (err) {
220                 error(ERR_NONFATAL, "unrecognised RDF segment type (%s)",
221                       p);
222                 code = 3;
223             }
224         }
225     }
226     for (i = 0; i < nsegments; i++) {
227         if (!strcmp(name, segments[i].segname)) {
228             if (code != -1 || reserved != 0)
229                 error(ERR_NONFATAL, "segment attributes specified on"
230                       " redeclaration of segment");
231             return segments[i].segnumber * 2;
232         }
233     }
234
235     /* declaring a new segment! */
236
237     if (code == -1) {
238         error(ERR_NONFATAL, "new segment declared without type code");
239         code = 3;
240     }
241     if (nsegments == RDF_MAXSEGS) {
242         error(ERR_FATAL, "reached compiled-in maximum segment limit (%d)",
243               RDF_MAXSEGS);
244         return NO_SEG;
245     }
246
247     segments[nsegments].segname = nasm_strdup(name);
248     i = seg_alloc();
249     if (i % 2 != 0)
250         error(ERR_PANIC, "seg_alloc() returned odd number");
251     segments[nsegments].segnumber = i >> 1;
252     segments[nsegments].segtype = code;
253     segments[nsegments].segreserved = reserved;
254     segments[nsegments].seglength = 0;
255
256     seg[nsegments] = saa_init(1L);
257
258     return i;
259 }
260
261 /*
262  * Write relocation record
263  */
264 static void write_reloc_rec(struct RelocRec *r)
265 {
266     char buf[4], *b;
267
268     if (r->refseg != (uint16_t) NO_SEG && (r->refseg & 1))        /* segment base ref */
269         r->type = RDFREC_SEGRELOC;
270
271     r->refseg >>= 1;            /* adjust segment nos to RDF rather than NASM */
272
273     saa_wbytes(header, &r->type, 1);
274     saa_wbytes(header, &r->reclen, 1);
275     saa_wbytes(header, &r->segment, 1);
276     b = buf;
277     WRITELONG(b, r->offset);
278     saa_wbytes(header, buf, 4);
279     saa_wbytes(header, &r->length, 1);
280     b = buf;
281     WRITESHORT(b, r->refseg);
282     saa_wbytes(header, buf, 2);
283     headerlength += r->reclen + 2;
284 }
285
286 /*
287  * Write export record
288  */
289 static void write_export_rec(struct ExportRec *r)
290 {
291     char buf[4], *b;
292
293     r->segment >>= 1;
294
295     saa_wbytes(header, &r->type, 1);
296     saa_wbytes(header, &r->reclen, 1);
297     saa_wbytes(header, &r->flags, 1);
298     saa_wbytes(header, &r->segment, 1);
299     b = buf;
300     WRITELONG(b, r->offset);
301     saa_wbytes(header, buf, 4);
302     saa_wbytes(header, r->label, strlen(r->label) + 1);
303     headerlength += r->reclen + 2;
304 }
305
306 static void write_import_rec(struct ImportRec *r)
307 {
308     char buf[4], *b;
309
310     r->segment >>= 1;
311
312     saa_wbytes(header, &r->type, 1);
313     saa_wbytes(header, &r->reclen, 1);
314     saa_wbytes(header, &r->flags, 1);
315     b = buf;
316     WRITESHORT(b, r->segment);
317     saa_wbytes(header, buf, 2);
318     saa_wbytes(header, r->label, strlen(r->label) + 1);
319     headerlength += r->reclen + 2;
320 }
321
322 /*
323  * Write BSS record
324  */
325 static void write_bss_rec(struct BSSRec *r)
326 {
327     char buf[4], *b;
328
329     saa_wbytes(header, &r->type, 1);
330     saa_wbytes(header, &r->reclen, 1);
331     b = buf;
332     WRITELONG(b, r->amount);
333     saa_wbytes(header, buf, 4);
334     headerlength += r->reclen + 2;
335 }
336
337 /*
338  * Write common variable record
339  */
340 static void write_common_rec(struct CommonRec *r)
341 {
342     char buf[4], *b;
343
344     r->segment >>= 1;
345
346     saa_wbytes(header, &r->type, 1);
347     saa_wbytes(header, &r->reclen, 1);
348     b = buf;
349     WRITESHORT(b, r->segment);
350     saa_wbytes(header, buf, 2);
351     b = buf;
352     WRITELONG(b, r->size);
353     saa_wbytes(header, buf, 4);
354     b = buf;
355     WRITESHORT(b, r->align);
356     saa_wbytes(header, buf, 2);
357     saa_wbytes(header, r->label, strlen(r->label) + 1);
358     headerlength += r->reclen + 2;
359 }
360
361 /*
362  * Write library record
363  */
364 static void write_dll_rec(struct DLLRec *r)
365 {
366     saa_wbytes(header, &r->type, 1);
367     saa_wbytes(header, &r->reclen, 1);
368     saa_wbytes(header, r->libname, strlen(r->libname) + 1);
369     headerlength += r->reclen + 2;
370 }
371
372 /*
373  * Write module name record
374  */
375 static void write_modname_rec(struct ModRec *r)
376 {
377     saa_wbytes(header, &r->type, 1);
378     saa_wbytes(header, &r->reclen, 1);
379     saa_wbytes(header, r->modname, strlen(r->modname) + 1);
380     headerlength += r->reclen + 2;
381 }
382
383 /*
384  * Handle export, import and common records.
385  */
386 static void rdf2_deflabel(char *name, int32_t segment, int64_t offset,
387                           int is_global, char *special)
388 {
389     struct ExportRec r;
390     struct ImportRec ri;
391     struct CommonRec ci;
392     static int farsym = 0;
393     static int i;
394     char symflags = 0;
395     int len;
396
397     /* Check if the label length is OK */
398     if ((len = strlen(name)) >= EXIM_LABEL_MAX) {
399         error(ERR_NONFATAL, "label size exceeds %d bytes", EXIM_LABEL_MAX);
400         return;
401     }
402     if (!len) {
403         error(ERR_NONFATAL, "zero-length label");
404         return;
405     }
406
407     if (is_global == 2) {
408         /* Common variable */
409         ci.type = RDFREC_COMMON;
410         ci.size = offset;
411         ci.segment = segment;
412         strcpy(ci.label, name);
413         ci.reclen = 9 + len;
414         ci.align = 0;
415
416         /*
417          * Check the special text to see if it's a valid number and power
418          * of two; if so, store it as the alignment for the common variable.
419          */
420         if (special) {
421             bool err;
422             ci.align = readnum(special, &err);
423             if (err)
424                 error(ERR_NONFATAL, "alignment constraint `%s' is not a"
425                       " valid number", special);
426             else if ((ci.align | (ci.align - 1)) != 2 * ci.align - 1)
427                 error(ERR_NONFATAL, "alignment constraint `%s' is not a"
428                       " power of two", special);
429         }
430         write_common_rec(&ci);
431     }
432
433     /* We don't care about local labels or fix-up hints */
434     if (is_global != 1)
435         return;
436
437     if (special) {
438         while (*special == ' ' || *special == '\t')
439             special++;
440
441         if (!nasm_strnicmp(special, "export", 6)) {
442             special += 6;
443             symflags |= SYM_GLOBAL;
444         } else if (!nasm_strnicmp(special, "import", 6)) {
445             special += 6;
446             symflags |= SYM_IMPORT;
447         }
448
449         if (*special) {
450             while (nasm_isspace(*special))
451                 special++;
452             if (!nasm_stricmp(special, "far")) {
453                 farsym = 1;
454             } else if (!nasm_stricmp(special, "near")) {
455                 farsym = 0;
456             } else if (!nasm_stricmp(special, "proc") ||
457                        !nasm_stricmp(special, "function")) {
458                 symflags |= SYM_FUNCTION;
459             } else if (!nasm_stricmp(special, "data") ||
460                        !nasm_stricmp(special, "object")) {
461                 symflags |= SYM_DATA;
462             } else
463                 error(ERR_NONFATAL, "unrecognised symbol type `%s'",
464                       special);
465         }
466     }
467
468     if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
469         error(ERR_NONFATAL, "unrecognised special symbol `%s'", name);
470         return;
471     }
472
473     for (i = 0; i < nsegments; i++) {
474         if (segments[i].segnumber == segment >> 1)
475             break;
476     }
477
478     if (i >= nsegments) {       /* EXTERN declaration */
479         ri.type = farsym ? RDFREC_FARIMPORT : RDFREC_IMPORT;
480         if (symflags & SYM_GLOBAL)
481             error(ERR_NONFATAL,
482                   "symbol type conflict - EXTERN cannot be EXPORT");
483         ri.flags = symflags;
484         ri.segment = segment;
485         strcpy(ri.label, name);
486         ri.reclen = 4 + len;
487         write_import_rec(&ri);
488     } else if (is_global) {
489         r.type = RDFREC_GLOBAL; /* GLOBAL declaration */
490         if (symflags & SYM_IMPORT)
491             error(ERR_NONFATAL,
492                   "symbol type conflict - GLOBAL cannot be IMPORT");
493         r.flags = symflags;
494         r.segment = segment;
495         r.offset = offset;
496         strcpy(r.label, name);
497         r.reclen = 7 + len;
498         write_export_rec(&r);
499     }
500 }
501
502 static void membufwrite(int segment, const void *data, int bytes)
503 {
504     int i;
505     char buf[4], *b;
506
507     for (i = 0; i < nsegments; i++) {
508         if (segments[i].segnumber == segment)
509             break;
510     }
511     if (i == nsegments)
512         error(ERR_PANIC, "can't find segment %d", segment);
513
514     if (bytes < 0) {
515         b = buf;
516         if (bytes == -2)
517             WRITESHORT(b, *(int16_t *)data);
518         else
519             WRITELONG(b, *(int32_t *)data);
520         data = buf;
521         bytes = -bytes;
522     }
523     segments[i].seglength += bytes;
524     saa_wbytes(seg[i], data, bytes);
525 }
526
527 static int getsegmentlength(int segment)
528 {
529     int i;
530     for (i = 0; i < nsegments; i++) {
531         if (segments[i].segnumber == segment)
532             break;
533     }
534     if (i == nsegments)
535         error(ERR_PANIC, "can't find segment %d", segment);
536
537     return segments[i].seglength;
538 }
539
540 static void rdf2_out(int32_t segto, const void *data,
541                      enum out_type type, uint64_t size,
542                      int32_t segment, int32_t wrt)
543 {
544     struct RelocRec rr;
545     uint8_t databuf[8], *pd;
546     int seg;
547
548     if (segto == NO_SEG) {
549         if (type != OUT_RESERVE)
550             error(ERR_NONFATAL,
551                   "attempt to assemble code in ABSOLUTE space");
552         return;
553     }
554
555     segto >>= 1;                /* convert NASM segment no to RDF number */
556
557     for (seg = 0; seg < nsegments; seg++) {
558         if (segments[seg].segnumber == segto)
559             break;
560     }
561     if (seg >= nsegments) {
562         error(ERR_NONFATAL,
563               "specified segment not supported by rdf output format");
564         return;
565     }
566
567     if (wrt != NO_SEG) {
568         wrt = NO_SEG;           /* continue to do _something_ */
569         error(ERR_NONFATAL, "WRT not supported by rdf output format");
570     }
571
572     if (segto == 2 && type != OUT_RESERVE) {
573         error(ERR_NONFATAL, "BSS segments may not be initialized");
574
575         /* just reserve the space for now... */
576
577         if (type == OUT_REL2ADR)
578             size = 2;
579         else
580             size = 4;
581         type = OUT_RESERVE;
582     }
583
584     if (type == OUT_RESERVE) {
585         if (segto == 2)         /* BSS segment space reserverd */
586             bsslength += size;
587         else
588             while (size--)
589                 membufwrite(segto, databuf, 1);
590     } else if (type == OUT_RAWDATA) {
591         if (segment != NO_SEG)
592             error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
593
594         membufwrite(segto, data, size);
595     } else if (type == OUT_ADDRESS) {
596
597         /* if segment == NO_SEG then we are writing an address of an
598            object within the same segment - do not produce reloc rec. */
599
600         /* FIXME - is this behaviour sane? at first glance it doesn't
601            appear to be. Must test this thoroughly...! */
602
603         if (segment != NO_SEG) {
604             /* it's an address, so we must write a relocation record */
605
606             rr.type = RDFREC_RELOC;     /* type signature */
607             rr.reclen = 8;
608             rr.segment = segto; /* segment we're currently in */
609             rr.offset = getsegmentlength(segto);        /* current offset */
610             rr.length = size;  /* length of reference */
611             rr.refseg = segment;        /* segment referred to */
612             write_reloc_rec(&rr);
613         }
614
615         pd = databuf;           /* convert address to little-endian */
616         WRITEADDR(pd, *(int64_t *)data, size);
617         membufwrite(segto, databuf, size);
618     } else if (type == OUT_REL2ADR) {
619         if (segment == segto)
620             error(ERR_PANIC, "intra-segment OUT_REL2ADR");
621
622         rr.reclen = 8;
623         rr.offset = getsegmentlength(segto);    /* current offset */
624         rr.length = 2;          /* length of reference */
625         rr.refseg = segment;    /* segment referred to (will be >>1'd) */
626
627         if (segment != NO_SEG && segment % 2) {
628             rr.type = RDFREC_SEGRELOC;
629             rr.segment = segto; /* memory base refs *aren't ever* relative! */
630             write_reloc_rec(&rr);
631
632             /* what do we put in the code? Simply the data. This should almost
633              * always be zero, unless someone's doing segment arithmetic...
634              */
635             rr.offset = *(int64_t *)data;
636         } else {
637             rr.type = RDFREC_RELOC;     /* type signature */
638             rr.segment = segto + 64;    /* segment we're currently in + rel flag */
639             write_reloc_rec(&rr);
640
641             /* work out what to put in the code: offset of the end of this operand,
642              * subtracted from any data specified, so that loader can just add
643              * address of imported symbol onto it to get address relative to end of
644              * instruction: import_address + data(offset) - end_of_instrn */
645
646             rr.offset = *(int32_t *)data - (rr.offset + size);
647         }
648
649         membufwrite(segto, &rr.offset, -2);
650     } else if (type == OUT_REL4ADR) {
651         if ((segment == segto) && (globalbits != 64))
652             error(ERR_PANIC, "intra-segment OUT_REL4ADR");
653         if (segment != NO_SEG && segment % 2) {
654             error(ERR_PANIC, "erm... 4 byte segment base ref?");
655         }
656
657         rr.type = RDFREC_RELOC; /* type signature */
658         rr.segment = segto + 64;        /* segment we're currently in + rel tag */
659         rr.offset = getsegmentlength(segto);    /* current offset */
660         rr.length = 4;          /* length of reference */
661         rr.refseg = segment;    /* segment referred to */
662         rr.reclen = 8;
663         write_reloc_rec(&rr);
664
665         rr.offset = *(int64_t *)data - (rr.offset + size);
666
667         membufwrite(segto, &rr.offset, -4);
668     }
669 }
670
671 static void rdf2_cleanup(int debuginfo)
672 {
673     int32_t l;
674     struct BSSRec bs;
675     int i;
676
677     (void)debuginfo;
678
679     /* should write imported & exported symbol declarations to header here */
680
681     /* generate the output file... */
682     fwrite(RDOFF2Id, 6, 1, ofile);      /* file type magic number */
683
684     if (bsslength != 0) {       /* reserve BSS */
685         bs.type = RDFREC_BSS;
686         bs.amount = bsslength;
687         bs.reclen = 4;
688         write_bss_rec(&bs);
689     }
690
691     /*
692      * calculate overall length of the output object
693      */
694     l = headerlength + 4;
695
696     for (i = 0; i < nsegments; i++) {
697         if (i == 2)
698             continue;           /* skip BSS segment */
699         l += 10 + segments[i].seglength;
700     }
701     l += 10;                    /* null segment */
702
703     fwriteint32_t(l, ofile);
704
705     fwriteint32_t(headerlength, ofile);
706     saa_fpwrite(header, ofile); /* dump header */
707     saa_free(header);
708
709     for (i = 0; i < nsegments; i++) {
710         if (i == 2)
711             continue;
712
713         fwriteint16_t(segments[i].segtype, ofile);
714         fwriteint16_t(segments[i].segnumber, ofile);
715         fwriteint16_t(segments[i].segreserved, ofile);
716         fwriteint32_t(segments[i].seglength, ofile);
717
718         saa_fpwrite(seg[i], ofile);
719         saa_free(seg[i]);
720     }
721
722     /* null segment - write 10 bytes of zero */
723     fwriteint32_t(0, ofile);
724     fwriteint32_t(0, ofile);
725     fwriteint16_t(0, ofile);
726 }
727
728 static int32_t rdf2_segbase(int32_t segment)
729 {
730     return segment;
731 }
732
733 /*
734  * Handle RDOFF2 specific directives
735  */
736 static int rdf2_directive(enum directives directive, char *value, int pass)
737 {
738     size_t n;
739
740     switch (directive) {
741     case D_LIBRARY:
742         n = strlen(value);
743         if (n >= MODLIB_NAME_MAX) {
744             error(ERR_NONFATAL, "name size exceeds %d bytes", MODLIB_NAME_MAX);
745             return 1;
746         }
747         if (pass == 1) {
748             struct DLLRec r;
749             r.type = RDFREC_DLL;
750             r.reclen = n + 1;
751             strcpy(r.libname, value);
752             write_dll_rec(&r);
753         }
754         return 1;
755         
756     case D_MODULE:
757         if ((n = strlen(value)) >= MODLIB_NAME_MAX) {
758             error(ERR_NONFATAL, "name size exceeds %d bytes", MODLIB_NAME_MAX);
759             return 1;
760         }
761         if (pass == 1) {
762             struct ModRec r;
763             r.type = RDFREC_MODNAME;
764             r.reclen = n + 1;
765             strcpy(r.modname, value);
766             write_modname_rec(&r);
767         }
768         return 1;
769
770     default:
771         return 0;
772     }
773 }
774
775 static void rdf2_filename(char *inname, char *outname, efunc error)
776 {
777     standard_extension(inname, outname, ".rdf", error);
778 }
779
780 extern macros_t rdf2_stdmac[];
781
782 static int rdf2_set_info(enum geninfo type, char **val)
783 {
784     (void)type;
785     (void)val;
786     return 0;
787 }
788
789 struct ofmt of_rdf2 = {
790     "Relocatable Dynamic Object File Format v2.0",
791     "rdf",
792     0,
793     null_debug_arr,
794     &null_debug_form,
795     rdf2_stdmac,
796     rdf2_init,
797     rdf2_set_info,
798     rdf2_out,
799     rdf2_deflabel,
800     rdf2_section_names,
801     rdf2_segbase,
802     rdf2_directive,
803     rdf2_filename,
804     rdf2_cleanup
805 };
806
807 #endif                          /* OF_RDF2 */