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
24 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
25 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
29 * Comment this out to allow the module to read & write header record types
30 * that it isn't aware of. With this defined, unrecognised header records
31 * will generate error number 8, reported as 'unknown extended header record'.
36 /* ========================================================================
37 * Code for memory buffers (for delayed writing of header until we know
39 * ======================================================================== */
42 memorybuffer
* newmembuf()
46 t
= malloc(sizeof(memorybuffer
));
54 void membufwrite(memorybuffer
*const b
, void *data
, int bytes
)
59 if (b
->next
) { /* memory buffer full - use next buffer */
60 membufwrite(b
->next
,data
,bytes
);
64 if ((bytes
< 0 && b
->length
- bytes
> BUF_BLOCK_LEN
)
65 || (bytes
> 0 && b
->length
+ bytes
> BUF_BLOCK_LEN
))
68 /* buffer full and no next allocated... allocate and initialise next
70 b
->next
= newmembuf();
71 membufwrite(b
->next
,data
,bytes
);
76 case -4: /* convert to little-endian */
78 b
->buffer
[b
->length
++] = l
& 0xFF;
80 b
->buffer
[b
->length
++] = l
& 0xFF;
82 b
->buffer
[b
->length
++] = l
& 0xFF;
84 b
->buffer
[b
->length
++] = l
& 0xFF;
88 w
= * (int16
*) data
;
89 b
->buffer
[b
->length
++] = w
& 0xFF;
91 b
->buffer
[b
->length
++] = w
& 0xFF;
96 b
->buffer
[b
->length
++] = *(* (unsigned char **) &data
);
98 (* (unsigned char **) &data
)++ ;
104 void membufdump(memorybuffer
*b
,FILE *fp
)
108 fwrite (b
->buffer
, 1, b
->length
, fp
);
110 membufdump(b
->next
,fp
);
113 int membuflength(memorybuffer
*b
)
116 return b
->length
+ membuflength(b
->next
);
119 void freemembuf(memorybuffer
*b
)
126 /* =========================================================================
127 General purpose routines and variables used by the library functions
128 ========================================================================= */
131 * translatelong() and translateshort()
133 * translate from little endian to local representation
135 long translatelong(long in
)
140 i
= (unsigned char *)&in
;
149 int16
translateshort(int16 in
)
154 i
= (unsigned char *)&in
;
155 r
= (i
[1] << 8) + i
[0];
160 const char *RDOFFId
= "RDOFF2"; /* written to the start of RDOFF files */
162 const char *rdf_errors
[11] = {
163 "no error occurred","could not open file","invalid file format",
164 "error reading file","unknown error","header not read",
165 "out of memory", "RDOFF v1 not supported",
166 "unknown extended header record",
167 "header record of known type but unknown length",
172 /* ========================================================================
173 The library functions
174 ======================================================================== */
176 int rdfopen(rdffile
*f
, const char *name
)
180 fp
= fopen(name
,"rb");
181 if (!fp
) return rdf_errno
= 1; /* error 1: file open error */
183 return rdfopenhere(f
,fp
,NULL
,name
);
186 int rdfopenhere(rdffile
*f
, FILE *fp
, int *refcount
, const char *name
)
193 if (translatelong(0x01020304) != 0x01020304)
194 { /* fix this to be portable! */
195 fputs("*** this program requires a little endian machine\n",stderr
);
196 fprintf(stderr
,"01020304h = %08lxh\n",translatelong(0x01020304));
203 fread(buf
,6,1,f
->fp
); /* read header */
206 if (strcmp(buf
,RDOFFId
)) {
208 if (!strcmp(buf
,"RDOFF1"))
209 return rdf_errno
= 7; /* error 7: RDOFF 1 not supported */
210 return rdf_errno
= 2; /* error 2: invalid file format */
213 if (fread(&l
,1,4,f
->fp
) != 4 ||
214 fread(&f
->header_len
,1,4,f
->fp
) != 4) {
216 return rdf_errno
= 3; /* error 3: file read error */
219 f
->header_ofs
= ftell(f
->fp
);
220 f
->eof_offset
= f
->header_ofs
+ translatelong(l
) - 4;
222 if (fseek(f
->fp
,f
->header_len
,SEEK_CUR
)) {
224 return rdf_errno
= 2; /* seek past end of file...? */
227 if (fread(&s
,1,2,f
->fp
) != 2) {
229 return rdf_errno
= 3;
236 f
->seg
[f
->nsegs
].type
= s
;
237 if (fread(&f
->seg
[f
->nsegs
].number
,1,2,f
->fp
) != 2 ||
238 fread(&f
->seg
[f
->nsegs
].reserved
,1,2,f
->fp
) != 2 ||
239 fread(&f
->seg
[f
->nsegs
].length
,1,4,f
->fp
) != 4)
242 return rdf_errno
= 3;
245 f
->seg
[f
->nsegs
].offset
= ftell(f
->fp
);
246 if (fseek(f
->fp
,f
->seg
[f
->nsegs
].length
,SEEK_CUR
)) {
248 return rdf_errno
= 2;
252 if (fread(&s
,1,2,f
->fp
) != 2) {
254 return rdf_errno
= 3;
258 if (f
->eof_offset
!= ftell(f
->fp
) + 8) /* +8 = skip null segment header */
260 fprintf(stderr
, "warning: eof_offset [%ld] and actual eof offset "
261 "[%ld] don't match\n", f
->eof_offset
, ftell(f
->fp
) + 8);
263 fseek(f
->fp
,initpos
,SEEK_SET
);
264 f
->header_loc
= NULL
;
266 f
->name
= newstr(name
);
267 f
->refcount
= refcount
;
268 if (refcount
) (*refcount
)++;
272 int rdfclose(rdffile
*f
)
274 if (! f
->refcount
|| ! --(*f
->refcount
))
284 void rdfperror(const char *app
,const char *name
)
286 fprintf(stderr
,"%s:%s: %s\n",app
,name
,rdf_errors
[rdf_errno
]);
287 if (rdf_errno
== 1 || rdf_errno
== 3)
294 int rdffindsegment(rdffile
* f
, int segno
)
297 for (i
= 0; i
< f
->nsegs
; i
++)
298 if (f
->seg
[i
].number
== segno
) return i
;
302 int rdfloadseg(rdffile
*f
,int segment
,void *buffer
)
309 fpos
= f
->header_ofs
;
310 slen
= f
->header_len
;
311 f
->header_loc
= (byte
*)buffer
;
315 if (segment
< f
->nsegs
) {
316 fpos
= f
->seg
[segment
].offset
;
317 slen
= f
->seg
[segment
].length
;
318 f
->seg
[segment
].data
= (byte
*)buffer
;
321 return rdf_errno
= 10; /* no such segment */
325 if (fseek(f
->fp
,fpos
,SEEK_SET
))
326 return rdf_errno
= 4;
328 if (fread(buffer
,1,slen
,f
->fp
) != slen
)
329 return rdf_errno
= 3;
334 /* Macros for reading integers from header in memory */
336 #define RI8(v) v = f->header_loc[f->header_fp++]
337 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
338 (f->header_loc[f->header_fp+1] << 8)); \
341 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
342 (f->header_loc[f->header_fp+1] << 8) + \
343 (f->header_loc[f->header_fp+2] << 16) + \
344 (f->header_loc[f->header_fp+3] << 24)); \
347 #define RS(str,max) { for(i=0;i<max;i++){\
348 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
350 rdfheaderrec
*rdfgetheaderrec(rdffile
*f
)
352 static rdfheaderrec r
;
355 if (!f
->header_loc
) {
360 if (f
->header_fp
>= f
->header_len
) return 0;
366 case RDFREC_RELOC
: /* Relocation record */
367 case RDFREC_SEGRELOC
:
368 if (r
.r
.reclen
!= 8) {
378 case RDFREC_IMPORT
: /* Imported symbol record */
379 case RDFREC_FARIMPORT
:
384 case RDFREC_GLOBAL
: /* Exported symbol record */
391 case RDFREC_DLL
: /* DLL record */
395 case RDFREC_BSS
: /* BSS reservation record */
396 if (r
.r
.reclen
!= 4) {
403 case RDFREC_MODNAME
: /* Module name record */
407 case RDFREC_COMMON
: /* Common variable */
416 rdf_errno
= 8; /* unknown header record */
419 for (i
= 0; i
< r
.g
.reclen
; i
++)
426 void rdfheaderrewind(rdffile
*f
)
432 rdf_headerbuf
* rdfnewheader(void)
434 rdf_headerbuf
* hb
= malloc(sizeof(rdf_headerbuf
));
435 if (hb
== NULL
) return NULL
;
437 hb
->buf
= newmembuf();
444 int rdfaddheader(rdf_headerbuf
* h
, rdfheaderrec
* r
)
446 #ifndef STRICT_ERRORS
449 membufwrite(h
->buf
,&r
->type
,1);
450 membufwrite(h
->buf
,&r
->g
.reclen
,1);
454 case RDFREC_GENERIC
: /* generic */
455 membufwrite(h
->buf
, &r
->g
.data
, r
->g
.reclen
);
458 case RDFREC_SEGRELOC
:
459 membufwrite(h
->buf
,&r
->r
.segment
,1);
460 membufwrite(h
->buf
,&r
->r
.offset
,-4);
461 membufwrite(h
->buf
,&r
->r
.length
,1);
462 membufwrite(h
->buf
,&r
->r
.refseg
,-2); /* 9 bytes written */
465 case RDFREC_IMPORT
: /* import */
466 case RDFREC_FARIMPORT
:
467 membufwrite(h
->buf
,&r
->i
.segment
,-2);
468 membufwrite(h
->buf
,&r
->i
.label
,strlen(r
->i
.label
) + 1);
471 case RDFREC_GLOBAL
: /* export */
472 membufwrite(h
->buf
,&r
->e
.flags
,1);
473 membufwrite(h
->buf
,&r
->e
.segment
,1);
474 membufwrite(h
->buf
,&r
->e
.offset
,-4);
475 membufwrite(h
->buf
,&r
->e
.label
,strlen(r
->e
.label
) + 1);
478 case RDFREC_DLL
: /* DLL */
479 membufwrite(h
->buf
,&r
->d
.libname
,strlen(r
->d
.libname
) + 1);
482 case RDFREC_BSS
: /* BSS */
483 membufwrite(h
->buf
,&r
->b
.amount
,-4);
486 case RDFREC_MODNAME
: /* Module name */
487 membufwrite(h
->buf
,&r
->m
.modname
,strlen(r
->m
.modname
) + 1);
492 return (rdf_errno
= 8);
494 for (i
= 0; i
< r
->g
.reclen
; i
++)
495 membufwrite(h
->buf
, r
->g
.data
[i
], 1);
501 int rdfaddsegment(rdf_headerbuf
*h
, long seglength
)
504 h
->seglength
+= seglength
;
508 int rdfwriteheader(FILE * fp
, rdf_headerbuf
* h
)
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
)