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
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.
29 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
30 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
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'.
41 /* ========================================================================
42 * Code for memory buffers (for delayed writing of header until we know
44 * ======================================================================== */
47 memorybuffer
* newmembuf()
51 t
= malloc(sizeof(memorybuffer
));
58 void membufwrite(memorybuffer
*b
, void *data
, int bytes
)
63 if (b
->next
) { /* memory buffer full - use next buffer */
64 membufwrite(b
->next
,data
,bytes
);
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
74 b
->next
= newmembuf();
75 membufwrite(b
->next
,data
,bytes
);
80 case -4: /* convert to little-endian */
82 b
->buffer
[b
->length
++] = l
& 0xFF;
84 b
->buffer
[b
->length
++] = l
& 0xFF;
86 b
->buffer
[b
->length
++] = l
& 0xFF;
88 b
->buffer
[b
->length
++] = l
& 0xFF;
92 w
= * (int16
*) data
;
93 b
->buffer
[b
->length
++] = w
& 0xFF;
95 b
->buffer
[b
->length
++] = w
& 0xFF;
100 b
->buffer
[b
->length
++] = *(* (unsigned char **) &data
);
102 (* (unsigned char **) &data
)++ ;
108 void membufdump(memorybuffer
*b
,FILE *fp
)
112 fwrite (b
->buffer
, 1, b
->length
, fp
);
114 membufdump(b
->next
,fp
);
117 int membuflength(memorybuffer
*b
)
120 return b
->length
+ membuflength(b
->next
);
123 void freemembuf(memorybuffer
*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
)
144 i
= (unsigned char *)&in
;
153 int16
translateshort(int16 in
)
158 i
= (unsigned char *)&in
;
159 r
= (i
[1] << 8) + i
[0];
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",
176 /* ========================================================================
177 The library functions
178 ======================================================================== */
180 int rdfopen(rdffile
*f
, const char *name
)
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
)
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));
207 fread(buf
,6,1,f
->fp
); /* read header */
210 if (strcmp(buf
,RDOFFId
)) {
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) {
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
)) {
228 return rdf_errno
= 2; /* seek past end of file...? */
231 if (fread(&s
,1,2,f
->fp
) != 2) {
233 return rdf_errno
= 3;
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)
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
)) {
252 return rdf_errno
= 2;
256 if (fread(&s
,1,2,f
->fp
) != 2) {
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
)++;
276 int rdfclose(rdffile
*f
)
278 if (! f
->refcount
|| ! --(*f
->refcount
))
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)
295 int rdffindsegment(rdffile
* f
, int segno
)
298 for (i
= 0; i
< f
->nsegs
; i
++)
299 if (f
->seg
[i
].number
== segno
) return i
;
303 int rdfloadseg(rdffile
*f
,int segment
,void *buffer
)
310 fpos
= f
->header_ofs
;
311 slen
= f
->header_len
;
312 f
->header_loc
= (byte
*)buffer
;
316 if (segment
< f
->nsegs
) {
317 fpos
= f
->seg
[segment
].offset
;
318 slen
= f
->seg
[segment
].length
;
319 f
->seg
[segment
].data
= (byte
*)buffer
;
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;
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)); \
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)); \
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
;
356 if (!f
->header_loc
) {
361 if (f
->header_fp
>= f
->header_len
) return 0;
367 case 1: /* Relocation record */
369 if (r
.r
.reclen
!= 8) {
379 case 2: /* Imported symbol record */
385 case 3: /* Exported symbol record */
391 case 4: /* DLL record */
395 case 5: /* BSS reservation record */
396 if (r
.r
.reclen
!= 4) {
405 rdf_errno
= 8; /* unknown header record */
408 for (i
= 0; i
< r
.g
.reclen
; i
++)
415 void rdfheaderrewind(rdffile
*f
)
421 rdf_headerbuf
* rdfnewheader(void)
423 rdf_headerbuf
* hb
= malloc(sizeof(hb
));
424 if (hb
== NULL
) return NULL
;
426 hb
->buf
= newmembuf();
433 int rdfaddheader(rdf_headerbuf
* h
, rdfheaderrec
* r
)
435 #ifndef STRICT_ERRORS
438 membufwrite(h
->buf
,&r
->type
,1);
439 membufwrite(h
->buf
,&r
->g
.reclen
,1);
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 */
453 membufwrite(h
->buf
,&r
->i
.segment
,-2);
454 membufwrite(h
->buf
,&r
->i
.label
,strlen(r
->i
.label
) + 1);
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);
464 membufwrite(h
->buf
,&r
->d
.libname
,strlen(r
->d
.libname
) + 1);
468 membufwrite(h
->buf
,&r
->b
.amount
,-4);
473 return (rdf_errno
= 8);
475 for (i
= 0; i
< r
->g
.reclen
; i
++)
476 membufwrite(h
->buf
, r
->g
.data
[i
], 1);
482 int rdfaddsegment(rdf_headerbuf
*h
, long seglength
)
485 h
->seglength
+= seglength
;
489 int rdfwriteheader(FILE * fp
, rdf_headerbuf
* h
)
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
)