/* BFD back-end for ALPHA Extended-Coff files.
- Copyright 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1993, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
Modified from coff-mips.c by Steve Chamberlain <sac@cygnus.com> and
Ian Lance Taylor <ian@cygnus.com>.
#include "coff/symconst.h"
#include "coff/ecoff.h"
#include "coff/alpha.h"
+#include "aout/ar.h"
#include "libcoff.h"
#include "libecoff.h"
\f
arelent *));
static void alpha_adjust_reloc_out PARAMS ((bfd *, const arelent *,
struct internal_reloc *));
+static reloc_howto_type *alpha_bfd_reloc_type_lookup
+ PARAMS ((bfd *, bfd_reloc_code_real_type));
static bfd_byte *alpha_ecoff_get_relocated_section_contents
PARAMS ((bfd *abfd, struct bfd_link_info *, struct bfd_link_order *,
bfd_byte *data, boolean relocateable, asymbol **symbols));
bfd_byte *, PTR));
static boolean alpha_adjust_headers
PARAMS ((bfd *, struct internal_filehdr *, struct internal_aouthdr *));
+static PTR alpha_ecoff_read_ar_hdr PARAMS ((bfd *));
+static bfd *alpha_ecoff_get_elt_at_filepos PARAMS ((bfd *, file_ptr));
+static bfd *alpha_ecoff_openr_next_archived_file PARAMS ((bfd *, bfd *));
+static bfd *alpha_ecoff_get_elt_at_index PARAMS ((bfd *, symindex));
\f
/* ECOFF has COFF sections, but the debugging information is stored in
a completely different format. ECOFF targets use some of the
intern->r_vaddr = bfd_h_get_64 (abfd, (bfd_byte *) ext->r_vaddr);
intern->r_symndx = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_symndx);
- BFD_ASSERT (abfd->xvec->header_byteorder_big_p == false);
+ BFD_ASSERT (bfd_header_little_endian (abfd));
intern->r_type = ((ext->r_bits[0] & RELOC_BITS0_TYPE_LITTLE)
>> RELOC_BITS0_TYPE_SH_LITTLE);
/* The IGNORE reloc generally follows a GPDISP reloc, and is
against the .lita section. The section is irrelevant. */
if (! intern->r_extern &&
- (intern->r_symndx == RELOC_SECTION_NONE
- || intern->r_symndx == RELOC_SECTION_ABS))
+ intern->r_symndx == RELOC_SECTION_ABS)
abort ();
if (! intern->r_extern && intern->r_symndx == RELOC_SECTION_LITA)
- intern->r_symndx = RELOC_SECTION_NONE;
+ intern->r_symndx = RELOC_SECTION_ABS;
}
}
}
else if (intern->r_type == ALPHA_R_IGNORE
&& ! intern->r_extern
- && intern->r_symndx == RELOC_SECTION_NONE)
+ && intern->r_symndx == RELOC_SECTION_ABS)
{
symndx = RELOC_SECTION_LITA;
size = intern->r_size;
bfd_h_put_64 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr);
bfd_h_put_32 (abfd, symndx, (bfd_byte *) ext->r_symndx);
- BFD_ASSERT (abfd->xvec->header_byteorder_big_p == false);
+ BFD_ASSERT (bfd_header_little_endian (abfd));
ext->r_bits[0] = ((intern->r_type << RELOC_BITS0_TYPE_SH_LITTLE)
& RELOC_BITS0_TYPE_LITTLE);
case ALPHA_R_SREL16:
case ALPHA_R_SREL32:
case ALPHA_R_SREL64:
- /* The PC relative relocs do not seem to use the section VMA as
- a negative addend. */
- rptr->addend = 0;
+ /* This relocs appear to be fully resolved when they are against
+ internal symbols. Against external symbols, BRADDR at least
+ appears to be resolved against the next instruction. */
+ if (! intern->r_extern)
+ rptr->addend = 0;
+ else
+ rptr->addend = - (intern->r_vaddr + 4);
break;
case ALPHA_R_GPREL32:
case ALPHA_R_IGNORE:
intern->r_vaddr = rel->address;
- if (intern->r_symndx == RELOC_SECTION_ABS)
- intern->r_symndx = RELOC_SECTION_NONE;
break;
default:
if (reloc_size < 0)
goto error_return;
- reloc_vector = (arelent **) malloc (reloc_size);
+ reloc_vector = (arelent **) bfd_malloc (reloc_size);
if (reloc_vector == NULL && reloc_size != 0)
- {
- bfd_set_error (bfd_error_no_memory);
- goto error_return;
- }
+ goto error_return;
if (! bfd_get_section_contents (input_bfd, input_section, data,
(file_ptr) 0, input_section->_raw_size))
/* Get the GP value for the output BFD. */
gp_undefined = false;
- if (ecoff_data (abfd)->gp == 0)
+ gp = _bfd_get_gp_value (abfd);
+ if (gp == 0)
{
if (relocateable != false)
{
|| strcmp (sec->name, ".lita") == 0))
lo = sec->vma;
}
- ecoff_data (abfd)->gp = lo + 0x8000;
+ gp = lo + 0x8000;
+ _bfd_set_gp_value (abfd, gp);
}
else
{
|| h->type != bfd_link_hash_defined)
gp_undefined = true;
else
- ecoff_data (abfd)->gp = (h->u.def.value
- + h->u.def.section->output_section->vma
- + h->u.def.section->output_offset);
+ {
+ gp = (h->u.def.value
+ + h->u.def.section->output_section->vma
+ + h->u.def.section->output_offset);
+ _bfd_set_gp_value (abfd, gp);
+ }
}
}
- gp = ecoff_data (abfd)->gp;
for (; *reloc_vector != (arelent *) NULL; reloc_vector++)
{
if (r == bfd_reloc_ok && gp_undefined)
{
r = bfd_reloc_dangerous;
- err = (char *) "GP relative relocation used when GP not defined";
+ err = (char *) _("GP relative relocation used when GP not defined");
}
break;
{
r = bfd_reloc_dangerous;
err =
- (char *) "GP relative relocation used when GP not defined";
+ (char *) _("GP relative relocation used when GP not defined");
}
}
break;
/* This marks the ldah of an ldah/lda pair which loads the
gp register with the difference of the gp value and the
current location. The second of the pair is r_size bytes
- ahead, and is marked with an ALPHA_R_IGNORE reloc. */
+ ahead; it used to be marked with an ALPHA_R_IGNORE reloc,
+ but that no longer happens in OSF/1 3.2. */
{
unsigned long insn1, insn2;
bfd_vma addend;
- BFD_ASSERT (reloc_vector[1] != NULL
- && reloc_vector[1]->howto->type == ALPHA_R_IGNORE
- && (rel->address + rel->addend
- == reloc_vector[1]->address));
-
/* Get the two instructions. */
insn1 = bfd_get_32 (input_bfd, data + rel->address);
insn2 = bfd_get_32 (input_bfd, data + rel->address + rel->addend);
/* The existing addend includes the different between the
gp of the input BFD and the address in the input BFD.
Subtract this out. */
- addend -= (reloc_vector[1]->addend
+ addend -= (ecoff_data (input_bfd)->gp
- (input_section->vma + rel->address));
/* Now add in the final gp value, and subtract out the
case bfd_reloc_undefined:
if (! ((*link_info->callbacks->undefined_symbol)
(link_info, bfd_asymbol_name (*rel->sym_ptr_ptr),
- input_bfd, input_section, rel->address)))
+ input_bfd, input_section, rel->address, true)))
goto error_return;
break;
case bfd_reloc_dangerous:
bfd_byte *contents;
PTR external_relocs;
{
- asection **symndx_to_section;
+ asection **symndx_to_section, *lita_sec;
struct ecoff_link_hash_entry **sym_hashes;
bfd_vma gp;
boolean gp_undefined;
(NUM_RELOC_SECTIONS
* sizeof (asection *))));
if (!symndx_to_section)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
symndx_to_section[RELOC_SECTION_NONE] = NULL;
symndx_to_section[RELOC_SECTION_TEXT] =
sym_hashes = ecoff_data (input_bfd)->sym_hashes;
- gp = ecoff_data (output_bfd)->gp;
- if (gp == 0)
- gp_undefined = true;
- else
- gp_undefined = false;
+ /* On the Alpha, the .lita section must be addressable by the global
+ pointer. To support large programs, we need to allow multiple
+ global pointers. This works as long as each input .lita section
+ is <64KB big. This implies that when producing relocatable
+ output, the .lita section is limited to 64KB. . */
+
+ lita_sec = symndx_to_section[RELOC_SECTION_LITA];
+ gp = _bfd_get_gp_value (output_bfd);
+ if (! info->relocateable && lita_sec != NULL)
+ {
+ struct ecoff_section_tdata *lita_sec_data;
+
+ /* Make sure we have a section data structure to which we can
+ hang on to the gp value we pick for the section. */
+ lita_sec_data = ecoff_section_data (input_bfd, lita_sec);
+ if (lita_sec_data == NULL)
+ {
+ lita_sec_data = ((struct ecoff_section_tdata *)
+ bfd_zalloc (input_bfd,
+ sizeof (struct ecoff_section_tdata)));
+ ecoff_section_data (input_bfd, lita_sec) = lita_sec_data;
+ }
+
+ if (lita_sec_data->gp != 0)
+ {
+ /* If we already assigned a gp to this section, we better
+ stick with that value. */
+ gp = lita_sec_data->gp;
+ }
+ else
+ {
+ bfd_vma lita_vma;
+ bfd_size_type lita_size;
+
+ lita_vma = lita_sec->output_offset + lita_sec->output_section->vma;
+ lita_size = lita_sec->_cooked_size;
+ if (lita_size == 0)
+ lita_size = lita_sec->_raw_size;
+
+ if (gp == 0
+ || lita_vma < gp - 0x8000
+ || lita_vma + lita_size >= gp + 0x8000)
+ {
+ /* Either gp hasn't been set at all or the current gp
+ cannot address this .lita section. In both cases we
+ reset the gp to point into the "middle" of the
+ current input .lita section. */
+ if (gp && !ecoff_data (output_bfd)->issued_multiple_gp_warning)
+ {
+ (*info->callbacks->warning) (info,
+ _("using multiple gp values"),
+ (char *) NULL, output_bfd,
+ (asection *) NULL, (bfd_vma) 0);
+ ecoff_data (output_bfd)->issued_multiple_gp_warning = true;
+ }
+ if (lita_vma < gp - 0x8000)
+ gp = lita_vma + lita_size - 0x8000;
+ else
+ gp = lita_vma + 0x8000;
- BFD_ASSERT (output_bfd->xvec->header_byteorder_big_p == false);
- BFD_ASSERT (input_bfd->xvec->header_byteorder_big_p == false);
+ }
+
+ lita_sec_data->gp = gp;
+ }
+
+ _bfd_set_gp_value (output_bfd, gp);
+ }
+
+ gp_undefined = (gp == 0);
+
+ BFD_ASSERT (bfd_header_little_endian (output_bfd));
+ BFD_ASSERT (bfd_header_little_endian (input_bfd));
ext_rel = (struct external_reloc *) external_relocs;
ext_rel_end = ext_rel + input_section->reloc_count;
abort ();
case ALPHA_R_IGNORE:
- /* This reloc appears after a GPDISP reloc. It marks the
- position of the second instruction to be altered by the
- GPDISP reloc, but is not otherwise used for anything.
- For some reason, the address of the relocation does not
- appear to include the section VMA, unlike the other
- relocation types. */
+ /* This reloc appears after a GPDISP reloc. On earlier
+ versions of OSF/1, It marked the position of the second
+ instruction to be altered by the GPDISP reloc, but it is
+ not otherwise used for anything. For some reason, the
+ address of the relocation does not appear to include the
+ section VMA, unlike the other relocation types. */
if (info->relocateable)
bfd_h_put_64 (input_bfd,
input_section->output_offset + r_vaddr,
case ALPHA_R_REFLONG:
case ALPHA_R_REFQUAD:
- case ALPHA_R_BRADDR:
case ALPHA_R_HINT:
+ relocatep = true;
+ break;
+
+ case ALPHA_R_BRADDR:
case ALPHA_R_SREL16:
case ALPHA_R_SREL32:
case ALPHA_R_SREL64:
+ if (r_extern)
+ addend += - (r_vaddr + 4);
relocatep = true;
break;
/* This marks the ldah of an ldah/lda pair which loads the
gp register with the difference of the gp value and the
current location. The second of the pair is r_symndx
- bytes ahead, and is also marked with an ALPHA_R_IGNORE
- reloc. */
+ bytes ahead. It used to be marked with an ALPHA_R_IGNORE
+ reloc, but OSF/1 3.2 no longer does that. */
{
unsigned long insn1, insn2;
- BFD_ASSERT (ext_rel + 1 < ext_rel_end
- && (((ext_rel + 1)->r_bits[0]
- & RELOC_BITS0_TYPE_LITTLE)
- >> RELOC_BITS0_TYPE_SH_LITTLE) == ALPHA_R_IGNORE
- && (bfd_h_get_64 (input_bfd,
- (bfd_byte *) (ext_rel + 1)->r_vaddr)
- == r_vaddr - input_section->vma + r_symndx));
-
/* Get the two instructions. */
insn1 = bfd_get_32 (input_bfd,
contents + r_vaddr - input_section->vma);
relocated. */
if (! ((*info->callbacks->undefined_symbol)
(info, h->root.root.string, input_bfd,
- input_section, (bfd_vma) 0)))
+ input_section, (bfd_vma) 0, true)))
return false;
addend = 0;
}
if (! ((*info->callbacks->undefined_symbol)
(info, h->root.root.string, input_bfd,
input_section,
- r_vaddr - input_section->vma)))
+ r_vaddr - input_section->vma, true)))
return false;
relocation = 0;
}
if (gp_usedp && gp_undefined)
{
if (! ((*info->callbacks->reloc_dangerous)
- (info, "GP relative relocation when GP not defined",
+ (info, _("GP relative relocation when GP not defined"),
input_bfd, input_section, r_vaddr - input_section->vma)))
return false;
/* Only give the error once per link. */
- ecoff_data (output_bfd)->gp = gp = 4;
+ gp = 4;
+ _bfd_set_gp_value (output_bfd, gp);
gp_undefined = false;
}
}
return true;
}
\f
+/* Archive handling. In OSF/1 (or Digital Unix) v3.2, Digital
+ introduced archive packing, in which the elements in an archive are
+ optionally compressed using a simple dictionary scheme. We know
+ how to read such archives, but we don't write them. */
+
+#define alpha_ecoff_slurp_armap _bfd_ecoff_slurp_armap
+#define alpha_ecoff_slurp_extended_name_table \
+ _bfd_ecoff_slurp_extended_name_table
+#define alpha_ecoff_construct_extended_name_table \
+ _bfd_ecoff_construct_extended_name_table
+#define alpha_ecoff_truncate_arname _bfd_ecoff_truncate_arname
+#define alpha_ecoff_write_armap _bfd_ecoff_write_armap
+#define alpha_ecoff_generic_stat_arch_elt _bfd_ecoff_generic_stat_arch_elt
+#define alpha_ecoff_update_armap_timestamp _bfd_ecoff_update_armap_timestamp
+
+/* A compressed file uses this instead of ARFMAG. */
+
+#define ARFZMAG "Z\012"
+
+/* Read an archive header. This is like the standard routine, but it
+ also accepts ARFZMAG. */
+
+static PTR
+alpha_ecoff_read_ar_hdr (abfd)
+ bfd *abfd;
+{
+ struct areltdata *ret;
+ struct ar_hdr *h;
+
+ ret = (struct areltdata *) _bfd_generic_read_ar_hdr_mag (abfd, ARFZMAG);
+ if (ret == NULL)
+ return NULL;
+
+ h = (struct ar_hdr *) ret->arch_header;
+ if (strncmp (h->ar_fmag, ARFZMAG, 2) == 0)
+ {
+ bfd_byte ab[8];
+
+ /* This is a compressed file. We must set the size correctly.
+ The size is the eight bytes after the dummy file header. */
+ if (bfd_seek (abfd, FILHSZ, SEEK_CUR) != 0
+ || bfd_read (ab, 1, 8, abfd) != 8
+ || bfd_seek (abfd, - (FILHSZ + 8), SEEK_CUR) != 0)
+ return NULL;
+
+ ret->parsed_size = bfd_h_get_64 (abfd, ab);
+ }
+
+ return (PTR) ret;
+}
+
+/* Get an archive element at a specified file position. This is where
+ we uncompress the archive element if necessary. */
+
+static bfd *
+alpha_ecoff_get_elt_at_filepos (archive, filepos)
+ bfd *archive;
+ file_ptr filepos;
+{
+ bfd *nbfd = NULL;
+ struct areltdata *tdata;
+ struct ar_hdr *hdr;
+ bfd_byte ab[8];
+ bfd_size_type size;
+ bfd_byte *buf, *p;
+ struct bfd_in_memory *bim;
+
+ nbfd = _bfd_get_elt_at_filepos (archive, filepos);
+ if (nbfd == NULL)
+ goto error_return;
+
+ if ((nbfd->flags & BFD_IN_MEMORY) != 0)
+ {
+ /* We have already expanded this BFD. */
+ return nbfd;
+ }
+
+ tdata = (struct areltdata *) nbfd->arelt_data;
+ hdr = (struct ar_hdr *) tdata->arch_header;
+ if (strncmp (hdr->ar_fmag, ARFZMAG, 2) != 0)
+ return nbfd;
+
+ /* We must uncompress this element. We do this by copying it into a
+ memory buffer, and making bfd_read and bfd_seek use that buffer.
+ This can use a lot of memory, but it's simpler than getting a
+ temporary file, making that work with the file descriptor caching
+ code, and making sure that it is deleted at all appropriate
+ times. It can be changed if it ever becomes important. */
+
+ /* The compressed file starts with a dummy ECOFF file header. */
+ if (bfd_seek (nbfd, FILHSZ, SEEK_SET) != 0)
+ goto error_return;
+
+ /* The next eight bytes are the real file size. */
+ if (bfd_read (ab, 1, 8, nbfd) != 8)
+ goto error_return;
+ size = bfd_h_get_64 (nbfd, ab);
+
+ if (size == 0)
+ buf = NULL;
+ else
+ {
+ bfd_size_type left;
+ bfd_byte dict[4096];
+ unsigned int h;
+ bfd_byte b;
+
+ buf = (bfd_byte *) bfd_alloc (nbfd, size);
+ if (buf == NULL)
+ goto error_return;
+ p = buf;
+
+ left = size;
+
+ /* I don't know what the next eight bytes are for. */
+ if (bfd_read (ab, 1, 8, nbfd) != 8)
+ goto error_return;
+
+ /* This is the uncompression algorithm. It's a simple
+ dictionary based scheme in which each character is predicted
+ by a hash of the previous three characters. A control byte
+ indicates whether the character is predicted or whether it
+ appears in the input stream; each control byte manages the
+ next eight bytes in the output stream. */
+ memset (dict, 0, sizeof dict);
+ h = 0;
+ while (bfd_read (&b, 1, 1, nbfd) == 1)
+ {
+ unsigned int i;
+
+ for (i = 0; i < 8; i++, b >>= 1)
+ {
+ bfd_byte n;
+
+ if ((b & 1) == 0)
+ n = dict[h];
+ else
+ {
+ if (! bfd_read (&n, 1, 1, nbfd))
+ goto error_return;
+ dict[h] = n;
+ }
+
+ *p++ = n;
+
+ --left;
+ if (left == 0)
+ break;
+
+ h <<= 4;
+ h ^= n;
+ h &= sizeof dict - 1;
+ }
+
+ if (left == 0)
+ break;
+ }
+ }
+
+ /* Now the uncompressed file contents are in buf. */
+ bim = ((struct bfd_in_memory *)
+ bfd_alloc (nbfd, sizeof (struct bfd_in_memory)));
+ if (bim == NULL)
+ goto error_return;
+ bim->size = size;
+ bim->buffer = buf;
+
+ nbfd->mtime_set = true;
+ nbfd->mtime = strtol (hdr->ar_date, (char **) NULL, 10);
+
+ nbfd->flags |= BFD_IN_MEMORY;
+ nbfd->iostream = (PTR) bim;
+ BFD_ASSERT (! nbfd->cacheable);
+
+ return nbfd;
+
+ error_return:
+ if (nbfd != NULL)
+ bfd_close (nbfd);
+ return NULL;
+}
+
+/* Open the next archived file. */
+
+static bfd *
+alpha_ecoff_openr_next_archived_file (archive, last_file)
+ bfd *archive;
+ bfd *last_file;
+{
+ file_ptr filestart;
+
+ if (last_file == NULL)
+ filestart = bfd_ardata (archive)->first_file_filepos;
+ else
+ {
+ struct areltdata *t;
+ struct ar_hdr *h;
+ bfd_size_type size;
+
+ /* We can't use arelt_size here, because that uses parsed_size,
+ which is the uncompressed size. We need the compressed size. */
+ t = (struct areltdata *) last_file->arelt_data;
+ h = (struct ar_hdr *) t->arch_header;
+ size = strtol (h->ar_size, (char **) NULL, 10);
+
+ /* Pad to an even boundary...
+ Note that last_file->origin can be odd in the case of
+ BSD-4.4-style element with a long odd size. */
+ filestart = last_file->origin + size;
+ filestart += filestart % 2;
+ }
+
+ return alpha_ecoff_get_elt_at_filepos (archive, filestart);
+}
+
+/* Open the archive file given an index into the armap. */
+
+static bfd *
+alpha_ecoff_get_elt_at_index (abfd, index)
+ bfd *abfd;
+ symindex index;
+{
+ carsym *entry;
+
+ entry = bfd_ardata (abfd)->symdefs + index;
+ return alpha_ecoff_get_elt_at_filepos (abfd, entry->file_offset);
+}
+\f
/* This is the ECOFF backend structure. The backend field of the
target vector points to this. */
(unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */
alpha_ecoff_swap_filehdr_out, alpha_ecoff_swap_aouthdr_out,
alpha_ecoff_swap_scnhdr_out,
- FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, true,
+ FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, FILNMLEN, true, false, 4, false, 2,
alpha_ecoff_swap_filehdr_in, alpha_ecoff_swap_aouthdr_in,
alpha_ecoff_swap_scnhdr_in, NULL,
alpha_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook,
alpha_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags,
_bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL
},
/* Supported architecture. */
bfd_arch_alpha,
/* Relocate section contents while linking. */
alpha_relocate_section,
/* Do final adjustments to filehdr and aouthdr. */
- alpha_adjust_headers
+ alpha_adjust_headers,
+ /* Read an element from an archive at a given file position. */
+ alpha_ecoff_get_elt_at_filepos
};
/* Looking up a reloc type is Alpha specific. */
/* Relaxing sections is generic. */
#define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section
+#define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections
const bfd_target ecoffalpha_little_vec =
{
"ecoff-littlealpha", /* name */
bfd_target_ecoff_flavour,
- false, /* data byte order is little */
- false, /* header byte order is little */
+ BFD_ENDIAN_LITTLE, /* data byte order is little */
+ BFD_ENDIAN_LITTLE, /* header byte order is little */
(HAS_RELOC | EXEC_P | /* object flags */
HAS_LINENO | HAS_DEBUG |
BFD_JUMP_TABLE_GENERIC (_bfd_ecoff),
BFD_JUMP_TABLE_COPY (_bfd_ecoff),
BFD_JUMP_TABLE_CORE (_bfd_nocore),
- BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff),
+ BFD_JUMP_TABLE_ARCHIVE (alpha_ecoff),
BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff),
BFD_JUMP_TABLE_RELOCS (_bfd_ecoff),
BFD_JUMP_TABLE_WRITE (_bfd_ecoff),
BFD_JUMP_TABLE_LINK (_bfd_ecoff),
BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+ NULL,
+
(PTR) &alpha_ecoff_backend_data
};