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.
30 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
31 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
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'.
42 /* ========================================================================
43 * Code for memory buffers (for delayed writing of header until we know
45 * ======================================================================== */
48 memorybuffer
* newmembuf()
52 t
= malloc(sizeof(memorybuffer
));
60 void membufwrite(memorybuffer
*const b
, void *data
, int bytes
)
65 if (b
->next
) { /* memory buffer full - use next buffer */
66 membufwrite(b
->next
,data
,bytes
);
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
76 b
->next
= newmembuf();
77 membufwrite(b
->next
,data
,bytes
);
82 case -4: /* convert to little-endian */
84 b
->buffer
[b
->length
++] = l
& 0xFF;
86 b
->buffer
[b
->length
++] = l
& 0xFF;
88 b
->buffer
[b
->length
++] = l
& 0xFF;
90 b
->buffer
[b
->length
++] = l
& 0xFF;
94 w
= * (int16
*) data
;
95 b
->buffer
[b
->length
++] = w
& 0xFF;
97 b
->buffer
[b
->length
++] = w
& 0xFF;
102 b
->buffer
[b
->length
++] = *(* (unsigned char **) &data
);
104 (* (unsigned char **) &data
)++ ;
110 void membufdump(memorybuffer
*b
,FILE *fp
)
114 fwrite (b
->buffer
, 1, b
->length
, fp
);
116 membufdump(b
->next
,fp
);
119 int membuflength(memorybuffer
*b
)
122 return b
->length
+ membuflength(b
->next
);
125 void freemembuf(memorybuffer
*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
)
146 i
= (unsigned char *)&in
;
155 int16
translateshort(int16 in
)
160 i
= (unsigned char *)&in
;
161 r
= (i
[1] << 8) + i
[0];
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",
178 /* ========================================================================
179 The library functions
180 ======================================================================== */
182 int rdfopen(rdffile
*f
, const char *name
)
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
)
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));
209 fread(buf
,6,1,f
->fp
); /* read header */
212 if (strcmp(buf
,RDOFFId
)) {
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) {
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
)) {
230 return rdf_errno
= 2; /* seek past end of file...? */
233 if (fread(&s
,1,2,f
->fp
) != 2) {
235 return rdf_errno
= 3;
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)
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
)) {
254 return rdf_errno
= 2;
258 if (fread(&s
,1,2,f
->fp
) != 2) {
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
)++;
278 int rdfclose(rdffile
*f
)
280 if (! f
->refcount
|| ! --(*f
->refcount
))
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)
300 int rdffindsegment(rdffile
* f
, int segno
)
303 for (i
= 0; i
< f
->nsegs
; i
++)
304 if (f
->seg
[i
].number
== segno
) return i
;
308 int rdfloadseg(rdffile
*f
,int segment
,void *buffer
)
315 fpos
= f
->header_ofs
;
316 slen
= f
->header_len
;
317 f
->header_loc
= (byte
*)buffer
;
321 if (segment
< f
->nsegs
) {
322 fpos
= f
->seg
[segment
].offset
;
323 slen
= f
->seg
[segment
].length
;
324 f
->seg
[segment
].data
= (byte
*)buffer
;
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;
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)); \
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)); \
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
;
361 if (!f
->header_loc
) {
366 if (f
->header_fp
>= f
->header_len
) return 0;
372 case 1: /* Relocation record */
374 if (r
.r
.reclen
!= 8) {
384 case 2: /* Imported symbol record */
390 case 3: /* Exported symbol record */
396 case 4: /* DLL record */
400 case 5: /* BSS reservation record */
401 if (r
.r
.reclen
!= 4) {
408 case 8: /* Module name record */
414 rdf_errno
= 8; /* unknown header record */
417 for (i
= 0; i
< r
.g
.reclen
; i
++)
424 void rdfheaderrewind(rdffile
*f
)
430 rdf_headerbuf
* rdfnewheader(void)
432 rdf_headerbuf
* hb
= malloc(sizeof(rdf_headerbuf
));
433 if (hb
== NULL
) return NULL
;
435 hb
->buf
= newmembuf();
442 int rdfaddheader(rdf_headerbuf
* h
, rdfheaderrec
* r
)
444 #ifndef STRICT_ERRORS
447 membufwrite(h
->buf
,&r
->type
,1);
448 membufwrite(h
->buf
,&r
->g
.reclen
,1);
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 */
462 membufwrite(h
->buf
,&r
->i
.segment
,-2);
463 membufwrite(h
->buf
,&r
->i
.label
,strlen(r
->i
.label
) + 1);
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);
473 membufwrite(h
->buf
,&r
->d
.libname
,strlen(r
->d
.libname
) + 1);
477 membufwrite(h
->buf
,&r
->b
.amount
,-4);
480 case 8: /* Module name */
481 membufwrite(h
->buf
,&r
->m
.modname
,strlen(r
->m
.modname
) + 1);
485 case 9: /* MultiBoot header */
486 membufwrite(h
->buf
,&r
->mbh
.mb
,sizeof(struct tMultiBootHeader
)+RDFLDRMOVER_SIZE
);
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
)