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
26 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
27 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
31 * Comment this out to allow the module to read & write header record types
32 * that it isn't aware of. With this defined, unrecognised header records
33 * will generate error number 8, reported as 'unknown extended header record'.
38 /* ========================================================================
39 * Code for memory buffers (for delayed writing of header until we know
41 * ======================================================================== */
44 memorybuffer
* newmembuf()
48 t
= malloc(sizeof(memorybuffer
));
56 void membufwrite(memorybuffer
*const b
, void *data
, int bytes
)
61 if (b
->next
) { /* memory buffer full - use next buffer */
62 membufwrite(b
->next
,data
,bytes
);
66 if ((bytes
< 0 && b
->length
- bytes
> BUF_BLOCK_LEN
)
67 || (bytes
> 0 && b
->length
+ bytes
> BUF_BLOCK_LEN
))
70 /* buffer full and no next allocated... allocate and initialise next
72 b
->next
= newmembuf();
73 membufwrite(b
->next
,data
,bytes
);
78 case -4: /* convert to little-endian */
80 b
->buffer
[b
->length
++] = l
& 0xFF;
82 b
->buffer
[b
->length
++] = l
& 0xFF;
84 b
->buffer
[b
->length
++] = l
& 0xFF;
86 b
->buffer
[b
->length
++] = l
& 0xFF;
90 w
= * (int16
*) data
;
91 b
->buffer
[b
->length
++] = w
& 0xFF;
93 b
->buffer
[b
->length
++] = w
& 0xFF;
98 b
->buffer
[b
->length
++] = *(* (unsigned char **) &data
);
100 (* (unsigned char **) &data
)++ ;
106 void membufdump(memorybuffer
*b
,FILE *fp
)
110 fwrite (b
->buffer
, 1, b
->length
, fp
);
112 membufdump(b
->next
,fp
);
115 int membuflength(memorybuffer
*b
)
118 return b
->length
+ membuflength(b
->next
);
121 void freemembuf(memorybuffer
*b
)
128 /* =========================================================================
129 General purpose routines and variables used by the library functions
130 ========================================================================= */
133 * translatelong() and translateshort()
135 * translate from little endian to local representation
137 long translatelong(long in
)
142 i
= (unsigned char *)&in
;
151 int16
translateshort(int16 in
)
156 i
= (unsigned char *)&in
;
157 r
= (i
[1] << 8) + i
[0];
162 const char *RDOFFId
= "RDOFF2"; /* written to the start of RDOFF files */
164 const char *rdf_errors
[11] = {
165 "no error occurred","could not open file","invalid file format",
166 "error reading file","unknown error","header not read",
167 "out of memory", "RDOFF v1 not supported",
168 "unknown extended header record",
169 "header record of known type but unknown length",
174 /* ========================================================================
175 The library functions
176 ======================================================================== */
178 int rdfopen(rdffile
*f
, const char *name
)
182 fp
= fopen(name
,"rb");
183 if (!fp
) return rdf_errno
= 1; /* error 1: file open error */
185 return rdfopenhere(f
,fp
,NULL
,name
);
188 int rdfopenhere(rdffile
*f
, FILE *fp
, int *refcount
, const char *name
)
195 if (translatelong(0x01020304) != 0x01020304)
196 { /* fix this to be portable! */
197 fputs("*** this program requires a little endian machine\n",stderr
);
198 fprintf(stderr
,"01020304h = %08lxh\n",translatelong(0x01020304));
205 fread(buf
,6,1,f
->fp
); /* read header */
208 if (strcmp(buf
,RDOFFId
)) {
210 if (!strcmp(buf
,"RDOFF1"))
211 return rdf_errno
= 7; /* error 7: RDOFF 1 not supported */
212 return rdf_errno
= 2; /* error 2: invalid file format */
215 if (fread(&l
,1,4,f
->fp
) != 4 ||
216 fread(&f
->header_len
,1,4,f
->fp
) != 4) {
218 return rdf_errno
= 3; /* error 3: file read error */
221 f
->header_ofs
= ftell(f
->fp
);
222 f
->eof_offset
= f
->header_ofs
+ translatelong(l
) - 4;
224 if (fseek(f
->fp
,f
->header_len
,SEEK_CUR
)) {
226 return rdf_errno
= 2; /* seek past end of file...? */
229 if (fread(&s
,1,2,f
->fp
) != 2) {
231 return rdf_errno
= 3;
238 f
->seg
[f
->nsegs
].type
= s
;
239 if (fread(&f
->seg
[f
->nsegs
].number
,1,2,f
->fp
) != 2 ||
240 fread(&f
->seg
[f
->nsegs
].reserved
,1,2,f
->fp
) != 2 ||
241 fread(&f
->seg
[f
->nsegs
].length
,1,4,f
->fp
) != 4)
244 return rdf_errno
= 3;
247 f
->seg
[f
->nsegs
].offset
= ftell(f
->fp
);
248 if (fseek(f
->fp
,f
->seg
[f
->nsegs
].length
,SEEK_CUR
)) {
250 return rdf_errno
= 2;
254 if (fread(&s
,1,2,f
->fp
) != 2) {
256 return rdf_errno
= 3;
260 if (f
->eof_offset
!= ftell(f
->fp
) + 8) /* +8 = skip null segment header */
262 fprintf(stderr
, "warning: eof_offset [%ld] and actual eof offset "
263 "[%ld] don't match\n", f
->eof_offset
, ftell(f
->fp
) + 8);
265 fseek(f
->fp
,initpos
,SEEK_SET
);
266 f
->header_loc
= NULL
;
268 f
->name
= newstr(name
);
269 f
->refcount
= refcount
;
270 if (refcount
) (*refcount
)++;
274 int rdfclose(rdffile
*f
)
276 if (! f
->refcount
|| ! --(*f
->refcount
))
286 void rdfperror(const char *app
,const char *name
)
288 fprintf(stderr
,"%s:%s: %s\n",app
,name
,rdf_errors
[rdf_errno
]);
289 if (rdf_errno
== 1 || rdf_errno
== 3)
296 int rdffindsegment(rdffile
* f
, int segno
)
299 for (i
= 0; i
< f
->nsegs
; i
++)
300 if (f
->seg
[i
].number
== segno
) return i
;
304 int rdfloadseg(rdffile
*f
,int segment
,void *buffer
)
311 fpos
= f
->header_ofs
;
312 slen
= f
->header_len
;
313 f
->header_loc
= (byte
*)buffer
;
317 if (segment
< f
->nsegs
) {
318 fpos
= f
->seg
[segment
].offset
;
319 slen
= f
->seg
[segment
].length
;
320 f
->seg
[segment
].data
= (byte
*)buffer
;
323 return rdf_errno
= 10; /* no such segment */
327 if (fseek(f
->fp
,fpos
,SEEK_SET
))
328 return rdf_errno
= 4;
330 if (fread(buffer
,1,slen
,f
->fp
) != slen
)
331 return rdf_errno
= 3;
336 /* Macros for reading integers from header in memory */
338 #define RI8(v) v = f->header_loc[f->header_fp++]
339 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
340 (f->header_loc[f->header_fp+1] << 8)); \
343 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
344 (f->header_loc[f->header_fp+1] << 8) + \
345 (f->header_loc[f->header_fp+2] << 16) + \
346 (f->header_loc[f->header_fp+3] << 24)); \
349 #define RS(str,max) { for(i=0;i<max;i++){\
350 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
352 rdfheaderrec
*rdfgetheaderrec(rdffile
*f
)
354 static rdfheaderrec r
;
357 if (!f
->header_loc
) {
362 if (f
->header_fp
>= f
->header_len
) return 0;
368 case 1: /* Relocation record */
370 if (r
.r
.reclen
!= 8) {
380 case 2: /* Imported symbol record */
386 case 3: /* Exported symbol record */
393 case 4: /* DLL record */
397 case 5: /* BSS reservation record */
398 if (r
.r
.reclen
!= 4) {
405 case 8: /* Module name record */
411 rdf_errno
= 8; /* unknown header record */
414 for (i
= 0; i
< r
.g
.reclen
; i
++)
421 void rdfheaderrewind(rdffile
*f
)
427 rdf_headerbuf
* rdfnewheader(void)
429 rdf_headerbuf
* hb
= malloc(sizeof(rdf_headerbuf
));
430 if (hb
== NULL
) return NULL
;
432 hb
->buf
= newmembuf();
439 int rdfaddheader(rdf_headerbuf
* h
, rdfheaderrec
* r
)
441 #ifndef STRICT_ERRORS
444 membufwrite(h
->buf
,&r
->type
,1);
445 membufwrite(h
->buf
,&r
->g
.reclen
,1);
451 membufwrite(h
->buf
,&r
->r
.segment
,1);
452 membufwrite(h
->buf
,&r
->r
.offset
,-4);
453 membufwrite(h
->buf
,&r
->r
.length
,1);
454 membufwrite(h
->buf
,&r
->r
.refseg
,-2); /* 9 bytes written */
459 membufwrite(h
->buf
,&r
->i
.segment
,-2);
460 membufwrite(h
->buf
,&r
->i
.label
,strlen(r
->i
.label
) + 1);
464 membufwrite(h
->buf
,&r
->e
.flags
,1);
465 membufwrite(h
->buf
,&r
->e
.segment
,1);
466 membufwrite(h
->buf
,&r
->e
.offset
,-4);
467 membufwrite(h
->buf
,&r
->e
.label
,strlen(r
->e
.label
) + 1);
471 membufwrite(h
->buf
,&r
->d
.libname
,strlen(r
->d
.libname
) + 1);
475 membufwrite(h
->buf
,&r
->b
.amount
,-4);
478 case 8: /* Module name */
479 membufwrite(h
->buf
,&r
->m
.modname
,strlen(r
->m
.modname
) + 1);
483 case 9: /* MultiBoot header */
484 membufwrite(h
->buf
,&r
->mbh
.mb
,sizeof(struct tMultiBootHeader
)+TRAMPOLINESIZE
);
490 return (rdf_errno
= 8);
492 for (i
= 0; i
< r
->g
.reclen
; i
++)
493 membufwrite(h
->buf
, r
->g
.data
[i
], 1);
499 int rdfaddsegment(rdf_headerbuf
*h
, long seglength
)
502 h
->seglength
+= seglength
;
506 int rdfwriteheader(FILE * fp
, rdf_headerbuf
* h
)
510 fwrite (RDOFFId
, 1, strlen(RDOFFId
), fp
) ;
512 l
= membuflength (h
->buf
);
513 l2
= l
+ 14 + 10*h
->nsegments
+ h
->seglength
;
514 l
= translatelong(l
);
515 l2
= translatelong(l2
);
516 fwrite (&l2
, 4, 1, fp
); /* object length */
517 fwrite (&l
, 4, 1, fp
); /* header length */
519 membufdump(h
->buf
, fp
);
521 return 0; /* no error handling in here... CHANGE THIS! */
524 void rdfdoneheader(rdf_headerbuf
* h
)