NASM 0.98.03
[nasm/avx512.git] / rdoff / rdoff.c
blob7f4937ac112ba730823c732b9e6c0086fa86f486
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.
17 * This module no longer supports RDOFF1. If anybody *really*
18 * needs the functionality of supporting both types at the
19 * same time, I'll add it back in.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
27 #include "rdoff.h"
29 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
30 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
31 s1),s2)
34 * Comment this out to allow the module to read & write header record types
35 * that it isn't aware of. With this defined, unrecognised header records
36 * will generate error number 8, reported as 'unknown extended header record'.
39 #define STRICT_ERRORS
41 /* ========================================================================
42 * Code for memory buffers (for delayed writing of header until we know
43 * how long it is).
44 * ======================================================================== */
47 memorybuffer * newmembuf()
49 memorybuffer * t;
51 t = malloc(sizeof(memorybuffer));
53 t->length = 0;
54 t->next = NULL;
55 return t;
58 void membufwrite(memorybuffer *b, void *data, int bytes)
60 int16 w;
61 long 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))
72 /* buffer full and no next allocated... allocate and initialise next
73 * buffer */
74 b->next = newmembuf();
75 membufwrite(b->next,data,bytes);
76 return;
79 switch(bytes) {
80 case -4: /* convert to little-endian */
81 l = * (long *) data ;
82 b->buffer[b->length++] = l & 0xFF;
83 l >>= 8 ;
84 b->buffer[b->length++] = l & 0xFF;
85 l >>= 8 ;
86 b->buffer[b->length++] = l & 0xFF;
87 l >>= 8 ;
88 b->buffer[b->length++] = l & 0xFF;
89 break;
91 case -2:
92 w = * (int16 *) data ;
93 b->buffer[b->length++] = w & 0xFF;
94 w >>= 8 ;
95 b->buffer[b->length++] = w & 0xFF;
96 break;
98 default:
99 while(bytes--) {
100 b->buffer[b->length++] = *(* (unsigned char **) &data);
102 (* (unsigned char **) &data)++ ;
104 break;
108 void membufdump(memorybuffer *b,FILE *fp)
110 if (!b) return;
112 fwrite (b->buffer, 1, b->length, fp);
114 membufdump(b->next,fp);
117 int membuflength(memorybuffer *b)
119 if (!b) return 0;
120 return b->length + membuflength(b->next);
123 void freemembuf(memorybuffer *b)
125 if (!b) return;
126 freemembuf(b->next);
127 free(b);
130 /* =========================================================================
131 General purpose routines and variables used by the library functions
132 ========================================================================= */
135 * translatelong() and translateshort()
137 * translate from little endian to local representation
139 long translatelong(long in)
141 long r;
142 unsigned char *i;
144 i = (unsigned char *)&in;
145 r = i[3];
146 r = (r << 8) + i[2];
147 r = (r << 8) + i[1];
148 r = (r << 8) + *i;
150 return r;
153 int16 translateshort(int16 in)
155 int16 r;
156 unsigned char * i;
158 i = (unsigned char *)&in;
159 r = (i[1] << 8) + i[0];
161 return r;
164 const char *RDOFFId = "RDOFF2"; /* written to the start of RDOFF files */
166 const char *rdf_errors[11] = {
167 "no error occurred","could not open file","invalid file format",
168 "error reading file","unknown error","header not read",
169 "out of memory", "RDOFF v1 not supported",
170 "unknown extended header record",
171 "header record of known type but unknown length",
172 "no such segment"};
174 int rdf_errno = 0;
176 /* ========================================================================
177 The library functions
178 ======================================================================== */
180 int rdfopen(rdffile *f, const char *name)
182 FILE * fp;
184 fp = fopen(name,"rb");
185 if (!fp) return rdf_errno = 1; /* error 1: file open error */
187 return rdfopenhere(f,fp,NULL,name);
190 int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name)
192 char buf[8];
193 long initpos;
194 long l;
195 int16 s;
197 if (translatelong(0x01020304) != 0x01020304)
198 { /* fix this to be portable! */
199 fputs("*** this program requires a little endian machine\n",stderr);
200 fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304));
201 exit(3);
204 f->fp = fp;
205 initpos = ftell(fp);
207 fread(buf,6,1,f->fp); /* read header */
208 buf[6] = 0;
210 if (strcmp(buf,RDOFFId)) {
211 fclose(f->fp);
212 if (!strcmp(buf,"RDOFF1"))
213 return rdf_errno = 7; /* error 7: RDOFF 1 not supported */
214 return rdf_errno = 2; /* error 2: invalid file format */
217 if (fread(&l,1,4,f->fp) != 4 ||
218 fread(&f->header_len,1,4,f->fp) != 4) {
219 fclose(f->fp);
220 return rdf_errno = 3; /* error 3: file read error */
223 f->header_ofs = ftell(f->fp);
224 f->eof_offset = f->header_ofs + translatelong(l) - 4;
226 if (fseek(f->fp,f->header_len,SEEK_CUR)) {
227 fclose(f->fp);
228 return rdf_errno = 2; /* seek past end of file...? */
231 if (fread(&s,1,2,f->fp) != 2) {
232 fclose(f->fp);
233 return rdf_errno = 3;
236 f->nsegs = 0;
238 while (s != 0)
240 f->seg[f->nsegs].type = s;
241 if (fread(&f->seg[f->nsegs].number,1,2,f->fp) != 2 ||
242 fread(&f->seg[f->nsegs].reserved,1,2,f->fp) != 2 ||
243 fread(&f->seg[f->nsegs].length,1,4,f->fp) != 4)
245 fclose(f->fp);
246 return rdf_errno = 3;
249 f->seg[f->nsegs].offset = ftell(f->fp);
250 if (fseek(f->fp,f->seg[f->nsegs].length,SEEK_CUR)) {
251 fclose(f->fp);
252 return rdf_errno = 2;
254 f->nsegs++;
256 if (fread(&s,1,2,f->fp) != 2) {
257 fclose(f->fp);
258 return rdf_errno = 3;
262 if (f->eof_offset != ftell(f->fp) + 8) /* +8 = skip null segment header */
264 fprintf(stderr, "warning: eof_offset [%ld] and actual eof offset "
265 "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
267 fseek(f->fp,initpos,SEEK_SET);
268 f->header_loc = NULL;
270 f->name = newstr(name);
271 f->refcount = refcount;
272 if (refcount) (*refcount)++;
273 return 0;
276 int rdfclose(rdffile *f)
278 if (! f->refcount || ! --(*f->refcount))
279 fclose(f->fp);
280 free(f->name);
282 return 0;
285 void rdfperror(const char *app,const char *name)
287 fprintf(stderr,"%s:%s: %s\n",app,name,rdf_errors[rdf_errno]);
288 if (rdf_errno == 1 || rdf_errno == 3)
290 perror(app);
295 int rdffindsegment(rdffile * f, int segno)
297 int i;
298 for (i = 0; i < f->nsegs; i++)
299 if (f->seg[i].number == segno) return i;
300 return -1;
303 int rdfloadseg(rdffile *f,int segment,void *buffer)
305 long fpos;
306 long slen;
308 switch(segment) {
309 case RDOFF_HEADER:
310 fpos = f->header_ofs;
311 slen = f->header_len;
312 f->header_loc = (byte *)buffer;
313 f->header_fp = 0;
314 break;
315 default:
316 if (segment < f->nsegs) {
317 fpos = f->seg[segment].offset;
318 slen = f->seg[segment].length;
319 f->seg[segment].data = (byte *)buffer;
321 else {
322 return rdf_errno = 10; /* no such segment */
326 if (fseek(f->fp,fpos,SEEK_SET))
327 return rdf_errno = 4;
329 if (fread(buffer,1,slen,f->fp) != slen)
330 return rdf_errno = 3;
332 return 0;
335 /* Macros for reading integers from header in memory */
337 #define RI8(v) v = f->header_loc[f->header_fp++]
338 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
339 (f->header_loc[f->header_fp+1] << 8)); \
340 f->header_fp += 2; }
342 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
343 (f->header_loc[f->header_fp+1] << 8) + \
344 (f->header_loc[f->header_fp+2] << 16) + \
345 (f->header_loc[f->header_fp+3] << 24)); \
346 f->header_fp += 4; }
348 #define RS(str,max) { for(i=0;i<max;i++){\
349 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
351 rdfheaderrec *rdfgetheaderrec(rdffile *f)
353 static rdfheaderrec r;
354 int i;
356 if (!f->header_loc) {
357 rdf_errno = 5;
358 return NULL;
361 if (f->header_fp >= f->header_len) return 0;
363 RI8(r.type);
364 RI8(r.g.reclen);
366 switch(r.type) {
367 case 1: /* Relocation record */
368 case 6:
369 if (r.r.reclen != 8) {
370 rdf_errno = 9;
371 return NULL;
373 RI8(r.r.segment);
374 RI32(r.r.offset);
375 RI8(r.r.length);
376 RI16(r.r.refseg);
377 break;
379 case 2: /* Imported symbol record */
380 case 7:
381 RI16(r.i.segment);
382 RS(r.i.label,32);
383 break;
385 case 3: /* Exported symbol record */
386 RI8(r.e.segment);
387 RI32(r.e.offset);
388 RS(r.e.label,32);
389 break;
391 case 4: /* DLL record */
392 RS(r.d.libname,127);
393 break;
395 case 5: /* BSS reservation record */
396 if (r.r.reclen != 4) {
397 rdf_errno = 9;
398 return NULL;
400 RI32(r.b.amount);
401 break;
403 default:
404 #ifdef STRICT_ERRORS
405 rdf_errno = 8; /* unknown header record */
406 return NULL;
407 #else
408 for (i = 0; i < r.g.reclen; i++)
409 RI8(r.g.data[i]);
410 #endif
412 return &r;
415 void rdfheaderrewind(rdffile *f)
417 f->header_fp = 0;
421 rdf_headerbuf * rdfnewheader(void)
423 rdf_headerbuf * hb = malloc(sizeof(hb));
424 if (hb == NULL) return NULL;
426 hb->buf = newmembuf();
427 hb->nsegments = 0;
428 hb->seglength = 0;
430 return hb;
433 int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
435 #ifndef STRICT_ERRORS
436 int i;
437 #endif
438 membufwrite(h->buf,&r->type,1);
439 membufwrite(h->buf,&r->g.reclen,1);
441 switch (r->type)
443 case 1:
444 case 6:
445 membufwrite(h->buf,&r->r.segment,1);
446 membufwrite(h->buf,&r->r.offset,-4);
447 membufwrite(h->buf,&r->r.length,1);
448 membufwrite(h->buf,&r->r.refseg,-2); /* 9 bytes written */
449 break;
451 case 2: /* import */
452 case 7:
453 membufwrite(h->buf,&r->i.segment,-2);
454 membufwrite(h->buf,&r->i.label,strlen(r->i.label) + 1);
455 break ;
457 case 3: /* export */
458 membufwrite(h->buf,&r->e.segment,1);
459 membufwrite(h->buf,&r->e.offset,-4);
460 membufwrite(h->buf,&r->e.label,strlen(r->e.label) + 1);
461 break ;
463 case 4: /* DLL */
464 membufwrite(h->buf,&r->d.libname,strlen(r->d.libname) + 1);
465 break ;
467 case 5: /* BSS */
468 membufwrite(h->buf,&r->b.amount,-4);
469 break ;
471 default:
472 #ifdef STRICT_ERRORS
473 return (rdf_errno = 8);
474 #else
475 for (i = 0; i < r->g.reclen; i++)
476 membufwrite(h->buf, r->g.data[i], 1);
477 #endif
479 return 0;
482 int rdfaddsegment(rdf_headerbuf *h, long seglength)
484 h->nsegments ++;
485 h->seglength += seglength;
486 return 0;
489 int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
491 long l, l2;
493 fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ;
495 l = membuflength (h->buf);
496 l2 = l + 14 + 10*h->nsegments + h->seglength;
497 l = translatelong(l);
498 l2 = translatelong(l2);
499 fwrite (&l2, 4, 1, fp); /* object length */
500 fwrite (&l, 4, 1, fp); /* header length */
502 membufdump(h->buf, fp);
504 return 0; /* no error handling in here... CHANGE THIS! */
507 void rdfdoneheader(rdf_headerbuf * h)
509 freemembuf(h->buf);
510 free(h);