/* Generic ECOFF (Extended-COFF) routines.
- Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
Original version by Per Bothner.
Full support added by Ian Lance Taylor, ian@cygnus.com.
#include "libbfd.h"
#include "aout/ar.h"
#include "aout/ranlib.h"
+#include "aout/stab_gnu.h"
/* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines
some other stuff which we don't want and which conflicts with stuff
/* Prototypes for static functions. */
static int ecoff_get_magic PARAMS ((bfd *abfd));
+static long ecoff_sec_to_styp_flags PARAMS ((const char *name,
+ flagword flags));
static boolean ecoff_slurp_symbolic_header PARAMS ((bfd *abfd));
static boolean ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym,
asymbol *asym, int ext,
/* Create an ECOFF object. */
boolean
-ecoff_mkobject (abfd)
+_bfd_ecoff_mkobject (abfd)
bfd *abfd;
{
abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *)
specific information. */
PTR
-ecoff_mkobject_hook (abfd, filehdr, aouthdr)
+_bfd_ecoff_mkobject_hook (abfd, filehdr, aouthdr)
bfd *abfd;
PTR filehdr;
PTR aouthdr;
struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr;
ecoff_data_type *ecoff;
- if (ecoff_mkobject (abfd) == false)
+ if (_bfd_ecoff_mkobject (abfd) == false)
return NULL;
ecoff = ecoff_data (abfd);
/*ARGSUSED*/
asection *
-ecoff_make_section_hook (abfd, name)
+_bfd_ecoff_make_section_hook (abfd, name)
bfd *abfd;
char *name;
{
/* Initialize a new section. */
boolean
-ecoff_new_section_hook (abfd, section)
+_bfd_ecoff_new_section_hook (abfd, section)
bfd *abfd;
asection *section;
{
/* For the .pdata section, which has a special meaning on the Alpha,
- we set the alignment to 8. We correct this later in
+ we set the alignment power to 3. We correct this later in
ecoff_compute_section_file_positions. We do this hackery because
we need to know the exact unaligned size of the .pdata section in
- order to set the lnnoptr field correctly. */
+ order to set the lnnoptr field correctly. For every other
+ section we use an alignment power of 4; this could be made target
+ dependent by adding a field to ecoff_backend_data, but 4 appears
+ to be correct for both the MIPS and the Alpha. */
if (strcmp (section->name, _PDATA) == 0)
section->alignment_power = 3;
else
- section->alignment_power = abfd->xvec->align_power_min;
+ section->alignment_power = 4;
if (strcmp (section->name, _TEXT) == 0)
section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
for each target, but there aren't all that many ECOFF targets. */
boolean
-ecoff_set_arch_mach_hook (abfd, filehdr)
+_bfd_ecoff_set_arch_mach_hook (abfd, filehdr)
bfd *abfd;
PTR filehdr;
{
}
/* Get the magic number to use based on the architecture and machine.
- This is the inverse of ecoff_set_arch_mach_hook, above. */
+ This is the inverse of _bfd_ecoff_set_arch_mach_hook, above. */
static int
ecoff_get_magic (abfd)
/* Get the section s_flags to use for a section. */
-long
+static long
ecoff_sec_to_styp_flags (name, flags)
- CONST char *name;
+ const char *name;
flagword flags;
{
long styp;
/*ARGSUSED*/
flagword
-ecoff_styp_to_sec_flags (abfd, hdr)
+_bfd_ecoff_styp_to_sec_flags (abfd, hdr, name)
bfd *abfd;
PTR hdr;
+ const char *name;
{
struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
long styp_flags = internal_s->s_flags;
info comes from the file header record (fh-fBigendian). */
void
-ecoff_swap_tir_in (bigend, ext_copy, intern)
+_bfd_ecoff_swap_tir_in (bigend, ext_copy, intern)
int bigend;
- struct tir_ext *ext_copy;
+ const struct tir_ext *ext_copy;
TIR *intern;
{
struct tir_ext ext[1];
info comes from the file header record (fh-fBigendian). */
void
-ecoff_swap_tir_out (bigend, intern_copy, ext)
+_bfd_ecoff_swap_tir_out (bigend, intern_copy, ext)
int bigend;
- TIR *intern_copy;
+ const TIR *intern_copy;
struct tir_ext *ext;
{
TIR intern[1];
big-endian or little-endian format.*/
void
-ecoff_swap_rndx_in (bigend, ext_copy, intern)
+_bfd_ecoff_swap_rndx_in (bigend, ext_copy, intern)
int bigend;
- struct rndx_ext *ext_copy;
+ const struct rndx_ext *ext_copy;
RNDXR *intern;
{
struct rndx_ext ext[1];
big-endian or little-endian format.*/
void
-ecoff_swap_rndx_out (bigend, intern_copy, ext)
+_bfd_ecoff_swap_rndx_out (bigend, intern_copy, ext)
int bigend;
- RNDXR *intern_copy;
+ const RNDXR *intern_copy;
struct rndx_ext *ext;
{
RNDXR intern[1];
}
/* Read in and swap the important symbolic information for an ECOFF
- object file. This is called by gdb. */
+ object file. This is called by gdb via the read_debug_info entry
+ point in the backend structure. */
+/*ARGSUSED*/
boolean
-ecoff_slurp_symbolic_info (abfd)
+_bfd_ecoff_slurp_symbolic_info (abfd, ignore, debug)
bfd *abfd;
+ asection *ignore;
+ struct ecoff_debug_info *debug;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
HDRR *internal_symhdr;
bfd_size_type raw_end;
bfd_size_type cb_end;
+ BFD_ASSERT (debug == &ecoff_data (abfd)->debug_info);
+
/* Check whether we've already gotten it, and whether there's any to
get. */
if (ecoff_data (abfd)->raw_syments != (PTR) NULL)
if (! ecoff_slurp_symbolic_header (abfd))
return false;
- internal_symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
+ internal_symhdr = &debug->symbolic_header;
/* Read all the symbolic information at once. */
raw_base = (ecoff_data (abfd)->sym_filepos
/* Get pointers for the numeric offsets in the HDRR structure. */
#define FIX(off1, off2, type) \
if (internal_symhdr->off1 == 0) \
- ecoff_data (abfd)->debug_info.off2 = (type) NULL; \
+ debug->off2 = (type) NULL; \
else \
- ecoff_data (abfd)->debug_info.off2 = (type) ((char *) raw \
- + internal_symhdr->off1 \
- - raw_base)
+ debug->off2 = (type) ((char *) raw \
+ + internal_symhdr->off1 \
+ - raw_base)
FIX (cbLineOffset, line, unsigned char *);
FIX (cbDnOffset, external_dnr, PTR);
FIX (cbPdOffset, external_pdr, PTR);
We need to look at the fdr to deal with a lot of information in
the symbols, so we swap them here. */
- ecoff_data (abfd)->debug_info.fdr =
- (struct fdr *) bfd_alloc (abfd,
- (internal_symhdr->ifdMax *
- sizeof (struct fdr)));
- if (ecoff_data (abfd)->debug_info.fdr == NULL)
+ debug->fdr = (struct fdr *) bfd_alloc (abfd,
+ (internal_symhdr->ifdMax *
+ sizeof (struct fdr)));
+ if (debug->fdr == NULL)
{
bfd_set_error (bfd_error_no_memory);
return false;
}
external_fdr_size = backend->debug_swap.external_fdr_size;
- fdr_ptr = ecoff_data (abfd)->debug_info.fdr;
- fraw_src = (char *) ecoff_data (abfd)->debug_info.external_fdr;
+ fdr_ptr = debug->fdr;
+ fraw_src = (char *) debug->external_fdr;
fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size;
for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
(*backend->debug_swap.swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr);
/* Create an empty symbol. */
asymbol *
-ecoff_make_empty_symbol (abfd)
+_bfd_ecoff_make_empty_symbol (abfd)
bfd *abfd;
{
ecoff_symbol_type *new;
asym->the_bfd = abfd;
asym->value = ecoff_sym->value;
asym->section = &bfd_debug_section;
- asym->udata = NULL;
+ asym->udata.i = 0;
/* An indirect symbol requires two consecutive stabs symbols. */
if (*indirect_ptr_ptr != (asymbol *) NULL)
(*indirect_ptr_ptr)->value = (bfd_vma) asym;
asym->flags = BSF_DEBUGGING;
- asym->section = &bfd_und_section;
+ asym->section = bfd_und_section_ptr;
*indirect_ptr_ptr = NULL;
return true;
}
&& (ECOFF_UNMARK_STAB (ecoff_sym->index) | N_EXT) == (N_INDR | N_EXT))
{
asym->flags = BSF_DEBUGGING | BSF_INDIRECT;
- asym->section = &bfd_ind_section;
+ asym->section = bfd_ind_section_ptr;
/* Pass this symbol on to the next call to this function. */
*indirect_ptr_ptr = asym;
return true;
if (ext)
asym->flags = BSF_EXPORT | BSF_GLOBAL;
else
- asym->flags = BSF_LOCAL;
+ {
+ asym->flags = BSF_LOCAL;
+ /* Normally, a local stProc symbol will have a corresponding
+ external symbol. We mark the local symbol as a debugging
+ symbol, in order to prevent nm from printing both out.
+ Similarly, we mark stLabel and stabs symbols as debugging
+ symbols. In both cases, we do want to set the value
+ correctly based on the symbol class. */
+ if (ecoff_sym->st == stProc
+ || ecoff_sym->st == stLabel
+ || ECOFF_IS_STAB (ecoff_sym))
+ asym->flags |= BSF_DEBUGGING;
+ }
switch (ecoff_sym->sc)
{
case scNil:
asym->flags = BSF_DEBUGGING;
break;
case scAbs:
- asym->section = &bfd_abs_section;
+ asym->section = bfd_abs_section_ptr;
break;
case scUndefined:
- asym->section = &bfd_und_section;
+ asym->section = bfd_und_section_ptr;
asym->flags = 0;
asym->value = 0;
break;
case scCommon:
if (asym->value > ecoff_data (abfd)->gp_size)
{
- asym->section = &bfd_com_section;
+ asym->section = bfd_com_section_ptr;
asym->flags = 0;
break;
}
asym->flags = BSF_DEBUGGING;
break;
case scSUndefined:
- asym->section = &bfd_und_section;
+ asym->section = bfd_und_section_ptr;
asym->flags = 0;
asym->value = 0;
break;
/* Read an ECOFF symbol table. */
boolean
-ecoff_slurp_symbol_table (abfd)
+_bfd_ecoff_slurp_symbol_table (abfd)
bfd *abfd;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
return true;
/* Get the symbolic information. */
- if (ecoff_slurp_symbolic_info (abfd) == false)
+ if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
+ &ecoff_data (abfd)->debug_info))
return false;
if (bfd_get_symcount (abfd) == 0)
return true;
/* Return the amount of space needed for the canonical symbols. */
long
-ecoff_get_symtab_upper_bound (abfd)
+_bfd_ecoff_get_symtab_upper_bound (abfd)
bfd *abfd;
{
- if (! ecoff_slurp_symbolic_info (abfd))
+ if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
+ &ecoff_data (abfd)->debug_info))
return -1;
if (bfd_get_symcount (abfd) == 0)
/* Get the canonical symbols. */
long
-ecoff_get_symtab (abfd, alocation)
+_bfd_ecoff_get_symtab (abfd, alocation)
bfd *abfd;
asymbol **alocation;
{
ecoff_symbol_type *symbase;
ecoff_symbol_type **location = (ecoff_symbol_type **) alocation;
- if (ecoff_slurp_symbol_table (abfd) == false)
+ if (_bfd_ecoff_slurp_symbol_table (abfd) == false)
return -1;
if (bfd_get_symcount (abfd) == 0)
return 0;
} qualifiers[7];
unsigned int basic_type;
int i;
- static char buffer1[1024];
+ char buffer1[1024];
static char buffer2[1024];
char *p1 = buffer1;
char *p2 = buffer2;
if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == -1)
return "-1 (no type)";
- ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti);
+ _bfd_ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti);
basic_type = u.ti.bt;
qualifiers[0].type = u.ti.tq0;
2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
case btStruct: /* Structure (Record) */
- ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
(long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
"struct");
2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
case btUnion: /* Union */
- ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
(long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
"union");
2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
case btEnum: /* Enumeration */
- ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
+ _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
ecoff_emit_aggregate (abfd, fdr, p1, &rndx,
(long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
"enum");
/*ARGSUSED*/
void
-ecoff_get_symbol_info (abfd, symbol, ret)
+_bfd_ecoff_get_symbol_info (abfd, symbol, ret)
bfd *abfd; /* Ignored. */
asymbol *symbol;
symbol_info *ret;
/* Print information about an ECOFF symbol. */
void
-ecoff_print_symbol (abfd, filep, symbol, how)
+_bfd_ecoff_print_symbol (abfd, filep, symbol, how)
bfd *abfd;
PTR filep;
asymbol *symbol;
|| (section->flags & SEC_CONSTRUCTOR) != 0)
return true;
- if (ecoff_slurp_symbol_table (abfd) == false)
+ if (_bfd_ecoff_slurp_symbol_table (abfd) == false)
return false;
internal_relocs = (arelent *) bfd_alloc (abfd,
else if (intern.r_symndx == RELOC_SECTION_NONE
|| intern.r_symndx == RELOC_SECTION_ABS)
{
- rptr->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr;
+ rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
rptr->addend = 0;
}
else
/* Get a canonical list of relocs. */
long
-ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
+_bfd_ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
bfd *abfd;
asection *section;
arelent **relptr;
return section->reloc_count;
}
\f
+
+static int
+cmp_fdrtab_entry (leftp, rightp)
+ const void *leftp, *rightp;
+{
+ const struct ecoff_fdrtab_entry *lp = leftp;
+ const struct ecoff_fdrtab_entry *rp = rightp;
+
+ if (lp->base_addr < rp->base_addr)
+ return -1;
+ if (lp->base_addr > rp->base_addr)
+ return 1;
+ return 0;
+}
+
+/* Each file descriptor (FDR) has a memory address, to simplify
+ looking up an FDR by address, we build a table covering all FDRs
+ that have a least one procedure descriptor in them. The final
+ table will be sorted by address so we can look it up via binary
+ search. */
+static boolean
+mk_fdrtab (abfd)
+ bfd *abfd;
+{
+ struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info;
+ const struct ecoff_debug_swap * const debug_swap
+ = &ecoff_backend (abfd)->debug_swap;
+ struct ecoff_fdrtab_entry *tab;
+ FDR *fdr_ptr;
+ FDR *fdr_start;
+ FDR *fdr_end;
+ boolean stabs;
+ long len;
+
+ /* Make sure we have the FDR's. */
+ if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, debug_info)
+ || bfd_get_symcount (abfd) == 0)
+ return false;
+
+ fdr_start = debug_info->fdr;
+ fdr_end = fdr_start + debug_info->symbolic_header.ifdMax;
+
+ /* First, let's see how long the table needs to be: */
+ for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
+ {
+ if (fdr_ptr->cpd == 0) /* skip FDRs that have no PDRs */
+ continue;
+ ++len;
+ }
+
+ /* Now, create and fill in the table: */
+
+ ecoff_data (abfd)->fdrtab = (struct ecoff_fdrtab_entry*)
+ bfd_zalloc (abfd,len * sizeof (struct ecoff_fdrtab_entry));
+ if (ecoff_data (abfd)->fdrtab == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ ecoff_data (abfd)->fdrtab_len = len;
+
+ tab = ecoff_data (abfd)->fdrtab;
+ for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
+ {
+ if (fdr_ptr->cpd == 0)
+ continue;
+
+ /* Check whether this file has stabs debugging information. In
+ a file with stabs debugging information, the second local
+ symbol is named @stabs. */
+ stabs = false;
+ if (fdr_ptr->csym >= 2)
+ {
+ char *sym_ptr;
+ SYMR sym;
+
+ sym_ptr = ((char *) debug_info->external_sym
+ + (fdr_ptr->isymBase + 1)*debug_swap->external_sym_size);
+ (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
+ if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
+ STABS_SYMBOL) == 0)
+ stabs = true;
+ }
+
+ if (!stabs)
+ {
+ bfd_size_type external_pdr_size;
+ char *pdr_ptr;
+ PDR pdr;
+
+ external_pdr_size = debug_swap->external_pdr_size;
+
+ pdr_ptr = ((char *) debug_info->external_pdr
+ + fdr_ptr->ipdFirst * external_pdr_size);
+ (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+ /* The address of the first PDR is the offset of that
+ procedure relative to the beginning of file FDR. */
+ tab->base_addr = fdr_ptr->adr - pdr.adr;
+ }
+ else
+ {
+ /* XXX I don't know about stabs, so this is a guess
+ (davidm@cs.arizona.edu): */
+ tab->base_addr = fdr_ptr->adr;
+ }
+ tab->fdr = fdr_ptr;
+ ++tab;
+ }
+ /* Finally, the table is sorted in increasing memory-address order.
+ The table is mostly sorted already, but there are cases (e.g.,
+ static functions in include files), where this does not hold.
+ Use "odump -PFv" to verify... */
+ qsort((char*) ecoff_data (abfd)->fdrtab, len,
+ sizeof(struct ecoff_fdrtab_entry), cmp_fdrtab_entry);
+
+ return true;
+}
+
+/* Return index of first FDR that covers to OFFSET. */
+static long
+lookup (abfd, offset)
+ bfd *abfd;
+ bfd_vma offset;
+{
+ long low, high, len;
+ long mid = -1;
+ struct ecoff_fdrtab_entry *tab;
+
+ len = ecoff_data(abfd)->fdrtab_len;
+ if (!len)
+ return -1;
+
+ tab = ecoff_data(abfd)->fdrtab;
+ for (low = 0, high = len - 1 ; low != high ;)
+ {
+ mid = (high + low) / 2;
+ if (offset >= tab[mid].base_addr && offset < tab[mid + 1].base_addr)
+ goto find_min;
+
+ if (tab[mid].base_addr > offset)
+ high = mid;
+ else
+ low = mid + 1;
+ }
+ ++mid;
+
+ /* last entry is catch-all for all higher addresses: */
+ if (offset < tab[mid].base_addr)
+ return -1;
+
+ find_min:
+
+ while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr)
+ --mid;
+
+ return mid;
+}
+
/* Provided a BFD, a section and an offset into the section, calculate
and return the name of the source file and the line nearest to the
wanted location. */
/*ARGSUSED*/
boolean
-ecoff_find_nearest_line (abfd,
- section,
- ignore_symbols,
- offset,
- filename_ptr,
- functionname_ptr,
- retline_ptr)
+_bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
+ filename_ptr, functionname_ptr, retline_ptr)
bfd *abfd;
asection *section;
asymbol **ignore_symbols;
{
const struct ecoff_debug_swap * const debug_swap
= &ecoff_backend (abfd)->debug_swap;
+ struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info;
+ struct ecoff_fdrtab_entry *tab;
+ boolean stabs;
FDR *fdr_ptr;
- FDR *fdr_start;
- FDR *fdr_end;
- FDR *fdr_hold;
- bfd_size_type external_pdr_size;
- char *pdr_ptr;
- char *pdr_end;
- PDR pdr;
- unsigned char *line_ptr;
- unsigned char *line_end;
- int lineno;
+ int i;
+ offset += section->vma;
/* If we're not in the .text section, we don't have any line
numbers. */
if (strcmp (section->name, _TEXT) != 0
|| offset < ecoff_data (abfd)->text_start
|| offset >= ecoff_data (abfd)->text_end)
return false;
-
- /* Make sure we have the FDR's. */
- if (ecoff_slurp_symbolic_info (abfd) == false
- || bfd_get_symcount (abfd) == 0)
- return false;
-
- /* Each file descriptor (FDR) has a memory address. Here we track
- down which FDR we want. The FDR's are stored in increasing
- memory order. If speed is ever important, this can become a
- binary search. We must ignore FDR's with no PDR entries; they
- will have the adr of the FDR before or after them. */
- fdr_start = ecoff_data (abfd)->debug_info.fdr;
- fdr_end = fdr_start + ecoff_data (abfd)->debug_info.symbolic_header.ifdMax;
- fdr_hold = (FDR *) NULL;
- for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++)
- {
- if (fdr_ptr->cpd == 0)
- continue;
- if (offset < fdr_ptr->adr)
- break;
- fdr_hold = fdr_ptr;
- }
- if (fdr_hold == (FDR *) NULL)
+ /* Build FDR table (sorted by object file's base-address) if we
+ don't have it already. */
+ if (!ecoff_data (abfd)->fdrtab && !mk_fdrtab (abfd))
return false;
- fdr_ptr = fdr_hold;
-
- /* Each FDR has a list of procedure descriptors (PDR). PDR's also
- have an address, which is relative to the FDR address, and are
- also stored in increasing memory order. */
- offset -= fdr_ptr->adr;
- external_pdr_size = debug_swap->external_pdr_size;
- pdr_ptr = ((char *) ecoff_data (abfd)->debug_info.external_pdr
- + fdr_ptr->ipdFirst * external_pdr_size);
- pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
- (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
-
- /* The address of the first PDR is an offset which applies to the
- addresses of all the PDR's. */
- offset += pdr.adr;
-
- for (pdr_ptr += external_pdr_size;
- pdr_ptr < pdr_end;
- pdr_ptr += external_pdr_size)
+ tab = ecoff_data (abfd)->fdrtab;
+
+ i = lookup(abfd, offset); /* find first FDR for address OFFSET */
+ if (i < 0)
+ return false; /* no FDR, no fun... */
+ fdr_ptr = tab[i].fdr;
+
+ /* Check whether this file has stabs debugging information. In a
+ file with stabs debugging information, the second local symbol is
+ named @stabs. */
+ stabs = false;
+ if (fdr_ptr->csym >= 2)
{
- (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
- if (offset < pdr.adr)
- break;
+ char *sym_ptr;
+ SYMR sym;
+
+ sym_ptr = ((char *) debug_info->external_sym
+ + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size);
+ (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
+ if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss,
+ STABS_SYMBOL) == 0)
+ stabs = true;
}
- /* Now we can look for the actual line number. The line numbers are
- stored in a very funky format, which I won't try to describe.
- Note that right here pdr_ptr and pdr hold the PDR *after* the one
- we want; we need this to compute line_end. */
- line_end = ecoff_data (abfd)->debug_info.line;
- if (pdr_ptr == pdr_end)
- line_end += fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
- else
- line_end += fdr_ptr->cbLineOffset + pdr.cbLineOffset;
-
- /* Now change pdr and pdr_ptr to the one we want. */
- pdr_ptr -= external_pdr_size;
- (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
-
- offset -= pdr.adr;
- lineno = pdr.lnLow;
- line_ptr = (ecoff_data (abfd)->debug_info.line
- + fdr_ptr->cbLineOffset
- + pdr.cbLineOffset);
- while (line_ptr < line_end)
+ if (!stabs)
{
- int delta;
- int count;
-
- delta = *line_ptr >> 4;
- if (delta >= 0x8)
- delta -= 0x10;
- count = (*line_ptr & 0xf) + 1;
- ++line_ptr;
- if (delta == -8)
+ bfd_size_type external_pdr_size;
+ char *pdr_ptr;
+ char *best_pdr = NULL;
+ FDR *best_fdr;
+ bfd_vma best_dist = ~0;
+ PDR pdr;
+ unsigned char *line_ptr;
+ unsigned char *line_end;
+ int lineno;
+ /* This file uses ECOFF debugging information. Each FDR has a
+ list of procedure descriptors (PDR). The address in the FDR
+ is the absolute address of the first procedure. The address
+ in the first PDR gives the offset of that procedure relative
+ to the object file's base-address. The addresses in
+ subsequent PDRs specify each procedure's address relative to
+ the object file's base-address. To make things more juicy,
+ whenever the PROF bit in the PDR is set, the real entry point
+ of the procedure may be 16 bytes below what would normally be
+ the procedure's entry point. Instead, DEC came up with a
+ wicked scheme to create profiled libraries "on the fly":
+ instead of shipping a regular and a profiled version of each
+ library, they insert 16 bytes of unused space in front of
+ each procedure and set the "prof" bit in the PDR to indicate
+ that there is a gap there (this is done automagically by "as"
+ when option "-pg" is specified). Thus, normally, you link
+ against such a library and, except for lots of 16 byte gaps
+ between functions, things will behave as usual. However,
+ when invoking "ld" with option "-pg", it will fill those gaps
+ with code that calls mcount(). It then moves the function's
+ entry point down by 16 bytes, and out pops a binary that has
+ all functions profiled.
+
+ NOTE: Neither FDRs nor PDRs are strictly sorted in memory
+ order. For example, when including header-files that
+ define functions, the FDRs follow behind the including
+ file, even though their code may have been generated at
+ a lower address. File coff-alpha.c from libbfd
+ illustrates this (use "odump -PFv" to look at a file's
+ FDR/PDR). Similarly, PDRs are sometimes out of order
+ as well. An example of this is OSF/1 v3.0 libc's
+ malloc.c. I'm not sure why this happens, but it could
+ be due to optimizations that reorder a function's
+ position within an object-file.
+
+ Strategy:
+
+ On the first call to this function, we build a table of FDRs
+ that is sorted by the base-address of the object-file the FDR
+ is referring to. Notice that each object-file may contain
+ code from multiple source files (e.g., due to code defined in
+ include files). Thus, for any given base-address, there may
+ be multiple FDRs (but this case is, fortunately, uncommon).
+ lookup(addr) guarantees to return the first FDR that applies
+ to address ADDR. Thus, after invoking lookup(), we have a
+ list of FDRs that may contain the PDR for ADDR. Next, we
+ walk through the PDRs of these FDRs and locate the one that
+ is closest to ADDR (i.e., for which the difference between
+ ADDR and the PDR's entry point is positive and minimal).
+ Once, the right FDR and PDR are located, we simply walk
+ through the line-number table to lookup the line-number that
+ best matches ADDR. Obviously, things could be sped up by
+ keeping a sorted list of PDRs instead of a sorted list of
+ FDRs. However, this would increase space requirements
+ considerably, which is undesirable. */
+ external_pdr_size = debug_swap->external_pdr_size;
+
+ /* Make offset relative to object file's start-address: */
+ offset -= tab[i].base_addr;
+ /* Search FDR list starting at tab[i] for the PDR that best matches
+ OFFSET. Normally, the FDR list is only one entry long. */
+ best_fdr = NULL;
+ do
{
- delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff);
- if (delta >= 0x8000)
- delta -= 0x10000;
- line_ptr += 2;
+ bfd_vma dist, min_dist = 0;
+ char *pdr_hold;
+ char *pdr_end;
+
+ fdr_ptr = tab[i].fdr;
+
+ pdr_ptr = ((char *) debug_info->external_pdr
+ + fdr_ptr->ipdFirst * external_pdr_size);
+ pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size;
+ (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+ /* Find PDR that is closest to OFFSET. If pdr.prof is set,
+ the procedure entry-point *may* be 0x10 below pdr.adr. We
+ simply pretend that pdr.prof *implies* a lower entry-point.
+ This is safe because it just means that may identify 4 NOPs
+ in front of the function as belonging to the function. */
+ for (pdr_hold = NULL;
+ pdr_ptr < pdr_end;
+ (pdr_ptr += external_pdr_size,
+ (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr)))
+ {
+ if (offset >= (pdr.adr - 0x10 * pdr.prof))
+ {
+ dist = offset - (pdr.adr - 0x10 * pdr.prof);
+ if (!pdr_hold || dist < min_dist)
+ {
+ min_dist = dist;
+ pdr_hold = pdr_ptr;
+ }
+ }
+ }
+
+ if (!best_pdr || min_dist < best_dist)
+ {
+ best_dist = min_dist;
+ best_fdr = fdr_ptr;
+ best_pdr = pdr_hold;
+ }
+ /* continue looping until base_addr of next entry is different: */
}
- lineno += delta;
- if (offset < count * 4)
- break;
- offset -= count * 4;
- }
+ while (++i < ecoff_data (abfd)->fdrtab_len
+ && tab[i].base_addr == tab[i - 1].base_addr);
- /* If fdr_ptr->rss is -1, then this file does not have full symbols,
- at least according to gdb/mipsread.c. */
- if (fdr_ptr->rss == -1)
- {
- *filename_ptr = NULL;
- if (pdr.isym == -1)
- *functionname_ptr = NULL;
+ if (!best_fdr || !best_pdr)
+ return false; /* shouldn't happen... */
+
+ /* phew, finally we got something that we can hold onto: */
+ fdr_ptr = best_fdr;
+ pdr_ptr = best_pdr;
+ (*debug_swap->swap_pdr_in) (abfd, (PTR) pdr_ptr, &pdr);
+ /* Now we can look for the actual line number. The line numbers
+ are stored in a very funky format, which I won't try to
+ describe. The search is bounded by the end of the FDRs line
+ number entries. */
+ line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine;
+
+ /* Make offset relative to procedure entry: */
+ offset -= pdr.adr - 0x10 * pdr.prof;
+ lineno = pdr.lnLow;
+ line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset;
+ while (line_ptr < line_end)
+ {
+ int delta;
+ int count;
+
+ delta = *line_ptr >> 4;
+ if (delta >= 0x8)
+ delta -= 0x10;
+ count = (*line_ptr & 0xf) + 1;
+ ++line_ptr;
+ if (delta == -8)
+ {
+ delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff);
+ if (delta >= 0x8000)
+ delta -= 0x10000;
+ line_ptr += 2;
+ }
+ lineno += delta;
+ if (offset < count * 4)
+ break;
+ offset -= count * 4;
+ }
+
+ /* If fdr_ptr->rss is -1, then this file does not have full
+ symbols, at least according to gdb/mipsread.c. */
+ if (fdr_ptr->rss == -1)
+ {
+ *filename_ptr = NULL;
+ if (pdr.isym == -1)
+ *functionname_ptr = NULL;
+ else
+ {
+ EXTR proc_ext;
+
+ (*debug_swap->swap_ext_in)
+ (abfd,
+ ((char *) debug_info->external_ext
+ + pdr.isym * debug_swap->external_ext_size),
+ &proc_ext);
+ *functionname_ptr = debug_info->ssext + proc_ext.asym.iss;
+ }
+ }
else
{
- EXTR proc_ext;
+ SYMR proc_sym;
- (*debug_swap->swap_ext_in)
+ *filename_ptr = debug_info->ss + fdr_ptr->issBase + fdr_ptr->rss;
+ (*debug_swap->swap_sym_in)
(abfd,
- ((char *) ecoff_data (abfd)->debug_info.external_ext
- + pdr.isym * debug_swap->external_ext_size),
- &proc_ext);
- *functionname_ptr = (ecoff_data (abfd)->debug_info.ssext
- + proc_ext.asym.iss);
+ ((char *) debug_info->external_sym
+ + (fdr_ptr->isymBase + pdr.isym) * debug_swap->external_sym_size),
+ &proc_sym);
+ *functionname_ptr = debug_info->ss + fdr_ptr->issBase + proc_sym.iss;
}
+ if (lineno == ilineNil)
+ lineno = 0;
+ *retline_ptr = lineno;
}
else
{
- SYMR proc_sym;
-
- *filename_ptr = (ecoff_data (abfd)->debug_info.ss
- + fdr_ptr->issBase
- + fdr_ptr->rss);
- (*debug_swap->swap_sym_in)
- (abfd,
- ((char *) ecoff_data (abfd)->debug_info.external_sym
- + (fdr_ptr->isymBase + pdr.isym) * debug_swap->external_sym_size),
- &proc_sym);
- *functionname_ptr = (ecoff_data (abfd)->debug_info.ss
- + fdr_ptr->issBase
- + proc_sym.iss);
+ bfd_size_type external_sym_size;
+ const char *directory_name;
+ const char *main_file_name;
+ const char *current_file_name;
+ const char *function_name;
+ const char *line_file_name;
+ bfd_vma low_func_vma;
+ bfd_vma low_line_vma;
+ char *sym_ptr, *sym_ptr_end;
+ size_t len, funclen;
+ char *buffer = NULL;
+
+ /* This file uses stabs debugging information. */
+
+ *filename_ptr = NULL;
+ *functionname_ptr = NULL;
+ *retline_ptr = 0;
+
+ directory_name = NULL;
+ main_file_name = NULL;
+ current_file_name = NULL;
+ function_name = NULL;
+ line_file_name = NULL;
+ low_func_vma = 0;
+ low_line_vma = 0;
+
+ external_sym_size = debug_swap->external_sym_size;
+
+ sym_ptr = ((char *) debug_info->external_sym
+ + (fdr_ptr->isymBase + 2) * external_sym_size);
+ sym_ptr_end = sym_ptr + fdr_ptr->csym * external_sym_size;
+ for (; sym_ptr < sym_ptr_end; sym_ptr += external_sym_size)
+ {
+ SYMR sym;
+
+ (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym);
+
+ if (ECOFF_IS_STAB (&sym))
+ {
+ switch (ECOFF_UNMARK_STAB (sym.index))
+ {
+ case N_SO:
+ main_file_name = current_file_name =
+ debug_info->ss + fdr_ptr->issBase + sym.iss;
+
+ /* Check the next symbol to see if it is also an
+ N_SO symbol. */
+ if (sym_ptr + external_sym_size < sym_ptr_end)
+ {
+ SYMR nextsym;
+
+ (*debug_swap->swap_sym_in) (abfd,
+ sym_ptr + external_sym_size,
+ &nextsym);
+ if (ECOFF_IS_STAB (&nextsym)
+ && ECOFF_UNMARK_STAB (nextsym.index) == N_SO)
+ {
+ directory_name = current_file_name;
+ main_file_name = current_file_name =
+ debug_info->ss + fdr_ptr->issBase + sym.iss;
+ sym_ptr += external_sym_size;
+ }
+ }
+ break;
+
+ case N_SOL:
+ current_file_name =
+ debug_info->ss + fdr_ptr->issBase + sym.iss;
+ break;
+
+ case N_FUN:
+ if (sym.value >= low_func_vma
+ && sym.value <= offset + section->vma)
+ {
+ low_func_vma = sym.value;
+ function_name =
+ debug_info->ss + fdr_ptr->issBase + sym.iss;
+ }
+ break;
+ }
+ }
+ else if (sym.st == stLabel && sym.index != indexNil)
+ {
+ if (sym.value > offset + section->vma)
+ {
+ /* We have passed the location in the file we are
+ looking for, so we can get out of the loop. */
+ break;
+ }
+
+ if (sym.value >= low_line_vma)
+ {
+ low_line_vma = sym.value;
+ line_file_name = current_file_name;
+ *retline_ptr = sym.index;
+ }
+ }
+ }
+
+ if (*retline_ptr != 0)
+ main_file_name = line_file_name;
+
+ /* We need to remove the stuff after the colon in the function
+ name. We also need to put the directory name and the file
+ name together. */
+ if (function_name == NULL)
+ len = funclen = 0;
+ else
+ len = funclen = strlen (function_name) + 1;
+
+ if (main_file_name != NULL
+ && directory_name != NULL
+ && main_file_name[0] != '/')
+ len += strlen (directory_name) + strlen (main_file_name) + 1;
+
+ if (len != 0)
+ {
+ if (ecoff_data (abfd)->find_buffer != NULL)
+ free (ecoff_data (abfd)->find_buffer);
+ buffer = (char *) malloc (len);
+ if (buffer == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ ecoff_data (abfd)->find_buffer = buffer;
+ }
+
+ if (function_name != NULL)
+ {
+ char *colon;
+
+ strcpy (buffer, function_name);
+ colon = strchr (buffer, ':');
+ if (colon != NULL)
+ *colon = '\0';
+ *functionname_ptr = buffer;
+ }
+
+ if (main_file_name != NULL)
+ {
+ if (directory_name == NULL || main_file_name[0] == '/')
+ *filename_ptr = main_file_name;
+ else
+ {
+ sprintf (buffer + funclen, "%s%s", directory_name,
+ main_file_name);
+ *filename_ptr = buffer + funclen;
+ }
+ }
}
- if (lineno == ilineNil)
- lineno = 0;
- *retline_ptr = lineno;
+
return true;
}
+
\f
/* Copy private BFD data. This is called by objcopy and strip. We
use it to copy the ECOFF debugging information from one BFD to the
information. */
boolean
-ecoff_bfd_copy_private_bfd_data (ibfd, obfd)
+_bfd_ecoff_bfd_copy_private_bfd_data (ibfd, obfd)
bfd *ibfd;
bfd *obfd;
{
size_t c;
boolean local;
- BFD_ASSERT (ibfd->xvec == obfd->xvec);
+ /* This function is selected based on the input vector. We only
+ want to copy information over if the output BFD also uses ECOFF
+ format. */
+ if (bfd_get_flavour (obfd) != bfd_target_ecoff_flavour)
+ return true;
/* Copy the GP value and the register masks. */
ecoff_data (obfd)->gp = ecoff_data (ibfd)->gp;
callers ignore the return value. */
boolean
-ecoff_set_arch_mach (abfd, arch, machine)
+_bfd_ecoff_set_arch_mach (abfd, arch, machine)
bfd *abfd;
enum bfd_architecture arch;
unsigned long machine;
/*ARGSUSED*/
int
-ecoff_sizeof_headers (abfd, reloc)
+_bfd_ecoff_sizeof_headers (abfd, reloc)
bfd *abfd;
boolean reloc;
{
/* Get the contents of a section. */
boolean
-ecoff_get_section_contents (abfd, section, location, offset, count)
+_bfd_ecoff_get_section_contents (abfd, section, location, offset, count)
bfd *abfd;
asection *section;
PTR location;
file_ptr old_sofar;
boolean first_data;
- sofar = ecoff_sizeof_headers (abfd, false);
+ sofar = _bfd_ecoff_sizeof_headers (abfd, false);
first_data = true;
for (current = abfd->sections;
/* Set the contents of a section. */
boolean
-ecoff_set_section_contents (abfd, section, location, offset, count)
+_bfd_ecoff_set_section_contents (abfd, section, location, offset, count)
bfd *abfd;
asection *section;
PTR location;
symbol. */
if ((esym->asym.sc == scUndefined
|| esym->asym.sc == scSUndefined)
- && bfd_get_section (sym) != &bfd_und_section)
+ && ! bfd_is_und_section (bfd_get_section (sym)))
esym->asym.sc = scAbs;
/* Adjust the FDR index for the symbol by that used for the input
/* Write out an ECOFF file. */
boolean
-ecoff_write_object_contents (abfd)
+_bfd_ecoff_write_object_contents (abfd)
bfd *abfd;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
}
if ((abfd->flags & D_PAGED) != 0)
- text_size = ecoff_sizeof_headers (abfd, false);
+ text_size = _bfd_ecoff_sizeof_headers (abfd, false);
else
text_size = 0;
text_start = 0;
goto error_return;
/* Build the external symbol information. This must be done before
- writing out the relocs so that we know the symbol indices. The
- condition checks makes sure this object was not created by
- ecoff_bfd_final_link, since if it was we do not want to tamper
- with the external symbols. */
- if (bfd_get_outsymbols (abfd) != (asymbol **) NULL)
+ writing out the relocs so that we know the symbol indices. We
+ don't do this if this BFD was created by the backend linker,
+ since it will have already handled the symbols and relocs. */
+ if (! ecoff_data (abfd)->linker)
{
symhdr->iextMax = 0;
symhdr->issExtMax = 0;
/* Read in the armap. */
boolean
-ecoff_slurp_armap (abfd)
+_bfd_ecoff_slurp_armap (abfd)
bfd *abfd;
{
char nextname[17];
/* Write out an armap. */
boolean
-ecoff_write_armap (abfd, elength, map, orl_count, stridx)
+_bfd_ecoff_write_armap (abfd, elength, map, orl_count, stridx)
bfd *abfd;
unsigned int elength;
struct orl *map;
/* See whether this BFD is an archive. If it is, read in the armap
and the extended name table. */
-bfd_target *
-ecoff_archive_p (abfd)
+const bfd_target *
+_bfd_ecoff_archive_p (abfd)
bfd *abfd;
{
char armag[SARMAG + 1];
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
- return (bfd_target *) NULL;
+ return (const bfd_target *) NULL;
}
/* We are setting bfd_ardata(abfd) here, but since bfd_ardata
if (bfd_ardata (abfd) == (struct artdata *) NULL)
{
bfd_set_error (bfd_error_no_memory);
- return (bfd_target *) NULL;
+ return (const bfd_target *) NULL;
}
bfd_ardata (abfd)->first_file_filepos = SARMAG;
bfd_ardata (abfd)->extended_names = NULL;
bfd_ardata (abfd)->tdata = NULL;
- if (ecoff_slurp_armap (abfd) == false
- || ecoff_slurp_extended_name_table (abfd) == false)
+ if (_bfd_ecoff_slurp_armap (abfd) == false
+ || _bfd_ecoff_slurp_extended_name_table (abfd) == false)
{
bfd_release (abfd, bfd_ardata (abfd));
abfd->tdata.aout_ar_data = (struct artdata *) NULL;
- return (bfd_target *) NULL;
+ return (const bfd_target *) NULL;
}
return abfd->xvec;
/* Set local fields. */
ret->indx = -1;
ret->abfd = NULL;
+ ret->written = 0;
+ ret->small = 0;
}
memset ((PTR) &ret->esym, 0, sizeof ret->esym);
/* Create an ECOFF link hash table. */
struct bfd_link_hash_table *
-ecoff_bfd_link_hash_table_create (abfd)
+_bfd_ecoff_bfd_link_hash_table_create (abfd)
bfd *abfd;
{
struct ecoff_link_hash_table *ret;
appropriate. */
boolean
-ecoff_bfd_link_add_symbols (abfd, info)
+_bfd_ecoff_bfd_link_add_symbols (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
if (! bfd_has_map (abfd))
{
+ /* An empty archive is a special case. */
+ if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL)
+ return true;
bfd_set_error (bfd_error_no_symbols);
return false;
}
value -= section->vma;
break;
case scAbs:
- section = &bfd_abs_section;
+ section = bfd_abs_section_ptr;
break;
case scUndefined:
- section = &bfd_und_section;
+ section = bfd_und_section_ptr;
break;
case scSData:
section = bfd_make_section_old_way (abfd, ".sdata");
case scCommon:
if (value > ecoff_data (abfd)->gp_size)
{
- section = &bfd_com_section;
+ section = bfd_com_section_ptr;
break;
}
/* Fall through. */
section = &ecoff_scom_section;
break;
case scSUndefined:
- section = &bfd_und_section;
+ section = bfd_und_section_ptr;
break;
case scInit:
section = bfd_make_section_old_way (abfd, ".init");
if (info->hash->creator->flavour == bfd_get_flavour (abfd))
{
if (h->abfd == (bfd *) NULL
- || (section != &bfd_und_section
+ || (! bfd_is_und_section (section)
&& (! bfd_is_com_section (section)
- || h->root.type != bfd_link_hash_defined)))
+ || (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak))))
{
h->abfd = abfd;
h->esym = esym;
}
+
+ /* Remember whether this symbol was small undefined. */
+ if (esym.asym.sc == scSUndefined)
+ h->small = 1;
+
+ /* If this symbol was ever small undefined, it needs to wind
+ up in a GP relative section. We can't control the
+ section of a defined symbol, but we can control the
+ section of a common symbol. This case is actually needed
+ on Ultrix 4.2 to handle the symbol cred in -lckrb. */
+ if (h->small
+ && h->root.type == bfd_link_hash_common
+ && strcmp (h->root.u.c.section->name, SCOMMON) != 0)
+ {
+ h->root.u.c.section = bfd_make_section_old_way (abfd, SCOMMON);
+ h->root.u.c.section->flags = SEC_ALLOC;
+ if (h->esym.asym.sc == scCommon)
+ h->esym.asym.sc = scSCommon;
+ }
}
}
close and reopen some input BFDs; I'll see how bad this is. */
boolean
-ecoff_bfd_final_link (abfd, info)
+_bfd_ecoff_bfd_final_link (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
bfd_get_symcount (abfd) = symhdr->iextMax + symhdr->isymMax;
+ ecoff_data (abfd)->linker = true;
+
return true;
}
}
/* If raw_syments is not NULL, then the data was already by read by
- ecoff_slurp_symbolic_info. */
+ _bfd_ecoff_slurp_symbolic_info. */
if (ecoff_data (input_bfd)->raw_syments == NULL)
{
READ (line, cbLineOffset, cbLine, sizeof (unsigned char),
/* FIXME: We should check if this symbol is being stripped. */
- if (h->root.written)
+ if (h->written)
return true;
if (h->abfd == (bfd *) NULL)
h->esym.asym.value = 0;
h->esym.asym.st = stGlobal;
- if (h->root.type != bfd_link_hash_defined)
+ if (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
h->esym.asym.sc = scAbs;
else
{
case bfd_link_hash_new:
abort ();
case bfd_link_hash_undefined:
- case bfd_link_hash_weak:
+ case bfd_link_hash_undefweak:
if (h->esym.asym.sc != scUndefined
&& h->esym.asym.sc != scSUndefined)
h->esym.asym.sc = scUndefined;
break;
case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
if (h->esym.asym.sc == scUndefined
|| h->esym.asym.sc == scSUndefined)
h->esym.asym.sc = scAbs;
/* bfd_ecoff_debug_one_external uses iextMax to keep track of the
symbol number. */
h->indx = ecoff_data (output_bfd)->debug_info.symbolic_header.iextMax;
- h->root.written = true;
+ h->written = 1;
return (bfd_ecoff_debug_one_external
(output_bfd, &ecoff_data (output_bfd)->debug_info,
rel.address = link_order->offset;
rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
- if (rel.howto == (const reloc_howto_type *) NULL)
+ if (rel.howto == 0)
{
bfd_set_error (bfd_error_bad_value);
return false;