Formatting: kill off "stealth whitespace"
[nasm.git] / rdoff / rdoff.c
blob8201c72c2b0bee16c9337f83aea6186417d46fe0
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 "compiler.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <inttypes.h>
26 #define RDOFF_UTILS
28 #include "rdoff.h"
30 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
31 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
32 s1),s2)
35 * Comment this out to allow the module to read & write header record types
36 * that it isn't aware of. With this defined, unrecognised header records
37 * will generate error number 8, reported as 'unknown extended header record'.
40 #define STRICT_ERRORS
42 /* ========================================================================
43 * Code for memory buffers (for delayed writing of header until we know
44 * how int32_t it is).
45 * ======================================================================== */
47 memorybuffer *newmembuf()
49 memorybuffer *t;
51 t = malloc(sizeof(memorybuffer));
52 if (!t)
53 return NULL;
55 t->length = 0;
56 t->next = NULL;
57 return t;
60 void membufwrite(memorybuffer * const b, void *data, int bytes)
62 uint16_t w;
63 int32_t l;
65 if (b->next) { /* memory buffer full - use next buffer */
66 membufwrite(b->next, data, bytes);
67 return;
70 if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
71 || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) {
73 /* buffer full and no next allocated... allocate and initialise next
74 * buffer */
75 b->next = newmembuf();
76 membufwrite(b->next, data, bytes);
77 return;
80 switch (bytes) {
81 case -4: /* convert to little-endian */
82 l = *(int32_t *)data;
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 l >>= 8;
89 b->buffer[b->length++] = l & 0xFF;
90 break;
92 case -2:
93 w = *(uint16_t *) data;
94 b->buffer[b->length++] = w & 0xFF;
95 w >>= 8;
96 b->buffer[b->length++] = w & 0xFF;
97 break;
99 default:
100 while (bytes--) {
101 b->buffer[b->length++] = *(*(uint8_t **)&data);
103 (*(uint8_t **)&data)++;
105 break;
109 void membufdump(memorybuffer * b, FILE * fp)
111 if (!b)
112 return;
114 fwrite(b->buffer, 1, b->length, fp);
116 membufdump(b->next, fp);
119 int membuflength(memorybuffer * b)
121 if (!b)
122 return 0;
123 return b->length + membuflength(b->next);
126 void freemembuf(memorybuffer * b)
128 if (!b)
129 return;
130 freemembuf(b->next);
131 free(b);
134 /* =========================================================================
135 General purpose routines and variables used by the library functions
136 ========================================================================= */
139 * translateint32_t() and translateint16_t()
141 * translate from little endian to local representation
143 int32_t translateint32_t(int32_t in)
145 int32_t r;
146 uint8_t *i;
148 i = (uint8_t *)&in;
149 r = i[3];
150 r = (r << 8) + i[2];
151 r = (r << 8) + i[1];
152 r = (r << 8) + *i;
154 return r;
157 uint16_t translateint16_t(uint16_t in)
159 uint16_t r;
160 uint8_t *i;
162 i = (uint8_t *)&in;
163 r = (i[1] << 8) + i[0];
165 return r;
168 /* Segment types */
169 static char *knownsegtypes[8] = {
170 "NULL", "text", "data", "object comment",
171 "linked comment", "loader comment",
172 "symbolic debug", "line number debug"
175 /* Get a textual string describing the segment type */
176 char *translatesegmenttype(uint16_t type)
178 if (type < 8)
179 return knownsegtypes[type];
180 if (type < 0x0020)
181 return "reserved";
182 if (type < 0x1000)
183 return "reserved - Moscow";
184 if (type < 0x8000)
185 return "reserved - system dependant";
186 if (type < 0xFFFF)
187 return "reserved - other";
188 if (type == 0xFFFF)
189 return "invalid type code";
190 return "type code out of range";
193 /* This signature is written to the start of RDOFF files */
194 const char *RDOFFId = RDOFF2_SIGNATURE;
196 /* Error messages. Must correspond to the codes defined in rdoff.h */
197 const char *rdf_errors[11] = {
198 /* 0 */ "no error occurred",
199 /* 1 */ "could not open file",
200 /* 2 */ "invalid file format",
201 /* 3 */ "error reading file",
202 /* 4 */ "unknown error",
203 /* 5 */ "header not read",
204 /* 6 */ "out of memory",
205 /* 7 */ "RDOFF v1 not supported",
206 /* 8 */ "unknown extended header record",
207 /* 9 */ "header record of known type but unknown length",
208 /* 10 */ "no such segment"
211 int rdf_errno = 0;
213 /* ========================================================================
214 The library functions
215 ======================================================================== */
217 int rdfopen(rdffile * f, const char *name)
219 FILE *fp;
221 fp = fopen(name, "rb");
222 if (!fp)
223 return rdf_errno = RDF_ERR_OPEN;
225 return rdfopenhere(f, fp, NULL, name);
228 int rdfopenhere(rdffile * f, FILE * fp, int *refcount, const char *name)
230 char buf[8];
231 int32_t initpos;
232 int32_t l;
233 uint16_t s;
235 if (translateint32_t(0x01020304) != 0x01020304) {
236 /* fix this to be portable! */
237 fputs("*** this program requires a little endian machine\n",
238 stderr);
239 fprintf(stderr, "01020304h = %08"PRIx32"h\n", translateint32_t(0x01020304));
240 exit(3);
243 f->fp = fp;
244 initpos = ftell(fp);
246 fread(buf, 6, 1, f->fp); /* read header */
247 buf[6] = 0;
249 if (strcmp(buf, RDOFFId)) {
250 fclose(f->fp);
251 if (!strcmp(buf, "RDOFF1"))
252 return rdf_errno = RDF_ERR_VER;
253 return rdf_errno = RDF_ERR_FORMAT;
256 if (fread(&l, 1, 4, f->fp) != 4
257 || fread(&f->header_len, 1, 4, f->fp) != 4) {
258 fclose(f->fp);
259 return rdf_errno = RDF_ERR_READ;
262 f->header_ofs = ftell(f->fp);
263 f->eof_offset = f->header_ofs + translateint32_t(l) - 4;
265 if (fseek(f->fp, f->header_len, SEEK_CUR)) {
266 fclose(f->fp);
267 return rdf_errno = RDF_ERR_FORMAT; /* seek past end of file...? */
270 if (fread(&s, 1, 2, f->fp) != 2) {
271 fclose(f->fp);
272 return rdf_errno = RDF_ERR_READ;
275 f->nsegs = 0;
277 while (s != 0) {
278 f->seg[f->nsegs].type = s;
279 if (fread(&f->seg[f->nsegs].number, 1, 2, f->fp) != 2 ||
280 fread(&f->seg[f->nsegs].reserved, 1, 2, f->fp) != 2 ||
281 fread(&f->seg[f->nsegs].length, 1, 4, f->fp) != 4) {
282 fclose(f->fp);
283 return rdf_errno = RDF_ERR_READ;
286 f->seg[f->nsegs].offset = ftell(f->fp);
287 if (fseek(f->fp, f->seg[f->nsegs].length, SEEK_CUR)) {
288 fclose(f->fp);
289 return rdf_errno = RDF_ERR_FORMAT;
291 f->nsegs++;
293 if (fread(&s, 1, 2, f->fp) != 2) {
294 fclose(f->fp);
295 return rdf_errno = RDF_ERR_READ;
299 if (f->eof_offset != ftell(f->fp) + 8) { /* +8 = skip null segment header */
300 fprintf(stderr, "warning: eof_offset [%"PRId32"] and actual eof offset "
301 "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
303 fseek(f->fp, initpos, SEEK_SET);
304 f->header_loc = NULL;
306 f->name = newstr(name);
307 f->refcount = refcount;
308 if (refcount)
309 (*refcount)++;
310 return RDF_OK;
313 int rdfclose(rdffile * f)
315 if (!f->refcount || !--(*f->refcount)) {
316 fclose(f->fp);
317 f->fp = NULL;
319 free(f->name);
321 return 0;
325 * Print the message for last error (from rdf_errno)
327 void rdfperror(const char *app, const char *name)
329 fprintf(stderr, "%s:%s: %s\n", app, name, rdf_errors[rdf_errno]);
330 if (rdf_errno == RDF_ERR_OPEN || rdf_errno == RDF_ERR_READ) {
331 perror(app);
336 * Find the segment by its number.
337 * Returns segment array index, or -1 if segment with such number was not found.
339 int rdffindsegment(rdffile * f, int segno)
341 int i;
342 for (i = 0; i < f->nsegs; i++)
343 if (f->seg[i].number == segno)
344 return i;
345 return -1;
349 * Load the segment. Returns status.
351 int rdfloadseg(rdffile * f, int segment, void *buffer)
353 int32_t fpos, slen;
355 switch (segment) {
356 case RDOFF_HEADER:
357 fpos = f->header_ofs;
358 slen = f->header_len;
359 f->header_loc = (uint8_t *) buffer;
360 f->header_fp = 0;
361 break;
362 default:
363 if (segment < f->nsegs) {
364 fpos = f->seg[segment].offset;
365 slen = f->seg[segment].length;
366 f->seg[segment].data = (uint8_t *) buffer;
367 } else {
368 return rdf_errno = RDF_ERR_SEGMENT;
372 if (fseek(f->fp, fpos, SEEK_SET))
373 return rdf_errno = RDF_ERR_UNKNOWN;
375 if (fread(buffer, 1, slen, f->fp) != slen)
376 return rdf_errno = RDF_ERR_READ;
378 return RDF_OK;
381 /* Macros for reading integers from header in memory */
383 #define RI8(v) v = f->header_loc[f->header_fp++]
384 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
385 (f->header_loc[f->header_fp+1] << 8)); \
386 f->header_fp += 2; }
388 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
389 (f->header_loc[f->header_fp+1] << 8) + \
390 (f->header_loc[f->header_fp+2] << 16) + \
391 (f->header_loc[f->header_fp+3] << 24)); \
392 f->header_fp += 4; }
394 #define RS(str,max) { for(i=0;i<max;i++){\
395 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
398 * Read a header record.
399 * Returns the address of record, or NULL in case of error.
401 rdfheaderrec *rdfgetheaderrec(rdffile * f)
403 static rdfheaderrec r;
404 int i;
406 if (!f->header_loc) {
407 rdf_errno = RDF_ERR_HEADER;
408 return NULL;
411 if (f->header_fp >= f->header_len)
412 return 0;
414 RI8(r.type);
415 RI8(r.g.reclen);
417 switch (r.type) {
418 case RDFREC_RELOC: /* Relocation record */
419 case RDFREC_SEGRELOC:
420 if (r.r.reclen != 8) {
421 rdf_errno = RDF_ERR_RECLEN;
422 return NULL;
424 RI8(r.r.segment);
425 RI32(r.r.offset);
426 RI8(r.r.length);
427 RI16(r.r.refseg);
428 break;
430 case RDFREC_IMPORT: /* Imported symbol record */
431 case RDFREC_FARIMPORT:
432 RI8(r.i.flags);
433 RI16(r.i.segment);
434 RS(r.i.label, EXIM_LABEL_MAX);
435 break;
437 case RDFREC_GLOBAL: /* Exported symbol record */
438 RI8(r.e.flags);
439 RI8(r.e.segment);
440 RI32(r.e.offset);
441 RS(r.e.label, EXIM_LABEL_MAX);
442 break;
444 case RDFREC_DLL: /* DLL record */
445 RS(r.d.libname, MODLIB_NAME_MAX);
446 break;
448 case RDFREC_BSS: /* BSS reservation record */
449 if (r.r.reclen != 4) {
450 rdf_errno = RDF_ERR_RECLEN;
451 return NULL;
453 RI32(r.b.amount);
454 break;
456 case RDFREC_MODNAME: /* Module name record */
457 RS(r.m.modname, MODLIB_NAME_MAX);
458 break;
460 case RDFREC_COMMON: /* Common variable */
461 RI16(r.c.segment);
462 RI32(r.c.size);
463 RI16(r.c.align);
464 RS(r.c.label, EXIM_LABEL_MAX);
465 break;
467 default:
468 #ifdef STRICT_ERRORS
469 rdf_errno = RDF_ERR_RECTYPE; /* unknown header record */
470 return NULL;
471 #else
472 for (i = 0; i < r.g.reclen; i++)
473 RI8(r.g.data[i]);
474 #endif
476 return &r;
480 * Rewind to the beginning of the file
482 void rdfheaderrewind(rdffile * f)
484 f->header_fp = 0;
487 rdf_headerbuf *rdfnewheader(void)
489 rdf_headerbuf *hb = malloc(sizeof(rdf_headerbuf));
490 if (hb == NULL)
491 return NULL;
493 hb->buf = newmembuf();
494 hb->nsegments = 0;
495 hb->seglength = 0;
497 return hb;
500 int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
502 #ifndef STRICT_ERRORS
503 int i;
504 #endif
505 membufwrite(h->buf, &r->type, 1);
506 membufwrite(h->buf, &r->g.reclen, 1);
508 switch (r->type) {
509 case RDFREC_GENERIC: /* generic */
510 membufwrite(h->buf, &r->g.data, r->g.reclen);
511 break;
512 case RDFREC_RELOC:
513 case RDFREC_SEGRELOC:
514 membufwrite(h->buf, &r->r.segment, 1);
515 membufwrite(h->buf, &r->r.offset, -4);
516 membufwrite(h->buf, &r->r.length, 1);
517 membufwrite(h->buf, &r->r.refseg, -2); /* 9 bytes written */
518 break;
520 case RDFREC_IMPORT: /* import */
521 case RDFREC_FARIMPORT:
522 membufwrite(h->buf, &r->i.flags, 1);
523 membufwrite(h->buf, &r->i.segment, -2);
524 membufwrite(h->buf, &r->i.label, strlen(r->i.label) + 1);
525 break;
527 case RDFREC_GLOBAL: /* export */
528 membufwrite(h->buf, &r->e.flags, 1);
529 membufwrite(h->buf, &r->e.segment, 1);
530 membufwrite(h->buf, &r->e.offset, -4);
531 membufwrite(h->buf, &r->e.label, strlen(r->e.label) + 1);
532 break;
534 case RDFREC_DLL: /* DLL */
535 membufwrite(h->buf, &r->d.libname, strlen(r->d.libname) + 1);
536 break;
538 case RDFREC_BSS: /* BSS */
539 membufwrite(h->buf, &r->b.amount, -4);
540 break;
542 case RDFREC_MODNAME: /* Module name */
543 membufwrite(h->buf, &r->m.modname, strlen(r->m.modname) + 1);
544 break;
546 default:
547 #ifdef STRICT_ERRORS
548 return rdf_errno = RDF_ERR_RECTYPE;
549 #else
550 for (i = 0; i < r->g.reclen; i++)
551 membufwrite(h->buf, r->g.data[i], 1);
552 #endif
554 return 0;
557 int rdfaddsegment(rdf_headerbuf * h, int32_t seglength)
559 h->nsegments++;
560 h->seglength += seglength;
561 return 0;
564 int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
566 int32_t l, l2;
568 fwrite(RDOFFId, 1, strlen(RDOFFId), fp);
570 l = membuflength(h->buf);
571 l2 = l + 14 + 10 * h->nsegments + h->seglength;
572 l = translateint32_t(l);
573 l2 = translateint32_t(l2);
574 fwrite(&l2, 4, 1, fp); /* object length */
575 fwrite(&l, 4, 1, fp); /* header length */
577 membufdump(h->buf, fp);
579 return 0; /* no error handling in here... CHANGE THIS! */
582 void rdfdoneheader(rdf_headerbuf * h)
584 freemembuf(h->buf);
585 free(h);