0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-07-24 10:25:42 -04:00
nasm/rdoff/rdoff.c
Ozkan Sezer 723fb2cc33 rdoff/rdfwriteheader: Write object length and header length in correct order
Compared to 2.12.xx rdfwriteheader() writes the object length and header
length in flipped order.  Issue seems to have been introduced by commit
8dc965347ddf.

BR3392717

Signed-off-by: Ozkan Sezer <sezeroz@gmail.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
2020-10-10 00:13:07 +03:00

628 lines
16 KiB
C

/* ----------------------------------------------------------------------- *
*
* Copyright 1996-2014 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ----------------------------------------------------------------------- */
/*
* rdoff.c library of routines for manipulating rdoff files
*/
/* TODO: The functions in this module assume they are running
* on a little-endian machine. This should be fixed to
* make it portable.
*/
#include "compiler.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "rdfutils.h"
/*
* Comment this out to allow the module to read & write header record types
* that it isn't aware of. With this defined, unrecognised header records
* will generate error number 8, reported as 'unknown extended header record'.
*/
#define STRICT_ERRORS
/* ========================================================================
* Code for memory buffers (for delayed writing of header until we know
* how int32_t it is).
* ======================================================================== */
static memorybuffer *newmembuf(void)
{
memorybuffer *t;
t = nasm_malloc(sizeof(memorybuffer));
if (!t)
return NULL;
t->length = 0;
t->next = NULL;
return t;
}
static void membufwrite(memorybuffer * const b, void *data, int bytes)
{
uint16_t w;
int32_t l;
char *c;
if (b->next) { /* memory buffer full - use next buffer */
membufwrite(b->next, data, bytes);
return;
}
if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
|| (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) {
/* buffer full and no next allocated... allocate and initialise next
* buffer */
b->next = newmembuf();
membufwrite(b->next, data, bytes);
return;
}
switch (bytes) {
case -4: /* convert to little-endian */
l = *(int32_t *)data;
b->buffer[b->length++] = l & 0xFF;
l >>= 8;
b->buffer[b->length++] = l & 0xFF;
l >>= 8;
b->buffer[b->length++] = l & 0xFF;
l >>= 8;
b->buffer[b->length++] = l & 0xFF;
break;
case -2:
w = *(uint16_t *) data;
b->buffer[b->length++] = w & 0xFF;
w >>= 8;
b->buffer[b->length++] = w & 0xFF;
break;
default:
c = data;
while (bytes--)
b->buffer[b->length++] = *c++;
break;
}
}
static void membufdump(memorybuffer * b, FILE * fp)
{
if (!b)
return;
nasm_write(b->buffer, b->length, fp);
membufdump(b->next, fp);
}
static int membuflength(memorybuffer * b)
{
if (!b)
return 0;
return b->length + membuflength(b->next);
}
static void freemembuf(memorybuffer * b)
{
if (!b)
return;
freemembuf(b->next);
nasm_free(b);
}
/* =========================================================================
General purpose routines and variables used by the library functions
========================================================================= */
/*
* translateint32_t() and translateint16_t()
*
* translate from little endian to local representation
*/
int32_t translateint32_t(int32_t in)
{
int32_t r;
uint8_t *i;
i = (uint8_t *)&in;
r = i[3];
r = (r << 8) + i[2];
r = (r << 8) + i[1];
r = (r << 8) + *i;
return r;
}
uint16_t translateint16_t(uint16_t in)
{
uint16_t r;
uint8_t *i;
i = (uint8_t *)&in;
r = (i[1] << 8) + i[0];
return r;
}
/* Segment types */
static char *knownsegtypes[8] = {
"NULL", "text", "data", "object comment",
"linked comment", "loader comment",
"symbolic debug", "line number debug"
};
/* Get a textual string describing the segment type */
char *translatesegmenttype(uint16_t type)
{
if (type < 8)
return knownsegtypes[type];
if (type < 0x0020)
return "reserved";
if (type < 0x1000)
return "reserved - Moscow";
if (type < 0x8000)
return "reserved - system dependant";
if (type < 0xFFFF)
return "reserved - other";
if (type == 0xFFFF)
return "invalid type code";
return "type code out of range";
}
/* This signature is written to the start of RDOFF files */
const char *RDOFFId = RDOFF2_SIGNATURE;
/* Error messages. Must correspond to the codes defined in rdoff.h */
const char *rdf_errors[11] = {
/* 0 */ "no error occurred",
/* 1 */ "could not open file",
/* 2 */ "invalid file format",
/* 3 */ "error reading file",
/* 4 */ "unknown error",
/* 5 */ "header not read",
/* 6 */ "out of memory",
/* 7 */ "RDOFF v1 not supported",
/* 8 */ "unknown extended header record",
/* 9 */ "header record of known type but unknown length",
/* 10 */ "no such segment"
};
int rdf_errno = 0;
/* ========================================================================
* Hook for nasm_error() to work
* ======================================================================== */
void nasm_verror(errflags severity, const char *fmt, va_list val)
{
severity &= ERR_MASK;
vfprintf(stderr, fmt, val);
if (severity >= ERR_FATAL)
exit(severity - ERR_FATAL + 1);
}
fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list val)
{
nasm_verror(severity, fmt, val);
abort();
}
void rdoff_init(void)
{
}
/* ========================================================================
The library functions
======================================================================== */
int rdfopen(rdffile * f, const char *name)
{
FILE *fp;
fp = fopen(name, "rb");
if (!fp)
return rdf_errno = RDF_ERR_OPEN;
return rdfopenhere(f, fp, NULL, name);
}
int rdfopenhere(rdffile * f, FILE * fp, int *refcount, const char *name)
{
char buf[8];
int32_t initpos;
int32_t l;
uint16_t s;
if (translateint32_t(0x01020304) != 0x01020304) {
/* fix this to be portable! */
fputs("*** this program requires a little endian machine\n",
stderr);
fprintf(stderr, "01020304h = %08"PRIx32"h\n", translateint32_t(0x01020304));
exit(3);
}
f->fp = fp;
initpos = ftell(fp);
/* read header */
if (fread(buf, 1, 6, f->fp) != 6) {
fclose(f->fp);
return rdf_errno = RDF_ERR_READ;
}
buf[6] = 0;
if (strcmp(buf, RDOFFId)) {
fclose(f->fp);
if (!strcmp(buf, "RDOFF1"))
return rdf_errno = RDF_ERR_VER;
return rdf_errno = RDF_ERR_FORMAT;
}
if (fread(&l, 1, 4, f->fp) != 4
|| fread(&f->header_len, 1, 4, f->fp) != 4) {
fclose(f->fp);
return rdf_errno = RDF_ERR_READ;
}
f->header_ofs = ftell(f->fp);
f->eof_offset = f->header_ofs + translateint32_t(l) - 4;
if (fseek(f->fp, f->header_len, SEEK_CUR)) {
fclose(f->fp);
return rdf_errno = RDF_ERR_FORMAT; /* seek past end of file...? */
}
if (fread(&s, 1, 2, f->fp) != 2) {
fclose(f->fp);
return rdf_errno = RDF_ERR_READ;
}
f->nsegs = 0;
while (s != 0) {
f->seg[f->nsegs].type = s;
if (fread(&f->seg[f->nsegs].number, 1, 2, f->fp) != 2 ||
fread(&f->seg[f->nsegs].reserved, 1, 2, f->fp) != 2 ||
fread(&f->seg[f->nsegs].length, 1, 4, f->fp) != 4) {
fclose(f->fp);
return rdf_errno = RDF_ERR_READ;
}
f->seg[f->nsegs].offset = ftell(f->fp);
if (fseek(f->fp, f->seg[f->nsegs].length, SEEK_CUR)) {
fclose(f->fp);
return rdf_errno = RDF_ERR_FORMAT;
}
f->nsegs++;
if (fread(&s, 1, 2, f->fp) != 2) {
fclose(f->fp);
return rdf_errno = RDF_ERR_READ;
}
}
if (f->eof_offset != ftell(f->fp) + 8) { /* +8 = skip null segment header */
fprintf(stderr, "warning: eof_offset [%"PRId32"] and actual eof offset "
"[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
}
fseek(f->fp, initpos, SEEK_SET);
f->header_loc = NULL;
f->name = nasm_strdup(name);
f->refcount = refcount;
if (refcount)
(*refcount)++;
return RDF_OK;
}
int rdfclose(rdffile * f)
{
if (!f->refcount || !--(*f->refcount)) {
fclose(f->fp);
f->fp = NULL;
}
nasm_free(f->name);
return 0;
}
/*
* Print the message for last error (from rdf_errno)
*/
void rdfperror(const char *app, const char *name)
{
fprintf(stderr, "%s:%s: %s\n", app, name, rdf_errors[rdf_errno]);
if (rdf_errno == RDF_ERR_OPEN || rdf_errno == RDF_ERR_READ) {
perror(app);
}
}
/*
* Find the segment by its number.
* Returns segment array index, or -1 if segment with such number was not found.
*/
int rdffindsegment(rdffile * f, int segno)
{
int i;
for (i = 0; i < f->nsegs; i++)
if (f->seg[i].number == segno)
return i;
return -1;
}
/*
* Load the segment. Returns status.
*/
int rdfloadseg(rdffile * f, int segment, void *buffer)
{
int32_t fpos;
size_t slen;
switch (segment) {
case RDOFF_HEADER:
fpos = f->header_ofs;
slen = f->header_len;
f->header_loc = (uint8_t *) buffer;
f->header_fp = 0;
break;
default:
if (segment < f->nsegs) {
fpos = f->seg[segment].offset;
slen = f->seg[segment].length;
f->seg[segment].data = (uint8_t *) buffer;
} else {
return rdf_errno = RDF_ERR_SEGMENT;
}
}
if (fseek(f->fp, fpos, SEEK_SET))
return rdf_errno = RDF_ERR_UNKNOWN;
if (fread(buffer, 1, slen, f->fp) != slen)
return rdf_errno = RDF_ERR_READ;
return RDF_OK;
}
/* Macros for reading integers from header in memory */
#define RI8(v) v = f->header_loc[f->header_fp++]
#define RI16(v) { v = (f->header_loc[f->header_fp] + \
(f->header_loc[f->header_fp+1] << 8)); \
f->header_fp += 2; }
#define RI32(v) { v = (f->header_loc[f->header_fp] + \
(f->header_loc[f->header_fp+1] << 8) + \
(f->header_loc[f->header_fp+2] << 16) + \
(f->header_loc[f->header_fp+3] << 24)); \
f->header_fp += 4; }
#define RS(str,max) { for(i=0;i<max;i++){\
RI8(str[i]); if (!str[i]) break;} str[i]=0; }
/*
* Read a header record.
* Returns the address of record, or NULL in case of error.
*/
rdfheaderrec *rdfgetheaderrec(rdffile * f)
{
static rdfheaderrec r;
int i;
if (!f->header_loc) {
rdf_errno = RDF_ERR_HEADER;
return NULL;
}
if (f->header_fp >= f->header_len)
return 0;
RI8(r.type);
RI8(r.g.reclen);
switch (r.type) {
case RDFREC_RELOC: /* Relocation record */
case RDFREC_SEGRELOC:
if (r.r.reclen != 8) {
rdf_errno = RDF_ERR_RECLEN;
return NULL;
}
RI8(r.r.segment);
RI32(r.r.offset);
RI8(r.r.length);
RI16(r.r.refseg);
break;
case RDFREC_IMPORT: /* Imported symbol record */
case RDFREC_FARIMPORT:
RI8(r.i.flags);
RI16(r.i.segment);
RS(r.i.label, EXIM_LABEL_MAX);
break;
case RDFREC_GLOBAL: /* Exported symbol record */
RI8(r.e.flags);
RI8(r.e.segment);
RI32(r.e.offset);
RS(r.e.label, EXIM_LABEL_MAX);
break;
case RDFREC_DLL: /* DLL record */
RS(r.d.libname, MODLIB_NAME_MAX);
break;
case RDFREC_BSS: /* BSS reservation record */
if (r.r.reclen != 4) {
rdf_errno = RDF_ERR_RECLEN;
return NULL;
}
RI32(r.b.amount);
break;
case RDFREC_MODNAME: /* Module name record */
RS(r.m.modname, MODLIB_NAME_MAX);
break;
case RDFREC_COMMON: /* Common variable */
RI16(r.c.segment);
RI32(r.c.size);
RI16(r.c.align);
RS(r.c.label, EXIM_LABEL_MAX);
break;
default:
#ifdef STRICT_ERRORS
rdf_errno = RDF_ERR_RECTYPE; /* unknown header record */
return NULL;
#else
for (i = 0; i < r.g.reclen; i++)
RI8(r.g.data[i]);
#endif
}
return &r;
}
/*
* Rewind to the beginning of the file
*/
void rdfheaderrewind(rdffile * f)
{
f->header_fp = 0;
}
rdf_headerbuf *rdfnewheader(void)
{
rdf_headerbuf *hb = nasm_malloc(sizeof(rdf_headerbuf));
if (hb == NULL)
return NULL;
hb->buf = newmembuf();
hb->nsegments = 0;
hb->seglength = 0;
return hb;
}
int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
{
#ifndef STRICT_ERRORS
int i;
#endif
membufwrite(h->buf, &r->type, 1);
membufwrite(h->buf, &r->g.reclen, 1);
switch (r->type) {
case RDFREC_GENERIC: /* generic */
membufwrite(h->buf, &r->g.data, r->g.reclen);
break;
case RDFREC_RELOC:
case RDFREC_SEGRELOC:
membufwrite(h->buf, &r->r.segment, 1);
membufwrite(h->buf, &r->r.offset, -4);
membufwrite(h->buf, &r->r.length, 1);
membufwrite(h->buf, &r->r.refseg, -2); /* 9 bytes written */
break;
case RDFREC_IMPORT: /* import */
case RDFREC_FARIMPORT:
membufwrite(h->buf, &r->i.flags, 1);
membufwrite(h->buf, &r->i.segment, -2);
membufwrite(h->buf, &r->i.label, strlen(r->i.label) + 1);
break;
case RDFREC_GLOBAL: /* export */
membufwrite(h->buf, &r->e.flags, 1);
membufwrite(h->buf, &r->e.segment, 1);
membufwrite(h->buf, &r->e.offset, -4);
membufwrite(h->buf, &r->e.label, strlen(r->e.label) + 1);
break;
case RDFREC_DLL: /* DLL */
membufwrite(h->buf, &r->d.libname, strlen(r->d.libname) + 1);
break;
case RDFREC_BSS: /* BSS */
membufwrite(h->buf, &r->b.amount, -4);
break;
case RDFREC_MODNAME: /* Module name */
membufwrite(h->buf, &r->m.modname, strlen(r->m.modname) + 1);
break;
default:
#ifdef STRICT_ERRORS
return rdf_errno = RDF_ERR_RECTYPE;
#else
for (i = 0; i < r->g.reclen; i++)
membufwrite(h->buf, r->g.data[i], 1);
#endif
}
return 0;
}
int rdfaddsegment(rdf_headerbuf * h, int32_t seglength)
{
h->nsegments++;
h->seglength += seglength;
return 0;
}
int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
{
int32_t l, l2;
nasm_write(RDOFFId, strlen(RDOFFId), fp);
l = membuflength(h->buf);
l2 = l + 14 + 10 * h->nsegments + h->seglength;
fwriteint32_t(l2, fp); /* object length */
fwriteint32_t(l, fp); /* header length */
membufdump(h->buf, fp);
return 0; /* no error handling in here... CHANGE THIS! */
}
void rdfdoneheader(rdf_headerbuf * h)
{
freemembuf(h->buf);
nasm_free(h);
}