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 * ======================================================================== */
44 memorybuffer
*newmembuf()
48 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
)) {
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;
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
)
111 fwrite(b
->buffer
, 1, b
->length
, fp
);
113 membufdump(b
->next
, fp
);
116 int membuflength(memorybuffer
* b
)
120 return b
->length
+ membuflength(b
->next
);
123 void freemembuf(memorybuffer
* b
)
131 /* =========================================================================
132 General purpose routines and variables used by the library functions
133 ========================================================================= */
136 * translatelong() and translateshort()
138 * translate from little endian to local representation
140 long translatelong(long in
)
145 i
= (unsigned char *)&in
;
154 uint16
translateshort(uint16 in
)
159 i
= (unsigned char *)&in
;
160 r
= (i
[1] << 8) + i
[0];
166 static char *knownsegtypes
[8] = {
167 "NULL", "text", "data", "object comment",
168 "linked comment", "loader comment",
169 "symbolic debug", "line number debug"
172 /* Get a textual string describing the segment type */
173 char *translatesegmenttype(uint16 type
)
176 return knownsegtypes
[type
];
180 return "reserved - Moscow";
182 return "reserved - system dependant";
184 return "reserved - other";
186 return "invalid type code";
187 return "type code out of range";
190 /* This signature is written to the start of RDOFF files */
191 const char *RDOFFId
= RDOFF2_SIGNATURE
;
193 /* Error messages. Must correspond to the codes defined in rdoff.h */
194 const char *rdf_errors
[11] = {
195 /* 0 */ "no error occurred",
196 /* 1 */ "could not open file",
197 /* 2 */ "invalid file format",
198 /* 3 */ "error reading file",
199 /* 4 */ "unknown error",
200 /* 5 */ "header not read",
201 /* 6 */ "out of memory",
202 /* 7 */ "RDOFF v1 not supported",
203 /* 8 */ "unknown extended header record",
204 /* 9 */ "header record of known type but unknown length",
205 /* 10 */ "no such segment"
210 /* ========================================================================
211 The library functions
212 ======================================================================== */
214 int rdfopen(rdffile
* f
, const char *name
)
218 fp
= fopen(name
, "rb");
220 return rdf_errno
= RDF_ERR_OPEN
;
222 return rdfopenhere(f
, fp
, NULL
, name
);
225 int rdfopenhere(rdffile
* f
, FILE * fp
, int *refcount
, const char *name
)
232 if (translatelong(0x01020304) != 0x01020304) {
233 /* fix this to be portable! */
234 fputs("*** this program requires a little endian machine\n",
236 fprintf(stderr
, "01020304h = %08lxh\n", translatelong(0x01020304));
243 fread(buf
, 6, 1, f
->fp
); /* read header */
246 if (strcmp(buf
, RDOFFId
)) {
248 if (!strcmp(buf
, "RDOFF1"))
249 return rdf_errno
= RDF_ERR_VER
;
250 return rdf_errno
= RDF_ERR_FORMAT
;
253 if (fread(&l
, 1, 4, f
->fp
) != 4
254 || fread(&f
->header_len
, 1, 4, f
->fp
) != 4) {
256 return rdf_errno
= RDF_ERR_READ
;
259 f
->header_ofs
= ftell(f
->fp
);
260 f
->eof_offset
= f
->header_ofs
+ translatelong(l
) - 4;
262 if (fseek(f
->fp
, f
->header_len
, SEEK_CUR
)) {
264 return rdf_errno
= RDF_ERR_FORMAT
; /* seek past end of file...? */
267 if (fread(&s
, 1, 2, f
->fp
) != 2) {
269 return rdf_errno
= RDF_ERR_READ
;
275 f
->seg
[f
->nsegs
].type
= s
;
276 if (fread(&f
->seg
[f
->nsegs
].number
, 1, 2, f
->fp
) != 2 ||
277 fread(&f
->seg
[f
->nsegs
].reserved
, 1, 2, f
->fp
) != 2 ||
278 fread(&f
->seg
[f
->nsegs
].length
, 1, 4, f
->fp
) != 4) {
280 return rdf_errno
= RDF_ERR_READ
;
283 f
->seg
[f
->nsegs
].offset
= ftell(f
->fp
);
284 if (fseek(f
->fp
, f
->seg
[f
->nsegs
].length
, SEEK_CUR
)) {
286 return rdf_errno
= RDF_ERR_FORMAT
;
290 if (fread(&s
, 1, 2, f
->fp
) != 2) {
292 return rdf_errno
= RDF_ERR_READ
;
296 if (f
->eof_offset
!= ftell(f
->fp
) + 8) { /* +8 = skip null segment header */
297 fprintf(stderr
, "warning: eof_offset [%ld] and actual eof offset "
298 "[%ld] don't match\n", f
->eof_offset
, ftell(f
->fp
) + 8);
300 fseek(f
->fp
, initpos
, SEEK_SET
);
301 f
->header_loc
= NULL
;
303 f
->name
= newstr(name
);
304 f
->refcount
= refcount
;
310 int rdfclose(rdffile
* f
)
312 if (!f
->refcount
|| !--(*f
->refcount
)) {
322 * Print the message for last error (from rdf_errno)
324 void rdfperror(const char *app
, const char *name
)
326 fprintf(stderr
, "%s:%s: %s\n", app
, name
, rdf_errors
[rdf_errno
]);
327 if (rdf_errno
== RDF_ERR_OPEN
|| rdf_errno
== RDF_ERR_READ
) {
333 * Find the segment by its number.
334 * Returns segment array index, or -1 if segment with such number was not found.
336 int rdffindsegment(rdffile
* f
, int segno
)
339 for (i
= 0; i
< f
->nsegs
; i
++)
340 if (f
->seg
[i
].number
== segno
)
346 * Load the segment. Returns status.
348 int rdfloadseg(rdffile
* f
, int segment
, void *buffer
)
354 fpos
= f
->header_ofs
;
355 slen
= f
->header_len
;
356 f
->header_loc
= (byte
*) buffer
;
360 if (segment
< f
->nsegs
) {
361 fpos
= f
->seg
[segment
].offset
;
362 slen
= f
->seg
[segment
].length
;
363 f
->seg
[segment
].data
= (byte
*) buffer
;
365 return rdf_errno
= RDF_ERR_SEGMENT
;
369 if (fseek(f
->fp
, fpos
, SEEK_SET
))
370 return rdf_errno
= RDF_ERR_UNKNOWN
;
372 if (fread(buffer
, 1, slen
, f
->fp
) != slen
)
373 return rdf_errno
= RDF_ERR_READ
;
378 /* Macros for reading integers from header in memory */
380 #define RI8(v) v = f->header_loc[f->header_fp++]
381 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
382 (f->header_loc[f->header_fp+1] << 8)); \
385 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
386 (f->header_loc[f->header_fp+1] << 8) + \
387 (f->header_loc[f->header_fp+2] << 16) + \
388 (f->header_loc[f->header_fp+3] << 24)); \
391 #define RS(str,max) { for(i=0;i<max;i++){\
392 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
395 * Read a header record.
396 * Returns the address of record, or NULL in case of error.
398 rdfheaderrec
*rdfgetheaderrec(rdffile
* f
)
400 static rdfheaderrec r
;
403 if (!f
->header_loc
) {
404 rdf_errno
= RDF_ERR_HEADER
;
408 if (f
->header_fp
>= f
->header_len
)
415 case RDFREC_RELOC
: /* Relocation record */
416 case RDFREC_SEGRELOC
:
417 if (r
.r
.reclen
!= 8) {
418 rdf_errno
= RDF_ERR_RECLEN
;
427 case RDFREC_IMPORT
: /* Imported symbol record */
428 case RDFREC_FARIMPORT
:
431 RS(r
.i
.label
, EXIM_LABEL_MAX
);
434 case RDFREC_GLOBAL
: /* Exported symbol record */
438 RS(r
.e
.label
, EXIM_LABEL_MAX
);
441 case RDFREC_DLL
: /* DLL record */
442 RS(r
.d
.libname
, MODLIB_NAME_MAX
);
445 case RDFREC_BSS
: /* BSS reservation record */
446 if (r
.r
.reclen
!= 4) {
447 rdf_errno
= RDF_ERR_RECLEN
;
453 case RDFREC_MODNAME
: /* Module name record */
454 RS(r
.m
.modname
, MODLIB_NAME_MAX
);
457 case RDFREC_COMMON
: /* Common variable */
461 RS(r
.c
.label
, EXIM_LABEL_MAX
);
466 rdf_errno
= RDF_ERR_RECTYPE
; /* unknown header record */
469 for (i
= 0; i
< r
.g
.reclen
; i
++)
477 * Rewind to the beginning of the file
479 void rdfheaderrewind(rdffile
* f
)
484 rdf_headerbuf
*rdfnewheader(void)
486 rdf_headerbuf
*hb
= malloc(sizeof(rdf_headerbuf
));
490 hb
->buf
= newmembuf();
497 int rdfaddheader(rdf_headerbuf
* h
, rdfheaderrec
* r
)
499 #ifndef STRICT_ERRORS
502 membufwrite(h
->buf
, &r
->type
, 1);
503 membufwrite(h
->buf
, &r
->g
.reclen
, 1);
506 case RDFREC_GENERIC
: /* generic */
507 membufwrite(h
->buf
, &r
->g
.data
, r
->g
.reclen
);
510 case RDFREC_SEGRELOC
:
511 membufwrite(h
->buf
, &r
->r
.segment
, 1);
512 membufwrite(h
->buf
, &r
->r
.offset
, -4);
513 membufwrite(h
->buf
, &r
->r
.length
, 1);
514 membufwrite(h
->buf
, &r
->r
.refseg
, -2); /* 9 bytes written */
517 case RDFREC_IMPORT
: /* import */
518 case RDFREC_FARIMPORT
:
519 membufwrite(h
->buf
, &r
->i
.flags
, 1);
520 membufwrite(h
->buf
, &r
->i
.segment
, -2);
521 membufwrite(h
->buf
, &r
->i
.label
, strlen(r
->i
.label
) + 1);
524 case RDFREC_GLOBAL
: /* export */
525 membufwrite(h
->buf
, &r
->e
.flags
, 1);
526 membufwrite(h
->buf
, &r
->e
.segment
, 1);
527 membufwrite(h
->buf
, &r
->e
.offset
, -4);
528 membufwrite(h
->buf
, &r
->e
.label
, strlen(r
->e
.label
) + 1);
531 case RDFREC_DLL
: /* DLL */
532 membufwrite(h
->buf
, &r
->d
.libname
, strlen(r
->d
.libname
) + 1);
535 case RDFREC_BSS
: /* BSS */
536 membufwrite(h
->buf
, &r
->b
.amount
, -4);
539 case RDFREC_MODNAME
: /* Module name */
540 membufwrite(h
->buf
, &r
->m
.modname
, strlen(r
->m
.modname
) + 1);
545 return rdf_errno
= RDF_ERR_RECTYPE
;
547 for (i
= 0; i
< r
->g
.reclen
; i
++)
548 membufwrite(h
->buf
, r
->g
.data
[i
], 1);
554 int rdfaddsegment(rdf_headerbuf
* h
, long seglength
)
557 h
->seglength
+= seglength
;
561 int rdfwriteheader(FILE * fp
, rdf_headerbuf
* h
)
565 fwrite(RDOFFId
, 1, strlen(RDOFFId
), fp
);
567 l
= membuflength(h
->buf
);
568 l2
= l
+ 14 + 10 * h
->nsegments
+ h
->seglength
;
569 l
= translatelong(l
);
570 l2
= translatelong(l2
);
571 fwrite(&l2
, 4, 1, fp
); /* object length */
572 fwrite(&l
, 4, 1, fp
); /* header length */
574 membufdump(h
->buf
, fp
);
576 return 0; /* no error handling in here... CHANGE THIS! */
579 void rdfdoneheader(rdf_headerbuf
* h
)