3868470366
serious floating point handling bug
322 lines
7 KiB
C
322 lines
7 KiB
C
/*
|
|
Reading the EM object file
|
|
*/
|
|
|
|
/* $Header$ */
|
|
|
|
#include <stdio.h>
|
|
#include <local.h> /* for VERSION */
|
|
#include <em_spec.h>
|
|
#include <as_spec.h> /* for as_magic */
|
|
|
|
#include "logging.h"
|
|
#include "nofloat.h"
|
|
#include "global.h"
|
|
#include "log.h"
|
|
#include "warn.h"
|
|
#include "mem.h"
|
|
#include "shadow.h"
|
|
#include "read.h"
|
|
#include "text.h"
|
|
|
|
#ifndef NOFLOAT
|
|
extern double str2double();
|
|
#endif NOFLOAT
|
|
|
|
/************************************************************************
|
|
* Read object file contents. *
|
|
************************************************************************
|
|
* *
|
|
* rd_open() - open object file. *
|
|
* rd_header() - read object file header. *
|
|
* rd_text() - read program text. *
|
|
* rd_gda() - read global data area. *
|
|
* rd_proctab() - read procedure descriptors, *
|
|
* rd_close() - close object file. *
|
|
* *
|
|
************************************************************************/
|
|
|
|
/* EM header Part 1 variables */
|
|
|
|
int FLAGS;
|
|
|
|
/* EM header Part 2 variables */
|
|
|
|
size NTEXT;
|
|
size NDATA;
|
|
long NPROC;
|
|
long ENTRY;
|
|
long NLINE;
|
|
size SZDATA;
|
|
|
|
PRIVATE FILE *load_fp; /* Filepointer of load file */
|
|
|
|
PRIVATE ptr rd_repeat();
|
|
PRIVATE ptr rd_descr();
|
|
PRIVATE int rd_byte();
|
|
PRIVATE long rd_int();
|
|
|
|
rd_open(fname)
|
|
char *fname;
|
|
{ /* Open loadfile */
|
|
if ((load_fp = fopen(fname, "r")) == NULL) {
|
|
fatal("Cannot open loadfile '%s'", fname);
|
|
}
|
|
}
|
|
|
|
rd_header()
|
|
{
|
|
/* Part 1 */
|
|
if (rd_int(2L) != as_magic)
|
|
fatal("Bad magic number in loadfile");
|
|
|
|
FLAGS = rd_int(2L);
|
|
|
|
if (rd_int(2L) != 0)
|
|
fatal("Unresolved references in loadfile");
|
|
|
|
if (rd_int(2L) != VERSION)
|
|
fatal("Incorrect version number in loadfile");
|
|
|
|
/* We only allow the following wordsize/pointersize combinations: */
|
|
/* 2/2, 2/4, 4/4 */
|
|
/* A fatal error will be generated if other combinations occur. */
|
|
|
|
wsize = rd_int(2L);
|
|
if (!(wsize == 2 || wsize == 4))
|
|
fatal("Bad wordsize in loadfile");
|
|
|
|
dwsize = 2 * wsize; /* set double wordsize */
|
|
wsizem1 = wsize - 1; /* wordsize - 1 used often */
|
|
|
|
psize = rd_int(2L);
|
|
if (!(psize == 2 || psize == 4) || psize < wsize)
|
|
fatal("Bad pointersize in loadfile");
|
|
if (2 * psize > FRALimit)
|
|
fatal("FRA maximum size too small");
|
|
|
|
rd_int(2L); /* Entry 7 is unused */
|
|
rd_int(2L); /* Entry 8 is unused */
|
|
|
|
/* Part 2 */
|
|
NTEXT = rd_int(psize);
|
|
NDATA = rd_int(psize);
|
|
NPROC = rd_int(psize);
|
|
ENTRY = rd_int(psize);
|
|
if (ENTRY < 0 || ENTRY >= NPROC)
|
|
fatal("Bad entry point");
|
|
NLINE = rd_int(psize);
|
|
if (NLINE == 0) {
|
|
warning(WNLINEZR);
|
|
NLINE = I_MAXS4;
|
|
}
|
|
SZDATA = rd_int(psize);
|
|
|
|
rd_int(psize); /* entry 7 is unused */
|
|
rd_int(psize); /* entry 8 is unused */
|
|
}
|
|
|
|
rd_text()
|
|
{
|
|
fread(text, 1, (int) DB, load_fp);
|
|
}
|
|
|
|
rd_gda()
|
|
{
|
|
register int type, prev_type;
|
|
register ptr pos, prev_pos; /* prev_pos invalid if prev_type==0 */
|
|
register long i;
|
|
|
|
type = prev_type = 0;
|
|
pos = prev_pos = i2p(0);
|
|
for (i = 1; i <= NDATA; i++) {
|
|
type = btol(rd_byte());
|
|
LOG((" r6 rd_gda(), i = %ld, pos = %u", i, pos));
|
|
if (type == 0) {
|
|
/* repetition descriptor */
|
|
register size count = rd_int(psize);
|
|
|
|
LOG((" r6 rd_gda(), case 0: count = %lu", count));
|
|
if (prev_type == 0) {
|
|
fatal("Type 0 initialisation on type 0");
|
|
}
|
|
pos = rd_repeat(pos, count, prev_pos);
|
|
prev_type = 0;
|
|
}
|
|
else {
|
|
/* filling descriptor */
|
|
register size count = btol(rd_byte());
|
|
|
|
LOG((" r6 rd_gda(), case %d: count = %lu",
|
|
type, count));
|
|
prev_pos = pos;
|
|
pos = rd_descr(type, count, prev_pos);
|
|
prev_type = type;
|
|
}
|
|
}
|
|
|
|
/* now protect the LIN and FIL area */
|
|
dt_prot(i2p(0), (long)LINSIZE);
|
|
dt_prot(i2p(4), psize);
|
|
}
|
|
|
|
rd_proctab()
|
|
{
|
|
register long p;
|
|
|
|
init_proctab();
|
|
for (p = 0; p < NPROC; p++) {
|
|
register long nloc = rd_int(psize);
|
|
register ptr ep = i2p(rd_int(psize));
|
|
|
|
add_proc(nloc, ep);
|
|
}
|
|
end_init_proctab();
|
|
}
|
|
|
|
rd_close()
|
|
{
|
|
fclose(load_fp);
|
|
load_fp = 0;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Read functions for several types. *
|
|
************************************************************************
|
|
* *
|
|
* rd_repeat() - repeat the previous initialisation *
|
|
* rd_descr() - read a descriptor *
|
|
* rd_byte() - read one byte, return a int. *
|
|
* rd_int(n) - read n byte integer, return a long. *
|
|
* *
|
|
************************************************************************/
|
|
|
|
/************************************************************************
|
|
* Reading a floating point number *
|
|
* *
|
|
* A double is 8 bytes, so it can contain 4- and 8-byte (EM) *
|
|
* floating point numbers. That's why a 4-byte floating point *
|
|
* number is also stored in a double. *
|
|
************************************************************************/
|
|
|
|
PRIVATE ptr rd_repeat(pos, count, prev_pos)
|
|
ptr pos, prev_pos;
|
|
size count;
|
|
{
|
|
register size diff = pos - prev_pos;
|
|
register size j;
|
|
|
|
for (j = 0; j < count; j++) {
|
|
register long i;
|
|
|
|
for (i = 0; i < diff; i++) {
|
|
data_loc(pos) = data_loc(pos - diff);
|
|
#ifdef LOGGING
|
|
/* copy shadow byte, including protection bit */
|
|
dt_sh(pos) = dt_sh(pos - diff);
|
|
#endif LOGGING
|
|
pos++;
|
|
}
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
PRIVATE ptr rd_descr(type, count, pos)
|
|
int type;
|
|
size count;
|
|
ptr pos;
|
|
{
|
|
register size j;
|
|
char fl_rep[128]; /* fp number representation */
|
|
register int fl_cnt;
|
|
|
|
switch (type) {
|
|
case 1: /* m uninitialized words */
|
|
j = count;
|
|
while (j--) {
|
|
dt_stn(pos, 0L, wsize);
|
|
pos += wsize;
|
|
}
|
|
break;
|
|
case 2: /* m initialized bytes */
|
|
j = count;
|
|
while (j--) {
|
|
dt_stn(pos++, btol(rd_byte()), 1L);
|
|
}
|
|
break;
|
|
case 3: /* m initialized wordsize integers */
|
|
for (j = 0; j < count; j++) {
|
|
dt_stn(pos, rd_int(wsize), wsize);
|
|
pos += wsize;
|
|
}
|
|
break;
|
|
case 4: /* m initialized data pointers */
|
|
for (j = 0; j < count; j++) {
|
|
dt_stdp(pos, i2p(rd_int(psize)));
|
|
pos += psize;
|
|
}
|
|
break;
|
|
case 5: /* m initialized instruction pointers */
|
|
for (j = 0; j < count; j++) {
|
|
dt_stip(pos, i2p(rd_int(psize)));
|
|
pos += psize;
|
|
}
|
|
break;
|
|
case 6: /* initialized integer of size m */
|
|
case 7: /* initialized unsigned int of size m */
|
|
if ((j = count) != 1 && j != 2 && j != 4)
|
|
fatal("Bad integersize during initialisation");
|
|
dt_stn(pos, rd_int(j), j);
|
|
pos += j;
|
|
break;
|
|
case 8: /* initialized float of size m */
|
|
if ((j = count) != 4 && j != 8)
|
|
fatal("Bad floatsize during initialisation");
|
|
/* get fp representation */
|
|
fl_cnt = 0;
|
|
while (fl_rep[fl_cnt] = rd_byte()) {
|
|
fl_cnt++;
|
|
if (fl_cnt >= sizeof (fl_rep)) {
|
|
fatal("Initialized float longer than %d chars",
|
|
sizeof (fl_rep));
|
|
}
|
|
}
|
|
#ifndef NOFLOAT
|
|
/* store the float */
|
|
dt_stf(pos, str2double(fl_rep), j);
|
|
#else NOFLOAT
|
|
/* we cannot store the float */
|
|
warning(WFLINIT);
|
|
#endif NOFLOAT
|
|
pos += j;
|
|
break;
|
|
default:
|
|
fatal("Unknown initializer type in global data.");
|
|
break;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
PRIVATE int rd_byte()
|
|
{
|
|
register int i;
|
|
|
|
if ((i = fgetc(load_fp)) == EOF)
|
|
fatal("EOF reached during initialization");
|
|
return (i);
|
|
}
|
|
|
|
PRIVATE long rd_int(n)
|
|
size n;
|
|
{
|
|
register long l;
|
|
register int i;
|
|
|
|
l = btol(rd_byte());
|
|
for (i = 1; i < n; i++) {
|
|
l |= (btol(rd_byte()) << (i*8));
|
|
}
|
|
return (l);
|
|
}
|
|
|