NASM 0.98.08
[nasm.git] / rdoff / rdoff.c
blobe7d8b764dbb11077b6cb4ef91cf81ce6c77f6f08
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 "multboot.h"
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 long it is).
45 * ======================================================================== */
48 memorybuffer * newmembuf()
50 memorybuffer * t;
52 t = malloc(sizeof(memorybuffer));
53 if (!t) return NULL;
55 t->length = 0;
56 t->next = NULL;
57 return t;
60 void membufwrite(memorybuffer *const b, void *data, int bytes)
62 int16 w;
63 long 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))
74 /* buffer full and no next allocated... allocate and initialise next
75 * buffer */
76 b->next = newmembuf();
77 membufwrite(b->next,data,bytes);
78 return;
81 switch(bytes) {
82 case -4: /* convert to little-endian */
83 l = * (long *) data ;
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 l >>= 8 ;
90 b->buffer[b->length++] = l & 0xFF;
91 break;
93 case -2:
94 w = * (int16 *) data ;
95 b->buffer[b->length++] = w & 0xFF;
96 w >>= 8 ;
97 b->buffer[b->length++] = w & 0xFF;
98 break;
100 default:
101 while(bytes--) {
102 b->buffer[b->length++] = *(* (unsigned char **) &data);
104 (* (unsigned char **) &data)++ ;
106 break;
110 void membufdump(memorybuffer *b,FILE *fp)
112 if (!b) return;
114 fwrite (b->buffer, 1, b->length, fp);
116 membufdump(b->next,fp);
119 int membuflength(memorybuffer *b)
121 if (!b) return 0;
122 return b->length + membuflength(b->next);
125 void freemembuf(memorybuffer *b)
127 if (!b) return;
128 freemembuf(b->next);
129 free(b);
132 /* =========================================================================
133 General purpose routines and variables used by the library functions
134 ========================================================================= */
137 * translatelong() and translateshort()
139 * translate from little endian to local representation
141 long translatelong(long in)
143 long r;
144 unsigned char *i;
146 i = (unsigned char *)&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 int16 translateshort(int16 in)
157 int16 r;
158 unsigned char * i;
160 i = (unsigned char *)&in;
161 r = (i[1] << 8) + i[0];
163 return r;
166 const char *RDOFFId = "RDOFF2"; /* written to the start of RDOFF files */
168 const char *rdf_errors[11] = {
169 "no error occurred","could not open file","invalid file format",
170 "error reading file","unknown error","header not read",
171 "out of memory", "RDOFF v1 not supported",
172 "unknown extended header record",
173 "header record of known type but unknown length",
174 "no such segment"};
176 int rdf_errno = 0;
178 /* ========================================================================
179 The library functions
180 ======================================================================== */
182 int rdfopen(rdffile *f, const char *name)
184 FILE * fp;
186 fp = fopen(name,"rb");
187 if (!fp) return rdf_errno = 1; /* error 1: file open error */
189 return rdfopenhere(f,fp,NULL,name);
192 int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name)
194 char buf[8];
195 long initpos;
196 long l;
197 int16 s;
199 if (translatelong(0x01020304) != 0x01020304)
200 { /* fix this to be portable! */
201 fputs("*** this program requires a little endian machine\n",stderr);
202 fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304));
203 exit(3);
206 f->fp = fp;
207 initpos = ftell(fp);
209 fread(buf,6,1,f->fp); /* read header */
210 buf[6] = 0;
212 if (strcmp(buf,RDOFFId)) {
213 fclose(f->fp);
214 if (!strcmp(buf,"RDOFF1"))
215 return rdf_errno = 7; /* error 7: RDOFF 1 not supported */
216 return rdf_errno = 2; /* error 2: invalid file format */
219 if (fread(&l,1,4,f->fp) != 4 ||
220 fread(&f->header_len,1,4,f->fp) != 4) {
221 fclose(f->fp);
222 return rdf_errno = 3; /* error 3: file read error */
225 f->header_ofs = ftell(f->fp);
226 f->eof_offset = f->header_ofs + translatelong(l) - 4;
228 if (fseek(f->fp,f->header_len,SEEK_CUR)) {
229 fclose(f->fp);
230 return rdf_errno = 2; /* seek past end of file...? */
233 if (fread(&s,1,2,f->fp) != 2) {
234 fclose(f->fp);
235 return rdf_errno = 3;
238 f->nsegs = 0;
240 while (s != 0)
242 f->seg[f->nsegs].type = s;
243 if (fread(&f->seg[f->nsegs].number,1,2,f->fp) != 2 ||
244 fread(&f->seg[f->nsegs].reserved,1,2,f->fp) != 2 ||
245 fread(&f->seg[f->nsegs].length,1,4,f->fp) != 4)
247 fclose(f->fp);
248 return rdf_errno = 3;
251 f->seg[f->nsegs].offset = ftell(f->fp);
252 if (fseek(f->fp,f->seg[f->nsegs].length,SEEK_CUR)) {
253 fclose(f->fp);
254 return rdf_errno = 2;
256 f->nsegs++;
258 if (fread(&s,1,2,f->fp) != 2) {
259 fclose(f->fp);
260 return rdf_errno = 3;
264 if (f->eof_offset != ftell(f->fp) + 8) /* +8 = skip null segment header */
266 fprintf(stderr, "warning: eof_offset [%ld] and actual eof offset "
267 "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
269 fseek(f->fp,initpos,SEEK_SET);
270 f->header_loc = NULL;
272 f->name = newstr(name);
273 f->refcount = refcount;
274 if (refcount) (*refcount)++;
275 return 0;
278 int rdfclose(rdffile *f)
280 if (! f->refcount || ! --(*f->refcount))
282 fclose(f->fp);
283 f->fp = NULL;
285 free(f->name);
287 return 0;
290 void rdfperror(const char *app,const char *name)
292 fprintf(stderr,"%s:%s: %s\n",app,name,rdf_errors[rdf_errno]);
293 if (rdf_errno == 1 || rdf_errno == 3)
295 perror(app);
300 int rdffindsegment(rdffile * f, int segno)
302 int i;
303 for (i = 0; i < f->nsegs; i++)
304 if (f->seg[i].number == segno) return i;
305 return -1;
308 int rdfloadseg(rdffile *f,int segment,void *buffer)
310 long fpos;
311 long slen;
313 switch(segment) {
314 case RDOFF_HEADER:
315 fpos = f->header_ofs;
316 slen = f->header_len;
317 f->header_loc = (byte *)buffer;
318 f->header_fp = 0;
319 break;
320 default:
321 if (segment < f->nsegs) {
322 fpos = f->seg[segment].offset;
323 slen = f->seg[segment].length;
324 f->seg[segment].data = (byte *)buffer;
326 else {
327 return rdf_errno = 10; /* no such segment */
331 if (fseek(f->fp,fpos,SEEK_SET))
332 return rdf_errno = 4;
334 if (fread(buffer,1,slen,f->fp) != slen)
335 return rdf_errno = 3;
337 return 0;
340 /* Macros for reading integers from header in memory */
342 #define RI8(v) v = f->header_loc[f->header_fp++]
343 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
344 (f->header_loc[f->header_fp+1] << 8)); \
345 f->header_fp += 2; }
347 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
348 (f->header_loc[f->header_fp+1] << 8) + \
349 (f->header_loc[f->header_fp+2] << 16) + \
350 (f->header_loc[f->header_fp+3] << 24)); \
351 f->header_fp += 4; }
353 #define RS(str,max) { for(i=0;i<max;i++){\
354 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
356 rdfheaderrec *rdfgetheaderrec(rdffile *f)
358 static rdfheaderrec r;
359 int i;
361 if (!f->header_loc) {
362 rdf_errno = 5;
363 return NULL;
366 if (f->header_fp >= f->header_len) return 0;
368 RI8(r.type);
369 RI8(r.g.reclen);
371 switch(r.type) {
372 case 1: /* Relocation record */
373 case 6:
374 if (r.r.reclen != 8) {
375 rdf_errno = 9;
376 return NULL;
378 RI8(r.r.segment);
379 RI32(r.r.offset);
380 RI8(r.r.length);
381 RI16(r.r.refseg);
382 break;
384 case 2: /* Imported symbol record */
385 case 7:
386 RI16(r.i.segment);
387 RS(r.i.label,32);
388 break;
390 case 3: /* Exported symbol record */
391 RI8(r.e.segment);
392 RI32(r.e.offset);
393 RS(r.e.label,32);
394 break;
396 case 4: /* DLL record */
397 RS(r.d.libname,127);
398 break;
400 case 5: /* BSS reservation record */
401 if (r.r.reclen != 4) {
402 rdf_errno = 9;
403 return NULL;
405 RI32(r.b.amount);
406 break;
408 case 8: /* Module name record */
409 RS(r.m.modname,127);
410 break;
412 default:
413 #ifdef STRICT_ERRORS
414 rdf_errno = 8; /* unknown header record */
415 return NULL;
416 #else
417 for (i = 0; i < r.g.reclen; i++)
418 RI8(r.g.data[i]);
419 #endif
421 return &r;
424 void rdfheaderrewind(rdffile *f)
426 f->header_fp = 0;
430 rdf_headerbuf * rdfnewheader(void)
432 rdf_headerbuf * hb = malloc(sizeof(rdf_headerbuf));
433 if (hb == NULL) return NULL;
435 hb->buf = newmembuf();
436 hb->nsegments = 0;
437 hb->seglength = 0;
439 return hb;
442 int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
444 #ifndef STRICT_ERRORS
445 int i;
446 #endif
447 membufwrite(h->buf,&r->type,1);
448 membufwrite(h->buf,&r->g.reclen,1);
450 switch (r->type)
452 case 1:
453 case 6:
454 membufwrite(h->buf,&r->r.segment,1);
455 membufwrite(h->buf,&r->r.offset,-4);
456 membufwrite(h->buf,&r->r.length,1);
457 membufwrite(h->buf,&r->r.refseg,-2); /* 9 bytes written */
458 break;
460 case 2: /* import */
461 case 7:
462 membufwrite(h->buf,&r->i.segment,-2);
463 membufwrite(h->buf,&r->i.label,strlen(r->i.label) + 1);
464 break ;
466 case 3: /* export */
467 membufwrite(h->buf,&r->e.segment,1);
468 membufwrite(h->buf,&r->e.offset,-4);
469 membufwrite(h->buf,&r->e.label,strlen(r->e.label) + 1);
470 break ;
472 case 4: /* DLL */
473 membufwrite(h->buf,&r->d.libname,strlen(r->d.libname) + 1);
474 break ;
476 case 5: /* BSS */
477 membufwrite(h->buf,&r->b.amount,-4);
478 break ;
480 case 8: /* Module name */
481 membufwrite(h->buf,&r->m.modname,strlen(r->m.modname) + 1);
482 break ;
484 #ifdef _MULTBOOT_H
485 case 9: /* MultiBoot header */
486 membufwrite(h->buf,&r->mbh.mb,sizeof(struct tMultiBootHeader)+RDFLDRMOVER_SIZE);
487 break ;
488 #endif
490 default:
491 #ifdef STRICT_ERRORS
492 return (rdf_errno = 8);
493 #else
494 for (i = 0; i < r->g.reclen; i++)
495 membufwrite(h->buf, r->g.data[i], 1);
496 #endif
498 return 0;
501 int rdfaddsegment(rdf_headerbuf *h, long seglength)
503 h->nsegments ++;
504 h->seglength += seglength;
505 return 0;
508 int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
510 long l, l2;
512 fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ;
514 l = membuflength (h->buf);
515 l2 = l + 14 + 10*h->nsegments + h->seglength;
516 l = translatelong(l);
517 l2 = translatelong(l2);
518 fwrite (&l2, 4, 1, fp); /* object length */
519 fwrite (&l, 4, 1, fp); /* header length */
521 membufdump(h->buf, fp);
523 return 0; /* no error handling in here... CHANGE THIS! */
526 void rdfdoneheader(rdf_headerbuf * h)
528 freemembuf(h->buf);
529 free(h);