Fixed c99 support for RDOFF Tools
[nasm.git] / rdoff / rdoff.c
blobfdafc92a133b8f237b5c5824f7edaa9ec6f40946
1 /* rdoff.c library of routines for manipulating rdoff files
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
8 * Permission to use this file in your own projects is granted, as int32_t
9 * as acknowledgement is given in an appropriate manner to its authors,
10 * with instructions of how to obtain a copy via ftp.
13 /* TODO: The functions in this module assume they are running
14 * on a little-endian machine. This should be fixed to
15 * make it portable.
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <inttypes.h>
24 #define RDOFF_UTILS
26 #include "rdoff.h"
28 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
29 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
30 s1),s2)
33 * Comment this out to allow the module to read & write header record types
34 * that it isn't aware of. With this defined, unrecognised header records
35 * will generate error number 8, reported as 'unknown extended header record'.
38 #define STRICT_ERRORS
40 /* ========================================================================
41 * Code for memory buffers (for delayed writing of header until we know
42 * how int32_t it is).
43 * ======================================================================== */
45 memorybuffer *newmembuf()
47 memorybuffer *t;
49 t = malloc(sizeof(memorybuffer));
50 if (!t)
51 return NULL;
53 t->length = 0;
54 t->next = NULL;
55 return t;
58 void membufwrite(memorybuffer * const b, void *data, int bytes)
60 uint16 w;
61 int32_t l;
63 if (b->next) { /* memory buffer full - use next buffer */
64 membufwrite(b->next, data, bytes);
65 return;
68 if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
69 || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) {
71 /* buffer full and no next allocated... allocate and initialise next
72 * buffer */
73 b->next = newmembuf();
74 membufwrite(b->next, data, bytes);
75 return;
78 switch (bytes) {
79 case -4: /* convert to little-endian */
80 l = *(int32_t *)data;
81 b->buffer[b->length++] = l & 0xFF;
82 l >>= 8;
83 b->buffer[b->length++] = l & 0xFF;
84 l >>= 8;
85 b->buffer[b->length++] = l & 0xFF;
86 l >>= 8;
87 b->buffer[b->length++] = l & 0xFF;
88 break;
90 case -2:
91 w = *(uint16 *) data;
92 b->buffer[b->length++] = w & 0xFF;
93 w >>= 8;
94 b->buffer[b->length++] = w & 0xFF;
95 break;
97 default:
98 while (bytes--) {
99 b->buffer[b->length++] = *(*(uint8_t **)&data);
101 (*(uint8_t **)&data)++;
103 break;
107 void membufdump(memorybuffer * b, FILE * fp)
109 if (!b)
110 return;
112 fwrite(b->buffer, 1, b->length, fp);
114 membufdump(b->next, fp);
117 int membuflength(memorybuffer * b)
119 if (!b)
120 return 0;
121 return b->length + membuflength(b->next);
124 void freemembuf(memorybuffer * b)
126 if (!b)
127 return;
128 freemembuf(b->next);
129 free(b);
132 /* =========================================================================
133 General purpose routines and variables used by the library functions
134 ========================================================================= */
137 * translateint32_t() and translateint16_t()
139 * translate from little endian to local representation
141 int32_t translateint32_t(int32_t in)
143 int32_t r;
144 uint8_t *i;
146 i = (uint8_t *)&in;
147 r = i[3];
148 r = (r << 8) + i[2];
149 r = (r << 8) + i[1];
150 r = (r << 8) + *i;
152 return r;
155 uint16 translateint16_t(uint16 in)
157 uint16 r;
158 uint8_t *i;
160 i = (uint8_t *)&in;
161 r = (i[1] << 8) + i[0];
163 return r;
166 /* Segment types */
167 static int8_t *knownsegtypes[8] = {
168 "NULL", "text", "data", "object comment",
169 "linked comment", "loader comment",
170 "symbolic debug", "line number debug"
173 /* Get a textual string describing the segment type */
174 int8_t *translatesegmenttype(uint16 type)
176 if (type < 8)
177 return knownsegtypes[type];
178 if (type < 0x0020)
179 return "reserved";
180 if (type < 0x1000)
181 return "reserved - Moscow";
182 if (type < 0x8000)
183 return "reserved - system dependant";
184 if (type < 0xFFFF)
185 return "reserved - other";
186 if (type == 0xFFFF)
187 return "invalid type code";
188 return "type code out of range";
191 /* This signature is written to the start of RDOFF files */
192 const int8_t *RDOFFId = RDOFF2_SIGNATURE;
194 /* Error messages. Must correspond to the codes defined in rdoff.h */
195 const int8_t *rdf_errors[11] = {
196 /* 0 */ "no error occurred",
197 /* 1 */ "could not open file",
198 /* 2 */ "invalid file format",
199 /* 3 */ "error reading file",
200 /* 4 */ "unknown error",
201 /* 5 */ "header not read",
202 /* 6 */ "out of memory",
203 /* 7 */ "RDOFF v1 not supported",
204 /* 8 */ "unknown extended header record",
205 /* 9 */ "header record of known type but unknown length",
206 /* 10 */ "no such segment"
209 int rdf_errno = 0;
211 /* ========================================================================
212 The library functions
213 ======================================================================== */
215 int rdfopen(rdffile * f, const int8_t *name)
217 FILE *fp;
219 fp = fopen(name, "rb");
220 if (!fp)
221 return rdf_errno = RDF_ERR_OPEN;
223 return rdfopenhere(f, fp, NULL, name);
226 int rdfopenhere(rdffile * f, FILE * fp, int *refcount, const int8_t *name)
228 int8_t buf[8];
229 int32_t initpos;
230 int32_t l;
231 uint16 s;
233 if (translateint32_t(0x01020304) != 0x01020304) {
234 /* fix this to be portable! */
235 fputs("*** this program requires a little endian machine\n",
236 stderr);
237 fprintf(stderr, "01020304h = %08lxh\n", translateint32_t(0x01020304));
238 exit(3);
241 f->fp = fp;
242 initpos = ftell(fp);
244 fread(buf, 6, 1, f->fp); /* read header */
245 buf[6] = 0;
247 if (strcmp(buf, RDOFFId)) {
248 fclose(f->fp);
249 if (!strcmp(buf, "RDOFF1"))
250 return rdf_errno = RDF_ERR_VER;
251 return rdf_errno = RDF_ERR_FORMAT;
254 if (fread(&l, 1, 4, f->fp) != 4
255 || fread(&f->header_len, 1, 4, f->fp) != 4) {
256 fclose(f->fp);
257 return rdf_errno = RDF_ERR_READ;
260 f->header_ofs = ftell(f->fp);
261 f->eof_offset = f->header_ofs + translateint32_t(l) - 4;
263 if (fseek(f->fp, f->header_len, SEEK_CUR)) {
264 fclose(f->fp);
265 return rdf_errno = RDF_ERR_FORMAT; /* seek past end of file...? */
268 if (fread(&s, 1, 2, f->fp) != 2) {
269 fclose(f->fp);
270 return rdf_errno = RDF_ERR_READ;
273 f->nsegs = 0;
275 while (s != 0) {
276 f->seg[f->nsegs].type = s;
277 if (fread(&f->seg[f->nsegs].number, 1, 2, f->fp) != 2 ||
278 fread(&f->seg[f->nsegs].reserved, 1, 2, f->fp) != 2 ||
279 fread(&f->seg[f->nsegs].length, 1, 4, f->fp) != 4) {
280 fclose(f->fp);
281 return rdf_errno = RDF_ERR_READ;
284 f->seg[f->nsegs].offset = ftell(f->fp);
285 if (fseek(f->fp, f->seg[f->nsegs].length, SEEK_CUR)) {
286 fclose(f->fp);
287 return rdf_errno = RDF_ERR_FORMAT;
289 f->nsegs++;
291 if (fread(&s, 1, 2, f->fp) != 2) {
292 fclose(f->fp);
293 return rdf_errno = RDF_ERR_READ;
297 if (f->eof_offset != ftell(f->fp) + 8) { /* +8 = skip null segment header */
298 fprintf(stderr, "warning: eof_offset [%ld] and actual eof offset "
299 "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
301 fseek(f->fp, initpos, SEEK_SET);
302 f->header_loc = NULL;
304 f->name = newstr(name);
305 f->refcount = refcount;
306 if (refcount)
307 (*refcount)++;
308 return RDF_OK;
311 int rdfclose(rdffile * f)
313 if (!f->refcount || !--(*f->refcount)) {
314 fclose(f->fp);
315 f->fp = NULL;
317 free(f->name);
319 return 0;
323 * Print the message for last error (from rdf_errno)
325 void rdfperror(const int8_t *app, const int8_t *name)
327 fprintf(stderr, "%s:%s: %s\n", app, name, rdf_errors[rdf_errno]);
328 if (rdf_errno == RDF_ERR_OPEN || rdf_errno == RDF_ERR_READ) {
329 perror(app);
334 * Find the segment by its number.
335 * Returns segment array index, or -1 if segment with such number was not found.
337 int rdffindsegment(rdffile * f, int segno)
339 int i;
340 for (i = 0; i < f->nsegs; i++)
341 if (f->seg[i].number == segno)
342 return i;
343 return -1;
347 * Load the segment. Returns status.
349 int rdfloadseg(rdffile * f, int segment, void *buffer)
351 int32_t fpos, slen;
353 switch (segment) {
354 case RDOFF_HEADER:
355 fpos = f->header_ofs;
356 slen = f->header_len;
357 f->header_loc = (byte *) buffer;
358 f->header_fp = 0;
359 break;
360 default:
361 if (segment < f->nsegs) {
362 fpos = f->seg[segment].offset;
363 slen = f->seg[segment].length;
364 f->seg[segment].data = (byte *) buffer;
365 } else {
366 return rdf_errno = RDF_ERR_SEGMENT;
370 if (fseek(f->fp, fpos, SEEK_SET))
371 return rdf_errno = RDF_ERR_UNKNOWN;
373 if (fread(buffer, 1, slen, f->fp) != slen)
374 return rdf_errno = RDF_ERR_READ;
376 return RDF_OK;
379 /* Macros for reading integers from header in memory */
381 #define RI8(v) v = f->header_loc[f->header_fp++]
382 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
383 (f->header_loc[f->header_fp+1] << 8)); \
384 f->header_fp += 2; }
386 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
387 (f->header_loc[f->header_fp+1] << 8) + \
388 (f->header_loc[f->header_fp+2] << 16) + \
389 (f->header_loc[f->header_fp+3] << 24)); \
390 f->header_fp += 4; }
392 #define RS(str,max) { for(i=0;i<max;i++){\
393 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
396 * Read a header record.
397 * Returns the address of record, or NULL in case of error.
399 rdfheaderrec *rdfgetheaderrec(rdffile * f)
401 static rdfheaderrec r;
402 int i;
404 if (!f->header_loc) {
405 rdf_errno = RDF_ERR_HEADER;
406 return NULL;
409 if (f->header_fp >= f->header_len)
410 return 0;
412 RI8(r.type);
413 RI8(r.g.reclen);
415 switch (r.type) {
416 case RDFREC_RELOC: /* Relocation record */
417 case RDFREC_SEGRELOC:
418 if (r.r.reclen != 8) {
419 rdf_errno = RDF_ERR_RECLEN;
420 return NULL;
422 RI8(r.r.segment);
423 RI32(r.r.offset);
424 RI8(r.r.length);
425 RI16(r.r.refseg);
426 break;
428 case RDFREC_IMPORT: /* Imported symbol record */
429 case RDFREC_FARIMPORT:
430 RI8(r.i.flags);
431 RI16(r.i.segment);
432 RS(r.i.label, EXIM_LABEL_MAX);
433 break;
435 case RDFREC_GLOBAL: /* Exported symbol record */
436 RI8(r.e.flags);
437 RI8(r.e.segment);
438 RI32(r.e.offset);
439 RS(r.e.label, EXIM_LABEL_MAX);
440 break;
442 case RDFREC_DLL: /* DLL record */
443 RS(r.d.libname, MODLIB_NAME_MAX);
444 break;
446 case RDFREC_BSS: /* BSS reservation record */
447 if (r.r.reclen != 4) {
448 rdf_errno = RDF_ERR_RECLEN;
449 return NULL;
451 RI32(r.b.amount);
452 break;
454 case RDFREC_MODNAME: /* Module name record */
455 RS(r.m.modname, MODLIB_NAME_MAX);
456 break;
458 case RDFREC_COMMON: /* Common variable */
459 RI16(r.c.segment);
460 RI32(r.c.size);
461 RI16(r.c.align);
462 RS(r.c.label, EXIM_LABEL_MAX);
463 break;
465 default:
466 #ifdef STRICT_ERRORS
467 rdf_errno = RDF_ERR_RECTYPE; /* unknown header record */
468 return NULL;
469 #else
470 for (i = 0; i < r.g.reclen; i++)
471 RI8(r.g.data[i]);
472 #endif
474 return &r;
478 * Rewind to the beginning of the file
480 void rdfheaderrewind(rdffile * f)
482 f->header_fp = 0;
485 rdf_headerbuf *rdfnewheader(void)
487 rdf_headerbuf *hb = malloc(sizeof(rdf_headerbuf));
488 if (hb == NULL)
489 return NULL;
491 hb->buf = newmembuf();
492 hb->nsegments = 0;
493 hb->seglength = 0;
495 return hb;
498 int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
500 #ifndef STRICT_ERRORS
501 int i;
502 #endif
503 membufwrite(h->buf, &r->type, 1);
504 membufwrite(h->buf, &r->g.reclen, 1);
506 switch (r->type) {
507 case RDFREC_GENERIC: /* generic */
508 membufwrite(h->buf, &r->g.data, r->g.reclen);
509 break;
510 case RDFREC_RELOC:
511 case RDFREC_SEGRELOC:
512 membufwrite(h->buf, &r->r.segment, 1);
513 membufwrite(h->buf, &r->r.offset, -4);
514 membufwrite(h->buf, &r->r.length, 1);
515 membufwrite(h->buf, &r->r.refseg, -2); /* 9 bytes written */
516 break;
518 case RDFREC_IMPORT: /* import */
519 case RDFREC_FARIMPORT:
520 membufwrite(h->buf, &r->i.flags, 1);
521 membufwrite(h->buf, &r->i.segment, -2);
522 membufwrite(h->buf, &r->i.label, strlen(r->i.label) + 1);
523 break;
525 case RDFREC_GLOBAL: /* export */
526 membufwrite(h->buf, &r->e.flags, 1);
527 membufwrite(h->buf, &r->e.segment, 1);
528 membufwrite(h->buf, &r->e.offset, -4);
529 membufwrite(h->buf, &r->e.label, strlen(r->e.label) + 1);
530 break;
532 case RDFREC_DLL: /* DLL */
533 membufwrite(h->buf, &r->d.libname, strlen(r->d.libname) + 1);
534 break;
536 case RDFREC_BSS: /* BSS */
537 membufwrite(h->buf, &r->b.amount, -4);
538 break;
540 case RDFREC_MODNAME: /* Module name */
541 membufwrite(h->buf, &r->m.modname, strlen(r->m.modname) + 1);
542 break;
544 default:
545 #ifdef STRICT_ERRORS
546 return rdf_errno = RDF_ERR_RECTYPE;
547 #else
548 for (i = 0; i < r->g.reclen; i++)
549 membufwrite(h->buf, r->g.data[i], 1);
550 #endif
552 return 0;
555 int rdfaddsegment(rdf_headerbuf * h, int32_t seglength)
557 h->nsegments++;
558 h->seglength += seglength;
559 return 0;
562 int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
564 int32_t l, l2;
566 fwrite(RDOFFId, 1, strlen(RDOFFId), fp);
568 l = membuflength(h->buf);
569 l2 = l + 14 + 10 * h->nsegments + h->seglength;
570 l = translateint32_t(l);
571 l2 = translateint32_t(l2);
572 fwrite(&l2, 4, 1, fp); /* object length */
573 fwrite(&l, 4, 1, fp); /* header length */
575 membufdump(h->buf, fp);
577 return 0; /* no error handling in here... CHANGE THIS! */
580 void rdfdoneheader(rdf_headerbuf * h)
582 freemembuf(h->buf);
583 free(h);