1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2014 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * rdoff.c library of routines for manipulating rdoff files
38 /* TODO: The functions in this module assume they are running
39 * on a little-endian machine. This should be fixed to
52 * Comment this out to allow the module to read & write header record types
53 * that it isn't aware of. With this defined, unrecognised header records
54 * will generate error number 8, reported as 'unknown extended header record'.
59 /* ========================================================================
60 * Code for memory buffers (for delayed writing of header until we know
62 * ======================================================================== */
64 static memorybuffer
*newmembuf(void)
68 t
= nasm_malloc(sizeof(memorybuffer
));
77 static void membufwrite(memorybuffer
* const b
, void *data
, int bytes
)
83 if (b
->next
) { /* memory buffer full - use next buffer */
84 membufwrite(b
->next
, data
, bytes
);
88 if ((bytes
< 0 && b
->length
- bytes
> BUF_BLOCK_LEN
)
89 || (bytes
> 0 && b
->length
+ bytes
> BUF_BLOCK_LEN
)) {
91 /* buffer full and no next allocated... allocate and initialise next
93 b
->next
= newmembuf();
94 membufwrite(b
->next
, data
, bytes
);
99 case -4: /* convert to little-endian */
100 l
= *(int32_t *)data
;
101 b
->buffer
[b
->length
++] = l
& 0xFF;
103 b
->buffer
[b
->length
++] = l
& 0xFF;
105 b
->buffer
[b
->length
++] = l
& 0xFF;
107 b
->buffer
[b
->length
++] = l
& 0xFF;
111 w
= *(uint16_t *) data
;
112 b
->buffer
[b
->length
++] = w
& 0xFF;
114 b
->buffer
[b
->length
++] = w
& 0xFF;
120 b
->buffer
[b
->length
++] = *c
++;
125 static void membufdump(memorybuffer
* b
, FILE * fp
)
130 nasm_write(b
->buffer
, b
->length
, fp
);
131 membufdump(b
->next
, fp
);
134 static int membuflength(memorybuffer
* b
)
138 return b
->length
+ membuflength(b
->next
);
141 static void freemembuf(memorybuffer
* b
)
149 /* =========================================================================
150 General purpose routines and variables used by the library functions
151 ========================================================================= */
154 * translateint32_t() and translateint16_t()
156 * translate from little endian to local representation
158 int32_t translateint32_t(int32_t in
)
172 uint16_t translateint16_t(uint16_t in
)
178 r
= (i
[1] << 8) + i
[0];
184 static char *knownsegtypes
[8] = {
185 "NULL", "text", "data", "object comment",
186 "linked comment", "loader comment",
187 "symbolic debug", "line number debug"
190 /* Get a textual string describing the segment type */
191 char *translatesegmenttype(uint16_t type
)
194 return knownsegtypes
[type
];
198 return "reserved - Moscow";
200 return "reserved - system dependant";
202 return "reserved - other";
204 return "invalid type code";
205 return "type code out of range";
208 /* This signature is written to the start of RDOFF files */
209 const char *RDOFFId
= RDOFF2_SIGNATURE
;
211 /* Error messages. Must correspond to the codes defined in rdoff.h */
212 const char *rdf_errors
[11] = {
213 /* 0 */ "no error occurred",
214 /* 1 */ "could not open file",
215 /* 2 */ "invalid file format",
216 /* 3 */ "error reading file",
217 /* 4 */ "unknown error",
218 /* 5 */ "header not read",
219 /* 6 */ "out of memory",
220 /* 7 */ "RDOFF v1 not supported",
221 /* 8 */ "unknown extended header record",
222 /* 9 */ "header record of known type but unknown length",
223 /* 10 */ "no such segment"
228 /* ========================================================================
229 * Hook for nasm_error() to work
230 * ======================================================================== */
231 void nasm_verror(errflags severity
, const char *fmt
, va_list val
)
233 severity
&= ERR_MASK
;
235 vfprintf(stderr
, fmt
, val
);
236 if (severity
>= ERR_FATAL
)
237 exit(severity
- ERR_FATAL
+ 1);
240 fatal_func
nasm_verror_critical(errflags severity
, const char *fmt
, va_list val
)
242 nasm_verror(severity
, fmt
, val
);
246 void rdoff_init(void)
251 /* ========================================================================
252 The library functions
253 ======================================================================== */
255 int rdfopen(rdffile
* f
, const char *name
)
259 fp
= fopen(name
, "rb");
261 return rdf_errno
= RDF_ERR_OPEN
;
263 return rdfopenhere(f
, fp
, NULL
, name
);
266 int rdfopenhere(rdffile
* f
, FILE * fp
, int *refcount
, const char *name
)
273 if (translateint32_t(0x01020304) != 0x01020304) {
274 /* fix this to be portable! */
275 fputs("*** this program requires a little endian machine\n",
277 fprintf(stderr
, "01020304h = %08"PRIx32
"h\n", translateint32_t(0x01020304));
285 if (fread(buf
, 1, 6, f
->fp
) != 6) {
287 return rdf_errno
= RDF_ERR_READ
;
291 if (strcmp(buf
, RDOFFId
)) {
293 if (!strcmp(buf
, "RDOFF1"))
294 return rdf_errno
= RDF_ERR_VER
;
295 return rdf_errno
= RDF_ERR_FORMAT
;
298 if (fread(&l
, 1, 4, f
->fp
) != 4
299 || fread(&f
->header_len
, 1, 4, f
->fp
) != 4) {
301 return rdf_errno
= RDF_ERR_READ
;
304 f
->header_ofs
= ftell(f
->fp
);
305 f
->eof_offset
= f
->header_ofs
+ translateint32_t(l
) - 4;
307 if (fseek(f
->fp
, f
->header_len
, SEEK_CUR
)) {
309 return rdf_errno
= RDF_ERR_FORMAT
; /* seek past end of file...? */
312 if (fread(&s
, 1, 2, f
->fp
) != 2) {
314 return rdf_errno
= RDF_ERR_READ
;
320 f
->seg
[f
->nsegs
].type
= s
;
321 if (fread(&f
->seg
[f
->nsegs
].number
, 1, 2, f
->fp
) != 2 ||
322 fread(&f
->seg
[f
->nsegs
].reserved
, 1, 2, f
->fp
) != 2 ||
323 fread(&f
->seg
[f
->nsegs
].length
, 1, 4, f
->fp
) != 4) {
325 return rdf_errno
= RDF_ERR_READ
;
328 f
->seg
[f
->nsegs
].offset
= ftell(f
->fp
);
329 if (fseek(f
->fp
, f
->seg
[f
->nsegs
].length
, SEEK_CUR
)) {
331 return rdf_errno
= RDF_ERR_FORMAT
;
335 if (fread(&s
, 1, 2, f
->fp
) != 2) {
337 return rdf_errno
= RDF_ERR_READ
;
341 if (f
->eof_offset
!= ftell(f
->fp
) + 8) { /* +8 = skip null segment header */
342 fprintf(stderr
, "warning: eof_offset [%"PRId32
"] and actual eof offset "
343 "[%ld] don't match\n", f
->eof_offset
, ftell(f
->fp
) + 8);
345 fseek(f
->fp
, initpos
, SEEK_SET
);
346 f
->header_loc
= NULL
;
348 f
->name
= nasm_strdup(name
);
349 f
->refcount
= refcount
;
355 int rdfclose(rdffile
* f
)
357 if (!f
->refcount
|| !--(*f
->refcount
)) {
367 * Print the message for last error (from rdf_errno)
369 void rdfperror(const char *app
, const char *name
)
371 fprintf(stderr
, "%s:%s: %s\n", app
, name
, rdf_errors
[rdf_errno
]);
372 if (rdf_errno
== RDF_ERR_OPEN
|| rdf_errno
== RDF_ERR_READ
) {
378 * Find the segment by its number.
379 * Returns segment array index, or -1 if segment with such number was not found.
381 int rdffindsegment(rdffile
* f
, int segno
)
384 for (i
= 0; i
< f
->nsegs
; i
++)
385 if (f
->seg
[i
].number
== segno
)
391 * Load the segment. Returns status.
393 int rdfloadseg(rdffile
* f
, int segment
, void *buffer
)
400 fpos
= f
->header_ofs
;
401 slen
= f
->header_len
;
402 f
->header_loc
= (uint8_t *) buffer
;
406 if (segment
< f
->nsegs
) {
407 fpos
= f
->seg
[segment
].offset
;
408 slen
= f
->seg
[segment
].length
;
409 f
->seg
[segment
].data
= (uint8_t *) buffer
;
411 return rdf_errno
= RDF_ERR_SEGMENT
;
415 if (fseek(f
->fp
, fpos
, SEEK_SET
))
416 return rdf_errno
= RDF_ERR_UNKNOWN
;
418 if (fread(buffer
, 1, slen
, f
->fp
) != slen
)
419 return rdf_errno
= RDF_ERR_READ
;
424 /* Macros for reading integers from header in memory */
426 #define RI8(v) v = f->header_loc[f->header_fp++]
427 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
428 (f->header_loc[f->header_fp+1] << 8)); \
431 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
432 (f->header_loc[f->header_fp+1] << 8) + \
433 (f->header_loc[f->header_fp+2] << 16) + \
434 (f->header_loc[f->header_fp+3] << 24)); \
437 #define RS(str,max) { for(i=0;i<max;i++){\
438 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
441 * Read a header record.
442 * Returns the address of record, or NULL in case of error.
444 rdfheaderrec
*rdfgetheaderrec(rdffile
* f
)
446 static rdfheaderrec r
;
449 if (!f
->header_loc
) {
450 rdf_errno
= RDF_ERR_HEADER
;
454 if (f
->header_fp
>= f
->header_len
)
461 case RDFREC_RELOC
: /* Relocation record */
462 case RDFREC_SEGRELOC
:
463 if (r
.r
.reclen
!= 8) {
464 rdf_errno
= RDF_ERR_RECLEN
;
473 case RDFREC_IMPORT
: /* Imported symbol record */
474 case RDFREC_FARIMPORT
:
477 RS(r
.i
.label
, EXIM_LABEL_MAX
);
480 case RDFREC_GLOBAL
: /* Exported symbol record */
484 RS(r
.e
.label
, EXIM_LABEL_MAX
);
487 case RDFREC_DLL
: /* DLL record */
488 RS(r
.d
.libname
, MODLIB_NAME_MAX
);
491 case RDFREC_BSS
: /* BSS reservation record */
492 if (r
.r
.reclen
!= 4) {
493 rdf_errno
= RDF_ERR_RECLEN
;
499 case RDFREC_MODNAME
: /* Module name record */
500 RS(r
.m
.modname
, MODLIB_NAME_MAX
);
503 case RDFREC_COMMON
: /* Common variable */
507 RS(r
.c
.label
, EXIM_LABEL_MAX
);
512 rdf_errno
= RDF_ERR_RECTYPE
; /* unknown header record */
515 for (i
= 0; i
< r
.g
.reclen
; i
++)
523 * Rewind to the beginning of the file
525 void rdfheaderrewind(rdffile
* f
)
530 rdf_headerbuf
*rdfnewheader(void)
532 rdf_headerbuf
*hb
= nasm_malloc(sizeof(rdf_headerbuf
));
536 hb
->buf
= newmembuf();
543 int rdfaddheader(rdf_headerbuf
* h
, rdfheaderrec
* r
)
545 #ifndef STRICT_ERRORS
548 membufwrite(h
->buf
, &r
->type
, 1);
549 membufwrite(h
->buf
, &r
->g
.reclen
, 1);
552 case RDFREC_GENERIC
: /* generic */
553 membufwrite(h
->buf
, &r
->g
.data
, r
->g
.reclen
);
556 case RDFREC_SEGRELOC
:
557 membufwrite(h
->buf
, &r
->r
.segment
, 1);
558 membufwrite(h
->buf
, &r
->r
.offset
, -4);
559 membufwrite(h
->buf
, &r
->r
.length
, 1);
560 membufwrite(h
->buf
, &r
->r
.refseg
, -2); /* 9 bytes written */
563 case RDFREC_IMPORT
: /* import */
564 case RDFREC_FARIMPORT
:
565 membufwrite(h
->buf
, &r
->i
.flags
, 1);
566 membufwrite(h
->buf
, &r
->i
.segment
, -2);
567 membufwrite(h
->buf
, &r
->i
.label
, strlen(r
->i
.label
) + 1);
570 case RDFREC_GLOBAL
: /* export */
571 membufwrite(h
->buf
, &r
->e
.flags
, 1);
572 membufwrite(h
->buf
, &r
->e
.segment
, 1);
573 membufwrite(h
->buf
, &r
->e
.offset
, -4);
574 membufwrite(h
->buf
, &r
->e
.label
, strlen(r
->e
.label
) + 1);
577 case RDFREC_DLL
: /* DLL */
578 membufwrite(h
->buf
, &r
->d
.libname
, strlen(r
->d
.libname
) + 1);
581 case RDFREC_BSS
: /* BSS */
582 membufwrite(h
->buf
, &r
->b
.amount
, -4);
585 case RDFREC_MODNAME
: /* Module name */
586 membufwrite(h
->buf
, &r
->m
.modname
, strlen(r
->m
.modname
) + 1);
591 return rdf_errno
= RDF_ERR_RECTYPE
;
593 for (i
= 0; i
< r
->g
.reclen
; i
++)
594 membufwrite(h
->buf
, r
->g
.data
[i
], 1);
600 int rdfaddsegment(rdf_headerbuf
* h
, int32_t seglength
)
603 h
->seglength
+= seglength
;
607 int rdfwriteheader(FILE * fp
, rdf_headerbuf
* h
)
611 nasm_write(RDOFFId
, strlen(RDOFFId
), fp
);
613 l
= membuflength(h
->buf
);
614 l2
= l
+ 14 + 10 * h
->nsegments
+ h
->seglength
;
615 fwriteint32_t(l
, fp
);
616 fwriteint32_t(l2
, fp
);
618 membufdump(h
->buf
, fp
);
620 return 0; /* no error handling in here... CHANGE THIS! */
623 void rdfdoneheader(rdf_headerbuf
* h
)