binutils-gdb/bfd/coff-mips.c
John Gilmore 23b0b55855 Merge Per Bothner's MIPS changes from 31 March 1991 (bfd-0.5.2-patch1a)
and make the result compile and run on the DEC 3100.  It still has
trouble running but it can handle opening exec and symbol files in
ecoff format.
1991-05-02 23:10:23 +00:00

611 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* MIPS Extended-Coff handler for Binary File Diddling.
Written by Per Bothner.
/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Diddler.
BFD 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 1, or (at your option)
any later version.
BFD 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 BFD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This does not compile on anything but a MIPS yet (and I haven't been
able to test it there either since the latest merge!). So it stays
out by default. */
#define MIPS 1
#include <stdio.h>
#include <string.h>
#include "bfd.h"
#include "libbfd.h"
#include "sysdep.h"
#include "intel-coff.h"
#include "libcoff.h" /* to allow easier abstraction-breaking */
static reloc_howto_type howto_table[] =
{
{0},
{1},
{2},
{3},
{4},
{5},
{6},
{7},
{8},
{9},
{10},
{11},
{12},
{13},
{14},
{15},
{16},
{ R_RELLONG, 0, 2, 32, 0, 0, true, true},
{18},
{19},
{20},
{21},
{22},
{23},
{24},
{ R_IPRMED, 2, 2,22,1,0, true, true},
{26},
/* FIXME: What do we do with this - ? */
#if 1
{ R_OPTCALL, 0,2,32,0,0, true, true},
#else
{ R_OPTCALL, 0,3,32,0,0, true, true},
#endif
};
#define ALIGN(this, boundary) \
((( (this) + ((boundary) -1)) & (~((boundary)-1))))
/* Support for Motorola 88k bcs coff as well as Intel 960 coff */
/* Align an address by rounding it up to a power of two. It leaves the
address unchanged if align == 0 (2^0 = alignment of 1 byte) */
#define i960_align(addr, align) \
( ((addr) + ((1<<(align))-1)) & (-1 << (align)))
#define TAG_SECTION_NAME ".tagbits"
/* Libraries shouldn't be doing this stuff anyway! */
void fatal();
/* void warning(); */
/* initialize a section structure with information
* peculiar to this particular implementation of coff
*/
static boolean
ecoff_new_section_hook(abfd, section)
bfd *abfd;
asection *section;
{
return true;
}
/* actually it makes itself and its children from the file headers */
static boolean
make_a_section_from_file (abfd, hdr)
bfd *abfd;
struct scnhdr *hdr;
{
asection *return_section ;
{ char *name = (char *)xmalloc(9);
strncpy(name, (char *)&hdr->s_name[0], 8);
return_section = bfd_make_section(abfd, name);
(return_section->name)[8] = 0;
}
/* s_paddr is presumed to be = to s_vaddr */
/* FIXME -- needs to call swapping routines */
#define assign(to, from) return_section->to = hdr->from
assign (vma, s_vaddr);
/* assign (vma, s_vaddr);*/
assign (size, s_size);
assign (filepos, s_scnptr);
assign (rel_filepos, s_relptr);
assign (reloc_count, s_nreloc);
#ifdef I960
assign (alignment, s_align);
#endif
assign (line_filepos, s_lnnoptr);
/* return_section->linesize = hdr->s_nlnno * sizeof (struct lineno);*/
#undef assign
return_section->lineno_count = hdr->s_nlnno;
return_section->userdata = (void *)NULL;
return_section->next = (asection *)NULL;
if ((hdr->s_flags & STYP_TEXT) || (hdr->s_flags & STYP_DATA))
return_section->flags = (SEC_LOAD | SEC_ALLOC);
else if (hdr->s_flags & STYP_BSS)
return_section->flags = SEC_ALLOC;
if (hdr->s_nreloc != 0) return_section->flags |= SEC_RELOC;
return true;
}
bfd_target *
ecoff_real_object_p (abfd, nscns, opthdr)
bfd *abfd;
unsigned short nscns, opthdr;
{
struct icofdata *tdata;
char *file_info; /* buffer for all the headers */
long readsize; /* length of file_info */
struct filehdr* filehdr; /* points into file_info */
struct scnhdr *sections; /* points into file_info */
/* OK, now we know the format, read in the filehdr, soi-disant
"optional header", and all the sections.*/
readsize = sizeof(struct filehdr) + opthdr + (nscns * sizeof (struct scnhdr));
file_info = (char*)bfd_alloc (abfd, readsize);
if (file_info == NULL) {
bfd_error = no_memory;
return 0;
}
if (bfd_seek (abfd, 0, false) < 0) return 0;
if (bfd_read (file_info, 1, readsize, abfd) != readsize) return 0;
filehdr = (struct filehdr *) file_info;
sections = (struct scnhdr *) (file_info + sizeof (struct filehdr) + opthdr);
/* Now copy data as required; construct all asections etc */
tdata = (struct icofdata *) bfd_zalloc (abfd, sizeof (struct icofdata) +
sizeof (AOUTHDR));
if (tdata == NULL) {
bfd_release (abfd, file_info);
bfd_error = no_memory;
return 0;
}
if (nscns != 0)
{
unsigned int i;
for (i = 0; i < nscns; i++)
{
make_a_section_from_file (abfd, sections + i);
}
}
abfd->flags |= HAS_RELOC | HAS_LINENO | HAS_LOCALS;
/* FIXME, the guess should be set by OR-ing info from the sections */
if ((filehdr->f_flags & F_RELFLG) != F_RELFLG) abfd->flags &= ~HAS_RELOC;
if ((filehdr->f_flags & F_EXEC) == F_EXEC) abfd->flags |= EXEC_P;
if ((filehdr->f_flags & F_LNNO) != F_LNNO) abfd->flags &= ~HAS_LINENO;
if ((filehdr->f_flags & F_LSYMS) != F_LSYMS) abfd->flags &= ~HAS_LOCALS;
set_tdata (abfd, tdata);
bfd_get_symcount (abfd) = filehdr->f_nsyms;
if (filehdr->f_nsyms) abfd->flags |= HAS_SYMS;
tdata->sym_filepos = filehdr->f_symptr;
/* FIXME, needs byte swapping */
tdata->hdr = *(struct aouthdr *)(file_info + sizeof (struct filehdr));
tdata->symbols = (coff_symbol_type *)NULL;
bfd_get_start_address (abfd) = exec_hdr (abfd).entry;
return abfd->xvec;
}
bfd_target *
ecoff_object_p (abfd)
bfd *abfd;
{
unsigned short magic, nscns, opthdr;
bfd_error = no_error;
/* figure out how much to read */
if (bfd_read (&magic, 1, sizeof (magic), abfd) != sizeof (magic))
return 0;
magic = bfd_h_getshort (abfd, (unsigned char *)&magic);
if (magic != (abfd->xvec->byteorder_big_p ? 0x160 : 0x162)) {
bfd_error = wrong_format;
return 0;
}
if (bfd_read (&nscns, 1, sizeof (nscns), abfd) != sizeof (nscns))
return 0;
nscns = bfd_h_getshort (abfd, (unsigned char *)&nscns);
if (bfd_seek (abfd,(file_ptr) ((sizeof (long)) * 3), true) < 0)
return 0;
if (bfd_read (&opthdr, 1, sizeof (opthdr), abfd) != sizeof (opthdr))
return 0;
opthdr = bfd_h_getshort (abfd, (unsigned char *)&opthdr);
return ecoff_real_object_p (abfd, nscns, opthdr);
}
static boolean
ecoff_mkobject (abfd)
bfd *abfd;
{
char *rawptr;
bfd_error = no_error;
/* Use an intermediate variable for clarity */
rawptr = (char*)bfd_zalloc (abfd, sizeof (struct icofdata));
if (rawptr == NULL) {
bfd_error = no_memory;
return false;
}
set_tdata (abfd, rawptr);
return true;
}
static void
ecoff_count_linenumbers(abfd)
bfd *abfd;
{
unsigned int limit = bfd_get_symcount(abfd);
unsigned int i;
asymbol **p;
{
asection *s = abfd->sections->output_section;
while (s) {
BFD_ASSERT(s->lineno_count == 0);
s = s->next;
}
}
for (p = abfd->outsymbols,i = 0; i < limit; i++, p++)
{
asymbol *q_maybe = *p;
if (q_maybe->the_bfd->xvec->flavour == bfd_target_coff_flavour_enum) {
coff_symbol_type *q = coffsymbol(q_maybe);
if (q->lineno)
{
/* This symbol has a linenumber, increment the
* owning section's linenumber count */
alent *l = q->lineno;
q->symbol.section->output_section->lineno_count++;
l++;
while (l->line_number) {
q->symbol.section->output_section->lineno_count++;
l++;
}
}
}
}
}
static void
ecoff_write_symbols(abfd)
bfd *abfd;
{
}
void
ecoff_write_linenumbers(abfd)
bfd *abfd;
{
}
asymbol *
ecoff_make_empty_symbol(abfd, n)
bfd *abfd;
unsigned int n;
{
coff_symbol_type *new = (coff_symbol_type *)xmalloc(sizeof(coff_symbol_type));
new->native = 0;
new->lineno = (alent *)NULL;
new->symbol.the_bfd = abfd;
return &new->symbol;
}
/*SUPPRESS 558*/
/*SUPPRESS 529*/
boolean
ecoff_write_object_contents (abfd)
bfd *abfd;
{
return false;
}
/* Calculate the file position for each section. */
static void
ecoff_compute_section_file_positions (abfd)
bfd *abfd;
{
abort();
}
boolean
ecoff_set_section_contents (abfd, section, location, offset, count)
bfd *abfd;
sec_ptr section;
unsigned char *location;
file_ptr offset;
int count;
{
return false;
}
boolean
ecoff_set_section_linenos (abfd, section, location, offset, count)
bfd *abfd;
sec_ptr section;
unsigned char *location;
file_ptr offset;
int count;
{
return 0;
}
boolean
ecoff_close_and_cleanup (abfd)
bfd *abfd;
{
return false;
}
static
struct sec *section_from_bfd_index(abfd, index)
bfd *abfd;
int index;
{
if (index > 0) {
struct sec *answer = abfd->sections;
while (--index) {
answer = answer->next;
}
return answer;
}
return 0;
}
static int
ecoff_get_symcount_upper_bound (abfd)
bfd *abfd;
{
fatal("call to ecoff_get_symcount_upper_bound");
return 0;
}
static symindex
ecoff_get_first_symbol (abfd)
bfd * abfd;
{
return 0;
}
static symindex
ecoff_get_next_symbol (abfd, oidx)
bfd *abfd;
symindex oidx;
{
if (oidx == BFD_NO_MORE_SYMBOLS) return BFD_NO_MORE_SYMBOLS;
return ++oidx >= bfd_get_symcount (abfd) ? BFD_NO_MORE_SYMBOLS : oidx;
}
static char *
ecoff_symbol_name (abfd, idx)
bfd *abfd;
symindex idx;
{
return (obj_symbols (abfd) + idx)->symbol.name;
}
static long
ecoff_symbol_value (abfd, idx)
bfd *abfd;
symindex idx;
{
return (obj_symbols (abfd) + idx)->symbol.value;
}
static symclass
ecoff_classify_symbol (abfd, idx)
bfd *abfd;
symindex idx;
{
abort();
}
static boolean
ecoff_symbol_hasclass (abfd, idx, class)
bfd *abfd;
symindex idx;
symclass class;
{
abort();
}
static
boolean
ecoff_slurp_line_table (abfd, asect)
bfd *abfd;
asection *asect;
{
return true;
}
static boolean
ecoff_slurp_symbol_table(abfd)
bfd *abfd;
{
abort();
}
unsigned int
ecoff_get_symtab_upper_bound (abfd)
bfd *abfd;
{
if (!ecoff_slurp_symbol_table (abfd)) return 0;
return (bfd_get_symcount (abfd)+1) * (sizeof (coff_symbol_type *));
}
unsigned int
ecoff_get_symtab(abfd, alocation)
bfd *abfd;
asymbol **alocation;
{
unsigned int counter = 0;
coff_symbol_type *symbase;
coff_symbol_type **location = (coff_symbol_type **)(alocation);
if (!ecoff_slurp_symbol_table (abfd)) return 0;
for (symbase = obj_symbols (abfd); counter++ < bfd_get_symcount (abfd);)
*(location++) = symbase++;
*location++ =0;
return counter;
}
unsigned int
ecoff_get_reloc_upper_bound (abfd, asect)
bfd *abfd;
sec_ptr asect;
{
if (bfd_get_format (abfd) != bfd_object) {
bfd_error = invalid_operation;
return 0;
}
return (asect->reloc_count + 1) * sizeof(arelent *);
}
boolean
ecoff_slurp_reloc_table (abfd, asect)
bfd *abfd;
sec_ptr asect;
{
abort();
}
/* This is stupid. This function should be a boolean predicate */
unsigned int
ecoff_canonicalize_reloc (abfd, section, relptr)
bfd *abfd;
sec_ptr section;
arelent **relptr;
{
return 0;
}
boolean
ecoff_get_section_contents (abfd, section, location, offset, count)
bfd *abfd;
sec_ptr section;
PTR location;
file_ptr offset;
int count;
{
if (count) {
if (offset >= section->size) return false;
bfd_seek (abfd, section->filepos + offset, SEEK_SET);
return (bfd_read (location, 1, count, abfd) == count) ? true:false;
}
else return true;
}
alent *
ecoff_get_lineno(ignore_abfd, ignore_symbol)
bfd *ignore_abfd;
PTR ignore_symbol;
{
return (alent *)NULL;
}
#define ecoff_core_file_failing_command _bfd_dummy_core_file_failing_command
#define ecoff_core_file_failing_signal _bfd_dummy_core_file_failing_signal
#define ecoff_core_file_matches_executable_p _bfd_dummy_core_file_matches_executable_p
#define ecoff_slurp_armap bfd_false
#define ecoff_slurp_extended_name_table bfd_false
#define ecoff_truncate_arname bfd_void
#define ecoff_write_armap bfd_false
#define ecoff_print_symbol bfd_void
#define ecoff_set_arch_mach bfd_false
#define ecoff_openr_next_archived_file bfd_generic_openr_next_archived_file
#define ecoff_find_nearest_line bfd_false
#define ecoff_generic_stat_arch_elt bfd_generic_stat_arch_elt
#define ecoff_sizeof_headers bfd_0
bfd_target ecoff_little_vec =
{"ecoff-littlemips", /* name */
bfd_target_coff_flavour_enum,
false, /* data byte order is little */
false, /* header byte order is little */
(HAS_RELOC | EXEC_P | /* object flags */
HAS_LINENO | HAS_DEBUG |
HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT),
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
'/', /* ar_pad_char */
15, /* ar_max_namelen */
_do_getllong, _do_putllong, _do_getlshort, _do_putlshort, /* data */
_do_getllong, _do_putllong, _do_getlshort, _do_putlshort, /* hdrs */
{_bfd_dummy_target, ecoff_object_p, /* bfd_check_format */
bfd_generic_archive_p, _bfd_dummy_target},
{bfd_false, ecoff_mkobject, bfd_false, /* bfd_set_format */
bfd_false},
JUMP_TABLE (ecoff)
};
bfd_target ecoff_big_vec =
{"ecoff-bigmips", /* name */
bfd_target_coff_flavour_enum,
true, /* data byte order is big */
true, /* header byte order is big */
(HAS_RELOC | EXEC_P | /* object flags */
HAS_LINENO | HAS_DEBUG |
HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT),
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
' ', /* ar_pad_char */
16, /* ar_max_namelen */
_do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* data */
_do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* hdrs */
{_bfd_dummy_target, ecoff_object_p, /* bfd_check_format */
bfd_generic_archive_p, _bfd_dummy_target},
{bfd_false, ecoff_mkobject, bfd_false, /* bfd_set_format */
bfd_false},
JUMP_TABLE(ecoff)
};