make: Lift up openwcom.mak for build on FreeDOS
[nasm.git] / rdoff / rdoff.c
blob3c7b33607e5af40a00ea72f31884f257a1f63a71
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.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
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.
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.
32 * ----------------------------------------------------------------------- */
35 * rdoff.c library of routines for manipulating rdoff files
38 /* TODO: The functions in this module assume they are running
39 * on a little-endian machine. This should be fixed to
40 * make it portable.
43 #include "compiler.h"
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <inttypes.h>
51 #define RDOFF_UTILS
53 #include "rdoff.h"
55 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
56 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
57 s1),s2)
60 * Comment this out to allow the module to read & write header record types
61 * that it isn't aware of. With this defined, unrecognised header records
62 * will generate error number 8, reported as 'unknown extended header record'.
65 #define STRICT_ERRORS
67 /* ========================================================================
68 * Code for memory buffers (for delayed writing of header until we know
69 * how int32_t it is).
70 * ======================================================================== */
72 memorybuffer *newmembuf()
74 memorybuffer *t;
76 t = malloc(sizeof(memorybuffer));
77 if (!t)
78 return NULL;
80 t->length = 0;
81 t->next = NULL;
82 return t;
85 void membufwrite(memorybuffer * const b, void *data, int bytes)
87 uint16_t w;
88 int32_t l;
89 char *c;
91 if (b->next) { /* memory buffer full - use next buffer */
92 membufwrite(b->next, data, bytes);
93 return;
96 if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
97 || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) {
99 /* buffer full and no next allocated... allocate and initialise next
100 * buffer */
101 b->next = newmembuf();
102 membufwrite(b->next, data, bytes);
103 return;
106 switch (bytes) {
107 case -4: /* convert to little-endian */
108 l = *(int32_t *)data;
109 b->buffer[b->length++] = l & 0xFF;
110 l >>= 8;
111 b->buffer[b->length++] = l & 0xFF;
112 l >>= 8;
113 b->buffer[b->length++] = l & 0xFF;
114 l >>= 8;
115 b->buffer[b->length++] = l & 0xFF;
116 break;
118 case -2:
119 w = *(uint16_t *) data;
120 b->buffer[b->length++] = w & 0xFF;
121 w >>= 8;
122 b->buffer[b->length++] = w & 0xFF;
123 break;
125 default:
126 c = data;
127 while (bytes--)
128 b->buffer[b->length++] = *c++;
129 break;
133 void membufdump(memorybuffer * b, FILE * fp)
135 if (!b)
136 return;
138 fwrite(b->buffer, 1, b->length, fp);
140 membufdump(b->next, fp);
143 int membuflength(memorybuffer * b)
145 if (!b)
146 return 0;
147 return b->length + membuflength(b->next);
150 void freemembuf(memorybuffer * b)
152 if (!b)
153 return;
154 freemembuf(b->next);
155 free(b);
158 /* =========================================================================
159 General purpose routines and variables used by the library functions
160 ========================================================================= */
163 * translateint32_t() and translateint16_t()
165 * translate from little endian to local representation
167 int32_t translateint32_t(int32_t in)
169 int32_t r;
170 uint8_t *i;
172 i = (uint8_t *)&in;
173 r = i[3];
174 r = (r << 8) + i[2];
175 r = (r << 8) + i[1];
176 r = (r << 8) + *i;
178 return r;
181 uint16_t translateint16_t(uint16_t in)
183 uint16_t r;
184 uint8_t *i;
186 i = (uint8_t *)&in;
187 r = (i[1] << 8) + i[0];
189 return r;
192 /* Segment types */
193 static char *knownsegtypes[8] = {
194 "NULL", "text", "data", "object comment",
195 "linked comment", "loader comment",
196 "symbolic debug", "line number debug"
199 /* Get a textual string describing the segment type */
200 char *translatesegmenttype(uint16_t type)
202 if (type < 8)
203 return knownsegtypes[type];
204 if (type < 0x0020)
205 return "reserved";
206 if (type < 0x1000)
207 return "reserved - Moscow";
208 if (type < 0x8000)
209 return "reserved - system dependant";
210 if (type < 0xFFFF)
211 return "reserved - other";
212 if (type == 0xFFFF)
213 return "invalid type code";
214 return "type code out of range";
217 /* This signature is written to the start of RDOFF files */
218 const char *RDOFFId = RDOFF2_SIGNATURE;
220 /* Error messages. Must correspond to the codes defined in rdoff.h */
221 const char *rdf_errors[11] = {
222 /* 0 */ "no error occurred",
223 /* 1 */ "could not open file",
224 /* 2 */ "invalid file format",
225 /* 3 */ "error reading file",
226 /* 4 */ "unknown error",
227 /* 5 */ "header not read",
228 /* 6 */ "out of memory",
229 /* 7 */ "RDOFF v1 not supported",
230 /* 8 */ "unknown extended header record",
231 /* 9 */ "header record of known type but unknown length",
232 /* 10 */ "no such segment"
235 int rdf_errno = 0;
237 /* ========================================================================
238 The library functions
239 ======================================================================== */
241 int rdfopen(rdffile * f, const char *name)
243 FILE *fp;
245 fp = fopen(name, "rb");
246 if (!fp)
247 return rdf_errno = RDF_ERR_OPEN;
249 return rdfopenhere(f, fp, NULL, name);
252 int rdfopenhere(rdffile * f, FILE * fp, int *refcount, const char *name)
254 char buf[8];
255 int32_t initpos;
256 int32_t l;
257 uint16_t s;
259 if (translateint32_t(0x01020304) != 0x01020304) {
260 /* fix this to be portable! */
261 fputs("*** this program requires a little endian machine\n",
262 stderr);
263 fprintf(stderr, "01020304h = %08"PRIx32"h\n", translateint32_t(0x01020304));
264 exit(3);
267 f->fp = fp;
268 initpos = ftell(fp);
270 fread(buf, 6, 1, f->fp); /* read header */
271 buf[6] = 0;
273 if (strcmp(buf, RDOFFId)) {
274 fclose(f->fp);
275 if (!strcmp(buf, "RDOFF1"))
276 return rdf_errno = RDF_ERR_VER;
277 return rdf_errno = RDF_ERR_FORMAT;
280 if (fread(&l, 1, 4, f->fp) != 4
281 || fread(&f->header_len, 1, 4, f->fp) != 4) {
282 fclose(f->fp);
283 return rdf_errno = RDF_ERR_READ;
286 f->header_ofs = ftell(f->fp);
287 f->eof_offset = f->header_ofs + translateint32_t(l) - 4;
289 if (fseek(f->fp, f->header_len, SEEK_CUR)) {
290 fclose(f->fp);
291 return rdf_errno = RDF_ERR_FORMAT; /* seek past end of file...? */
294 if (fread(&s, 1, 2, f->fp) != 2) {
295 fclose(f->fp);
296 return rdf_errno = RDF_ERR_READ;
299 f->nsegs = 0;
301 while (s != 0) {
302 f->seg[f->nsegs].type = s;
303 if (fread(&f->seg[f->nsegs].number, 1, 2, f->fp) != 2 ||
304 fread(&f->seg[f->nsegs].reserved, 1, 2, f->fp) != 2 ||
305 fread(&f->seg[f->nsegs].length, 1, 4, f->fp) != 4) {
306 fclose(f->fp);
307 return rdf_errno = RDF_ERR_READ;
310 f->seg[f->nsegs].offset = ftell(f->fp);
311 if (fseek(f->fp, f->seg[f->nsegs].length, SEEK_CUR)) {
312 fclose(f->fp);
313 return rdf_errno = RDF_ERR_FORMAT;
315 f->nsegs++;
317 if (fread(&s, 1, 2, f->fp) != 2) {
318 fclose(f->fp);
319 return rdf_errno = RDF_ERR_READ;
323 if (f->eof_offset != ftell(f->fp) + 8) { /* +8 = skip null segment header */
324 fprintf(stderr, "warning: eof_offset [%"PRId32"] and actual eof offset "
325 "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
327 fseek(f->fp, initpos, SEEK_SET);
328 f->header_loc = NULL;
330 f->name = newstr(name);
331 f->refcount = refcount;
332 if (refcount)
333 (*refcount)++;
334 return RDF_OK;
337 int rdfclose(rdffile * f)
339 if (!f->refcount || !--(*f->refcount)) {
340 fclose(f->fp);
341 f->fp = NULL;
343 free(f->name);
345 return 0;
349 * Print the message for last error (from rdf_errno)
351 void rdfperror(const char *app, const char *name)
353 fprintf(stderr, "%s:%s: %s\n", app, name, rdf_errors[rdf_errno]);
354 if (rdf_errno == RDF_ERR_OPEN || rdf_errno == RDF_ERR_READ) {
355 perror(app);
360 * Find the segment by its number.
361 * Returns segment array index, or -1 if segment with such number was not found.
363 int rdffindsegment(rdffile * f, int segno)
365 int i;
366 for (i = 0; i < f->nsegs; i++)
367 if (f->seg[i].number == segno)
368 return i;
369 return -1;
373 * Load the segment. Returns status.
375 int rdfloadseg(rdffile * f, int segment, void *buffer)
377 int32_t fpos;
378 size_t slen;
380 switch (segment) {
381 case RDOFF_HEADER:
382 fpos = f->header_ofs;
383 slen = f->header_len;
384 f->header_loc = (uint8_t *) buffer;
385 f->header_fp = 0;
386 break;
387 default:
388 if (segment < f->nsegs) {
389 fpos = f->seg[segment].offset;
390 slen = f->seg[segment].length;
391 f->seg[segment].data = (uint8_t *) buffer;
392 } else {
393 return rdf_errno = RDF_ERR_SEGMENT;
397 if (fseek(f->fp, fpos, SEEK_SET))
398 return rdf_errno = RDF_ERR_UNKNOWN;
400 if (fread(buffer, 1, slen, f->fp) != slen)
401 return rdf_errno = RDF_ERR_READ;
403 return RDF_OK;
406 /* Macros for reading integers from header in memory */
408 #define RI8(v) v = f->header_loc[f->header_fp++]
409 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
410 (f->header_loc[f->header_fp+1] << 8)); \
411 f->header_fp += 2; }
413 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
414 (f->header_loc[f->header_fp+1] << 8) + \
415 (f->header_loc[f->header_fp+2] << 16) + \
416 (f->header_loc[f->header_fp+3] << 24)); \
417 f->header_fp += 4; }
419 #define RS(str,max) { for(i=0;i<max;i++){\
420 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
423 * Read a header record.
424 * Returns the address of record, or NULL in case of error.
426 rdfheaderrec *rdfgetheaderrec(rdffile * f)
428 static rdfheaderrec r;
429 int i;
431 if (!f->header_loc) {
432 rdf_errno = RDF_ERR_HEADER;
433 return NULL;
436 if (f->header_fp >= f->header_len)
437 return 0;
439 RI8(r.type);
440 RI8(r.g.reclen);
442 switch (r.type) {
443 case RDFREC_RELOC: /* Relocation record */
444 case RDFREC_SEGRELOC:
445 if (r.r.reclen != 8) {
446 rdf_errno = RDF_ERR_RECLEN;
447 return NULL;
449 RI8(r.r.segment);
450 RI32(r.r.offset);
451 RI8(r.r.length);
452 RI16(r.r.refseg);
453 break;
455 case RDFREC_IMPORT: /* Imported symbol record */
456 case RDFREC_FARIMPORT:
457 RI8(r.i.flags);
458 RI16(r.i.segment);
459 RS(r.i.label, EXIM_LABEL_MAX);
460 break;
462 case RDFREC_GLOBAL: /* Exported symbol record */
463 RI8(r.e.flags);
464 RI8(r.e.segment);
465 RI32(r.e.offset);
466 RS(r.e.label, EXIM_LABEL_MAX);
467 break;
469 case RDFREC_DLL: /* DLL record */
470 RS(r.d.libname, MODLIB_NAME_MAX);
471 break;
473 case RDFREC_BSS: /* BSS reservation record */
474 if (r.r.reclen != 4) {
475 rdf_errno = RDF_ERR_RECLEN;
476 return NULL;
478 RI32(r.b.amount);
479 break;
481 case RDFREC_MODNAME: /* Module name record */
482 RS(r.m.modname, MODLIB_NAME_MAX);
483 break;
485 case RDFREC_COMMON: /* Common variable */
486 RI16(r.c.segment);
487 RI32(r.c.size);
488 RI16(r.c.align);
489 RS(r.c.label, EXIM_LABEL_MAX);
490 break;
492 default:
493 #ifdef STRICT_ERRORS
494 rdf_errno = RDF_ERR_RECTYPE; /* unknown header record */
495 return NULL;
496 #else
497 for (i = 0; i < r.g.reclen; i++)
498 RI8(r.g.data[i]);
499 #endif
501 return &r;
505 * Rewind to the beginning of the file
507 void rdfheaderrewind(rdffile * f)
509 f->header_fp = 0;
512 rdf_headerbuf *rdfnewheader(void)
514 rdf_headerbuf *hb = malloc(sizeof(rdf_headerbuf));
515 if (hb == NULL)
516 return NULL;
518 hb->buf = newmembuf();
519 hb->nsegments = 0;
520 hb->seglength = 0;
522 return hb;
525 int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
527 #ifndef STRICT_ERRORS
528 int i;
529 #endif
530 membufwrite(h->buf, &r->type, 1);
531 membufwrite(h->buf, &r->g.reclen, 1);
533 switch (r->type) {
534 case RDFREC_GENERIC: /* generic */
535 membufwrite(h->buf, &r->g.data, r->g.reclen);
536 break;
537 case RDFREC_RELOC:
538 case RDFREC_SEGRELOC:
539 membufwrite(h->buf, &r->r.segment, 1);
540 membufwrite(h->buf, &r->r.offset, -4);
541 membufwrite(h->buf, &r->r.length, 1);
542 membufwrite(h->buf, &r->r.refseg, -2); /* 9 bytes written */
543 break;
545 case RDFREC_IMPORT: /* import */
546 case RDFREC_FARIMPORT:
547 membufwrite(h->buf, &r->i.flags, 1);
548 membufwrite(h->buf, &r->i.segment, -2);
549 membufwrite(h->buf, &r->i.label, strlen(r->i.label) + 1);
550 break;
552 case RDFREC_GLOBAL: /* export */
553 membufwrite(h->buf, &r->e.flags, 1);
554 membufwrite(h->buf, &r->e.segment, 1);
555 membufwrite(h->buf, &r->e.offset, -4);
556 membufwrite(h->buf, &r->e.label, strlen(r->e.label) + 1);
557 break;
559 case RDFREC_DLL: /* DLL */
560 membufwrite(h->buf, &r->d.libname, strlen(r->d.libname) + 1);
561 break;
563 case RDFREC_BSS: /* BSS */
564 membufwrite(h->buf, &r->b.amount, -4);
565 break;
567 case RDFREC_MODNAME: /* Module name */
568 membufwrite(h->buf, &r->m.modname, strlen(r->m.modname) + 1);
569 break;
571 default:
572 #ifdef STRICT_ERRORS
573 return rdf_errno = RDF_ERR_RECTYPE;
574 #else
575 for (i = 0; i < r->g.reclen; i++)
576 membufwrite(h->buf, r->g.data[i], 1);
577 #endif
579 return 0;
582 int rdfaddsegment(rdf_headerbuf * h, int32_t seglength)
584 h->nsegments++;
585 h->seglength += seglength;
586 return 0;
589 int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
591 int32_t l, l2;
593 fwrite(RDOFFId, 1, strlen(RDOFFId), fp);
595 l = membuflength(h->buf);
596 l2 = l + 14 + 10 * h->nsegments + h->seglength;
597 l = translateint32_t(l);
598 l2 = translateint32_t(l2);
599 fwrite(&l2, 4, 1, fp); /* object length */
600 fwrite(&l, 4, 1, fp); /* header length */
602 membufdump(h->buf, fp);
604 return 0; /* no error handling in here... CHANGE THIS! */
607 void rdfdoneheader(rdf_headerbuf * h)
609 freemembuf(h->buf);
610 free(h);