Update dependencies
[nasm/avx512.git] / rdoff / rdoff.c
blobbfdb9cc1e2f141102b4aecef3a6124c2d3da7f88
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 long
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>
23 #define RDOFF_UTILS
25 #include "rdoff.h"
27 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
28 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
29 s1),s2)
32 * Comment this out to allow the module to read & write header record types
33 * that it isn't aware of. With this defined, unrecognised header records
34 * will generate error number 8, reported as 'unknown extended header record'.
37 #define STRICT_ERRORS
39 /* ========================================================================
40 * Code for memory buffers (for delayed writing of header until we know
41 * how long it is).
42 * ======================================================================== */
45 memorybuffer * newmembuf()
47 memorybuffer * t;
49 t = malloc(sizeof(memorybuffer));
50 if (!t) return NULL;
52 t->length = 0;
53 t->next = NULL;
54 return t;
57 void membufwrite(memorybuffer *const b, void *data, int bytes)
59 uint16 w;
60 long l;
62 if (b->next) { /* memory buffer full - use next buffer */
63 membufwrite(b->next,data,bytes);
64 return;
67 if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
68 || (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 = * (long *) 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++] = *(* (unsigned char **) &data);
101 (* (unsigned char **) &data)++ ;
103 break;
107 void membufdump(memorybuffer *b,FILE *fp)
109 if (!b) return;
111 fwrite (b->buffer, 1, b->length, fp);
113 membufdump(b->next,fp);
116 int membuflength(memorybuffer *b)
118 if (!b) return 0;
119 return b->length + membuflength(b->next);
122 void freemembuf(memorybuffer *b)
124 if (!b) return;
125 freemembuf(b->next);
126 free(b);
129 /* =========================================================================
130 General purpose routines and variables used by the library functions
131 ========================================================================= */
134 * translatelong() and translateshort()
136 * translate from little endian to local representation
138 long translatelong(long in)
140 long r;
141 unsigned char *i;
143 i = (unsigned char *)&in;
144 r = i[3];
145 r = (r << 8) + i[2];
146 r = (r << 8) + i[1];
147 r = (r << 8) + *i;
149 return r;
152 uint16 translateshort(uint16 in)
154 uint16 r;
155 unsigned char * i;
157 i = (unsigned char *)&in;
158 r = (i[1] << 8) + i[0];
160 return r;
163 /* Segment types */
164 static char *knownsegtypes[8] = {
165 "NULL", "text", "data", "object comment",
166 "linked comment", "loader comment",
167 "symbolic debug", "line number debug"
170 /* Get a textual string describing the segment type */
171 char *translatesegmenttype(uint16 type)
173 if (type < 8)
174 return knownsegtypes[type];
175 if (type < 0x0020)
176 return "reserved";
177 if (type < 0x1000)
178 return "reserved - Moscow";
179 if (type < 0x8000)
180 return "reserved - system dependant";
181 if (type < 0xFFFF)
182 return "reserved - other";
183 if (type == 0xFFFF)
184 return "invalid type code";
185 return "type code out of range";
188 /* This signature is written to the start of RDOFF files */
189 const char *RDOFFId = RDOFF2_SIGNATURE;
191 /* Error messages. Must correspond to the codes defined in rdoff.h */
192 const char *rdf_errors[11] = {
193 /* 0 */ "no error occurred",
194 /* 1 */ "could not open file",
195 /* 2 */ "invalid file format",
196 /* 3 */ "error reading file",
197 /* 4 */ "unknown error",
198 /* 5 */ "header not read",
199 /* 6 */ "out of memory",
200 /* 7 */ "RDOFF v1 not supported",
201 /* 8 */ "unknown extended header record",
202 /* 9 */ "header record of known type but unknown length",
203 /* 10 */ "no such segment"
206 int rdf_errno = 0;
208 /* ========================================================================
209 The library functions
210 ======================================================================== */
212 int rdfopen(rdffile *f, const char *name)
214 FILE * fp;
216 fp = fopen(name,"rb");
217 if (!fp)
218 return rdf_errno = RDF_ERR_OPEN;
220 return rdfopenhere(f,fp,NULL,name);
223 int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name)
225 char buf[8];
226 long initpos;
227 long l;
228 uint16 s;
230 if (translatelong(0x01020304) != 0x01020304) {
231 /* fix this to be portable! */
232 fputs("*** this program requires a little endian machine\n",stderr);
233 fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304));
234 exit(3);
237 f->fp = fp;
238 initpos = ftell(fp);
240 fread(buf,6,1,f->fp); /* read header */
241 buf[6] = 0;
243 if (strcmp(buf,RDOFFId)) {
244 fclose(f->fp);
245 if (!strcmp(buf,"RDOFF1"))
246 return rdf_errno = RDF_ERR_VER;
247 return rdf_errno = RDF_ERR_FORMAT;
250 if (fread(&l,1,4,f->fp) != 4 || fread(&f->header_len,1,4,f->fp) != 4) {
251 fclose(f->fp);
252 return rdf_errno = RDF_ERR_READ;
255 f->header_ofs = ftell(f->fp);
256 f->eof_offset = f->header_ofs + translatelong(l) - 4;
258 if (fseek(f->fp,f->header_len,SEEK_CUR)) {
259 fclose(f->fp);
260 return rdf_errno = RDF_ERR_FORMAT; /* seek past end of file...? */
263 if (fread(&s,1,2,f->fp) != 2) {
264 fclose(f->fp);
265 return rdf_errno = RDF_ERR_READ;
268 f->nsegs = 0;
270 while (s != 0) {
271 f->seg[f->nsegs].type = s;
272 if (fread(&f->seg[f->nsegs].number,1,2,f->fp) != 2 ||
273 fread(&f->seg[f->nsegs].reserved,1,2,f->fp) != 2 ||
274 fread(&f->seg[f->nsegs].length,1,4,f->fp) != 4) {
275 fclose(f->fp);
276 return rdf_errno = RDF_ERR_READ;
279 f->seg[f->nsegs].offset = ftell(f->fp);
280 if (fseek(f->fp,f->seg[f->nsegs].length,SEEK_CUR)) {
281 fclose(f->fp);
282 return rdf_errno = RDF_ERR_FORMAT;
284 f->nsegs++;
286 if (fread(&s,1,2,f->fp) != 2) {
287 fclose(f->fp);
288 return rdf_errno = RDF_ERR_READ;
292 if (f->eof_offset != ftell(f->fp) + 8) { /* +8 = skip null segment header */
293 fprintf(stderr, "warning: eof_offset [%ld] and actual eof offset "
294 "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
296 fseek(f->fp,initpos,SEEK_SET);
297 f->header_loc = NULL;
299 f->name = newstr(name);
300 f->refcount = refcount;
301 if (refcount) (*refcount)++;
302 return RDF_OK;
305 int rdfclose(rdffile *f)
307 if (! f->refcount || ! --(*f->refcount)) {
308 fclose(f->fp);
309 f->fp = NULL;
311 free(f->name);
313 return 0;
317 * Print the message for last error (from rdf_errno)
319 void rdfperror(const char *app, const char *name)
321 fprintf(stderr,"%s:%s: %s\n",app,name,rdf_errors[rdf_errno]);
322 if (rdf_errno == RDF_ERR_OPEN || rdf_errno == RDF_ERR_READ) {
323 perror(app);
328 * Find the segment by its number.
329 * Returns segment array index, or -1 if segment with such number was not found.
331 int rdffindsegment(rdffile * f, int segno)
333 int i;
334 for (i = 0; i < f->nsegs; i++)
335 if (f->seg[i].number == segno) return i;
336 return -1;
340 * Load the segment. Returns status.
342 int rdfloadseg(rdffile *f,int segment,void *buffer)
344 long fpos, slen;
346 switch(segment) {
347 case RDOFF_HEADER:
348 fpos = f->header_ofs;
349 slen = f->header_len;
350 f->header_loc = (byte *)buffer;
351 f->header_fp = 0;
352 break;
353 default:
354 if (segment < f->nsegs) {
355 fpos = f->seg[segment].offset;
356 slen = f->seg[segment].length;
357 f->seg[segment].data = (byte *)buffer;
358 } else {
359 return rdf_errno = RDF_ERR_SEGMENT;
363 if (fseek(f->fp,fpos,SEEK_SET))
364 return rdf_errno = RDF_ERR_UNKNOWN;
366 if (fread(buffer,1,slen,f->fp) != slen)
367 return rdf_errno = RDF_ERR_READ;
369 return RDF_OK;
372 /* Macros for reading integers from header in memory */
374 #define RI8(v) v = f->header_loc[f->header_fp++]
375 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
376 (f->header_loc[f->header_fp+1] << 8)); \
377 f->header_fp += 2; }
379 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
380 (f->header_loc[f->header_fp+1] << 8) + \
381 (f->header_loc[f->header_fp+2] << 16) + \
382 (f->header_loc[f->header_fp+3] << 24)); \
383 f->header_fp += 4; }
385 #define RS(str,max) { for(i=0;i<max;i++){\
386 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
389 * Read a header record.
390 * Returns the address of record, or NULL in case of error.
392 rdfheaderrec *rdfgetheaderrec(rdffile *f)
394 static rdfheaderrec r;
395 int i;
397 if (!f->header_loc) {
398 rdf_errno = RDF_ERR_HEADER;
399 return NULL;
402 if (f->header_fp >= f->header_len) return 0;
404 RI8(r.type);
405 RI8(r.g.reclen);
407 switch(r.type) {
408 case RDFREC_RELOC: /* Relocation record */
409 case RDFREC_SEGRELOC:
410 if (r.r.reclen != 8) {
411 rdf_errno = RDF_ERR_RECLEN;
412 return NULL;
414 RI8(r.r.segment);
415 RI32(r.r.offset);
416 RI8(r.r.length);
417 RI16(r.r.refseg);
418 break;
420 case RDFREC_IMPORT: /* Imported symbol record */
421 case RDFREC_FARIMPORT:
422 RI8(r.i.flags);
423 RI16(r.i.segment);
424 RS(r.i.label, EXIM_LABEL_MAX);
425 break;
427 case RDFREC_GLOBAL: /* Exported symbol record */
428 RI8(r.e.flags);
429 RI8(r.e.segment);
430 RI32(r.e.offset);
431 RS(r.e.label, EXIM_LABEL_MAX);
432 break;
434 case RDFREC_DLL: /* DLL record */
435 RS(r.d.libname, MODLIB_NAME_MAX);
436 break;
438 case RDFREC_BSS: /* BSS reservation record */
439 if (r.r.reclen != 4) {
440 rdf_errno = RDF_ERR_RECLEN;
441 return NULL;
443 RI32(r.b.amount);
444 break;
446 case RDFREC_MODNAME: /* Module name record */
447 RS(r.m.modname, MODLIB_NAME_MAX);
448 break;
450 case RDFREC_COMMON: /* Common variable */
451 RI16(r.c.segment);
452 RI32(r.c.size);
453 RI16(r.c.align);
454 RS(r.c.label, EXIM_LABEL_MAX);
455 break;
457 default:
458 #ifdef STRICT_ERRORS
459 rdf_errno = RDF_ERR_RECTYPE; /* unknown header record */
460 return NULL;
461 #else
462 for (i = 0; i < r.g.reclen; i++)
463 RI8(r.g.data[i]);
464 #endif
466 return &r;
470 * Rewind to the beginning of the file
472 void rdfheaderrewind(rdffile *f)
474 f->header_fp = 0;
478 rdf_headerbuf * rdfnewheader(void)
480 rdf_headerbuf * hb = malloc(sizeof(rdf_headerbuf));
481 if (hb == NULL) return NULL;
483 hb->buf = newmembuf();
484 hb->nsegments = 0;
485 hb->seglength = 0;
487 return hb;
490 int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
492 #ifndef STRICT_ERRORS
493 int i;
494 #endif
495 membufwrite(h->buf,&r->type,1);
496 membufwrite(h->buf,&r->g.reclen,1);
498 switch (r->type) {
499 case RDFREC_GENERIC: /* generic */
500 membufwrite(h->buf, &r->g.data, r->g.reclen);
501 break;
502 case RDFREC_RELOC:
503 case RDFREC_SEGRELOC:
504 membufwrite(h->buf,&r->r.segment,1);
505 membufwrite(h->buf,&r->r.offset,-4);
506 membufwrite(h->buf,&r->r.length,1);
507 membufwrite(h->buf,&r->r.refseg,-2); /* 9 bytes written */
508 break;
510 case RDFREC_IMPORT: /* import */
511 case RDFREC_FARIMPORT:
512 membufwrite(h->buf,&r->i.flags,1);
513 membufwrite(h->buf,&r->i.segment,-2);
514 membufwrite(h->buf,&r->i.label,strlen(r->i.label) + 1);
515 break ;
517 case RDFREC_GLOBAL: /* export */
518 membufwrite(h->buf,&r->e.flags,1);
519 membufwrite(h->buf,&r->e.segment,1);
520 membufwrite(h->buf,&r->e.offset,-4);
521 membufwrite(h->buf,&r->e.label,strlen(r->e.label) + 1);
522 break ;
524 case RDFREC_DLL: /* DLL */
525 membufwrite(h->buf,&r->d.libname,strlen(r->d.libname) + 1);
526 break ;
528 case RDFREC_BSS: /* BSS */
529 membufwrite(h->buf,&r->b.amount,-4);
530 break ;
532 case RDFREC_MODNAME: /* Module name */
533 membufwrite(h->buf,&r->m.modname,strlen(r->m.modname) + 1);
534 break ;
536 default:
537 #ifdef STRICT_ERRORS
538 return rdf_errno = RDF_ERR_RECTYPE;
539 #else
540 for (i = 0; i < r->g.reclen; i++)
541 membufwrite(h->buf, r->g.data[i], 1);
542 #endif
544 return 0;
547 int rdfaddsegment(rdf_headerbuf *h, long seglength)
549 h->nsegments ++;
550 h->seglength += seglength;
551 return 0;
554 int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
556 long l, l2;
558 fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ;
560 l = membuflength (h->buf);
561 l2 = l + 14 + 10*h->nsegments + h->seglength;
562 l = translatelong(l);
563 l2 = translatelong(l2);
564 fwrite (&l2, 4, 1, fp); /* object length */
565 fwrite (&l, 4, 1, fp); /* header length */
567 membufdump(h->buf, fp);
569 return 0; /* no error handling in here... CHANGE THIS! */
572 void rdfdoneheader(rdf_headerbuf * h)
574 freemembuf(h->buf);
575 free(h);