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
27 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
28 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
32 * Comment this out to allow the module to read & write header record types
33 * that it isn't aware of. With this defined, unrecognised header records
34 * will generate error number 8, reported as 'unknown extended header record'.
39 /* ========================================================================
40 * Code for memory buffers (for delayed writing of header until we know
42 * ======================================================================== */
45 memorybuffer
* newmembuf()
49 t
= malloc(sizeof(memorybuffer
));
57 void membufwrite(memorybuffer
*const b
, void *data
, int bytes
)
62 if (b
->next
) { /* memory buffer full - use next buffer */
63 membufwrite(b
->next
,data
,bytes
);
67 if ((bytes
< 0 && b
->length
- bytes
> BUF_BLOCK_LEN
)
68 || (bytes
> 0 && b
->length
+ bytes
> BUF_BLOCK_LEN
))
71 /* buffer full and no next allocated... allocate and initialise next
73 b
->next
= newmembuf();
74 membufwrite(b
->next
,data
,bytes
);
79 case -4: /* convert to little-endian */
81 b
->buffer
[b
->length
++] = l
& 0xFF;
83 b
->buffer
[b
->length
++] = l
& 0xFF;
85 b
->buffer
[b
->length
++] = l
& 0xFF;
87 b
->buffer
[b
->length
++] = l
& 0xFF;
91 w
= * (uint16
*) data
;
92 b
->buffer
[b
->length
++] = w
& 0xFF;
94 b
->buffer
[b
->length
++] = w
& 0xFF;
99 b
->buffer
[b
->length
++] = *(* (unsigned char **) &data
);
101 (* (unsigned char **) &data
)++ ;
107 void membufdump(memorybuffer
*b
,FILE *fp
)
111 fwrite (b
->buffer
, 1, b
->length
, fp
);
113 membufdump(b
->next
,fp
);
116 int membuflength(memorybuffer
*b
)
119 return b
->length
+ membuflength(b
->next
);
122 void freemembuf(memorybuffer
*b
)
129 /* =========================================================================
130 General purpose routines and variables used by the library functions
131 ========================================================================= */
134 * translatelong() and translateshort()
136 * translate from little endian to local representation
138 long translatelong(long in
)
143 i
= (unsigned char *)&in
;
152 uint16
translateshort(uint16 in
)
157 i
= (unsigned char *)&in
;
158 r
= (i
[1] << 8) + i
[0];
164 static char *knownsegtypes
[8] = {
165 "NULL", "text", "data", "object comment",
166 "linked comment", "loader comment",
167 "symbolic debug", "line number debug"
170 /* Get a textual string describing the segment type */
171 char *translatesegmenttype(uint16 type
)
174 return knownsegtypes
[type
];
178 return "reserved - Moscow";
180 return "reserved - system dependant";
182 return "reserved - other";
184 return "invalid type code";
185 return "type code out of range";
188 /* This signature is written to the start of RDOFF files */
189 const char *RDOFFId
= RDOFF2_SIGNATURE
;
191 /* Error messages. Must correspond to the codes defined in rdoff.h */
192 const char *rdf_errors
[11] = {
193 /* 0 */ "no error occurred",
194 /* 1 */ "could not open file",
195 /* 2 */ "invalid file format",
196 /* 3 */ "error reading file",
197 /* 4 */ "unknown error",
198 /* 5 */ "header not read",
199 /* 6 */ "out of memory",
200 /* 7 */ "RDOFF v1 not supported",
201 /* 8 */ "unknown extended header record",
202 /* 9 */ "header record of known type but unknown length",
203 /* 10 */ "no such segment"
208 /* ========================================================================
209 The library functions
210 ======================================================================== */
212 int rdfopen(rdffile
*f
, const char *name
)
216 fp
= fopen(name
,"rb");
218 return rdf_errno
= RDF_ERR_OPEN
;
220 return rdfopenhere(f
,fp
,NULL
,name
);
223 int rdfopenhere(rdffile
*f
, FILE *fp
, int *refcount
, const char *name
)
230 if (translatelong(0x01020304) != 0x01020304) {
231 /* fix this to be portable! */
232 fputs("*** this program requires a little endian machine\n",stderr
);
233 fprintf(stderr
,"01020304h = %08lxh\n",translatelong(0x01020304));
240 fread(buf
,6,1,f
->fp
); /* read header */
243 if (strcmp(buf
,RDOFFId
)) {
245 if (!strcmp(buf
,"RDOFF1"))
246 return rdf_errno
= RDF_ERR_VER
;
247 return rdf_errno
= RDF_ERR_FORMAT
;
250 if (fread(&l
,1,4,f
->fp
) != 4 || fread(&f
->header_len
,1,4,f
->fp
) != 4) {
252 return rdf_errno
= RDF_ERR_READ
;
255 f
->header_ofs
= ftell(f
->fp
);
256 f
->eof_offset
= f
->header_ofs
+ translatelong(l
) - 4;
258 if (fseek(f
->fp
,f
->header_len
,SEEK_CUR
)) {
260 return rdf_errno
= RDF_ERR_FORMAT
; /* seek past end of file...? */
263 if (fread(&s
,1,2,f
->fp
) != 2) {
265 return rdf_errno
= RDF_ERR_READ
;
271 f
->seg
[f
->nsegs
].type
= s
;
272 if (fread(&f
->seg
[f
->nsegs
].number
,1,2,f
->fp
) != 2 ||
273 fread(&f
->seg
[f
->nsegs
].reserved
,1,2,f
->fp
) != 2 ||
274 fread(&f
->seg
[f
->nsegs
].length
,1,4,f
->fp
) != 4) {
276 return rdf_errno
= RDF_ERR_READ
;
279 f
->seg
[f
->nsegs
].offset
= ftell(f
->fp
);
280 if (fseek(f
->fp
,f
->seg
[f
->nsegs
].length
,SEEK_CUR
)) {
282 return rdf_errno
= RDF_ERR_FORMAT
;
286 if (fread(&s
,1,2,f
->fp
) != 2) {
288 return rdf_errno
= RDF_ERR_READ
;
292 if (f
->eof_offset
!= ftell(f
->fp
) + 8) { /* +8 = skip null segment header */
293 fprintf(stderr
, "warning: eof_offset [%ld] and actual eof offset "
294 "[%ld] don't match\n", f
->eof_offset
, ftell(f
->fp
) + 8);
296 fseek(f
->fp
,initpos
,SEEK_SET
);
297 f
->header_loc
= NULL
;
299 f
->name
= newstr(name
);
300 f
->refcount
= refcount
;
301 if (refcount
) (*refcount
)++;
305 int rdfclose(rdffile
*f
)
307 if (! f
->refcount
|| ! --(*f
->refcount
)) {
317 * Print the message for last error (from rdf_errno)
319 void rdfperror(const char *app
, const char *name
)
321 fprintf(stderr
,"%s:%s: %s\n",app
,name
,rdf_errors
[rdf_errno
]);
322 if (rdf_errno
== RDF_ERR_OPEN
|| rdf_errno
== RDF_ERR_READ
) {
328 * Find the segment by its number.
329 * Returns segment array index, or -1 if segment with such number was not found.
331 int rdffindsegment(rdffile
* f
, int segno
)
334 for (i
= 0; i
< f
->nsegs
; i
++)
335 if (f
->seg
[i
].number
== segno
) return i
;
340 * Load the segment. Returns status.
342 int rdfloadseg(rdffile
*f
,int segment
,void *buffer
)
348 fpos
= f
->header_ofs
;
349 slen
= f
->header_len
;
350 f
->header_loc
= (byte
*)buffer
;
354 if (segment
< f
->nsegs
) {
355 fpos
= f
->seg
[segment
].offset
;
356 slen
= f
->seg
[segment
].length
;
357 f
->seg
[segment
].data
= (byte
*)buffer
;
359 return rdf_errno
= RDF_ERR_SEGMENT
;
363 if (fseek(f
->fp
,fpos
,SEEK_SET
))
364 return rdf_errno
= RDF_ERR_UNKNOWN
;
366 if (fread(buffer
,1,slen
,f
->fp
) != slen
)
367 return rdf_errno
= RDF_ERR_READ
;
372 /* Macros for reading integers from header in memory */
374 #define RI8(v) v = f->header_loc[f->header_fp++]
375 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
376 (f->header_loc[f->header_fp+1] << 8)); \
379 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
380 (f->header_loc[f->header_fp+1] << 8) + \
381 (f->header_loc[f->header_fp+2] << 16) + \
382 (f->header_loc[f->header_fp+3] << 24)); \
385 #define RS(str,max) { for(i=0;i<max;i++){\
386 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
389 * Read a header record.
390 * Returns the address of record, or NULL in case of error.
392 rdfheaderrec
*rdfgetheaderrec(rdffile
*f
)
394 static rdfheaderrec r
;
397 if (!f
->header_loc
) {
398 rdf_errno
= RDF_ERR_HEADER
;
402 if (f
->header_fp
>= f
->header_len
) return 0;
408 case RDFREC_RELOC
: /* Relocation record */
409 case RDFREC_SEGRELOC
:
410 if (r
.r
.reclen
!= 8) {
411 rdf_errno
= RDF_ERR_RECLEN
;
420 case RDFREC_IMPORT
: /* Imported symbol record */
421 case RDFREC_FARIMPORT
:
424 RS(r
.i
.label
, EXIM_LABEL_MAX
);
427 case RDFREC_GLOBAL
: /* Exported symbol record */
431 RS(r
.e
.label
, EXIM_LABEL_MAX
);
434 case RDFREC_DLL
: /* DLL record */
435 RS(r
.d
.libname
, MODLIB_NAME_MAX
);
438 case RDFREC_BSS
: /* BSS reservation record */
439 if (r
.r
.reclen
!= 4) {
440 rdf_errno
= RDF_ERR_RECLEN
;
446 case RDFREC_MODNAME
: /* Module name record */
447 RS(r
.m
.modname
, MODLIB_NAME_MAX
);
450 case RDFREC_COMMON
: /* Common variable */
454 RS(r
.c
.label
, EXIM_LABEL_MAX
);
459 rdf_errno
= RDF_ERR_RECTYPE
; /* unknown header record */
462 for (i
= 0; i
< r
.g
.reclen
; i
++)
470 * Rewind to the beginning of the file
472 void rdfheaderrewind(rdffile
*f
)
478 rdf_headerbuf
* rdfnewheader(void)
480 rdf_headerbuf
* hb
= malloc(sizeof(rdf_headerbuf
));
481 if (hb
== NULL
) return NULL
;
483 hb
->buf
= newmembuf();
490 int rdfaddheader(rdf_headerbuf
* h
, rdfheaderrec
* r
)
492 #ifndef STRICT_ERRORS
495 membufwrite(h
->buf
,&r
->type
,1);
496 membufwrite(h
->buf
,&r
->g
.reclen
,1);
499 case RDFREC_GENERIC
: /* generic */
500 membufwrite(h
->buf
, &r
->g
.data
, r
->g
.reclen
);
503 case RDFREC_SEGRELOC
:
504 membufwrite(h
->buf
,&r
->r
.segment
,1);
505 membufwrite(h
->buf
,&r
->r
.offset
,-4);
506 membufwrite(h
->buf
,&r
->r
.length
,1);
507 membufwrite(h
->buf
,&r
->r
.refseg
,-2); /* 9 bytes written */
510 case RDFREC_IMPORT
: /* import */
511 case RDFREC_FARIMPORT
:
512 membufwrite(h
->buf
,&r
->i
.flags
,1);
513 membufwrite(h
->buf
,&r
->i
.segment
,-2);
514 membufwrite(h
->buf
,&r
->i
.label
,strlen(r
->i
.label
) + 1);
517 case RDFREC_GLOBAL
: /* export */
518 membufwrite(h
->buf
,&r
->e
.flags
,1);
519 membufwrite(h
->buf
,&r
->e
.segment
,1);
520 membufwrite(h
->buf
,&r
->e
.offset
,-4);
521 membufwrite(h
->buf
,&r
->e
.label
,strlen(r
->e
.label
) + 1);
524 case RDFREC_DLL
: /* DLL */
525 membufwrite(h
->buf
,&r
->d
.libname
,strlen(r
->d
.libname
) + 1);
528 case RDFREC_BSS
: /* BSS */
529 membufwrite(h
->buf
,&r
->b
.amount
,-4);
532 case RDFREC_MODNAME
: /* Module name */
533 membufwrite(h
->buf
,&r
->m
.modname
,strlen(r
->m
.modname
) + 1);
538 return rdf_errno
= RDF_ERR_RECTYPE
;
540 for (i
= 0; i
< r
->g
.reclen
; i
++)
541 membufwrite(h
->buf
, r
->g
.data
[i
], 1);
547 int rdfaddsegment(rdf_headerbuf
*h
, long seglength
)
550 h
->seglength
+= seglength
;
554 int rdfwriteheader(FILE * fp
, rdf_headerbuf
* h
)
558 fwrite (RDOFFId
, 1, strlen(RDOFFId
), fp
) ;
560 l
= membuflength (h
->buf
);
561 l2
= l
+ 14 + 10*h
->nsegments
+ h
->seglength
;
562 l
= translatelong(l
);
563 l2
= translatelong(l2
);
564 fwrite (&l2
, 4, 1, fp
); /* object length */
565 fwrite (&l
, 4, 1, fp
); /* header length */
567 membufdump(h
->buf
, fp
);
569 return 0; /* no error handling in here... CHANGE THIS! */
572 void rdfdoneheader(rdf_headerbuf
* h
)