blob: 841442475fc68564198bf4ad19d6e301223c67e3 [file] [log] [blame]
/* BFD back-end for ieee-695 objects.
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
2000, 2001
Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#define KEEPMINUSPCININST 0
/* IEEE 695 format is a stream of records, which we parse using a simple one-
token (which is one byte in this lexicon) lookahead recursive decent
parser. */
#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "ieee.h"
#include "libieee.h"
#include <ctype.h>
static boolean ieee_write_byte PARAMS ((bfd *, int));
static boolean ieee_write_2bytes PARAMS ((bfd *, int));
static boolean ieee_write_int PARAMS ((bfd *, bfd_vma));
static boolean ieee_write_id PARAMS ((bfd *, const char *));
static boolean ieee_write_expression
PARAMS ((bfd *, bfd_vma, asymbol *, boolean, unsigned int));
static void ieee_write_int5 PARAMS ((bfd_byte *, bfd_vma));
static boolean ieee_write_int5_out PARAMS ((bfd *, bfd_vma));
static boolean ieee_write_section_part PARAMS ((bfd *));
static boolean do_with_relocs PARAMS ((bfd *, asection *));
static boolean do_as_repeat PARAMS ((bfd *, asection *));
static boolean do_without_relocs PARAMS ((bfd *, asection *));
static boolean ieee_write_external_part PARAMS ((bfd *));
static boolean ieee_write_data_part PARAMS ((bfd *));
static boolean ieee_write_debug_part PARAMS ((bfd *));
static boolean ieee_write_me_part PARAMS ((bfd *));
static boolean ieee_write_processor PARAMS ((bfd *));
static boolean ieee_slurp_debug PARAMS ((bfd *));
static boolean ieee_slurp_section_data PARAMS ((bfd *));
/* Functions for writing to ieee files in the strange way that the
standard requires. */
static boolean
ieee_write_byte (abfd, barg)
bfd *abfd;
int barg;
{
bfd_byte byte;
byte = barg;
if (bfd_write ((PTR) &byte, 1, 1, abfd) != 1)
return false;
return true;
}
static boolean
ieee_write_2bytes (abfd, bytes)
bfd *abfd;
int bytes;
{
bfd_byte buffer[2];
buffer[0] = bytes >> 8;
buffer[1] = bytes & 0xff;
if (bfd_write ((PTR) buffer, 1, 2, abfd) != 2)
return false;
return true;
}
static boolean
ieee_write_int (abfd, value)
bfd *abfd;
bfd_vma value;
{
if (value <= 127)
{
if (! ieee_write_byte (abfd, (bfd_byte) value))
return false;
}
else
{
unsigned int length;
/* How many significant bytes ? */
/* FIXME FOR LONGER INTS */
if (value & 0xff000000)
length = 4;
else if (value & 0x00ff0000)
length = 3;
else if (value & 0x0000ff00)
length = 2;
else
length = 1;
if (! ieee_write_byte (abfd,
(bfd_byte) ((int) ieee_number_repeat_start_enum
+ length)))
return false;
switch (length)
{
case 4:
if (! ieee_write_byte (abfd, (bfd_byte) (value >> 24)))
return false;
/* Fall through. */
case 3:
if (! ieee_write_byte (abfd, (bfd_byte) (value >> 16)))
return false;
/* Fall through. */
case 2:
if (! ieee_write_byte (abfd, (bfd_byte) (value >> 8)))
return false;
/* Fall through. */
case 1:
if (! ieee_write_byte (abfd, (bfd_byte) (value)))
return false;
}
}
return true;
}
static boolean
ieee_write_id (abfd, id)
bfd *abfd;
const char *id;
{
size_t length = strlen (id);
if (length <= 127)
{
if (! ieee_write_byte (abfd, (bfd_byte) length))
return false;
}
else if (length < 255)
{
if (! ieee_write_byte (abfd, ieee_extension_length_1_enum)
|| ! ieee_write_byte (abfd, (bfd_byte) length))
return false;
}
else if (length < 65535)
{
if (! ieee_write_byte (abfd, ieee_extension_length_2_enum)
|| ! ieee_write_2bytes (abfd, (int) length))
return false;
}
else
{
(*_bfd_error_handler)
(_("%s: string too long (%d chars, max 65535)"),
bfd_get_filename (abfd), length);
bfd_set_error (bfd_error_invalid_operation);
return false;
}
if (bfd_write ((PTR) id, 1, length, abfd) != length)
return false;
return true;
}
/***************************************************************************
Functions for reading from ieee files in the strange way that the
standard requires:
*/
#define this_byte(ieee) *((ieee)->input_p)
#define next_byte(ieee) ((ieee)->input_p++)
#define this_byte_and_next(ieee) (*((ieee)->input_p++))
static unsigned short
read_2bytes (ieee)
common_header_type *ieee;
{
unsigned char c1 = this_byte_and_next (ieee);
unsigned char c2 = this_byte_and_next (ieee);
return (c1 << 8) | c2;
}
static void
bfd_get_string (ieee, string, length)
common_header_type *ieee;
char *string;
size_t length;
{
size_t i;
for (i = 0; i < length; i++)
{
string[i] = this_byte_and_next (ieee);
}
}
static char *
read_id (ieee)
common_header_type *ieee;
{
size_t length;
char *string;
length = this_byte_and_next (ieee);
if (length <= 0x7f)
{
/* Simple string of length 0 to 127 */
}
else if (length == 0xde)
{
/* Length is next byte, allowing 0..255 */
length = this_byte_and_next (ieee);
}
else if (length == 0xdf)
{
/* Length is next two bytes, allowing 0..65535 */
length = this_byte_and_next (ieee);
length = (length * 256) + this_byte_and_next (ieee);
}
/* Buy memory and read string */
string = bfd_alloc (ieee->abfd, length + 1);
if (!string)
return NULL;
bfd_get_string (ieee, string, length);
string[length] = 0;
return string;
}
static boolean
ieee_write_expression (abfd, value, symbol, pcrel, index)
bfd *abfd;
bfd_vma value;
asymbol *symbol;
boolean pcrel;
unsigned int index;
{
unsigned int term_count = 0;
if (value != 0)
{
if (! ieee_write_int (abfd, value))
return false;
term_count++;
}
if (bfd_is_com_section (symbol->section)
|| bfd_is_und_section (symbol->section))
{
/* Def of a common symbol */
if (! ieee_write_byte (abfd, ieee_variable_X_enum)
|| ! ieee_write_int (abfd, symbol->value))
return false;
term_count++;
}
else if (! bfd_is_abs_section (symbol->section))
{
/* Ref to defined symbol - */
if (symbol->flags & BSF_GLOBAL)
{
if (! ieee_write_byte (abfd, ieee_variable_I_enum)
|| ! ieee_write_int (abfd, symbol->value))
return false;
term_count++;
}
else if (symbol->flags & (BSF_LOCAL | BSF_SECTION_SYM))
{
/* This is a reference to a defined local symbol. We can
easily do a local as a section+offset. */
if (! ieee_write_byte (abfd, ieee_variable_R_enum)
|| ! ieee_write_byte (abfd,
(bfd_byte) (symbol->section->index
+ IEEE_SECTION_NUMBER_BASE)))
return false;
term_count++;
if (symbol->value != 0)
{
if (! ieee_write_int (abfd, symbol->value))
return false;
term_count++;
}
}
else
{
(*_bfd_error_handler)
(_("%s: unrecognized symbol `%s' flags 0x%x"),
bfd_get_filename (abfd), bfd_asymbol_name (symbol),
symbol->flags);
bfd_set_error (bfd_error_invalid_operation);
return false;
}
}
if (pcrel)
{
/* subtract the pc from here by asking for PC of this section*/
if (! ieee_write_byte (abfd, ieee_variable_P_enum)
|| ! ieee_write_byte (abfd,
(bfd_byte) (index + IEEE_SECTION_NUMBER_BASE))
|| ! ieee_write_byte (abfd, ieee_function_minus_enum))
return false;
}
/* Handle the degenerate case of a 0 address. */
if (term_count == 0)
{
if (! ieee_write_int (abfd, 0))
return false;
}
while (term_count > 1)
{
if (! ieee_write_byte (abfd, ieee_function_plus_enum))
return false;
term_count--;
}
return true;
}
/*****************************************************************************/
/*
writes any integer into the buffer supplied and always takes 5 bytes
*/
static void
ieee_write_int5 (buffer, value)
bfd_byte *buffer;
bfd_vma value;
{
buffer[0] = (bfd_byte) ieee_number_repeat_4_enum;
buffer[1] = (value >> 24) & 0xff;
buffer[2] = (value >> 16) & 0xff;
buffer[3] = (value >> 8) & 0xff;
buffer[4] = (value >> 0) & 0xff;
}
static boolean
ieee_write_int5_out (abfd, value)
bfd *abfd;
bfd_vma value;
{
bfd_byte b[5];
ieee_write_int5 (b, value);
if (bfd_write ((PTR) b, 1, 5, abfd) != 5)
return false;
return true;
}
static boolean
parse_int (ieee, value_ptr)
common_header_type *ieee;
bfd_vma *value_ptr;
{
int value = this_byte (ieee);
int result;
if (value >= 0 && value <= 127)
{
*value_ptr = value;
next_byte (ieee);
return true;
}
else if (value >= 0x80 && value <= 0x88)
{
unsigned int count = value & 0xf;
result = 0;
next_byte (ieee);
while (count)
{
result = (result << 8) | this_byte_and_next (ieee);
count--;
}
*value_ptr = result;
return true;
}
return false;
}
static int
parse_i (ieee, ok)
common_header_type *ieee;
boolean *ok;
{
bfd_vma x;
*ok = parse_int (ieee, &x);
return x;
}
static bfd_vma
must_parse_int (ieee)
common_header_type *ieee;
{
bfd_vma result;
BFD_ASSERT (parse_int (ieee, &result) == true);
return result;
}
typedef struct
{
bfd_vma value;
asection *section;
ieee_symbol_index_type symbol;
} ieee_value_type;
#if KEEPMINUSPCININST
#define SRC_MASK(arg) arg
#define PCREL_OFFSET false
#else
#define SRC_MASK(arg) 0
#define PCREL_OFFSET true
#endif
static reloc_howto_type abs32_howto =
HOWTO (1,
0,
2,
32,
false,
0,
complain_overflow_bitfield,
0,
"abs32",
true,
0xffffffff,
0xffffffff,
false);
static reloc_howto_type abs16_howto =
HOWTO (1,
0,
1,
16,
false,
0,
complain_overflow_bitfield,
0,
"abs16",
true,
0x0000ffff,
0x0000ffff,
false);
static reloc_howto_type abs8_howto =
HOWTO (1,
0,
0,
8,
false,
0,
complain_overflow_bitfield,
0,
"abs8",
true,
0x000000ff,
0x000000ff,
false);
static reloc_howto_type rel32_howto =
HOWTO (1,
0,
2,
32,
true,
0,
complain_overflow_signed,
0,
"rel32",
true,
SRC_MASK (0xffffffff),
0xffffffff,
PCREL_OFFSET);
static reloc_howto_type rel16_howto =
HOWTO (1,
0,
1,
16,
true,
0,
complain_overflow_signed,
0,
"rel16",
true,
SRC_MASK (0x0000ffff),
0x0000ffff,
PCREL_OFFSET);
static reloc_howto_type rel8_howto =
HOWTO (1,
0,
0,
8,
true,
0,
complain_overflow_signed,
0,
"rel8",
true,
SRC_MASK (0x000000ff),
0x000000ff,
PCREL_OFFSET);
static ieee_symbol_index_type NOSYMBOL = {0, 0};
static void
parse_expression (ieee, value, symbol, pcrel, extra, section)
ieee_data_type *ieee;
bfd_vma *value;
ieee_symbol_index_type *symbol;
boolean *pcrel;
unsigned int *extra;
asection **section;
{
#define POS sp[1]
#define TOS sp[0]
#define NOS sp[-1]
#define INC sp++;
#define DEC sp--;
boolean loop = true;
ieee_value_type stack[10];
/* The stack pointer always points to the next unused location */
#define PUSH(x,y,z) TOS.symbol=x;TOS.section=y;TOS.value=z;INC;
#define POP(x,y,z) DEC;x=TOS.symbol;y=TOS.section;z=TOS.value;
ieee_value_type *sp = stack;
while (loop)
{
switch (this_byte (&(ieee->h)))
{
case ieee_variable_P_enum:
/* P variable, current program counter for section n */
{
int section_n;
next_byte (&(ieee->h));
*pcrel = true;
section_n = must_parse_int (&(ieee->h));
PUSH (NOSYMBOL, bfd_abs_section_ptr, 0);
break;
}
case ieee_variable_L_enum:
/* L variable address of section N */
next_byte (&(ieee->h));
PUSH (NOSYMBOL, ieee->section_table[must_parse_int (&(ieee->h))], 0);
break;
case ieee_variable_R_enum:
/* R variable, logical address of section module */
/* FIXME, this should be different to L */
next_byte (&(ieee->h));
PUSH (NOSYMBOL, ieee->section_table[must_parse_int (&(ieee->h))], 0);
break;
case ieee_variable_S_enum:
/* S variable, size in MAUS of section module */
next_byte (&(ieee->h));
PUSH (NOSYMBOL,
0,
ieee->section_table[must_parse_int (&(ieee->h))]->_raw_size);
break;
case ieee_variable_I_enum:
/* Push the address of variable n */
{
ieee_symbol_index_type sy;
next_byte (&(ieee->h));
sy.index = (int) must_parse_int (&(ieee->h));
sy.letter = 'I';
PUSH (sy, bfd_abs_section_ptr, 0);
}
break;
case ieee_variable_X_enum:
/* Push the address of external variable n */
{
ieee_symbol_index_type sy;
next_byte (&(ieee->h));
sy.index = (int) (must_parse_int (&(ieee->h)));
sy.letter = 'X';
PUSH (sy, bfd_und_section_ptr, 0);
}
break;
case ieee_function_minus_enum:
{
bfd_vma value1, value2;
asection *section1, *section_dummy;
ieee_symbol_index_type sy;
next_byte (&(ieee->h));
POP (sy, section1, value1);
POP (sy, section_dummy, value2);
PUSH (sy, section1 ? section1 : section_dummy, value2 - value1);
}
break;
case ieee_function_plus_enum:
{
bfd_vma value1, value2;
asection *section1;
asection *section2;
ieee_symbol_index_type sy1;
ieee_symbol_index_type sy2;
next_byte (&(ieee->h));
POP (sy1, section1, value1);
POP (sy2, section2, value2);
PUSH (sy1.letter ? sy1 : sy2,
bfd_is_abs_section (section1) ? section2 : section1,
value1 + value2);
}
break;
default:
{
bfd_vma va;
BFD_ASSERT (this_byte (&(ieee->h)) < (int) ieee_variable_A_enum
|| this_byte (&(ieee->h)) > (int) ieee_variable_Z_enum);
if (parse_int (&(ieee->h), &va))
{
PUSH (NOSYMBOL, bfd_abs_section_ptr, va);
}
else
{
/*
Thats all that we can understand. As far as I can see
there is a bug in the Microtec IEEE output which I'm
using to scan, whereby the comma operator is omitted
sometimes in an expression, giving expressions with too
many terms. We can tell if that's the case by ensuring
that sp == stack here. If not, then we've pushed
something too far, so we keep adding. */
while (sp != stack + 1)
{
asection *section1;
ieee_symbol_index_type sy1;
POP (sy1, section1, *extra);
}
{
asection *dummy;
POP (*symbol, dummy, *value);
if (section)
*section = dummy;
}
loop = false;
}
}
}
}
}
#define ieee_seek(abfd, offset) \
IEEE_DATA(abfd)->h.input_p = IEEE_DATA(abfd)->h.first_byte + offset
#define ieee_pos(abfd) \
(IEEE_DATA(abfd)->h.input_p - IEEE_DATA(abfd)->h.first_byte)
static unsigned int last_index;
static char last_type; /* is the index for an X or a D */
static ieee_symbol_type *
get_symbol (abfd,
ieee,
last_symbol,
symbol_count,
pptr,
max_index,
this_type
)
bfd *abfd ATTRIBUTE_UNUSED;
ieee_data_type *ieee;
ieee_symbol_type *last_symbol;
unsigned int *symbol_count;
ieee_symbol_type ***pptr;
unsigned int *max_index;
char this_type
;
{
/* Need a new symbol */
unsigned int new_index = must_parse_int (&(ieee->h));
if (new_index != last_index || this_type != last_type)
{
ieee_symbol_type *new_symbol = (ieee_symbol_type *) bfd_alloc (ieee->h.abfd,
sizeof (ieee_symbol_type));
if (!new_symbol)
return NULL;
new_symbol->index = new_index;
last_index = new_index;
(*symbol_count)++;
**pptr = new_symbol;
*pptr = &new_symbol->next;
if (new_index > *max_index)
{
*max_index = new_index;
}
last_type = this_type;
new_symbol->symbol.section = bfd_abs_section_ptr;
return new_symbol;
}
return last_symbol;
}
static boolean
ieee_slurp_external_symbols (abfd)
bfd *abfd;
{
ieee_data_type *ieee = IEEE_DATA (abfd);
file_ptr offset = ieee->w.r.external_part;
ieee_symbol_type **prev_symbols_ptr = &ieee->external_symbols;
ieee_symbol_type **prev_reference_ptr = &ieee->external_reference;
ieee_symbol_type *symbol = (ieee_symbol_type *) NULL;
unsigned int symbol_count = 0;
boolean loop = true;
last_index = 0xffffff;
ieee->symbol_table_full = true;
ieee_seek (abfd, offset);
while (loop)
{
switch (this_byte (&(ieee->h)))
{
case ieee_nn_record:
next_byte (&(ieee->h));
symbol = get_symbol (abfd, ieee, symbol, &symbol_count,
&prev_symbols_ptr,
&ieee->external_symbol_max_index, 'I');
if (symbol == NULL)
return false;
symbol->symbol.the_bfd = abfd;
symbol->symbol.name = read_id (&(ieee->h));
symbol->symbol.udata.p = (PTR) NULL;
symbol->symbol.flags = BSF_NO_FLAGS;
break;
case ieee_external_symbol_enum:
next_byte (&(ieee->h));
symbol = get_symbol (abfd, ieee, symbol, &symbol_count,
&prev_symbols_ptr,
&ieee->external_symbol_max_index, 'D');
if (symbol == NULL)
return false;
BFD_ASSERT (symbol->index >= ieee->external_symbol_min_index);
symbol->symbol.the_bfd = abfd;
symbol->symbol.name = read_id (&(ieee->h));
symbol->symbol.udata.p = (PTR) NULL;
symbol->symbol.flags = BSF_NO_FLAGS;
break;
case ieee_attribute_record_enum >> 8:
{
unsigned int symbol_name_index;
unsigned int symbol_type_index;
unsigned int symbol_attribute_def;
bfd_vma value;
switch (read_2bytes (ieee))
{
case ieee_attribute_record_enum:
symbol_name_index = must_parse_int (&(ieee->h));
symbol_type_index = must_parse_int (&(ieee->h));
symbol_attribute_def = must_parse_int (&(ieee->h));
switch (symbol_attribute_def)
{
case 8:
case 19:
parse_int (&ieee->h, &value);
break;
default:
(*_bfd_error_handler)
(_("%s: unimplemented ATI record %u for symbol %u"),
bfd_get_filename (abfd), symbol_attribute_def,
symbol_name_index);
bfd_set_error (bfd_error_bad_value);
return false;
break;
}
break;
case ieee_external_reference_info_record_enum:
/* Skip over ATX record. */
parse_int (&(ieee->h), &value);
parse_int (&(ieee->h), &value);
parse_int (&(ieee->h), &value);
parse_int (&(ieee->h), &value);
break;
case ieee_atn_record_enum:
/* We may get call optimization information here,
which we just ignore. The format is
{$F1}${CE}{index}{$00}{$3F}{$3F}{#_of_ASNs} */
parse_int (&ieee->h, &value);
parse_int (&ieee->h, &value);
parse_int (&ieee->h, &value);
if (value != 0x3f)
{
(*_bfd_error_handler)
(_("%s: unexpected ATN type %d in external part"),
bfd_get_filename (abfd), (int) value);
bfd_set_error (bfd_error_bad_value);
return false;
}
parse_int (&ieee->h, &value);
parse_int (&ieee->h, &value);
while (value > 0)
{
bfd_vma val1;
--value;
switch (read_2bytes (ieee))
{
case ieee_asn_record_enum:
parse_int (&ieee->h, &val1);
parse_int (&ieee->h, &val1);
break;
default:
(*_bfd_error_handler)
(_("%s: unexpected type after ATN"),
bfd_get_filename (abfd));
bfd_set_error (bfd_error_bad_value);
return false;
}
}
}
}
break;
case ieee_value_record_enum >> 8:
{
unsigned int symbol_name_index;
ieee_symbol_index_type symbol_ignore;
boolean pcrel_ignore;
unsigned int extra;
next_byte (&(ieee->h));
next_byte (&(ieee->h));
symbol_name_index = must_parse_int (&(ieee->h));
parse_expression (ieee,
&symbol->symbol.value,
&symbol_ignore,
&pcrel_ignore,
&extra,
&symbol->symbol.section);
/* Fully linked IEEE-695 files tend to give every symbol
an absolute value. Try to convert that back into a
section relative value. FIXME: This won't always to
the right thing. */
if (bfd_is_abs_section (symbol->symbol.section)
&& (abfd->flags & HAS_RELOC) == 0)
{
bfd_vma val;
asection *s;
val = symbol->symbol.value;
for (s = abfd->sections; s != NULL; s = s->next)
{
if (val >= s->vma && val < s->vma + s->_raw_size)
{
symbol->symbol.section = s;
symbol->symbol.value -= s->vma;
break;
}
}
}
symbol->symbol.flags = BSF_GLOBAL | BSF_EXPORT;
}
break;
case ieee_weak_external_reference_enum:
{
bfd_vma size;
bfd_vma value;
next_byte (&(ieee->h));
/* Throw away the external reference index */
(void) must_parse_int (&(ieee->h));
/* Fetch the default size if not resolved */
size = must_parse_int (&(ieee->h));
/* Fetch the defautlt value if available */
if (parse_int (&(ieee->h), &value) == false)
{
value = 0;
}
/* This turns into a common */
symbol->symbol.section = bfd_com_section_ptr;
symbol->symbol.value = size;
}
break;
case ieee_external_reference_enum:
next_byte (&(ieee->h));
symbol = get_symbol (abfd, ieee, symbol, &symbol_count,
&prev_reference_ptr,
&ieee->external_reference_max_index, 'X');
if (symbol == NULL)
return false;
symbol->symbol.the_bfd = abfd;
symbol->symbol.name = read_id (&(ieee->h));
symbol->symbol.udata.p = (PTR) NULL;
symbol->symbol.section = bfd_und_section_ptr;
symbol->symbol.value = (bfd_vma) 0;
symbol->symbol.flags = 0;
BFD_ASSERT (symbol->index >= ieee->external_reference_min_index);
break;
default:
loop = false;
}
}
if (ieee->external_symbol_max_index != 0)
{
ieee->external_symbol_count =
ieee->external_symbol_max_index -
ieee->external_symbol_min_index + 1;
}
else
{
ieee->external_symbol_count = 0;
}
if (ieee->external_reference_max_index != 0)
{
ieee->external_reference_count =
ieee->external_reference_max_index -
ieee->external_reference_min_index + 1;
}
else
{
ieee->external_reference_count = 0;
}
abfd->symcount =
ieee->external_reference_count + ieee->external_symbol_count;
if (symbol_count != abfd->symcount)
{
/* There are gaps in the table -- */
ieee->symbol_table_full = false;
}
*prev_symbols_ptr = (ieee_symbol_type *) NULL;
*prev_reference_ptr = (ieee_symbol_type *) NULL;
return true;
}
static boolean
ieee_slurp_symbol_table (abfd)
bfd *abfd;
{
if (IEEE_DATA (abfd)->read_symbols == false)
{
if (! ieee_slurp_external_symbols (abfd))
return false;
IEEE_DATA (abfd)->read_symbols = true;
}
return true;
}
long
ieee_get_symtab_upper_bound (abfd)
bfd *abfd;
{
if (! ieee_slurp_symbol_table (abfd))
return -1;
return (abfd->symcount != 0) ?
(abfd->symcount + 1) * (sizeof (ieee_symbol_type *)) : 0;
}
/*
Move from our internal lists to the canon table, and insert in
symbol index order
*/
extern const bfd_target ieee_vec;
long
ieee_get_symtab (abfd, location)
bfd *abfd;
asymbol **location;
{
ieee_symbol_type *symp;
static bfd dummy_bfd;
static asymbol empty_symbol =
{
&dummy_bfd,
" ieee empty",
(symvalue) 0,
BSF_DEBUGGING,
bfd_abs_section_ptr
#ifdef __STDC__
/* K&R compilers can't initialise unions. */
, { 0 }
#endif
};
if (abfd->symcount)
{
ieee_data_type *ieee = IEEE_DATA (abfd);
dummy_bfd.xvec = &ieee_vec;
if (! ieee_slurp_symbol_table (abfd))
return -1;
if (ieee->symbol_table_full == false)
{
/* Arrgh - there are gaps in the table, run through and fill them */
/* up with pointers to a null place */
unsigned int i;
for (i = 0; i < abfd->symcount; i++)
{
location[i] = &empty_symbol;
}
}
ieee->external_symbol_base_offset = -ieee->external_symbol_min_index;
for (symp = IEEE_DATA (abfd)->external_symbols;
symp != (ieee_symbol_type *) NULL;
symp = symp->next)
{
/* Place into table at correct index locations */
location[symp->index + ieee->external_symbol_base_offset] = &symp->symbol;
}
/* The external refs are indexed in a bit */
ieee->external_reference_base_offset =
-ieee->external_reference_min_index + ieee->external_symbol_count;
for (symp = IEEE_DATA (abfd)->external_reference;
symp != (ieee_symbol_type *) NULL;
symp = symp->next)
{
location[symp->index + ieee->external_reference_base_offset] =
&symp->symbol;
}
}
if (abfd->symcount)
{
location[abfd->symcount] = (asymbol *) NULL;
}
return abfd->symcount;
}
static asection *
get_section_entry (abfd, ieee, index)
bfd *abfd;
ieee_data_type *ieee;
unsigned int index;
{
if (index >= ieee->section_table_size)
{
unsigned int c, i;
asection **n;
c = ieee->section_table_size;
if (c == 0)
c = 20;
while (c <= index)
c *= 2;
n = ((asection **)
bfd_realloc (ieee->section_table, c * sizeof (asection *)));
if (n == NULL)
return NULL;
for (i = ieee->section_table_size; i < c; i++)
n[i] = NULL;
ieee->section_table = n;
ieee->section_table_size = c;
}
if (ieee->section_table[index] == (asection *) NULL)
{
char *tmp = bfd_alloc (abfd, 11);
asection *section;
if (!tmp)
return NULL;
sprintf (tmp, " fsec%4d", index);
section = bfd_make_section (abfd, tmp);
ieee->section_table[index] = section;
section->flags = SEC_NO_FLAGS;
section->target_index = index;
ieee->section_table[index] = section;
}
return ieee->section_table[index];
}
static void
ieee_slurp_sections (abfd)
bfd *abfd;
{
ieee_data_type *ieee = IEEE_DATA (abfd);
file_ptr offset = ieee->w.r.section_part;
asection *section = (asection *) NULL;
char *name;
if (offset != 0)
{
bfd_byte section_type[3];
ieee_seek (abfd, offset);
while (true)
{
switch (this_byte (&(ieee->h)))
{
case ieee_section_type_enum:
{
unsigned int section_index;
next_byte (&(ieee->h));
section_index = must_parse_int (&(ieee->h));
section = get_section_entry (abfd, ieee, section_index);
section_type[0] = this_byte_and_next (&(ieee->h));
/* Set minimal section attributes. Attributes are
extended later, based on section contents. */
switch (section_type[0])
{
case 0xC1:
/* Normal attributes for absolute sections */
section_type[1] = this_byte (&(ieee->h));
section->flags = SEC_ALLOC;
switch (section_type[1])
{
case 0xD3: /* AS Absolute section attributes */
next_byte (&(ieee->h));
section_type[2] = this_byte (&(ieee->h));
switch (section_type[2])
{
case 0xD0:
/* Normal code */
next_byte (&(ieee->h));
section->flags |= SEC_CODE;
break;
case 0xC4:
/* Normal data */
next_byte (&(ieee->h));
section->flags |= SEC_DATA;
break;
case 0xD2:
next_byte (&(ieee->h));
/* Normal rom data */
section->flags |= SEC_ROM | SEC_DATA;
break;
default:
break;
}
}
break;
case 0xC3: /* Named relocatable sections (type C) */
section_type[1] = this_byte (&(ieee->h));
section->flags = SEC_ALLOC;
switch (section_type[1])
{
case 0xD0: /* Normal code (CP) */
next_byte (&(ieee->h));
section->flags |= SEC_CODE;
break;
case 0xC4: /* Normal data (CD) */
next_byte (&(ieee->h));
section->flags |= SEC_DATA;
break;
case 0xD2: /* Normal rom data (CR) */
next_byte (&(ieee->h));
section->flags |= SEC_ROM | SEC_DATA;
break;
default:
break;
}
}
/* Read section name, use it if non empty. */
name = read_id (&ieee->h);
if (name[0])
section->name = name;
/* Skip these fields, which we don't care about */
{
bfd_vma parent, brother, context;
parse_int (&(ieee->h), &parent);
parse_int (&(ieee->h), &brother);
parse_int (&(ieee->h), &context);
}
}
break;
case ieee_section_alignment_enum:
{
unsigned int section_index;
bfd_vma value;
asection *section;
next_byte (&(ieee->h));
section_index = must_parse_int (&ieee->h);
section = get_section_entry (abfd, ieee, section_index);
if (section_index > ieee->section_count)
{
ieee->section_count = section_index;
}
section->alignment_power =
bfd_log2 (must_parse_int (&ieee->h));
(void) parse_int (&(ieee->h), &value);
}
break;
case ieee_e2_first_byte_enum:
{
ieee_record_enum_type t = (ieee_record_enum_type) (read_2bytes (&(ieee->h)));
switch (t)
{
case ieee_section_size_enum:
section = ieee->section_table[must_parse_int (&(ieee->h))];
section->_raw_size = must_parse_int (&(ieee->h));
break;
case ieee_physical_region_size_enum:
section = ieee->section_table[must_parse_int (&(ieee->h))];
section->_raw_size = must_parse_int (&(ieee->h));
break;
case ieee_region_base_address_enum:
section = ieee->section_table[must_parse_int (&(ieee->h))];
section->vma = must_parse_int (&(ieee->h));
section->lma = section->vma;
break;
case ieee_mau_size_enum:
must_parse_int (&(ieee->h));
must_parse_int (&(ieee->h));
break;
case ieee_m_value_enum:
must_parse_int (&(ieee->h));
must_parse_int (&(ieee->h));
break;
case ieee_section_base_address_enum:
section = ieee->section_table[must_parse_int (&(ieee->h))];
section->vma = must_parse_int (&(ieee->h));
section->lma = section->vma;
break;
case ieee_section_offset_enum:
(void) must_parse_int (&(ieee->h));
(void) must_parse_int (&(ieee->h));
break;
default:
return;
}
}
break;
default:
return;
}
}
}
}
/* Make a section for the debugging information, if any. We don't try
to interpret the debugging information; we just point the section
at the area in the file so that program which understand can dig it
out. */
static boolean
ieee_slurp_debug (abfd)
bfd *abfd;
{
ieee_data_type *ieee = IEEE_DATA (abfd);
asection *sec;
file_ptr debug_end;
if (ieee->w.r.debug_information_part == 0)
return true;
sec = bfd_make_section (abfd, ".debug");
if (sec == NULL)
return false;
sec->flags |= SEC_DEBUGGING | SEC_HAS_CONTENTS;
sec->filepos = ieee->w.r.debug_information_part;
debug_end = ieee->w.r.data_part;
if (debug_end == 0)
debug_end = ieee->w.r.trailer_part;
if (debug_end == 0)
debug_end = ieee->w.r.me_record;
sec->_raw_size = debug_end - ieee->w.r.debug_information_part;
return true;
}
/***********************************************************************
* archive stuff
*/
const bfd_target *
ieee_archive_p (abfd)
bfd *abfd;
{
char *library;
unsigned int i;
unsigned char buffer[512];
file_ptr buffer_offset = 0;
ieee_ar_data_type *save = abfd->tdata.ieee_ar_data;
ieee_ar_data_type *ieee;
unsigned int alc_elts;
ieee_ar_obstack_type *elts = NULL;
abfd->tdata.ieee_ar_data =
(ieee_ar_data_type *) bfd_alloc (abfd, sizeof (ieee_ar_data_type));
if (!abfd->tdata.ieee_ar_data)
goto error_return;
ieee = IEEE_AR_DATA (abfd);
/* FIXME: Check return value. I'm not sure whether it needs to read
the entire buffer or not. */
bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd);
ieee->h.first_byte = buffer;
ieee->h.input_p = buffer;
ieee->h.abfd = abfd;
if (this_byte (&(ieee->h)) != Module_Beginning)
goto got_wrong_format_error;
next_byte (&(ieee->h));
library = read_id (&(ieee->h));
if (strcmp (library, "LIBRARY") != 0)
goto got_wrong_format_error;
/* Throw away the filename. */
read_id (&(ieee->h));
ieee->element_count = 0;
ieee->element_index = 0;
next_byte (&(ieee->h)); /* Drop the ad part. */
must_parse_int (&(ieee->h)); /* And the two dummy numbers. */
must_parse_int (&(ieee->h));
alc_elts = 10;
elts = (ieee_ar_obstack_type *) bfd_malloc (alc_elts * sizeof *elts);
if (elts == NULL)
goto error_return;
/* Read the index of the BB table. */
while (1)
{
int rec;
ieee_ar_obstack_type *t;
rec = read_2bytes (&(ieee->h));
if (rec != (int) ieee_assign_value_to_variable_enum)
break;
if (ieee->element_count >= alc_elts)
{
ieee_ar_obstack_type *n;
alc_elts *= 2;
n = ((ieee_ar_obstack_type *)
bfd_realloc (elts, alc_elts * sizeof *elts));
if (n == NULL)
goto error_return;
elts = n;
}
t = &elts[ieee->element_count];
ieee->element_count++;
must_parse_int (&(ieee->h));
t->file_offset = must_parse_int (&(ieee->h));
t->abfd = (bfd *) NULL;
/* Make sure that we don't go over the end of the buffer. */
if ((size_t) ieee_pos (abfd) > sizeof (buffer) / 2)
{
/* Past half way, reseek and reprime. */
buffer_offset += ieee_pos (abfd);
if (bfd_seek (abfd, buffer_offset, SEEK_SET) != 0)
goto error_return;
/* FIXME: Check return value. I'm not sure whether it needs
to read the entire buffer or not. */
bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd);
ieee->h.first_byte = buffer;
ieee->h.input_p = buffer;
}
}
ieee->elements = ((ieee_ar_obstack_type *)
bfd_alloc (abfd,
ieee->element_count * sizeof *ieee->elements));
if (ieee->elements == NULL)
goto error_return;
memcpy (ieee->elements, elts,
ieee->element_count * sizeof *ieee->elements);
free (elts);
elts = NULL;
/* Now scan the area again, and replace BB offsets with file offsets. */
for (i = 2; i < ieee->element_count; i++)
{
if (bfd_seek (abfd, ieee->elements[i].file_offset, SEEK_SET) != 0)
goto error_return;
/* FIXME: Check return value. I'm not sure whether it needs to
read the entire buffer or not. */
bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd);
ieee->h.first_byte = buffer;
ieee->h.input_p = buffer;
next_byte (&(ieee->h)); /* Drop F8. */
next_byte (&(ieee->h)); /* Drop 14. */
must_parse_int (&(ieee->h)); /* Drop size of block. */
if (must_parse_int (&(ieee->h)) != 0)
/* This object has been deleted. */
ieee->elements[i].file_offset = 0;
else
ieee->elements[i].file_offset = must_parse_int (&(ieee->h));
}
/* abfd->has_armap = ;*/
return abfd->xvec;
got_wrong_format_error:
bfd_release (abfd, ieee);
abfd->tdata.ieee_ar_data = save;
bfd_set_error (bfd_error_wrong_format);
error_return:
if (elts != NULL)
free (elts);
return NULL;
}
static boolean
ieee_mkobject (abfd)
bfd *abfd;
{
abfd->tdata.ieee_data = (ieee_data_type *) bfd_zalloc (abfd, sizeof (ieee_data_type));
return abfd->tdata.ieee_data ? true : false;
}
const bfd_target *
ieee_object_p (abfd)
bfd *abfd;
{
char *processor;
unsigned int part;
ieee_data_type *ieee;
unsigned char buffer[300];
ieee_data_type *save = IEEE_DATA (abfd);
abfd->tdata.ieee_data = 0;
ieee_mkobject (abfd);
ieee = IEEE_DATA (abfd);
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
goto fail;
/* Read the first few bytes in to see if it makes sense */
/* FIXME: Check return value. I'm not sure whether it needs to read
the entire buffer or not. */
bfd_read ((PTR) buffer, 1, sizeof (buffer), abfd);
ieee->h.input_p = buffer;
if (this_byte_and_next (&(ieee->h)) != Module_Beginning)
goto got_wrong_format;
ieee->read_symbols = false;
ieee->read_data = false;
ieee->section_count = 0;
ieee->external_symbol_max_index = 0;
ieee->external_symbol_min_index = IEEE_PUBLIC_BASE;
ieee->external_reference_min_index = IEEE_REFERENCE_BASE;
ieee->external_reference_max_index = 0;
ieee->h.abfd = abfd;
ieee->section_table = NULL;
ieee->section_table_size = 0;
processor = ieee->mb.processor = read_id (&(ieee->h));
if (strcmp (processor, "LIBRARY") == 0)
goto got_wrong_format;
ieee->mb.module_name = read_id (&(ieee->h));
if (abfd->filename == (CONST char *) NULL)
{
abfd->filename = ieee->mb.module_name;
}
/* Determine the architecture and machine type of the object file.
*/
{
const bfd_arch_info_type *arch;
char family[10];
/* IEEE does not specify the format of the processor identificaton
string, so the compiler is free to put in it whatever it wants.
We try here to recognize different processors belonging to the
m68k family. Code for other processors can be added here. */
if ((processor[0] == '6') && (processor[1] == '8'))
{
if (processor[2] == '3') /* 683xx integrated processors */
{
switch (processor[3])
{
case '0': /* 68302, 68306, 68307 */
case '2': /* 68322, 68328 */
case '5': /* 68356 */
strcpy (family, "68000"); /* MC68000-based controllers */
break;
case '3': /* 68330, 68331, 68332, 68333,
68334, 68335, 68336, 68338 */
case '6': /* 68360 */
case '7': /* 68376 */
strcpy (family, "68332"); /* CPU32 and CPU32+ */
break;
case '4':
if (processor[4] == '9') /* 68349 */
strcpy (family, "68030"); /* CPU030 */
else /* 68340, 68341 */
strcpy (family, "68332"); /* CPU32 and CPU32+ */
break;
default: /* Does not exist yet */
strcpy (family, "68332"); /* Guess it will be CPU32 */
}
}
else if (toupper (processor[3]) == 'F') /* 68F333 */
strcpy (family, "68332"); /* CPU32 */
else if ((toupper (processor[3]) == 'C') /* Embedded controllers */
&& ((toupper (processor[2]) == 'E')
|| (toupper (processor[2]) == 'H')
|| (toupper (processor[2]) == 'L')))
{
strcpy (family, "68");
strncat (family, processor + 4, 7);
family[9] = '\0';
}
else /* "Regular" processors */
{
strncpy (family, processor, 9);
family[9] = '\0';
}
}
else if ((strncmp (processor, "cpu32", 5) == 0) /* CPU32 and CPU32+ */
|| (strncmp (processor, "CPU32", 5) == 0))
strcpy (family, "68332");
else
{
strncpy (family, processor, 9);
family[9] = '\0';
}
arch = bfd_scan_arch (family);
if (arch == 0)
goto got_wrong_format;
abfd->arch_info = arch;
}
if (this_byte (&(ieee->h)) != (int) ieee_address_descriptor_enum)
{
goto fail;
}
next_byte (&(ieee->h));
if (parse_int (&(ieee->h), &ieee->ad.number_of_bits_mau) == false)
{
goto fail;
}
if (parse_int (&(ieee->h), &ieee->ad.number_of_maus_in_address) == false)
{
goto fail;
}
/* If there is a byte order info, take it */
if (this_byte (&(ieee->h)) == (int) ieee_variable_L_enum ||
this_byte (&(ieee->h)) == (int) ieee_variable_M_enum)
next_byte (&(ieee->h));
for (part = 0; part < N_W_VARIABLES; part++)
{
boolean ok;
if (read_2bytes (&(ieee->h)) != (int) ieee_assign_value_to_variable_enum)
{
goto fail;
}
if (this_byte_and_next (&(ieee->h)) != part)
{
goto fail;
}
ieee->w.offset[part] = parse_i (&(ieee->h), &ok);
if (ok == false)
{
goto fail;
}
}
if (ieee->w.r.external_part != 0)
abfd->flags = HAS_SYMS;
/* By now we know that this is a real IEEE file, we're going to read
the whole thing into memory so that we can run up and down it
quickly. We can work out how big the file is from the trailer
record */
IEEE_DATA (abfd)->h.first_byte =
(unsigned char *) bfd_alloc (ieee->h.abfd, ieee->w.r.me_record + 1);
if (!IEEE_DATA (abfd)->h.first_byte)
goto fail;
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
goto fail;
/* FIXME: Check return value. I'm not sure whether it needs to read
the entire buffer or not. */
bfd_read ((PTR) (IEEE_DATA (abfd)->h.first_byte), 1,
ieee->w.r.me_record + 1, abfd);
ieee_slurp_sections (abfd);
if (! ieee_slurp_debug (abfd))
goto fail;
/* Parse section data to activate file and section flags implied by
section contents. */
if (! ieee_slurp_section_data (abfd))
goto fail;
return abfd->xvec;
got_wrong_format:
bfd_set_error (bfd_error_wrong_format);
fail:
(void) bfd_release (abfd, ieee);
abfd->tdata.ieee_data = save;
return (const bfd_target *) NULL;
}
void
ieee_get_symbol_info (ignore_abfd, symbol, ret)
bfd *ignore_abfd ATTRIBUTE_UNUSED;
asymbol *symbol;
symbol_info *ret;
{
bfd_symbol_info (symbol, ret);
if (symbol->name[0] == ' ')
ret->name = "* empty table entry ";
if (!symbol->section)
ret->type = (symbol->flags & BSF_LOCAL) ? 'a' : 'A';
}
void
ieee_print_symbol (ignore_abfd, afile, symbol, how)
bfd *ignore_abfd ATTRIBUTE_UNUSED;
PTR afile;
asymbol *symbol;
bfd_print_symbol_type how;
{
FILE *file = (FILE *) afile;
switch (how)
{
case bfd_print_symbol_name:
fprintf (file, "%s", symbol->name);
break;
case bfd_print_symbol_more:
#if 0
fprintf (file, "%4x %2x", aout_symbol (symbol)->desc & 0xffff,
aout_symbol (symbol)->other & 0xff);
#endif
BFD_FAIL ();
break;
case bfd_print_symbol_all:
{
const char *section_name =
(symbol->section == (asection *) NULL
? "*abs"
: symbol->section->name);
if (symbol->name[0] == ' ')
{
fprintf (file, "* empty table entry ");
}
else
{
bfd_print_symbol_vandf ((PTR) file, symbol);
fprintf (file, " %-5s %04x %02x %s",
section_name,
(unsigned) ieee_symbol (symbol)->index,
(unsigned) 0,
symbol->name);
}
}
break;
}
}
static boolean
do_one (ieee, current_map, location_ptr, s, iterations)
ieee_data_type *ieee;
ieee_per_section_type *current_map;
unsigned char *location_ptr;
asection *s;
int iterations;
{
switch (this_byte (&(ieee->h)))
{
case ieee_load_constant_bytes_enum:
{
unsigned int number_of_maus;
unsigned int i;
next_byte (&(ieee->h));
number_of_maus = must_parse_int (&(ieee->h));
for (i = 0; i < number_of_maus; i++)
{
location_ptr[current_map->pc++] = this_byte (&(ieee->h));
next_byte (&(ieee->h));
}
}
break;
case ieee_load_with_relocation_enum:
{
boolean loop = true;
next_byte (&(ieee->h));
while (loop)
{
switch (this_byte (&(ieee->h)))
{
case ieee_variable_R_enum:
case ieee_function_signed_open_b_enum:
case ieee_function_unsigned_open_b_enum:
case ieee_function_either_open_b_enum:
{
unsigned int extra = 4;
boolean pcrel = false;
asection *section;
ieee_reloc_type *r =
(ieee_reloc_type *) bfd_alloc (ieee->h.abfd,
sizeof (ieee_reloc_type));
if (!r)
return false;
*(current_map->reloc_tail_ptr) = r;
current_map->reloc_tail_ptr = &r->next;
r->next = (ieee_reloc_type *) NULL;
next_byte (&(ieee->h));
/* abort();*/
r->relent.sym_ptr_ptr = 0;
parse_expression (ieee,
&r->relent.addend,
&r->symbol,
&pcrel, &extra, &section);
r->relent.address = current_map->pc;
s->flags |= SEC_RELOC;
s->owner->flags |= HAS_RELOC;
s->reloc_count++;
if (r->relent.sym_ptr_ptr == NULL && section != NULL)
r->relent.sym_ptr_ptr = section->symbol_ptr_ptr;
if (this_byte (&(ieee->h)) == (int) ieee_comma)
{
next_byte (&(ieee->h));
/* Fetch number of bytes to pad */
extra = must_parse_int (&(ieee->h));
};
switch (this_byte (&(ieee->h)))
{
case ieee_function_signed_close_b_enum:
next_byte (&(ieee->h));
break;
case ieee_function_unsigned_close_b_enum:
next_byte (&(ieee->h));
break;
case ieee_function_either_close_b_enum:
next_byte (&(ieee->h));
break;
default:
break;
}
/* Build a relocation entry for this type */
/* If pc rel then stick -ve pc into instruction
and take out of reloc ..
I've changed this. It's all too complicated. I
keep 0 in the instruction now. */
switch (extra)
{
case 0:
case 4:
if (pcrel == true)
{
#if KEEPMINUSPCININST
bfd_put_32 (ieee->h.abfd, -current_map->pc, location_ptr +
current_map->pc);
r->relent.howto = &rel32_howto;
r->relent.addend -=
current_map->pc;
#else
bfd_put_32 (ieee->h.abfd, 0, location_ptr +
current_map->pc);
r->relent.howto = &rel32_howto;
#endif
}
else
{
bfd_put_32 (ieee->h.abfd, 0, location_ptr +
current_map->pc);
r->relent.howto = &abs32_howto;
}
current_map->pc += 4;
break;
case 2:
if (pcrel == true)
{
#if KEEPMINUSPCININST
bfd_put_16 (ieee->h.abfd, (int) (-current_map->pc), location_ptr + current_map->pc);
r->relent.addend -= current_map->pc;
r->relent.howto = &rel16_howto;
#else
bfd_put_16 (ieee->h.abfd, 0, location_ptr + current_map->pc);
r->relent.howto = &rel16_howto;
#endif
}
else
{
bfd_put_16 (ieee->h.abfd, 0, location_ptr + current_map->pc);
r->relent.howto = &abs16_howto;
}
current_map->pc += 2;
break;
case 1:
if (pcrel == true)
{
#if KEEPMINUSPCININST
bfd_put_8 (ieee->h.abfd, (int) (-current_map->pc), location_ptr + current_map->pc);
r->relent.addend -= current_map->pc;
r->relent.howto = &rel8_howto;
#else
bfd_put_8 (ieee->h.abfd, 0, location_ptr + current_map->pc);
r->relent.howto = &rel8_howto;
#endif
}
else
{
bfd_put_8 (ieee->h.abfd, 0, location_ptr + current_map->pc);
r->relent.howto = &abs8_howto;
}
current_map->pc += 1;
break;
default:
BFD_FAIL ();
return false;
}
}
break;
default:
{
bfd_vma this_size;
if (parse_int (&(ieee->h), &this_size) == true)
{
unsigned int i;
for (i = 0; i < this_size; i++)
{
location_ptr[current_map->pc++] = this_byte (&(ieee->h));
next_byte (&(ieee->h));
}
}
else
{
loop = false;
}
}
}
/* Prevent more than the first load-item of an LR record
from being repeated (MRI convention). */
if (iterations != 1)
loop = false;
}
}
}
return true;
}
/* Read in all the section data and relocation stuff too */
static boolean
ieee_slurp_section_data (abfd)
bfd *abfd;
{
bfd_byte *location_ptr = (bfd_byte *) NULL;
ieee_data_type *ieee = IEEE_DATA (abfd);
unsigned int section_number;
ieee_per_section_type *current_map = (ieee_per_section_type *) NULL;
asection *s;
/* Seek to the start of the data area */
if (ieee->read_data == true)
return true;
ieee->read_data = true;
ieee_seek (abfd, ieee->w.r.data_part);
/* Allocate enough space for all the section contents */
for (s = abfd->sections; s != (asection *) NULL; s = s->next)
{
ieee_per_section_type *per = (ieee_per_section_type *) s->used_by_bfd;
if ((s->flags & SEC_DEBUGGING) != 0)
continue;
per->data = (bfd_byte *) bfd_alloc (ieee->h.abfd, s->_raw_size);
if (!per->data)
return false;
/*SUPPRESS 68*/
per->reloc_tail_ptr =
(ieee_reloc_type **) & (s->relocation);
}
while (true)
{
switch (this_byte (&(ieee->h)))
{
/* IF we see anything strange then quit */
default:
return true;
case ieee_set_current_section_enum:
next_byte (&(ieee->h));
section_number = must_parse_int (&(ieee->h));
s = ieee->section_table[section_number];
s->flags |= SEC_LOAD | SEC_HAS_CONTENTS;
current_map = (ieee_per_section_type *) s->used_by_bfd;
location_ptr = current_map->data - s->vma;
/* The document I have says that Microtec's compilers reset */
/* this after a sec section, even though the standard says not */
/* to. SO .. */
current_map->pc = s->vma;
break;
case ieee_e2_first_byte_enum:
next_byte (&(ieee->h));
switch (this_byte (&(ieee->h)))
{
case ieee_set_current_pc_enum & 0xff:
{
bfd_vma value;
ieee_symbol_index_type symbol;
unsigned int extra;
boolean pcrel;
next_byte (&(ieee->h));
must_parse_int (&(ieee->h)); /* Thow away section #*/
parse_expression (ieee, &value,
&symbol,
&pcrel, &extra,
0);
current_map->pc = value;
BFD_ASSERT ((unsigned) (value - s->vma) <= s->_raw_size);
}
break;
case ieee_value_starting_address_enum & 0xff:
next_byte (&(ieee->h));
if (this_byte (&(ieee->h)) == ieee_function_either_open_b_enum)
next_byte (&(ieee->h));
abfd->start_address = must_parse_int (&(ieee->h));
/* We've got to the end of the data now - */
return true;
default:
BFD_FAIL ();
return false;
}
break;
case ieee_repeat_data_enum:
{
/* Repeat the following LD or LR n times - we do this by
remembering the stream pointer before running it and
resetting it and running it n times. We special case
the repetition of a repeat_data/load_constant
*/
unsigned int iterations;
unsigned char *start;
next_byte (&(ieee->h));
iterations = must_parse_int (&(ieee->h));
start = ieee->h.input_p;
if (start[0] == (int) ieee_load_constant_bytes_enum &&
start[1] == 1)
{
while (iterations != 0)
{
location_ptr[current_map->pc++] = start[2];
iterations--;
}
next_byte (&(ieee->h));
next_byte (&(ieee->h));
next_byte (&(ieee->h));
}
else
{
while (iterations != 0)
{
ieee->h.input_p = start;
if (!do_one (ieee, current_map, location_ptr, s,
iterations))
return false;
iterations--;
}
}
}
break;
case ieee_load_constant_bytes_enum:
case ieee_load_with_relocation_enum:
{
if (!do_one (ieee, current_map, location_ptr, s, 1))
return false;
}
}
}
}
boolean
ieee_new_section_hook (abfd, newsect)
bfd *abfd;
asection *newsect;
{
newsect->used_by_bfd = (PTR)
bfd_alloc (abfd, sizeof (ieee_per_section_type));
if (!newsect->used_by_bfd)
return false;
ieee_per_section (newsect)->data = (bfd_byte *) NULL;
ieee_per_section (newsect)->section = newsect;
return true;
}
long
ieee_get_reloc_upper_bound (abfd, asect)
bfd *abfd;
sec_ptr asect;
{
if ((asect->flags & SEC_DEBUGGING) != 0)
return 0;
if (! ieee_slurp_section_data (abfd))
return -1;
return (asect->reloc_count + 1) * sizeof (arelent *);
}
static boolean
ieee_get_section_contents (abfd, section, location, offset, count)
bfd *abfd;
sec_ptr section;
PTR location;
file_ptr offset;
bfd_size_type count;
{
ieee_per_section_type *p = (ieee_per_section_type *) section->used_by_bfd;
if ((section->flags & SEC_DEBUGGING) != 0)
return _bfd_generic_get_section_contents (abfd, section, location,
offset, count);
ieee_slurp_section_data (abfd);
(void) memcpy ((PTR) location, (PTR) (p->data + offset), (unsigned) count);
return true;
}
long
ieee_canonicalize_reloc (abfd, section, relptr, symbols)
bfd *abfd;
sec_ptr section;
arelent **relptr;
asymbol **symbols;
{
/* ieee_per_section_type *p = (ieee_per_section_type *) section->used_by_bfd;*/
ieee_reloc_type *src = (ieee_reloc_type *) (section->relocation);
ieee_data_type *ieee = IEEE_DATA (abfd);
if ((section->flags & SEC_DEBUGGING) != 0)
return 0;
while (src != (ieee_reloc_type *) NULL)
{
/* Work out which symbol to attach it this reloc to */
switch (src->symbol.letter)
{
case 'I':
src->relent.sym_ptr_ptr =
symbols + src->symbol.index + ieee->external_symbol_base_offset;
break;
case 'X':
src->relent.sym_ptr_ptr =
symbols + src->symbol.index + ieee->external_reference_base_offset;
break;
case 0:
if (src->relent.sym_ptr_ptr != NULL)
src->relent.sym_ptr_ptr =
src->relent.sym_ptr_ptr[0]->section->symbol_ptr_ptr;
break;
default:
BFD_FAIL ();
}
*relptr++ = &src->relent;
src = src->next;
}
*relptr = (arelent *) NULL;
return section->reloc_count;
}
static int
comp (ap, bp)
CONST PTR ap;
CONST PTR bp;
{
arelent *a = *((arelent **) ap);
arelent *b = *((arelent **) bp);
return a->address - b->address;
}
/* Write the section headers. */
static boolean
ieee_write_section_part (abfd)
bfd *abfd;
{
ieee_data_type *ieee = IEEE_DATA (abfd);
asection *s;
ieee->w.r.section_part = bfd_tell (abfd);
for (s = abfd->sections; s != (asection *) NULL; s = s->next)
{
if (! bfd_is_abs_section (s)
&& (s->flags & SEC_DEBUGGING) == 0)
{
if (! ieee_write_byte (abfd, ieee_section_type_enum)
|| ! ieee_write_byte (abfd,
(bfd_byte) (s->index
+ IEEE_SECTION_NUMBER_BASE)))
return false;
if (abfd->flags & EXEC_P)
{
/* This image is executable, so output absolute sections */
if (! ieee_write_byte (abfd, ieee_variable_A_enum)
|| ! ieee_write_byte (abfd, ieee_variable_S_enum))
return false;
}
else
{
if (! ieee_write_byte (abfd, ieee_variable_C_enum))
return false;
}
switch (s->flags & (SEC_CODE | SEC_DATA | SEC_ROM))
{
case SEC_CODE | SEC_LOAD:
case SEC_CODE:
if (! ieee_write_byte (abfd, ieee_variable_P_enum))
return false;
break;
case SEC_DATA:
default:
if (! ieee_write_byte (abfd, ieee_variable_D_enum))
return false;
break;
case SEC_ROM:
case SEC_ROM | SEC_DATA:
case SEC_ROM | SEC_LOAD:
case SEC_ROM | SEC_DATA | SEC_LOAD:
if (! ieee_write_byte (abfd, ieee_variable_R_enum))
return false;
}
if (! ieee_write_id (abfd, s->name))
return false;
#if 0
ieee_write_int (abfd, 0); /* Parent */
ieee_write_int (abfd, 0); /* Brother */
ieee_write_int (abfd, 0); /* Context */
#endif
/* Alignment */
if (! ieee_write_byte (abfd, ieee_section_alignment_enum)
|| ! ieee_write_byte (abfd,
(bfd_byte) (s->index
+ IEEE_SECTION_NUMBER_BASE))
|| ! ieee_write_int (abfd, 1 << s->alignment_power))
return false;
/* Size */
if (! ieee_write_2bytes (abfd, ieee_section_size_enum)
|| ! ieee_write_byte (abfd,
(bfd_byte) (s->index
+ IEEE_SECTION_NUMBER_BASE))
|| ! ieee_write_int (abfd, s->_raw_size))
return false;
if (abfd->flags & EXEC_P)
{
/* Relocateable sections don't have asl records */
/* Vma */
if (! ieee_write_2bytes (abfd, ieee_section_base_address_enum)
|| ! ieee_write_byte (abfd,
((bfd_byte)
(s->index
+ IEEE_SECTION_NUMBER_BASE)))
|| ! ieee_write_int (abfd, s->lma))
return false;
}
}
}
return true;
}
static boolean
do_with_relocs (abfd, s)
bfd *abfd;
asection *s;
{
unsigned int number_of_maus_in_address =
bfd_arch_bits_per_address (abfd) / bfd_arch_bits_per_byte (abfd);
unsigned int relocs_to_go = s->reloc_count;
bfd_byte *stream = ieee_per_section (s)->data;
arelent **p = s->orelocation;
bfd_size_type current_byte_index = 0;
qsort (s->orelocation,
relocs_to_go,
sizeof (arelent **),
comp);
/* Output the section preheader */
if (! ieee_write_byte (abfd, ieee_set_current_section_enum)
|| ! ieee_write_byte (abfd,
(bfd_byte) (s->index + IEEE_SECTION_NUMBER_BASE))
|| ! ieee_write_2bytes (abfd, ieee_set_current_pc_enum)
|| ! ieee_write_byte (abfd,
(bfd_byte) (s->index + IEEE_SECTION_NUMBER_BASE)))
return false;
if ((abfd->flags & EXEC_P) != 0 && relocs_to_go == 0)
{
if (! ieee_write_int (abfd, s->lma))
return false;
}
else
{
if (! ieee_write_expression (abfd, 0, s->symbol, 0, 0))
return false;
}
if (relocs_to_go == 0)
{
/* If there aren't any relocations then output the load constant
byte opcode rather than the load with relocation opcode */
while (current_byte_index < s->_raw_size)
{
bfd_size_type run;
unsigned int MAXRUN = 127;
run = MAXRUN;
if (run > s->_raw_size - current_byte_index)
{
run = s->_raw_size - current_byte_index;
}
if (run != 0)
{
if (! ieee_write_byte (abfd, ieee_load_constant_bytes_enum))
return false;
/* Output a stream of bytes */
if (! ieee_write_int (abfd, run))
return false;
if (bfd_write ((PTR) (stream + current_byte_index),
1,
run,
abfd)
!= run)
return false;
current_byte_index += run;
}
}
}
else
{
if (! ieee_write_byte (abfd, ieee_load_with_relocation_enum))
return false;
/* Output the data stream as the longest sequence of bytes
possible, allowing for the a reasonable packet size and
relocation stuffs. */
if ((PTR) stream == (PTR) NULL)
{
/* Outputting a section without data, fill it up */
stream = (unsigned char *) (bfd_alloc (abfd, s->_raw_size));
if (!stream)
return false;
memset ((PTR) stream, 0, (size_t) s->_raw_size);
}
while (current_byte_index < s->_raw_size)
{
bfd_size_type run;
unsigned int MAXRUN = 127;
if (relocs_to_go)
{
run = (*p)->address - current_byte_index;
if (run > MAXRUN)
run = MAXRUN;
}
else
{
run = MAXRUN;
}
if (run > s->_raw_size - current_byte_index)
{
run = s->_raw_size - current_byte_index;
}
if (run != 0)
{
/* Output a stream of bytes */
if (! ieee_write_int (abfd, run))
return false;
if (bfd_write ((PTR) (stream + current_byte_index),
1,
run,
abfd)
!= run)
return false;
current_byte_index += run;
}
/* Output any relocations here */
if (relocs_to_go && (*p) && (*p)->address == current_byte_index)
{
while (relocs_to_go
&& (*p) && (*p)->address == current_byte_index)
{
arelent *r = *p;
bfd_signed_vma ov;
#if 0
if (r->howto->pc_relative)
{
r->addend += current_byte_index;
}
#endif
switch (r->howto->size)
{
case 2:
ov = bfd_get_signed_32 (abfd,
stream + current_byte_index);
current_byte_index += 4;
break;
case 1:
ov = bfd_get_signed_16 (abfd,
stream + current_byte_index);
current_byte_index += 2;
break;
case 0:
ov = bfd_get_signed_8 (abfd,
stream + current_byte_index);
current_byte_index++;
break;
default:
ov = 0;
BFD_FAIL ();
return false;
}
ov &= r->howto->src_mask;
if (r->howto->pc_relative
&& ! r->howto->pcrel_offset)
ov += r->address;
if (! ieee_write_byte (abfd,
ieee_function_either_open_b_enum))
return false;
/* abort();*/
if (r->sym_ptr_ptr != (asymbol **) NULL)
{
if (! ieee_write_expression (abfd, r->addend + ov,
*(r->sym_ptr_ptr),
r->howto->pc_relative,
s->index))
return false;
}
else
{
if (! ieee_write_expression (abfd, r->addend + ov,
(asymbol *) NULL,
r->howto->pc_relative,
s->index))
return false;
}
if (number_of_maus_in_address
!= bfd_get_reloc_size (r->howto))
{
if (! ieee_write_int (abfd,
bfd_get_reloc_size (r->howto)))
return false;
}
if (! ieee_write_byte (abfd,
ieee_function_either_close_b_enum))
return false;
relocs_to_go--;
p++;
}
}
}
}
return true;
}
/* If there are no relocations in the output section then we can be
clever about how we write. We block items up into a max of 127
bytes. */
static boolean
do_as_repeat (abfd, s)
bfd *abfd;
asection *s;
{
if (s->_raw_size)
{
if (! ieee_write_byte (abfd, ieee_set_current_section_enum)
|| ! ieee_write_byte (abfd,
(bfd_byte) (s->index
+ IEEE_SECTION_NUMBER_BASE))
|| ! ieee_write_byte (abfd, ieee_set_current_pc_enum >> 8)
|| ! ieee_write_byte (abfd, ieee_set_current_pc_enum & 0xff)
|| ! ieee_write_byte (abfd,
(bfd_byte) (s->index
+ IEEE_SECTION_NUMBER_BASE))
|| ! ieee_write_int (abfd, s->lma)
|| ! ieee_write_byte (abfd, ieee_repeat_data_enum)
|| ! ieee_write_int (abfd, s->_raw_size)
|| ! ieee_write_byte (abfd, ieee_load_constant_bytes_enum)
|| ! ieee_write_byte (abfd, 1)
|| ! ieee_write_byte (abfd, 0))
return false;
}
return true;
}
static boolean
do_without_relocs (abfd, s)
bfd *abfd;
asection *s;
{
bfd_byte *stream = ieee_per_section (s)->data;
if (stream == 0 || ((s->flags & SEC_LOAD) == 0))
{
if (! do_as_repeat (abfd, s))
return false;
}
else
{
unsigned int i;
for (i = 0; i < s->_raw_size; i++)
{
if (stream[i] != 0)
{
if (! do_with_relocs (abfd, s))
return false;
return true;
}
}
if (! do_as_repeat (abfd, s))
return false;
}
return true;
}
static unsigned char *output_ptr_start;
static unsigned char *output_ptr;
static unsigned char *output_ptr_end;
static unsigned char *input_ptr_start;
static unsigned char *input_ptr;
static unsigned char *input_ptr_end;
static bfd *input_bfd;
static bfd *output_bfd;
static int output_buffer;
static void
fill ()
{
/* FIXME: Check return value. I'm not sure whether it needs to read
the entire buffer or not. */
bfd_read ((PTR) input_ptr_start, 1, input_ptr_end - input_ptr_start, input_bfd);
input_ptr = input_ptr_start;
}
static void
flush ()
{
if (bfd_write ((PTR) (output_ptr_start), 1, output_ptr - output_ptr_start,
output_bfd)
!= (bfd_size_type) (output_ptr - output_ptr_start))
abort ();
output_ptr = output_ptr_start;
output_buffer++;
}
#define THIS() ( *input_ptr )
#define NEXT() { input_ptr++; if (input_ptr == input_ptr_end) fill(); }
#define OUT(x) { *output_ptr++ = (x); if(output_ptr == output_ptr_end) flush(); }
static void
write_int (value)
int value;
{
if (value >= 0 && value <= 127)
{
OUT (value);
}
else
{
unsigned int length;
/* How many significant bytes ? */
/* FIXME FOR LONGER INTS */
if (value & 0xff000000)
{
length = 4;
}
else if (value & 0x00ff0000)
{
length = 3;
}
else if (value & 0x0000ff00)
{
length = 2;
}
else
length = 1;
OUT ((int) ieee_number_repeat_start_enum + length);
switch (length)
{
case 4:
OUT (value >> 24);
case 3:
OUT (value >> 16);
case 2:
OUT (value >> 8);
case 1:
OUT (value);
}
}
}
static void
copy_id ()
{
int length = THIS ();
char ch;
OUT (length);
NEXT ();
while (length--)
{
ch = THIS ();
OUT (ch);
NEXT ();
}
}
#define VAR(x) ((x | 0x80))
static void
copy_expression ()
{
int stack[10];
int *tos = stack;
int value = 0;
while (1)
{
switch (THIS ())
{
case 0x84:
NEXT ();
value = THIS ();
NEXT ();
value = (value << 8) | THIS ();
NEXT ();
value = (value << 8) | THIS ();
NEXT ();
value = (value << 8) | THIS ();
NEXT ();
*tos++ = value;
break;
case 0x83:
NEXT ();
value = THIS ();
NEXT ();
value = (value << 8) | THIS ();
NEXT ();
value = (value << 8) | THIS ();
NEXT ();
*tos++ = value;
break;
case 0x82:
NEXT ();
value = THIS ();
NEXT ();
value = (value << 8) | THIS ();
NEXT ();
*tos++ = value;
break;
case 0x81:
NEXT ();
value = THIS ();
NEXT ();
*tos++ = value;
break;
case 0x80:
NEXT ();
*tos++ = 0;
break;
default:
if (THIS () > 0x84)
{
/* Not a number, just bug out with the answer */
write_int (*(--tos));
return;
}
*tos++ = THIS ();
NEXT ();
value = 0;
break;
case 0xa5:
/* PLUS anything */
{
int value = *(--tos);
value += *(--tos);
*tos++ = value;
NEXT ();
}
break;
case VAR ('R'):
{
int section_number;
ieee_data_type *ieee;
asection *s;
NEXT ();
section_number = THIS ();
NEXT ();
ieee = IEEE_DATA (input_bfd);
s = ieee->section_table[section_number];
if (s->output_section)
{
value = s->output_section->lma;
}
else
{
value = 0;
}
value += s->output_offset;
*tos++ = value;
value = 0;
}
break;
case 0x90:
{
NEXT ();
write_int (*(--tos));
OUT (0x90);
return;
}
}
}
}
/* Drop the int in the buffer, and copy a null into the gap, which we
will overwrite later */
struct output_buffer_struct
{
unsigned char *ptrp;
int buffer;
};
static void
fill_int (buf)
struct output_buffer_struct *buf;
{
if (buf->buffer == output_buffer)
{
/* Still a chance to output the size */
int value = output_ptr - buf->ptrp + 3;
buf->ptrp[0] = value >> 24;
buf->ptrp[1] = value >> 16;
buf->ptrp[2] = value >> 8;
buf->ptrp[3] = value >> 0;
}
}
static void
drop_int (buf)
struct output_buffer_struct *buf;
{
int type = THIS ();
int ch;
if (type <= 0x84)
{
NEXT ();
switch (type)
{
case 0x84:
ch = THIS ();
NEXT ();
case 0x83:
ch = THIS ();
NEXT ();
case 0x82:
ch = THIS ();
NEXT ();
case 0x81:
ch = THIS ();
NEXT ();
case 0x80:
break;
}
}
OUT (0x84);
buf->ptrp = output_ptr;
buf->buffer = output_buffer;
OUT (0);
OUT (0);
OUT (0);
OUT (0);
}
static void
copy_int ()
{
int type = THIS ();
int ch;
if (type <= 0x84)
{
OUT (type);
NEXT ();
switch (type)
{
case 0x84:
ch = THIS ();
NEXT ();
OUT (ch);
case 0x83:
ch = THIS ();
NEXT ();
OUT (ch);
case 0x82: