#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "aout/ar.h"
#include "aout/ranlib.h"
#include "aout/stab_gnu.h"
#include "libaout.h"
#include "aout/aout64.h"
#undef N_ABS
#undef exec_hdr
#undef obj_sym_filepos
#include "coff/internal.h"
#include "coff/sym.h"
#include "coff/symconst.h"
#include "coff/ecoff.h"
#include "libcoff.h"
#include "libecoff.h"
static int ecoff_get_magic
PARAMS ((bfd *));
static long ecoff_sec_to_styp_flags
PARAMS ((const char *, flagword));
static bfd_boolean ecoff_slurp_symbolic_header
PARAMS ((bfd *));
static bfd_boolean ecoff_set_symbol_info
PARAMS ((bfd *, SYMR *, asymbol *, int, int));
static void ecoff_emit_aggregate
PARAMS ((bfd *, FDR *, char *, RNDXR *, long, const char *));
static char *ecoff_type_to_string
PARAMS ((bfd *, FDR *, unsigned int));
static bfd_boolean ecoff_slurp_reloc_table
PARAMS ((bfd *, asection *, asymbol **));
static int ecoff_sort_hdrs
PARAMS ((const PTR, const PTR));
static bfd_boolean ecoff_compute_section_file_positions
PARAMS ((bfd *));
static bfd_size_type ecoff_compute_reloc_file_positions
PARAMS ((bfd *));
static bfd_boolean ecoff_get_extr
PARAMS ((asymbol *, EXTR *));
static void ecoff_set_index
PARAMS ((asymbol *, bfd_size_type));
static unsigned int ecoff_armap_hash
PARAMS ((const char *, unsigned int *, unsigned int, unsigned int));
static asection bfd_debug_section =
{
"*DEBUG*", 0, 0, NULL, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0,
0, 0, 0, 0,
0, NULL, 0,
NULL, NULL, 0, 0, 0,
0, NULL, NULL, NULL, 0,
0, NULL, 0,
0, NULL, NULL, NULL,
(struct bfd_symbol *) NULL,
(struct bfd_symbol **) NULL,
NULL, NULL
};
bfd_boolean
_bfd_ecoff_mkobject (abfd)
bfd *abfd;
{
bfd_size_type amt = sizeof (ecoff_data_type);
abfd->tdata.ecoff_obj_data = (struct ecoff_tdata *) bfd_zalloc (abfd, amt);
if (abfd->tdata.ecoff_obj_data == NULL)
return FALSE;
return TRUE;
}
PTR
_bfd_ecoff_mkobject_hook (abfd, filehdr, aouthdr)
bfd *abfd;
PTR filehdr;
PTR aouthdr;
{
struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr;
ecoff_data_type *ecoff;
if (! _bfd_ecoff_mkobject (abfd))
return NULL;
ecoff = ecoff_data (abfd);
ecoff->gp_size = 8;
ecoff->sym_filepos = internal_f->f_symptr;
if (internal_a != (struct internal_aouthdr *) NULL)
{
int i;
ecoff->text_start = internal_a->text_start;
ecoff->text_end = internal_a->text_start + internal_a->tsize;
ecoff->gp = internal_a->gp_value;
ecoff->gprmask = internal_a->gprmask;
for (i = 0; i < 4; i++)
ecoff->cprmask[i] = internal_a->cprmask[i];
ecoff->fprmask = internal_a->fprmask;
if (internal_a->magic == ECOFF_AOUT_ZMAGIC)
abfd->flags |= D_PAGED;
else
abfd->flags &=~ D_PAGED;
}
return (PTR) ecoff;
}
bfd_boolean
_bfd_ecoff_new_section_hook (abfd, section)
bfd *abfd ATTRIBUTE_UNUSED;
asection *section;
{
section->alignment_power = 4;
if (strcmp (section->name, _TEXT) == 0
|| strcmp (section->name, _INIT) == 0
|| strcmp (section->name, _FINI) == 0)
section->flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
else if (strcmp (section->name, _DATA) == 0
|| strcmp (section->name, _SDATA) == 0)
section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
else if (strcmp (section->name, _RDATA) == 0
|| strcmp (section->name, _LIT8) == 0
|| strcmp (section->name, _LIT4) == 0
|| strcmp (section->name, _RCONST) == 0
|| strcmp (section->name, _PDATA) == 0)
section->flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
else if (strcmp (section->name, _BSS) == 0
|| strcmp (section->name, _SBSS) == 0)
section->flags |= SEC_ALLOC;
else if (strcmp (section->name, _LIB) == 0)
section->flags |= SEC_COFF_SHARED_LIBRARY;
return TRUE;
}
bfd_boolean
_bfd_ecoff_set_arch_mach_hook (abfd, filehdr)
bfd *abfd;
PTR filehdr;
{
struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
enum bfd_architecture arch;
unsigned long mach;
switch (internal_f->f_magic)
{
case MIPS_MAGIC_1:
case MIPS_MAGIC_LITTLE:
case MIPS_MAGIC_BIG:
arch = bfd_arch_mips;
mach = bfd_mach_mips3000;
break;
case MIPS_MAGIC_LITTLE2:
case MIPS_MAGIC_BIG2:
arch = bfd_arch_mips;
mach = bfd_mach_mips6000;
break;
case MIPS_MAGIC_LITTLE3:
case MIPS_MAGIC_BIG3:
arch = bfd_arch_mips;
mach = bfd_mach_mips4000;
break;
case ALPHA_MAGIC:
arch = bfd_arch_alpha;
mach = 0;
break;
default:
arch = bfd_arch_obscure;
mach = 0;
break;
}
return bfd_default_set_arch_mach (abfd, arch, mach);
}
static int
ecoff_get_magic (abfd)
bfd *abfd;
{
int big, little;
switch (bfd_get_arch (abfd))
{
case bfd_arch_mips:
switch (bfd_get_mach (abfd))
{
default:
case 0:
case bfd_mach_mips3000:
big = MIPS_MAGIC_BIG;
little = MIPS_MAGIC_LITTLE;
break;
case bfd_mach_mips6000:
big = MIPS_MAGIC_BIG2;
little = MIPS_MAGIC_LITTLE2;
break;
case bfd_mach_mips4000:
big = MIPS_MAGIC_BIG3;
little = MIPS_MAGIC_LITTLE3;
break;
}
return bfd_big_endian (abfd) ? big : little;
case bfd_arch_alpha:
return ALPHA_MAGIC;
default:
abort ();
return 0;
}
}
static long
ecoff_sec_to_styp_flags (name, flags)
const char *name;
flagword flags;
{
long styp;
styp = 0;
if (strcmp (name, _TEXT) == 0)
styp = STYP_TEXT;
else if (strcmp (name, _DATA) == 0)
styp = STYP_DATA;
else if (strcmp (name, _SDATA) == 0)
styp = STYP_SDATA;
else if (strcmp (name, _RDATA) == 0)
styp = STYP_RDATA;
else if (strcmp (name, _LITA) == 0)
styp = STYP_LITA;
else if (strcmp (name, _LIT8) == 0)
styp = STYP_LIT8;
else if (strcmp (name, _LIT4) == 0)
styp = STYP_LIT4;
else if (strcmp (name, _BSS) == 0)
styp = STYP_BSS;
else if (strcmp (name, _SBSS) == 0)
styp = STYP_SBSS;
else if (strcmp (name, _INIT) == 0)
styp = STYP_ECOFF_INIT;
else if (strcmp (name, _FINI) == 0)
styp = STYP_ECOFF_FINI;
else if (strcmp (name, _PDATA) == 0)
styp = STYP_PDATA;
else if (strcmp (name, _XDATA) == 0)
styp = STYP_XDATA;
else if (strcmp (name, _LIB) == 0)
styp = STYP_ECOFF_LIB;
else if (strcmp (name, _GOT) == 0)
styp = STYP_GOT;
else if (strcmp (name, _HASH) == 0)
styp = STYP_HASH;
else if (strcmp (name, _DYNAMIC) == 0)
styp = STYP_DYNAMIC;
else if (strcmp (name, _LIBLIST) == 0)
styp = STYP_LIBLIST;
else if (strcmp (name, _RELDYN) == 0)
styp = STYP_RELDYN;
else if (strcmp (name, _CONFLIC) == 0)
styp = STYP_CONFLIC;
else if (strcmp (name, _DYNSTR) == 0)
styp = STYP_DYNSTR;
else if (strcmp (name, _DYNSYM) == 0)
styp = STYP_DYNSYM;
else if (strcmp (name, _COMMENT) == 0)
{
styp = STYP_COMMENT;
flags &=~ SEC_NEVER_LOAD;
}
else if (strcmp (name, _RCONST) == 0)
styp = STYP_RCONST;
else if (flags & SEC_CODE)
styp = STYP_TEXT;
else if (flags & SEC_DATA)
styp = STYP_DATA;
else if (flags & SEC_READONLY)
styp = STYP_RDATA;
else if (flags & SEC_LOAD)
styp = STYP_REG;
else
styp = STYP_BSS;
if (flags & SEC_NEVER_LOAD)
styp |= STYP_NOLOAD;
return styp;
}
bfd_boolean
_bfd_ecoff_styp_to_sec_flags (abfd, hdr, name, section, flags_ptr)
bfd *abfd ATTRIBUTE_UNUSED;
PTR hdr;
const char *name ATTRIBUTE_UNUSED;
asection *section ATTRIBUTE_UNUSED;
flagword * flags_ptr;
{
struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr;
long styp_flags = internal_s->s_flags;
flagword sec_flags = 0;
if (styp_flags & STYP_NOLOAD)
sec_flags |= SEC_NEVER_LOAD;
if ((styp_flags & STYP_TEXT)
|| (styp_flags & STYP_ECOFF_INIT)
|| (styp_flags & STYP_ECOFF_FINI)
|| (styp_flags & STYP_DYNAMIC)
|| (styp_flags & STYP_LIBLIST)
|| (styp_flags & STYP_RELDYN)
|| styp_flags == STYP_CONFLIC
|| (styp_flags & STYP_DYNSTR)
|| (styp_flags & STYP_DYNSYM)
|| (styp_flags & STYP_HASH))
{
if (sec_flags & SEC_NEVER_LOAD)
sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY;
else
sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC;
}
else if ((styp_flags & STYP_DATA)
|| (styp_flags & STYP_RDATA)
|| (styp_flags & STYP_SDATA)
|| styp_flags == STYP_PDATA
|| styp_flags == STYP_XDATA
|| (styp_flags & STYP_GOT)
|| styp_flags == STYP_RCONST)
{
if (sec_flags & SEC_NEVER_LOAD)
sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY;
else
sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
if ((styp_flags & STYP_RDATA)
|| styp_flags == STYP_PDATA
|| styp_flags == STYP_RCONST)
sec_flags |= SEC_READONLY;
}
else if ((styp_flags & STYP_BSS)
|| (styp_flags & STYP_SBSS))
sec_flags |= SEC_ALLOC;
else if ((styp_flags & STYP_INFO) || styp_flags == STYP_COMMENT)
sec_flags |= SEC_NEVER_LOAD;
else if ((styp_flags & STYP_LITA)
|| (styp_flags & STYP_LIT8)
|| (styp_flags & STYP_LIT4))
sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
else if (styp_flags & STYP_ECOFF_LIB)
sec_flags |= SEC_COFF_SHARED_LIBRARY;
else
sec_flags |= SEC_ALLOC | SEC_LOAD;
* flags_ptr = sec_flags;
return TRUE;
}
static bfd_boolean
ecoff_slurp_symbolic_header (abfd)
bfd *abfd;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
bfd_size_type external_hdr_size;
PTR raw = NULL;
HDRR *internal_symhdr;
if (ecoff_data (abfd)->debug_info.symbolic_header.magic ==
backend->debug_swap.sym_magic)
return TRUE;
if (ecoff_data (abfd)->sym_filepos == 0)
{
bfd_get_symcount (abfd) = 0;
return TRUE;
}
external_hdr_size = backend->debug_swap.external_hdr_size;
if (bfd_get_symcount (abfd) != external_hdr_size)
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
raw = (PTR) bfd_malloc (external_hdr_size);
if (raw == NULL)
goto error_return;
if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) != 0
|| bfd_bread (raw, external_hdr_size, abfd) != external_hdr_size)
goto error_return;
internal_symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
(*backend->debug_swap.swap_hdr_in) (abfd, raw, internal_symhdr);
if (internal_symhdr->magic != backend->debug_swap.sym_magic)
{
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
bfd_get_symcount (abfd) = (internal_symhdr->isymMax
+ internal_symhdr->iextMax);
if (raw != NULL)
free (raw);
return TRUE;
error_return:
if (raw != NULL)
free (raw);
return FALSE;
}
bfd_boolean
_bfd_ecoff_slurp_symbolic_info (abfd, ignore, debug)
bfd *abfd;
asection *ignore ATTRIBUTE_UNUSED;
struct ecoff_debug_info *debug;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
HDRR *internal_symhdr;
bfd_size_type raw_base;
bfd_size_type raw_size;
PTR raw;
bfd_size_type external_fdr_size;
char *fraw_src;
char *fraw_end;
struct fdr *fdr_ptr;
bfd_size_type raw_end;
bfd_size_type cb_end;
bfd_size_type amt;
file_ptr pos;
BFD_ASSERT (debug == &ecoff_data (abfd)->debug_info);
if (ecoff_data (abfd)->raw_syments != (PTR) NULL)
return TRUE;
if (ecoff_data (abfd)->sym_filepos == 0)
{
bfd_get_symcount (abfd) = 0;
return TRUE;
}
if (! ecoff_slurp_symbolic_header (abfd))
return FALSE;
internal_symhdr = &debug->symbolic_header;
raw_base = (ecoff_data (abfd)->sym_filepos
+ backend->debug_swap.external_hdr_size);
raw_end = 0;
#define UPDATE_RAW_END(start, count, size) \
cb_end = internal_symhdr->start + internal_symhdr->count * (size); \
if (cb_end > raw_end) \
raw_end = cb_end
UPDATE_RAW_END (cbLineOffset, cbLine, sizeof (unsigned char));
UPDATE_RAW_END (cbDnOffset, idnMax, backend->debug_swap.external_dnr_size);
UPDATE_RAW_END (cbPdOffset, ipdMax, backend->debug_swap.external_pdr_size);
UPDATE_RAW_END (cbSymOffset, isymMax, backend->debug_swap.external_sym_size);
UPDATE_RAW_END (cbOptOffset, ioptMax, sizeof (char));
UPDATE_RAW_END (cbAuxOffset, iauxMax, sizeof (union aux_ext));
UPDATE_RAW_END (cbSsOffset, issMax, sizeof (char));
UPDATE_RAW_END (cbSsExtOffset, issExtMax, sizeof (char));
UPDATE_RAW_END (cbFdOffset, ifdMax, backend->debug_swap.external_fdr_size);
UPDATE_RAW_END (cbRfdOffset, crfd, backend->debug_swap.external_rfd_size);
UPDATE_RAW_END (cbExtOffset, iextMax, backend->debug_swap.external_ext_size);
#undef UPDATE_RAW_END
raw_size = raw_end - raw_base;
if (raw_size == 0)
{
ecoff_data (abfd)->sym_filepos = 0;
return TRUE;
}
raw = (PTR) bfd_alloc (abfd, raw_size);
if (raw == NULL)
return FALSE;
pos = ecoff_data (abfd)->sym_filepos;
pos += backend->debug_swap.external_hdr_size;
if (bfd_seek (abfd, pos, SEEK_SET) != 0
|| bfd_bread (raw, raw_size, abfd) != raw_size)
{
bfd_release (abfd, raw);
return FALSE;
}
ecoff_data (abfd)->raw_syments = raw;
#define FIX(off1, off2, type) \
if (internal_symhdr->off1 == 0) \
debug->off2 = (type) NULL; \
else \
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);
FIX (cbSymOffset, external_sym, PTR);
FIX (cbOptOffset, external_opt, PTR);
FIX (cbAuxOffset, external_aux, union aux_ext *);
FIX (cbSsOffset, ss, char *);
FIX (cbSsExtOffset, ssext, char *);
FIX (cbFdOffset, external_fdr, PTR);
FIX (cbRfdOffset, external_rfd, PTR);
FIX (cbExtOffset, external_ext, PTR);
#undef FIX
amt = internal_symhdr->ifdMax;
amt *= sizeof (struct fdr);
debug->fdr = (struct fdr *) bfd_alloc (abfd, amt);
if (debug->fdr == NULL)
return FALSE;
external_fdr_size = backend->debug_swap.external_fdr_size;
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);
return TRUE;
}
static asection ecoff_scom_section;
static asymbol ecoff_scom_symbol;
static asymbol *ecoff_scom_symbol_ptr;
asymbol *
_bfd_ecoff_make_empty_symbol (abfd)
bfd *abfd;
{
ecoff_symbol_type *new;
bfd_size_type amt = sizeof (ecoff_symbol_type);
new = (ecoff_symbol_type *) bfd_zalloc (abfd, amt);
if (new == (ecoff_symbol_type *) NULL)
return (asymbol *) NULL;
new->symbol.section = (asection *) NULL;
new->fdr = (FDR *) NULL;
new->local = FALSE;
new->native = NULL;
new->symbol.the_bfd = abfd;
return &new->symbol;
}
static bfd_boolean
ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext, weak)
bfd *abfd;
SYMR *ecoff_sym;
asymbol *asym;
int ext;
int weak;
{
asym->the_bfd = abfd;
asym->value = ecoff_sym->value;
asym->section = &bfd_debug_section;
asym->udata.i = 0;
switch (ecoff_sym->st)
{
case stGlobal:
case stStatic:
case stLabel:
case stProc:
case stStaticProc:
break;
case stNil:
if (ECOFF_IS_STAB (ecoff_sym))
{
asym->flags = BSF_DEBUGGING;
return TRUE;
}
break;
default:
asym->flags = BSF_DEBUGGING;
return TRUE;
}
if (weak)
asym->flags = BSF_EXPORT | BSF_WEAK;
else if (ext)
asym->flags = BSF_EXPORT | BSF_GLOBAL;
else
{
asym->flags = BSF_LOCAL;
if (ecoff_sym->st == stProc
|| ecoff_sym->st == stLabel
|| ECOFF_IS_STAB (ecoff_sym))
asym->flags |= BSF_DEBUGGING;
}
if (ecoff_sym->st == stProc || ecoff_sym->st == stStaticProc)
asym->flags |= BSF_FUNCTION;
switch (ecoff_sym->sc)
{
case scNil:
asym->flags = BSF_LOCAL;
break;
case scText:
asym->section = bfd_make_section_old_way (abfd, ".text");
asym->value -= asym->section->vma;
break;
case scData:
asym->section = bfd_make_section_old_way (abfd, ".data");
asym->value -= asym->section->vma;
break;
case scBss:
asym->section = bfd_make_section_old_way (abfd, ".bss");
asym->value -= asym->section->vma;
break;
case scRegister:
asym->flags = BSF_DEBUGGING;
break;
case scAbs:
asym->section = bfd_abs_section_ptr;
break;
case scUndefined:
asym->section = bfd_und_section_ptr;
asym->flags = 0;
asym->value = 0;
break;
case scCdbLocal:
case scBits:
case scCdbSystem:
case scRegImage:
case scInfo:
case scUserStruct:
asym->flags = BSF_DEBUGGING;
break;
case scSData:
asym->section = bfd_make_section_old_way (abfd, ".sdata");
asym->value -= asym->section->vma;
break;
case scSBss:
asym->section = bfd_make_section_old_way (abfd, ".sbss");
asym->value -= asym->section->vma;
break;
case scRData:
asym->section = bfd_make_section_old_way (abfd, ".rdata");
asym->value -= asym->section->vma;
break;
case scVar:
asym->flags = BSF_DEBUGGING;
break;
case scCommon:
if (asym->value > ecoff_data (abfd)->gp_size)
{
asym->section = bfd_com_section_ptr;
asym->flags = 0;
break;
}
case scSCommon:
if (ecoff_scom_section.name == NULL)
{
ecoff_scom_section.name = SCOMMON;
ecoff_scom_section.flags = SEC_IS_COMMON;
ecoff_scom_section.output_section = &ecoff_scom_section;
ecoff_scom_section.symbol = &ecoff_scom_symbol;
ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr;
ecoff_scom_symbol.name = SCOMMON;
ecoff_scom_symbol.flags = BSF_SECTION_SYM;
ecoff_scom_symbol.section = &ecoff_scom_section;
ecoff_scom_symbol_ptr = &ecoff_scom_symbol;
}
asym->section = &ecoff_scom_section;
asym->flags = 0;
break;
case scVarRegister:
case scVariant:
asym->flags = BSF_DEBUGGING;
break;
case scSUndefined:
asym->section = bfd_und_section_ptr;
asym->flags = 0;
asym->value = 0;
break;
case scInit:
asym->section = bfd_make_section_old_way (abfd, ".init");
asym->value -= asym->section->vma;
break;
case scBasedVar:
case scXData:
case scPData:
asym->flags = BSF_DEBUGGING;
break;
case scFini:
asym->section = bfd_make_section_old_way (abfd, ".fini");
asym->value -= asym->section->vma;
break;
case scRConst:
asym->section = bfd_make_section_old_way (abfd, ".rconst");
asym->value -= asym->section->vma;
break;
default:
break;
}
if (ECOFF_IS_STAB (ecoff_sym))
{
switch (ECOFF_UNMARK_STAB (ecoff_sym->index))
{
default:
break;
case N_SETA:
case N_SETT:
case N_SETD:
case N_SETB:
{
asym->flags |= BSF_CONSTRUCTOR;
}
break;
}
}
return TRUE;
}
bfd_boolean
_bfd_ecoff_slurp_symbol_table (abfd)
bfd *abfd;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
const bfd_size_type external_ext_size
= backend->debug_swap.external_ext_size;
const bfd_size_type external_sym_size
= backend->debug_swap.external_sym_size;
void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
= backend->debug_swap.swap_ext_in;
void (* const swap_sym_in) PARAMS ((bfd *, PTR, SYMR *))
= backend->debug_swap.swap_sym_in;
bfd_size_type internal_size;
ecoff_symbol_type *internal;
ecoff_symbol_type *internal_ptr;
char *eraw_src;
char *eraw_end;
FDR *fdr_ptr;
FDR *fdr_end;
if (ecoff_data (abfd)->canonical_symbols != NULL)
return TRUE;
if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
&ecoff_data (abfd)->debug_info))
return FALSE;
if (bfd_get_symcount (abfd) == 0)
return TRUE;
internal_size = bfd_get_symcount (abfd);
internal_size *= sizeof (ecoff_symbol_type);
internal = (ecoff_symbol_type *) bfd_alloc (abfd, internal_size);
if (internal == NULL)
return FALSE;
internal_ptr = internal;
eraw_src = (char *) ecoff_data (abfd)->debug_info.external_ext;
eraw_end = (eraw_src
+ (ecoff_data (abfd)->debug_info.symbolic_header.iextMax
* external_ext_size));
for (; eraw_src < eraw_end; eraw_src += external_ext_size, internal_ptr++)
{
EXTR internal_esym;
(*swap_ext_in) (abfd, (PTR) eraw_src, &internal_esym);
internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ssext
+ internal_esym.asym.iss);
if (!ecoff_set_symbol_info (abfd, &internal_esym.asym,
&internal_ptr->symbol, 1,
internal_esym.weakext))
return FALSE;
if (internal_esym.ifd >= 0)
internal_ptr->fdr = (ecoff_data (abfd)->debug_info.fdr
+ internal_esym.ifd);
else
internal_ptr->fdr = NULL;
internal_ptr->local = FALSE;
internal_ptr->native = (PTR) eraw_src;
}
fdr_ptr = ecoff_data (abfd)->debug_info.fdr;
fdr_end = fdr_ptr + ecoff_data (abfd)->debug_info.symbolic_header.ifdMax;
for (; fdr_ptr < fdr_end; fdr_ptr++)
{
char *lraw_src;
char *lraw_end;
lraw_src = ((char *) ecoff_data (abfd)->debug_info.external_sym
+ fdr_ptr->isymBase * external_sym_size);
lraw_end = lraw_src + fdr_ptr->csym * external_sym_size;
for (;
lraw_src < lraw_end;
lraw_src += external_sym_size, internal_ptr++)
{
SYMR internal_sym;
(*swap_sym_in) (abfd, (PTR) lraw_src, &internal_sym);
internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ss
+ fdr_ptr->issBase
+ internal_sym.iss);
if (!ecoff_set_symbol_info (abfd, &internal_sym,
&internal_ptr->symbol, 0, 0))
return FALSE;
internal_ptr->fdr = fdr_ptr;
internal_ptr->local = TRUE;
internal_ptr->native = (PTR) lraw_src;
}
}
ecoff_data (abfd)->canonical_symbols = internal;
return TRUE;
}
long
_bfd_ecoff_get_symtab_upper_bound (abfd)
bfd *abfd;
{
if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL,
&ecoff_data (abfd)->debug_info))
return -1;
if (bfd_get_symcount (abfd) == 0)
return 0;
return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *));
}
long
_bfd_ecoff_canonicalize_symtab (abfd, alocation)
bfd *abfd;
asymbol **alocation;
{
unsigned int counter = 0;
ecoff_symbol_type *symbase;
ecoff_symbol_type **location = (ecoff_symbol_type **) alocation;
if (! _bfd_ecoff_slurp_symbol_table (abfd))
return -1;
if (bfd_get_symcount (abfd) == 0)
return 0;
symbase = ecoff_data (abfd)->canonical_symbols;
while (counter < bfd_get_symcount (abfd))
{
*(location++) = symbase++;
counter++;
}
*location++ = (ecoff_symbol_type *) NULL;
return bfd_get_symcount (abfd);
}
static void
ecoff_emit_aggregate (abfd, fdr, string, rndx, isym, which)
bfd *abfd;
FDR *fdr;
char *string;
RNDXR *rndx;
long isym;
const char *which;
{
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;
unsigned int ifd = rndx->rfd;
unsigned int indx = rndx->index;
const char *name;
if (ifd == 0xfff)
ifd = isym;
if (ifd == 0xffffffff
|| (rndx->rfd == 0xfff && indx == 0))
name = "<undefined>";
else if (indx == indexNil)
name = "<no name>";
else
{
SYMR sym;
if (debug_info->external_rfd == NULL)
fdr = debug_info->fdr + ifd;
else
{
RFDT rfd;
(*debug_swap->swap_rfd_in) (abfd,
((char *) debug_info->external_rfd
+ ((fdr->rfdBase + ifd)
* debug_swap->external_rfd_size)),
&rfd);
fdr = debug_info->fdr + rfd;
}
indx += fdr->isymBase;
(*debug_swap->swap_sym_in) (abfd,
((char *) debug_info->external_sym
+ indx * debug_swap->external_sym_size),
&sym);
name = debug_info->ss + fdr->issBase + sym.iss;
}
sprintf (string,
"%s %s { ifd = %u, index = %lu }",
which, name, ifd,
((long) indx
+ debug_info->symbolic_header.iextMax));
}
static char *
ecoff_type_to_string (abfd, fdr, indx)
bfd *abfd;
FDR *fdr;
unsigned int indx;
{
union aux_ext *aux_ptr;
int bigendian;
AUXU u;
struct qual {
unsigned int type;
int low_bound;
int high_bound;
int stride;
} qualifiers[7];
unsigned int basic_type;
int i;
char buffer1[1024];
static char buffer2[1024];
char *p1 = buffer1;
char *p2 = buffer2;
RNDXR rndx;
aux_ptr = ecoff_data (abfd)->debug_info.external_aux + fdr->iauxBase;
bigendian = fdr->fBigendian;
for (i = 0; i < 7; i++)
{
qualifiers[i].low_bound = 0;
qualifiers[i].high_bound = 0;
qualifiers[i].stride = 0;
}
if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == (bfd_vma) -1)
return "-1 (no type)";
_bfd_ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti);
basic_type = u.ti.bt;
qualifiers[0].type = u.ti.tq0;
qualifiers[1].type = u.ti.tq1;
qualifiers[2].type = u.ti.tq2;
qualifiers[3].type = u.ti.tq3;
qualifiers[4].type = u.ti.tq4;
qualifiers[5].type = u.ti.tq5;
qualifiers[6].type = tqNil;
switch (basic_type)
{
case btNil:
strcpy (p1, "nil");
break;
case btAdr:
strcpy (p1, "address");
break;
case btChar:
strcpy (p1, "char");
break;
case btUChar:
strcpy (p1, "unsigned char");
break;
case btShort:
strcpy (p1, "short");
break;
case btUShort:
strcpy (p1, "unsigned short");
break;
case btInt:
strcpy (p1, "int");
break;
case btUInt:
strcpy (p1, "unsigned int");
break;
case btLong:
strcpy (p1, "long");
break;
case btULong:
strcpy (p1, "unsigned long");
break;
case btFloat:
strcpy (p1, "float");
break;
case btDouble:
strcpy (p1, "double");
break;
case btStruct:
_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");
indx++;
break;
case btUnion:
_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");
indx++;
break;
case btEnum:
_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");
indx++;
break;
case btTypedef:
strcpy (p1, "typedef");
break;
case btRange:
strcpy (p1, "subrange");
break;
case btSet:
strcpy (p1, "set");
break;
case btComplex:
strcpy (p1, "complex");
break;
case btDComplex:
strcpy (p1, "double complex");
break;
case btIndirect:
strcpy (p1, "forward/unamed typedef");
break;
case btFixedDec:
strcpy (p1, "fixed decimal");
break;
case btFloatDec:
strcpy (p1, "float decimal");
break;
case btString:
strcpy (p1, "string");
break;
case btBit:
strcpy (p1, "bit");
break;
case btPicture:
strcpy (p1, "picture");
break;
case btVoid:
strcpy (p1, "void");
break;
default:
sprintf (p1, _("Unknown basic type %d"), (int) basic_type);
break;
}
p1 += strlen (buffer1);
if (u.ti.fBitfield)
{
int bitsize;
bitsize = AUX_GET_WIDTH (bigendian, &aux_ptr[indx++]);
sprintf (p1, " : %d", bitsize);
p1 += strlen (buffer1);
}
if (qualifiers[0].type != tqNil)
{
for (i = 0; i < 7; i++)
{
if (qualifiers[i].type == tqArray)
{
qualifiers[i].low_bound =
AUX_GET_DNLOW (bigendian, &aux_ptr[indx+2]);
qualifiers[i].high_bound =
AUX_GET_DNHIGH (bigendian, &aux_ptr[indx+3]);
qualifiers[i].stride =
AUX_GET_WIDTH (bigendian, &aux_ptr[indx+4]);
indx += 5;
}
}
for (i = 0; i < 6; i++)
{
switch (qualifiers[i].type)
{
case tqNil:
case tqMax:
break;
case tqPtr:
strcpy (p2, "ptr to ");
p2 += sizeof ("ptr to ")-1;
break;
case tqVol:
strcpy (p2, "volatile ");
p2 += sizeof ("volatile ")-1;
break;
case tqFar:
strcpy (p2, "far ");
p2 += sizeof ("far ")-1;
break;
case tqProc:
strcpy (p2, "func. ret. ");
p2 += sizeof ("func. ret. ");
break;
case tqArray:
{
int first_array = i;
int j;
while (i < 5 && qualifiers[i+1].type == tqArray)
i++;
for (j = i; j >= first_array; j--)
{
strcpy (p2, "array [");
p2 += sizeof ("array [")-1;
if (qualifiers[j].low_bound != 0)
sprintf (p2,
"%ld:%ld {%ld bits}",
(long) qualifiers[j].low_bound,
(long) qualifiers[j].high_bound,
(long) qualifiers[j].stride);
else if (qualifiers[j].high_bound != -1)
sprintf (p2,
"%ld {%ld bits}",
(long) (qualifiers[j].high_bound + 1),
(long) (qualifiers[j].stride));
else
sprintf (p2, " {%ld bits}", (long) (qualifiers[j].stride));
p2 += strlen (p2);
strcpy (p2, "] of ");
p2 += sizeof ("] of ")-1;
}
}
break;
}
}
}
strcpy (p2, buffer1);
return buffer2;
}
void
_bfd_ecoff_get_symbol_info (abfd, symbol, ret)
bfd *abfd ATTRIBUTE_UNUSED;
asymbol *symbol;
symbol_info *ret;
{
bfd_symbol_info (symbol, ret);
}
bfd_boolean
_bfd_ecoff_bfd_is_local_label_name (abfd, name)
bfd *abfd ATTRIBUTE_UNUSED;
const char *name;
{
return name[0] == '$';
}
void
_bfd_ecoff_print_symbol (abfd, filep, symbol, how)
bfd *abfd;
PTR filep;
asymbol *symbol;
bfd_print_symbol_type how;
{
const struct ecoff_debug_swap * const debug_swap
= &ecoff_backend (abfd)->debug_swap;
FILE *file = (FILE *)filep;
switch (how)
{
case bfd_print_symbol_name:
fprintf (file, "%s", symbol->name);
break;
case bfd_print_symbol_more:
if (ecoffsymbol (symbol)->local)
{
SYMR ecoff_sym;
(*debug_swap->swap_sym_in) (abfd, ecoffsymbol (symbol)->native,
&ecoff_sym);
fprintf (file, "ecoff local ");
fprintf_vma (file, (bfd_vma) ecoff_sym.value);
fprintf (file, " %x %x", (unsigned) ecoff_sym.st,
(unsigned) ecoff_sym.sc);
}
else
{
EXTR ecoff_ext;
(*debug_swap->swap_ext_in) (abfd, ecoffsymbol (symbol)->native,
&ecoff_ext);
fprintf (file, "ecoff extern ");
fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value);
fprintf (file, " %x %x", (unsigned) ecoff_ext.asym.st,
(unsigned) ecoff_ext.asym.sc);
}
break;
case bfd_print_symbol_all:
{
char type;
int pos;
EXTR ecoff_ext;
char jmptbl;
char cobol_main;
char weakext;
if (ecoffsymbol (symbol)->local)
{
(*debug_swap->swap_sym_in) (abfd, ecoffsymbol (symbol)->native,
&ecoff_ext.asym);
type = 'l';
pos = ((((char *) ecoffsymbol (symbol)->native
- (char *) ecoff_data (abfd)->debug_info.external_sym)
/ debug_swap->external_sym_size)
+ ecoff_data (abfd)->debug_info.symbolic_header.iextMax);
jmptbl = ' ';
cobol_main = ' ';
weakext = ' ';
}
else
{
(*debug_swap->swap_ext_in) (abfd, ecoffsymbol (symbol)->native,
&ecoff_ext);
type = 'e';
pos = (((char *) ecoffsymbol (symbol)->native
- (char *) ecoff_data (abfd)->debug_info.external_ext)
/ debug_swap->external_ext_size);
jmptbl = ecoff_ext.jmptbl ? 'j' : ' ';
cobol_main = ecoff_ext.cobol_main ? 'c' : ' ';
weakext = ecoff_ext.weakext ? 'w' : ' ';
}
fprintf (file, "[%3d] %c ",
pos, type);
fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value);
fprintf (file, " st %x sc %x indx %x %c%c%c %s",
(unsigned) ecoff_ext.asym.st,
(unsigned) ecoff_ext.asym.sc,
(unsigned) ecoff_ext.asym.index,
jmptbl, cobol_main, weakext,
symbol->name);
if (ecoffsymbol (symbol)->fdr != NULL
&& ecoff_ext.asym.index != indexNil)
{
FDR *fdr;
unsigned int indx;
int bigendian;
bfd_size_type sym_base;
union aux_ext *aux_base;
fdr = ecoffsymbol (symbol)->fdr;
indx = ecoff_ext.asym.index;
sym_base = fdr->isymBase;
if (ecoffsymbol (symbol)->local)
sym_base +=
ecoff_data (abfd)->debug_info.symbolic_header.iextMax;
aux_base = (ecoff_data (abfd)->debug_info.external_aux
+ fdr->iauxBase);
bigendian = fdr->fBigendian;
switch (ecoff_ext.asym.st)
{
case stNil:
case stLabel:
break;
case stFile:
case stBlock:
fprintf (file, _("\n End+1 symbol: %ld"),
(long) (indx + sym_base));
break;
case stEnd:
if (ecoff_ext.asym.sc == scText
|| ecoff_ext.asym.sc == scInfo)
fprintf (file, _("\n First symbol: %ld"),
(long) (indx + sym_base));
else
fprintf (file, _("\n First symbol: %ld"),
((long)
(AUX_GET_ISYM (bigendian,
&aux_base[ecoff_ext.asym.index])
+ sym_base)));
break;
case stProc:
case stStaticProc:
if (ECOFF_IS_STAB (&ecoff_ext.asym))
;
else if (ecoffsymbol (symbol)->local)
fprintf (file, _("\n End+1 symbol: %-7ld Type: %s"),
((long)
(AUX_GET_ISYM (bigendian,
&aux_base[ecoff_ext.asym.index])
+ sym_base)),
ecoff_type_to_string (abfd, fdr, indx + 1));
else
fprintf (file, _("\n Local symbol: %ld"),
((long) indx
+ (long) sym_base
+ (ecoff_data (abfd)
->debug_info.symbolic_header.iextMax)));
break;
case stStruct:
fprintf (file, _("\n struct; End+1 symbol: %ld"),
(long) (indx + sym_base));
break;
case stUnion:
fprintf (file, _("\n union; End+1 symbol: %ld"),
(long) (indx + sym_base));
break;
case stEnum:
fprintf (file, _("\n enum; End+1 symbol: %ld"),
(long) (indx + sym_base));
break;
default:
if (! ECOFF_IS_STAB (&ecoff_ext.asym))
fprintf (file, _("\n Type: %s"),
ecoff_type_to_string (abfd, fdr, indx));
break;
}
}
}
break;
}
}
static bfd_boolean
ecoff_slurp_reloc_table (abfd, section, symbols)
bfd *abfd;
asection *section;
asymbol **symbols;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
arelent *internal_relocs;
bfd_size_type external_reloc_size;
bfd_size_type amt;
char *external_relocs;
arelent *rptr;
unsigned int i;
if (section->relocation != (arelent *) NULL
|| section->reloc_count == 0
|| (section->flags & SEC_CONSTRUCTOR) != 0)
return TRUE;
if (! _bfd_ecoff_slurp_symbol_table (abfd))
return FALSE;
amt = section->reloc_count;
amt *= sizeof (arelent);
internal_relocs = (arelent *) bfd_alloc (abfd, amt);
external_reloc_size = backend->external_reloc_size;
amt = external_reloc_size * section->reloc_count;
external_relocs = (char *) bfd_alloc (abfd, amt);
if (internal_relocs == (arelent *) NULL
|| external_relocs == (char *) NULL)
return FALSE;
if (bfd_seek (abfd, section->rel_filepos, SEEK_SET) != 0)
return FALSE;
if (bfd_bread (external_relocs, amt, abfd) != amt)
return FALSE;
for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++)
{
struct internal_reloc intern;
(*backend->swap_reloc_in) (abfd,
external_relocs + i * external_reloc_size,
&intern);
if (intern.r_extern)
{
BFD_ASSERT (intern.r_symndx >= 0
&& (intern.r_symndx
< (ecoff_data (abfd)
->debug_info.symbolic_header.iextMax)));
rptr->sym_ptr_ptr = symbols + intern.r_symndx;
rptr->addend = 0;
}
else if (intern.r_symndx == RELOC_SECTION_NONE
|| intern.r_symndx == RELOC_SECTION_ABS)
{
rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
rptr->addend = 0;
}
else
{
const char *sec_name;
asection *sec;
switch (intern.r_symndx)
{
case RELOC_SECTION_TEXT: sec_name = ".text"; break;
case RELOC_SECTION_RDATA: sec_name = ".rdata"; break;
case RELOC_SECTION_DATA: sec_name = ".data"; break;
case RELOC_SECTION_SDATA: sec_name = ".sdata"; break;
case RELOC_SECTION_SBSS: sec_name = ".sbss"; break;
case RELOC_SECTION_BSS: sec_name = ".bss"; break;
case RELOC_SECTION_INIT: sec_name = ".init"; break;
case RELOC_SECTION_LIT8: sec_name = ".lit8"; break;
case RELOC_SECTION_LIT4: sec_name = ".lit4"; break;
case RELOC_SECTION_XDATA: sec_name = ".xdata"; break;
case RELOC_SECTION_PDATA: sec_name = ".pdata"; break;
case RELOC_SECTION_FINI: sec_name = ".fini"; break;
case RELOC_SECTION_LITA: sec_name = ".lita"; break;
case RELOC_SECTION_RCONST: sec_name = ".rconst"; break;
default: abort ();
}
sec = bfd_get_section_by_name (abfd, sec_name);
if (sec == (asection *) NULL)
abort ();
rptr->sym_ptr_ptr = sec->symbol_ptr_ptr;
rptr->addend = - bfd_get_section_vma (abfd, sec);
}
rptr->address = intern.r_vaddr - bfd_get_section_vma (abfd, section);
(*backend->adjust_reloc_in) (abfd, &intern, rptr);
}
bfd_release (abfd, external_relocs);
section->relocation = internal_relocs;
return TRUE;
}
long
_bfd_ecoff_canonicalize_reloc (abfd, section, relptr, symbols)
bfd *abfd;
asection *section;
arelent **relptr;
asymbol **symbols;
{
unsigned int count;
if (section->flags & SEC_CONSTRUCTOR)
{
arelent_chain *chain;
for (count = 0, chain = section->constructor_chain;
count < section->reloc_count;
count++, chain = chain->next)
*relptr++ = &chain->relent;
}
else
{
arelent *tblptr;
if (! ecoff_slurp_reloc_table (abfd, section, symbols))
return -1;
tblptr = section->relocation;
for (count = 0; count < section->reloc_count; count++)
*relptr++ = tblptr++;
}
*relptr = (arelent *) NULL;
return section->reloc_count;
}
bfd_boolean
_bfd_ecoff_find_nearest_line (abfd, section, ignore_symbols, offset,
filename_ptr, functionname_ptr, retline_ptr)
bfd *abfd;
asection *section;
asymbol **ignore_symbols ATTRIBUTE_UNUSED;
bfd_vma offset;
const char **filename_ptr;
const char **functionname_ptr;
unsigned int *retline_ptr;
{
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_find_line *line_info;
if (! _bfd_ecoff_slurp_symbolic_info (abfd, (asection *) NULL, debug_info)
|| bfd_get_symcount (abfd) == 0)
return FALSE;
if (ecoff_data (abfd)->find_line_info == NULL)
{
bfd_size_type amt = sizeof (struct ecoff_find_line);
ecoff_data (abfd)->find_line_info
= (struct ecoff_find_line *) bfd_zalloc (abfd, amt);
if (ecoff_data (abfd)->find_line_info == NULL)
return FALSE;
}
line_info = ecoff_data (abfd)->find_line_info;
return _bfd_ecoff_locate_line (abfd, section, offset, debug_info,
debug_swap, line_info, filename_ptr,
functionname_ptr, retline_ptr);
}
bfd_boolean
_bfd_ecoff_bfd_copy_private_bfd_data (ibfd, obfd)
bfd *ibfd;
bfd *obfd;
{
struct ecoff_debug_info *iinfo = &ecoff_data (ibfd)->debug_info;
struct ecoff_debug_info *oinfo = &ecoff_data (obfd)->debug_info;
register int i;
asymbol **sym_ptr_ptr;
size_t c;
bfd_boolean local;
if (bfd_get_flavour (ibfd) != bfd_target_ecoff_flavour
|| bfd_get_flavour (obfd) != bfd_target_ecoff_flavour)
return TRUE;
ecoff_data (obfd)->gp = ecoff_data (ibfd)->gp;
ecoff_data (obfd)->gprmask = ecoff_data (ibfd)->gprmask;
ecoff_data (obfd)->fprmask = ecoff_data (ibfd)->fprmask;
for (i = 0; i < 3; i++)
ecoff_data (obfd)->cprmask[i] = ecoff_data (ibfd)->cprmask[i];
oinfo->symbolic_header.vstamp = iinfo->symbolic_header.vstamp;
c = bfd_get_symcount (obfd);
sym_ptr_ptr = bfd_get_outsymbols (obfd);
if (c == 0 || sym_ptr_ptr == (asymbol **) NULL)
return TRUE;
local = FALSE;
for (; c > 0; c--, sym_ptr_ptr++)
{
if (ecoffsymbol (*sym_ptr_ptr)->local)
{
local = TRUE;
break;
}
}
if (local)
{
oinfo->symbolic_header.ilineMax = iinfo->symbolic_header.ilineMax;
oinfo->symbolic_header.cbLine = iinfo->symbolic_header.cbLine;
oinfo->line = iinfo->line;
oinfo->symbolic_header.idnMax = iinfo->symbolic_header.idnMax;
oinfo->external_dnr = iinfo->external_dnr;
oinfo->symbolic_header.ipdMax = iinfo->symbolic_header.ipdMax;
oinfo->external_pdr = iinfo->external_pdr;
oinfo->symbolic_header.isymMax = iinfo->symbolic_header.isymMax;
oinfo->external_sym = iinfo->external_sym;
oinfo->symbolic_header.ioptMax = iinfo->symbolic_header.ioptMax;
oinfo->external_opt = iinfo->external_opt;
oinfo->symbolic_header.iauxMax = iinfo->symbolic_header.iauxMax;
oinfo->external_aux = iinfo->external_aux;
oinfo->symbolic_header.issMax = iinfo->symbolic_header.issMax;
oinfo->ss = iinfo->ss;
oinfo->symbolic_header.ifdMax = iinfo->symbolic_header.ifdMax;
oinfo->external_fdr = iinfo->external_fdr;
oinfo->symbolic_header.crfd = iinfo->symbolic_header.crfd;
oinfo->external_rfd = iinfo->external_rfd;
}
else
{
c = bfd_get_symcount (obfd);
sym_ptr_ptr = bfd_get_outsymbols (obfd);
for (; c > 0; c--, sym_ptr_ptr++)
{
EXTR esym;
(*(ecoff_backend (obfd)->debug_swap.swap_ext_in))
(obfd, ecoffsymbol (*sym_ptr_ptr)->native, &esym);
esym.ifd = ifdNil;
esym.asym.index = indexNil;
(*(ecoff_backend (obfd)->debug_swap.swap_ext_out))
(obfd, &esym, ecoffsymbol (*sym_ptr_ptr)->native);
}
}
return TRUE;
}
bfd_boolean
_bfd_ecoff_set_arch_mach (abfd, arch, machine)
bfd *abfd;
enum bfd_architecture arch;
unsigned long machine;
{
bfd_default_set_arch_mach (abfd, arch, machine);
return arch == ecoff_backend (abfd)->arch;
}
int
_bfd_ecoff_sizeof_headers (abfd, reloc)
bfd *abfd;
bfd_boolean reloc ATTRIBUTE_UNUSED;
{
asection *current;
int c;
int ret;
c = 0;
for (current = abfd->sections;
current != (asection *)NULL;
current = current->next)
++c;
ret = (bfd_coff_filhsz (abfd)
+ bfd_coff_aoutsz (abfd)
+ c * bfd_coff_scnhsz (abfd));
return BFD_ALIGN (ret, 16);
}
bfd_boolean
_bfd_ecoff_get_section_contents (abfd, section, location, offset, count)
bfd *abfd;
asection *section;
PTR location;
file_ptr offset;
bfd_size_type count;
{
return _bfd_generic_get_section_contents (abfd, section, location,
offset, count);
}
static int
ecoff_sort_hdrs (arg1, arg2)
const PTR arg1;
const PTR arg2;
{
const asection *hdr1 = *(const asection **) arg1;
const asection *hdr2 = *(const asection **) arg2;
if ((hdr1->flags & SEC_ALLOC) != 0)
{
if ((hdr2->flags & SEC_ALLOC) == 0)
return -1;
}
else
{
if ((hdr2->flags & SEC_ALLOC) != 0)
return 1;
}
if (hdr1->vma < hdr2->vma)
return -1;
else if (hdr1->vma > hdr2->vma)
return 1;
else
return 0;
}
static bfd_boolean
ecoff_compute_section_file_positions (abfd)
bfd *abfd;
{
file_ptr sofar, file_sofar;
asection **sorted_hdrs;
asection *current;
unsigned int i;
file_ptr old_sofar;
bfd_boolean rdata_in_text;
bfd_boolean first_data, first_nonalloc;
const bfd_vma round = ecoff_backend (abfd)->round;
bfd_size_type amt;
sofar = _bfd_ecoff_sizeof_headers (abfd, FALSE);
file_sofar = sofar;
amt = abfd->section_count;
amt *= sizeof (asection *);
sorted_hdrs = (asection **) bfd_malloc (amt);
if (sorted_hdrs == NULL)
return FALSE;
for (current = abfd->sections, i = 0;
current != NULL;
current = current->next, i++)
sorted_hdrs[i] = current;
BFD_ASSERT (i == abfd->section_count);
qsort (sorted_hdrs, abfd->section_count, sizeof (asection *),
ecoff_sort_hdrs);
rdata_in_text = ecoff_backend (abfd)->rdata_in_text;
if (rdata_in_text)
{
for (i = 0; i < abfd->section_count; i++)
{
current = sorted_hdrs[i];
if (strcmp (current->name, _RDATA) == 0)
break;
if ((current->flags & SEC_CODE) == 0
&& strcmp (current->name, _PDATA) != 0
&& strcmp (current->name, _RCONST) != 0)
{
rdata_in_text = FALSE;
break;
}
}
}
ecoff_data (abfd)->rdata_in_text = rdata_in_text;
first_data = TRUE;
first_nonalloc = TRUE;
for (i = 0; i < abfd->section_count; i++)
{
unsigned int alignment_power;
current = sorted_hdrs[i];
if (strcmp (current->name, _PDATA) == 0)
current->line_filepos = current->size / 8;
alignment_power = current->alignment_power;
if ((abfd->flags & EXEC_P) != 0
&& (abfd->flags & D_PAGED) != 0
&& ! first_data
&& (current->flags & SEC_CODE) == 0
&& (! rdata_in_text
|| strcmp (current->name, _RDATA) != 0)
&& strcmp (current->name, _PDATA) != 0
&& strcmp (current->name, _RCONST) != 0)
{
sofar = (sofar + round - 1) &~ (round - 1);
file_sofar = (file_sofar + round - 1) &~ (round - 1);
first_data = FALSE;
}
else if (strcmp (current->name, _LIB) == 0)
{
sofar = (sofar + round - 1) &~ (round - 1);
file_sofar = (file_sofar + round - 1) &~ (round - 1);
}
else if (first_nonalloc
&& (current->flags & SEC_ALLOC) == 0
&& (abfd->flags & D_PAGED) != 0)
{
first_nonalloc = FALSE;
sofar = (sofar + round - 1) &~ (round - 1);
file_sofar = (file_sofar + round - 1) &~ (round - 1);
}
sofar = BFD_ALIGN (sofar, 1 << alignment_power);
if ((current->flags & SEC_HAS_CONTENTS) != 0)
file_sofar = BFD_ALIGN (file_sofar, 1 << alignment_power);
if ((abfd->flags & D_PAGED) != 0
&& (current->flags & SEC_ALLOC) != 0)
{
sofar += (current->vma - sofar) % round;
if ((current->flags & SEC_HAS_CONTENTS) != 0)
file_sofar += (current->vma - file_sofar) % round;
}
if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) != 0)
current->filepos = file_sofar;
sofar += current->size;
if ((current->flags & SEC_HAS_CONTENTS) != 0)
file_sofar += current->size;
old_sofar = sofar;
sofar = BFD_ALIGN (sofar, 1 << alignment_power);
if ((current->flags & SEC_HAS_CONTENTS) != 0)
file_sofar = BFD_ALIGN (file_sofar, 1 << alignment_power);
current->size += sofar - old_sofar;
}
free (sorted_hdrs);
sorted_hdrs = NULL;
ecoff_data (abfd)->reloc_filepos = file_sofar;
return TRUE;
}
static bfd_size_type
ecoff_compute_reloc_file_positions (abfd)
bfd *abfd;
{
const bfd_size_type external_reloc_size =
ecoff_backend (abfd)->external_reloc_size;
file_ptr reloc_base;
bfd_size_type reloc_size;
asection *current;
file_ptr sym_base;
if (! abfd->output_has_begun)
{
if (! ecoff_compute_section_file_positions (abfd))
abort ();
abfd->output_has_begun = TRUE;
}
reloc_base = ecoff_data (abfd)->reloc_filepos;
reloc_size = 0;
for (current = abfd->sections;
current != (asection *)NULL;
current = current->next)
{
if (current->reloc_count == 0)
current->rel_filepos = 0;
else
{
bfd_size_type relsize;
current->rel_filepos = reloc_base;
relsize = current->reloc_count * external_reloc_size;
reloc_size += relsize;
reloc_base += relsize;
}
}
sym_base = ecoff_data (abfd)->reloc_filepos + reloc_size;
if ((abfd->flags & EXEC_P) != 0
&& (abfd->flags & D_PAGED) != 0)
sym_base = ((sym_base + ecoff_backend (abfd)->round - 1)
&~ (ecoff_backend (abfd)->round - 1));
ecoff_data (abfd)->sym_filepos = sym_base;
return reloc_size;
}
bfd_boolean
_bfd_ecoff_set_section_contents (abfd, section, location, offset, count)
bfd *abfd;
asection *section;
const PTR location;
file_ptr offset;
bfd_size_type count;
{
file_ptr pos;
if (! abfd->output_has_begun)
{
if (! ecoff_compute_section_file_positions (abfd))
return FALSE;
}
if (strcmp (section->name, _LIB) == 0)
{
bfd_byte *rec, *recend;
rec = (bfd_byte *) location;
recend = rec + count;
while (rec < recend)
{
++section->lma;
rec += bfd_get_32 (abfd, rec) * 4;
}
BFD_ASSERT (rec == recend);
}
if (count == 0)
return TRUE;
pos = section->filepos + offset;
if (bfd_seek (abfd, pos, SEEK_SET) != 0
|| bfd_bwrite (location, count, abfd) != count)
return FALSE;
return TRUE;
}
bfd_vma
bfd_ecoff_get_gp_value (abfd)
bfd *abfd;
{
if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour
|| bfd_get_format (abfd) != bfd_object)
{
bfd_set_error (bfd_error_invalid_operation);
return 0;
}
return ecoff_data (abfd)->gp;
}
bfd_boolean
bfd_ecoff_set_gp_value (abfd, gp_value)
bfd *abfd;
bfd_vma gp_value;
{
if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour
|| bfd_get_format (abfd) != bfd_object)
{
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
ecoff_data (abfd)->gp = gp_value;
return TRUE;
}
bfd_boolean
bfd_ecoff_set_regmasks (abfd, gprmask, fprmask, cprmask)
bfd *abfd;
unsigned long gprmask;
unsigned long fprmask;
unsigned long *cprmask;
{
ecoff_data_type *tdata;
if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour
|| bfd_get_format (abfd) != bfd_object)
{
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
tdata = ecoff_data (abfd);
tdata->gprmask = gprmask;
tdata->fprmask = fprmask;
if (cprmask != (unsigned long *) NULL)
{
int i;
for (i = 0; i < 3; i++)
tdata->cprmask[i] = cprmask[i];
}
return TRUE;
}
static bfd_boolean
ecoff_get_extr (sym, esym)
asymbol *sym;
EXTR *esym;
{
ecoff_symbol_type *ecoff_sym_ptr;
bfd *input_bfd;
if (bfd_asymbol_flavour (sym) != bfd_target_ecoff_flavour
|| ecoffsymbol (sym)->native == NULL)
{
if ((sym->flags & BSF_DEBUGGING) != 0
|| (sym->flags & BSF_LOCAL) != 0
|| (sym->flags & BSF_SECTION_SYM) != 0)
return FALSE;
esym->jmptbl = 0;
esym->cobol_main = 0;
esym->weakext = (sym->flags & BSF_WEAK) != 0;
esym->reserved = 0;
esym->ifd = ifdNil;
esym->asym.st = stGlobal;
esym->asym.sc = scAbs;
esym->asym.reserved = 0;
esym->asym.index = indexNil;
return TRUE;
}
ecoff_sym_ptr = ecoffsymbol (sym);
if (ecoff_sym_ptr->local)
return FALSE;
input_bfd = bfd_asymbol_bfd (sym);
(*(ecoff_backend (input_bfd)->debug_swap.swap_ext_in))
(input_bfd, ecoff_sym_ptr->native, esym);
if ((esym->asym.sc == scUndefined
|| esym->asym.sc == scSUndefined)
&& ! bfd_is_und_section (bfd_get_section (sym)))
esym->asym.sc = scAbs;
if (esym->ifd != -1)
{
struct ecoff_debug_info *input_debug;
input_debug = &ecoff_data (input_bfd)->debug_info;
BFD_ASSERT (esym->ifd < input_debug->symbolic_header.ifdMax);
if (input_debug->ifdmap != (RFDT *) NULL)
esym->ifd = input_debug->ifdmap[esym->ifd];
}
return TRUE;
}
static void
ecoff_set_index (sym, indx)
asymbol *sym;
bfd_size_type indx;
{
ecoff_set_sym_index (sym, indx);
}
bfd_boolean
_bfd_ecoff_write_object_contents (abfd)
bfd *abfd;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
const bfd_vma round = backend->round;
const bfd_size_type filhsz = bfd_coff_filhsz (abfd);
const bfd_size_type aoutsz = bfd_coff_aoutsz (abfd);
const bfd_size_type scnhsz = bfd_coff_scnhsz (abfd);
const bfd_size_type external_hdr_size
= backend->debug_swap.external_hdr_size;
const bfd_size_type external_reloc_size = backend->external_reloc_size;
void (* const adjust_reloc_out)
PARAMS ((bfd *, const arelent *, struct internal_reloc *))
= backend->adjust_reloc_out;
void (* const swap_reloc_out)
PARAMS ((bfd *, const struct internal_reloc *, PTR))
= backend->swap_reloc_out;
struct ecoff_debug_info * const debug = &ecoff_data (abfd)->debug_info;
HDRR * const symhdr = &debug->symbolic_header;
asection *current;
unsigned int count;
bfd_size_type reloc_size;
bfd_size_type text_size;
bfd_vma text_start;
bfd_boolean set_text_start;
bfd_size_type data_size;
bfd_vma data_start;
bfd_boolean set_data_start;
bfd_size_type bss_size;
PTR buff = NULL;
PTR reloc_buff = NULL;
struct internal_filehdr internal_f;
struct internal_aouthdr internal_a;
int i;
reloc_size = ecoff_compute_reloc_file_positions (abfd);
count = 1;
for (current = abfd->sections;
current != (asection *)NULL;
current = current->next)
{
current->target_index = count;
++count;
}
if ((abfd->flags & D_PAGED) != 0)
text_size = _bfd_ecoff_sizeof_headers (abfd, FALSE);
else
text_size = 0;
text_start = 0;
set_text_start = FALSE;
data_size = 0;
data_start = 0;
set_data_start = FALSE;
bss_size = 0;
{
bfd_size_type siz;
siz = scnhsz;
if (siz < filhsz)
siz = filhsz;
if (siz < aoutsz)
siz = aoutsz;
buff = (PTR) bfd_malloc (siz);
if (buff == NULL)
goto error_return;
}
internal_f.f_nscns = 0;
if (bfd_seek (abfd, (file_ptr) (filhsz + aoutsz), SEEK_SET) != 0)
goto error_return;
for (current = abfd->sections;
current != (asection *) NULL;
current = current->next)
{
struct internal_scnhdr section;
bfd_vma vma;
++internal_f.f_nscns;
strncpy (section.s_name, current->name, sizeof section.s_name);
vma = bfd_get_section_vma (abfd, current);
if (strcmp (current->name, _LIB) == 0)
section.s_vaddr = 0;
else
section.s_vaddr = vma;
section.s_paddr = current->lma;
section.s_size = current->size;
if ((current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
section.s_scnptr = 0;
else
section.s_scnptr = current->filepos;
section.s_relptr = current->rel_filepos;
if (strcmp (current->name, _PDATA) != 0)
section.s_lnnoptr = 0;
else
{
section.s_lnnoptr = current->line_filepos;
}
section.s_nreloc = current->reloc_count;
section.s_nlnno = 0;
section.s_flags = ecoff_sec_to_styp_flags (current->name,
current->flags);
if (bfd_coff_swap_scnhdr_out (abfd, (PTR) §ion, buff) == 0
|| bfd_bwrite (buff, scnhsz, abfd) != scnhsz)
goto error_return;
if ((section.s_flags & STYP_TEXT) != 0
|| ((section.s_flags & STYP_RDATA) != 0
&& ecoff_data (abfd)->rdata_in_text)
|| section.s_flags == STYP_PDATA
|| (section.s_flags & STYP_DYNAMIC) != 0
|| (section.s_flags & STYP_LIBLIST) != 0
|| (section.s_flags & STYP_RELDYN) != 0
|| section.s_flags == STYP_CONFLIC
|| (section.s_flags & STYP_DYNSTR) != 0
|| (section.s_flags & STYP_DYNSYM) != 0
|| (section.s_flags & STYP_HASH) != 0
|| (section.s_flags & STYP_ECOFF_INIT) != 0
|| (section.s_flags & STYP_ECOFF_FINI) != 0
|| section.s_flags == STYP_RCONST)
{
text_size += current->size;
if (! set_text_start || text_start > vma)
{
text_start = vma;
set_text_start = TRUE;
}
}
else if ((section.s_flags & STYP_RDATA) != 0
|| (section.s_flags & STYP_DATA) != 0
|| (section.s_flags & STYP_LITA) != 0
|| (section.s_flags & STYP_LIT8) != 0
|| (section.s_flags & STYP_LIT4) != 0
|| (section.s_flags & STYP_SDATA) != 0
|| section.s_flags == STYP_XDATA
|| (section.s_flags & STYP_GOT) != 0)
{
data_size += current->size;
if (! set_data_start || data_start > vma)
{
data_start = vma;
set_data_start = TRUE;
}
}
else if ((section.s_flags & STYP_BSS) != 0
|| (section.s_flags & STYP_SBSS) != 0)
bss_size += current->size;
else if (section.s_flags == 0
|| (section.s_flags & STYP_ECOFF_LIB) != 0
|| section.s_flags == STYP_COMMENT)
;
else
abort ();
}
internal_f.f_magic = ecoff_get_magic (abfd);
internal_f.f_timdat = 0;
if (bfd_get_symcount (abfd) != 0)
{
internal_f.f_nsyms = external_hdr_size;
internal_f.f_symptr = ecoff_data (abfd)->sym_filepos;
}
else
{
internal_f.f_nsyms = 0;
internal_f.f_symptr = 0;
}
internal_f.f_opthdr = aoutsz;
internal_f.f_flags = F_LNNO;
if (reloc_size == 0)
internal_f.f_flags |= F_RELFLG;
if (bfd_get_symcount (abfd) == 0)
internal_f.f_flags |= F_LSYMS;
if (abfd->flags & EXEC_P)
internal_f.f_flags |= F_EXEC;
if (bfd_little_endian (abfd))
internal_f.f_flags |= F_AR32WR;
else
internal_f.f_flags |= F_AR32W;
if ((abfd->flags & D_PAGED) != 0)
internal_a.magic = ECOFF_AOUT_ZMAGIC;
else
internal_a.magic = ECOFF_AOUT_OMAGIC;
internal_a.vstamp = symhdr->vstamp;
if ((abfd->flags & D_PAGED) != 0)
{
internal_a.tsize = (text_size + round - 1) &~ (round - 1);
internal_a.text_start = text_start &~ (round - 1);
internal_a.dsize = (data_size + round - 1) &~ (round - 1);
internal_a.data_start = data_start &~ (round - 1);
}
else
{
internal_a.tsize = text_size;
internal_a.text_start = text_start;
internal_a.dsize = data_size;
internal_a.data_start = data_start;
}
if (bss_size < internal_a.dsize - data_size)
bss_size = 0;
else
bss_size -= internal_a.dsize - data_size;
internal_a.bsize = bss_size;
internal_a.bss_start = internal_a.data_start + internal_a.dsize;
internal_a.entry = bfd_get_start_address (abfd);
internal_a.gp_value = ecoff_data (abfd)->gp;
internal_a.gprmask = ecoff_data (abfd)->gprmask;
internal_a.fprmask = ecoff_data (abfd)->fprmask;
for (i = 0; i < 4; i++)
internal_a.cprmask[i] = ecoff_data (abfd)->cprmask[i];
if (backend->adjust_headers)
{
if (! (*backend->adjust_headers) (abfd, &internal_f, &internal_a))
goto error_return;
}
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
goto error_return;
bfd_coff_swap_filehdr_out (abfd, (PTR) &internal_f, buff);
if (bfd_bwrite (buff, filhsz, abfd) != filhsz)
goto error_return;
bfd_coff_swap_aouthdr_out (abfd, (PTR) &internal_a, buff);
if (bfd_bwrite (buff, aoutsz, abfd) != aoutsz)
goto error_return;
if (! ecoff_data (abfd)->linker)
{
symhdr->iextMax = 0;
symhdr->issExtMax = 0;
debug->external_ext = debug->external_ext_end = NULL;
debug->ssext = debug->ssext_end = NULL;
if (! bfd_ecoff_debug_externals (abfd, debug, &backend->debug_swap,
(abfd->flags & EXEC_P) == 0,
ecoff_get_extr, ecoff_set_index))
goto error_return;
for (current = abfd->sections;
current != (asection *) NULL;
current = current->next)
{
arelent **reloc_ptr_ptr;
arelent **reloc_end;
char *out_ptr;
bfd_size_type amt;
if (current->reloc_count == 0)
continue;
amt = current->reloc_count * external_reloc_size;
reloc_buff = bfd_alloc (abfd, amt);
if (reloc_buff == NULL)
goto error_return;
reloc_ptr_ptr = current->orelocation;
reloc_end = reloc_ptr_ptr + current->reloc_count;
out_ptr = (char *) reloc_buff;
for (;
reloc_ptr_ptr < reloc_end;
reloc_ptr_ptr++, out_ptr += external_reloc_size)
{
arelent *reloc;
asymbol *sym;
struct internal_reloc in;
memset ((PTR) &in, 0, sizeof in);
reloc = *reloc_ptr_ptr;
sym = *reloc->sym_ptr_ptr;
in.r_vaddr = (reloc->address
+ bfd_get_section_vma (abfd, current));
in.r_type = reloc->howto->type;
if ((sym->flags & BSF_SECTION_SYM) == 0)
{
in.r_symndx = ecoff_get_sym_index (*reloc->sym_ptr_ptr);
in.r_extern = 1;
}
else
{
const char *name;
name = bfd_get_section_name (abfd, bfd_get_section (sym));
if (strcmp (name, ".text") == 0)
in.r_symndx = RELOC_SECTION_TEXT;
else if (strcmp (name, ".rdata") == 0)
in.r_symndx = RELOC_SECTION_RDATA;
else if (strcmp (name, ".data") == 0)
in.r_symndx = RELOC_SECTION_DATA;
else if (strcmp (name, ".sdata") == 0)
in.r_symndx = RELOC_SECTION_SDATA;
else if (strcmp (name, ".sbss") == 0)
in.r_symndx = RELOC_SECTION_SBSS;
else if (strcmp (name, ".bss") == 0)
in.r_symndx = RELOC_SECTION_BSS;
else if (strcmp (name, ".init") == 0)
in.r_symndx = RELOC_SECTION_INIT;
else if (strcmp (name, ".lit8") == 0)
in.r_symndx = RELOC_SECTION_LIT8;
else if (strcmp (name, ".lit4") == 0)
in.r_symndx = RELOC_SECTION_LIT4;
else if (strcmp (name, ".xdata") == 0)
in.r_symndx = RELOC_SECTION_XDATA;
else if (strcmp (name, ".pdata") == 0)
in.r_symndx = RELOC_SECTION_PDATA;
else if (strcmp (name, ".fini") == 0)
in.r_symndx = RELOC_SECTION_FINI;
else if (strcmp (name, ".lita") == 0)
in.r_symndx = RELOC_SECTION_LITA;
else if (strcmp (name, "*ABS*") == 0)
in.r_symndx = RELOC_SECTION_ABS;
else if (strcmp (name, ".rconst") == 0)
in.r_symndx = RELOC_SECTION_RCONST;
else
abort ();
in.r_extern = 0;
}
(*adjust_reloc_out) (abfd, reloc, &in);
(*swap_reloc_out) (abfd, &in, (PTR) out_ptr);
}
if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0)
goto error_return;
amt = current->reloc_count * external_reloc_size;
if (bfd_bwrite (reloc_buff, amt, abfd) != amt)
goto error_return;
bfd_release (abfd, reloc_buff);
reloc_buff = NULL;
}
if (bfd_get_symcount (abfd) > 0)
{
if (! bfd_ecoff_write_debug (abfd, debug, &backend->debug_swap,
ecoff_data (abfd)->sym_filepos))
goto error_return;
}
}
if (bfd_get_symcount (abfd) == 0
&& (abfd->flags & EXEC_P) != 0
&& (abfd->flags & D_PAGED) != 0)
{
char c;
if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1,
SEEK_SET) != 0)
goto error_return;
if (bfd_bread (&c, (bfd_size_type) 1, abfd) == 0)
c = 0;
if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1,
SEEK_SET) != 0)
goto error_return;
if (bfd_bwrite (&c, (bfd_size_type) 1, abfd) != 1)
goto error_return;
}
if (reloc_buff != NULL)
bfd_release (abfd, reloc_buff);
if (buff != NULL)
free (buff);
return TRUE;
error_return:
if (reloc_buff != NULL)
bfd_release (abfd, reloc_buff);
if (buff != NULL)
free (buff);
return FALSE;
}
#define ARMAP_BIG_ENDIAN 'B'
#define ARMAP_LITTLE_ENDIAN 'L'
#define ARMAP_MARKER 'E'
#define ARMAP_START_LENGTH 10
#define ARMAP_HEADER_MARKER_INDEX 10
#define ARMAP_HEADER_ENDIAN_INDEX 11
#define ARMAP_OBJECT_MARKER_INDEX 12
#define ARMAP_OBJECT_ENDIAN_INDEX 13
#define ARMAP_END_INDEX 14
#define ARMAP_END "_ "
#define ARMAP_HASH_MAGIC 0x9dd68ab5
static unsigned int
ecoff_armap_hash (s, rehash, size, hlog)
const char *s;
unsigned int *rehash;
unsigned int size;
unsigned int hlog;
{
unsigned int hash;
if (hlog == 0)
return 0;
hash = *s++;
while (*s != '\0')
hash = ((hash >> 27) | (hash << 5)) + *s++;
hash *= ARMAP_HASH_MAGIC;
*rehash = (hash & (size - 1)) | 1;
return hash >> (32 - hlog);
}
bfd_boolean
_bfd_ecoff_slurp_armap (abfd)
bfd *abfd;
{
char nextname[17];
unsigned int i;
struct areltdata *mapdata;
bfd_size_type parsed_size;
char *raw_armap;
struct artdata *ardata;
unsigned int count;
char *raw_ptr;
struct symdef *symdef_ptr;
char *stringbase;
bfd_size_type amt;
i = bfd_bread ((PTR) nextname, (bfd_size_type) 16, abfd);
if (i == 0)
return TRUE;
if (i != 16)
return FALSE;
if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0)
return FALSE;
if (strncmp (nextname, "/ ", 16) == 0)
return bfd_slurp_armap (abfd);
if (strncmp (nextname, ecoff_backend (abfd)->armap_start,
ARMAP_START_LENGTH) != 0
|| nextname[ARMAP_HEADER_MARKER_INDEX] != ARMAP_MARKER
|| (nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN
&& nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN)
|| nextname[ARMAP_OBJECT_MARKER_INDEX] != ARMAP_MARKER
|| (nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN
&& nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN)
|| strncmp (nextname + ARMAP_END_INDEX,
ARMAP_END, sizeof ARMAP_END - 1) != 0)
{
bfd_has_map (abfd) = FALSE;
return TRUE;
}
if (((nextname[ARMAP_HEADER_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN)
^ (bfd_header_big_endian (abfd)))
|| ((nextname[ARMAP_OBJECT_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN)
^ (bfd_big_endian (abfd))))
{
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
ardata = bfd_ardata (abfd);
mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
if (mapdata == (struct areltdata *) NULL)
return FALSE;
parsed_size = mapdata->parsed_size;
bfd_release (abfd, (PTR) mapdata);
raw_armap = (char *) bfd_alloc (abfd, parsed_size);
if (raw_armap == (char *) NULL)
return FALSE;
if (bfd_bread ((PTR) raw_armap, parsed_size, abfd) != parsed_size)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_malformed_archive);
bfd_release (abfd, (PTR) raw_armap);
return FALSE;
}
ardata->tdata = (PTR) raw_armap;
count = H_GET_32 (abfd, raw_armap);
ardata->symdef_count = 0;
ardata->cache = (struct ar_cache *) NULL;
stringbase = raw_armap + count * 8 + 8;
#ifdef CHECK_ARMAP_HASH
{
unsigned int hlog;
hlog = 0;
for (i = 1; i < count; i <<= 1)
hlog++;
BFD_ASSERT (i == count);
raw_ptr = raw_armap + 4;
for (i = 0; i < count; i++, raw_ptr += 8)
{
unsigned int name_offset, file_offset;
unsigned int hash, rehash, srch;
name_offset = H_GET_32 (abfd, raw_ptr);
file_offset = H_GET_32 (abfd, (raw_ptr + 4));
if (file_offset == 0)
continue;
hash = ecoff_armap_hash (stringbase + name_offset, &rehash, count,
hlog);
if (hash == i)
continue;
for (srch = (hash + rehash) & (count - 1);
srch != hash && srch != i;
srch = (srch + rehash) & (count - 1))
BFD_ASSERT (H_GET_32 (abfd, (raw_armap + 8 + srch * 8)) != 0);
BFD_ASSERT (srch == i);
}
}
#endif
raw_ptr = raw_armap + 4;
for (i = 0; i < count; i++, raw_ptr += 8)
if (H_GET_32 (abfd, (raw_ptr + 4)) != 0)
++ardata->symdef_count;
amt = ardata->symdef_count;
amt *= sizeof (struct symdef);
symdef_ptr = (struct symdef *) bfd_alloc (abfd, amt);
if (!symdef_ptr)
return FALSE;
ardata->symdefs = (carsym *) symdef_ptr;
raw_ptr = raw_armap + 4;
for (i = 0; i < count; i++, raw_ptr += 8)
{
unsigned int name_offset, file_offset;
file_offset = H_GET_32 (abfd, (raw_ptr + 4));
if (file_offset == 0)
continue;
name_offset = H_GET_32 (abfd, raw_ptr);
symdef_ptr->s.name = stringbase + name_offset;
symdef_ptr->file_offset = file_offset;
++symdef_ptr;
}
ardata->first_file_filepos = bfd_tell (abfd);
ardata->first_file_filepos += ardata->first_file_filepos % 2;
bfd_has_map (abfd) = TRUE;
return TRUE;
}
bfd_boolean
_bfd_ecoff_write_armap (abfd, elength, map, orl_count, stridx)
bfd *abfd;
unsigned int elength;
struct orl *map;
unsigned int orl_count;
int stridx;
{
unsigned int hashsize, hashlog;
bfd_size_type symdefsize;
int padit;
unsigned int stringsize;
unsigned int mapsize;
file_ptr firstreal;
struct ar_hdr hdr;
struct stat statbuf;
unsigned int i;
bfd_byte temp[4];
bfd_byte *hashtable;
bfd *current;
bfd *last_elt;
for (hashlog = 0; ((unsigned int) 1 << hashlog) <= 2 * orl_count; hashlog++)
;
hashsize = 1 << hashlog;
symdefsize = hashsize * 8;
padit = stridx % 2;
stringsize = stridx + padit;
mapsize = symdefsize + stringsize + 8;
firstreal = SARMAG + sizeof (struct ar_hdr) + mapsize + elength;
memset ((PTR) &hdr, 0, sizeof hdr);
strcpy (hdr.ar_name, ecoff_backend (abfd)->armap_start);
hdr.ar_name[ARMAP_HEADER_MARKER_INDEX] = ARMAP_MARKER;
hdr.ar_name[ARMAP_HEADER_ENDIAN_INDEX] =
(bfd_header_big_endian (abfd)
? ARMAP_BIG_ENDIAN
: ARMAP_LITTLE_ENDIAN);
hdr.ar_name[ARMAP_OBJECT_MARKER_INDEX] = ARMAP_MARKER;
hdr.ar_name[ARMAP_OBJECT_ENDIAN_INDEX] =
bfd_big_endian (abfd) ? ARMAP_BIG_ENDIAN : ARMAP_LITTLE_ENDIAN;
memcpy (hdr.ar_name + ARMAP_END_INDEX, ARMAP_END, sizeof ARMAP_END - 1);
stat (abfd->filename, &statbuf);
sprintf (hdr.ar_date, "%ld", (long) (statbuf.st_mtime + 60));
hdr.ar_uid[0] = '0';
hdr.ar_gid[0] = '0';
hdr.ar_mode[0] = '6';
hdr.ar_mode[1] = '4';
hdr.ar_mode[2] = '4';
sprintf (hdr.ar_size, "%-10d", (int) mapsize);
hdr.ar_fmag[0] = '`';
hdr.ar_fmag[1] = '\012';
for (i = 0; i < sizeof (struct ar_hdr); i++)
if (((char *) (&hdr))[i] == '\0')
(((char *) (&hdr))[i]) = ' ';
if (bfd_bwrite ((PTR) &hdr, (bfd_size_type) sizeof (struct ar_hdr), abfd)
!= sizeof (struct ar_hdr))
return FALSE;
H_PUT_32 (abfd, hashsize, temp);
if (bfd_bwrite ((PTR) temp, (bfd_size_type) 4, abfd) != 4)
return FALSE;
hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize);
if (!hashtable)
return FALSE;
current = abfd->archive_head;
last_elt = current;
for (i = 0; i < orl_count; i++)
{
unsigned int hash, rehash;
if (map[i].u.abfd != last_elt)
{
do
{
firstreal += arelt_size (current) + sizeof (struct ar_hdr);
firstreal += firstreal % 2;
current = current->next;
}
while (current != map[i].u.abfd);
}
last_elt = current;
hash = ecoff_armap_hash (*map[i].name, &rehash, hashsize, hashlog);
if (H_GET_32 (abfd, (hashtable + (hash * 8) + 4)) != 0)
{
unsigned int srch;
for (srch = (hash + rehash) & (hashsize - 1);
srch != hash;
srch = (srch + rehash) & (hashsize - 1))
if (H_GET_32 (abfd, (hashtable + (srch * 8) + 4)) == 0)
break;
BFD_ASSERT (srch != hash);
hash = srch;
}
H_PUT_32 (abfd, map[i].namidx, (hashtable + hash * 8));
H_PUT_32 (abfd, firstreal, (hashtable + hash * 8 + 4));
}
if (bfd_bwrite ((PTR) hashtable, symdefsize, abfd) != symdefsize)
return FALSE;
bfd_release (abfd, hashtable);
H_PUT_32 (abfd, stringsize, temp);
if (bfd_bwrite ((PTR) temp, (bfd_size_type) 4, abfd) != 4)
return FALSE;
for (i = 0; i < orl_count; i++)
{
bfd_size_type len;
len = strlen (*map[i].name) + 1;
if (bfd_bwrite ((PTR) (*map[i].name), len, abfd) != len)
return FALSE;
}
if (padit)
{
if (bfd_bwrite ("", (bfd_size_type) 1, abfd) != 1)
return FALSE;
}
return TRUE;
}
const bfd_target *
_bfd_ecoff_archive_p (abfd)
bfd *abfd;
{
struct artdata *tdata_hold;
char armag[SARMAG + 1];
bfd_size_type amt;
if (bfd_bread ((PTR) armag, (bfd_size_type) SARMAG, abfd) != SARMAG)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
return (const bfd_target *) NULL;
}
if (strncmp (armag, ARMAG, SARMAG) != 0)
{
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
tdata_hold = bfd_ardata (abfd);
amt = sizeof (struct artdata);
bfd_ardata (abfd) = (struct artdata *) bfd_zalloc (abfd, amt);
if (bfd_ardata (abfd) == (struct artdata *) NULL)
{
bfd_ardata (abfd) = tdata_hold;
return (const bfd_target *) NULL;
}
bfd_ardata (abfd)->first_file_filepos = SARMAG;
bfd_ardata (abfd)->cache = NULL;
bfd_ardata (abfd)->archive_head = NULL;
bfd_ardata (abfd)->symdefs = NULL;
bfd_ardata (abfd)->extended_names = NULL;
bfd_ardata (abfd)->tdata = NULL;
if (! _bfd_ecoff_slurp_armap (abfd)
|| ! _bfd_ecoff_slurp_extended_name_table (abfd))
{
bfd_release (abfd, bfd_ardata (abfd));
bfd_ardata (abfd) = tdata_hold;
return (const bfd_target *) NULL;
}
if (bfd_has_map (abfd))
{
bfd *first;
first = bfd_openr_next_archived_file (abfd, (bfd *) NULL);
if (first != NULL)
{
first->target_defaulted = FALSE;
if (bfd_check_format (first, bfd_object)
&& first->xvec != abfd->xvec)
{
bfd_set_error (bfd_error_wrong_object_format);
bfd_ardata (abfd) = tdata_hold;
return NULL;
}
}
}
return abfd->xvec;
}
static struct bfd_hash_entry *ecoff_link_hash_newfunc
PARAMS ((struct bfd_hash_entry *entry,
struct bfd_hash_table *table,
const char *string));
static bfd_boolean ecoff_link_add_archive_symbols
PARAMS ((bfd *, struct bfd_link_info *));
static bfd_boolean ecoff_link_check_archive_element
PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded));
static bfd_boolean ecoff_link_add_object_symbols
PARAMS ((bfd *, struct bfd_link_info *));
static bfd_boolean ecoff_link_add_externals
PARAMS ((bfd *, struct bfd_link_info *, PTR, char *));
static struct bfd_hash_entry *
ecoff_link_hash_newfunc (entry, table, string)
struct bfd_hash_entry *entry;
struct bfd_hash_table *table;
const char *string;
{
struct ecoff_link_hash_entry *ret = (struct ecoff_link_hash_entry *) entry;
if (ret == (struct ecoff_link_hash_entry *) NULL)
ret = ((struct ecoff_link_hash_entry *)
bfd_hash_allocate (table, sizeof (struct ecoff_link_hash_entry)));
if (ret == (struct ecoff_link_hash_entry *) NULL)
return NULL;
ret = ((struct ecoff_link_hash_entry *)
_bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
if (ret)
{
ret->indx = -1;
ret->abfd = NULL;
ret->written = 0;
ret->small = 0;
}
memset ((PTR) &ret->esym, 0, sizeof ret->esym);
return (struct bfd_hash_entry *) ret;
}
struct bfd_link_hash_table *
_bfd_ecoff_bfd_link_hash_table_create (abfd)
bfd *abfd;
{
struct ecoff_link_hash_table *ret;
bfd_size_type amt = sizeof (struct ecoff_link_hash_table);
ret = (struct ecoff_link_hash_table *) bfd_malloc (amt);
if (ret == NULL)
return NULL;
if (! _bfd_link_hash_table_init (&ret->root, abfd,
ecoff_link_hash_newfunc))
{
free (ret);
return (struct bfd_link_hash_table *) NULL;
}
return &ret->root;
}
#define ecoff_link_hash_lookup(table, string, create, copy, follow) \
((struct ecoff_link_hash_entry *) \
bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow)))
#define ecoff_link_hash_traverse(table, func, info) \
(bfd_link_hash_traverse \
(&(table)->root, \
(bfd_boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \
(info)))
#define ecoff_hash_table(p) ((struct ecoff_link_hash_table *) ((p)->hash))
bfd_boolean
_bfd_ecoff_bfd_link_add_symbols (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
switch (bfd_get_format (abfd))
{
case bfd_object:
return ecoff_link_add_object_symbols (abfd, info);
case bfd_archive:
return ecoff_link_add_archive_symbols (abfd, info);
default:
bfd_set_error (bfd_error_wrong_format);
return FALSE;
}
}
static bfd_boolean
ecoff_link_add_archive_symbols (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
const bfd_byte *raw_armap;
struct bfd_link_hash_entry **pundef;
unsigned int armap_count;
unsigned int armap_log;
unsigned int i;
const bfd_byte *hashtable;
const char *stringbase;
if (! bfd_has_map (abfd))
{
if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL)
return TRUE;
bfd_set_error (bfd_error_no_armap);
return FALSE;
}
raw_armap = (const bfd_byte *) bfd_ardata (abfd)->tdata;
if (raw_armap == (bfd_byte *) NULL)
return (_bfd_generic_link_add_archive_symbols
(abfd, info, ecoff_link_check_archive_element));
armap_count = H_GET_32 (abfd, raw_armap);
armap_log = 0;
for (i = 1; i < armap_count; i <<= 1)
armap_log++;
BFD_ASSERT (i == armap_count);
hashtable = raw_armap + 4;
stringbase = (const char *) raw_armap + armap_count * 8 + 8;
pundef = &info->hash->undefs;
while (*pundef != (struct bfd_link_hash_entry *) NULL)
{
struct bfd_link_hash_entry *h;
unsigned int hash, rehash;
unsigned int file_offset;
const char *name;
bfd *element;
h = *pundef;
if (h->type != bfd_link_hash_undefined
&& h->type != bfd_link_hash_common)
{
if (*pundef != info->hash->undefs_tail)
*pundef = (*pundef)->u.undef.next;
else
pundef = &(*pundef)->u.undef.next;
continue;
}
if (h->type != bfd_link_hash_undefined)
{
pundef = &(*pundef)->u.undef.next;
continue;
}
hash = ecoff_armap_hash (h->root.string, &rehash, armap_count,
armap_log);
file_offset = H_GET_32 (abfd, hashtable + (hash * 8) + 4);
if (file_offset == 0)
{
pundef = &(*pundef)->u.undef.next;
continue;
}
name = stringbase + H_GET_32 (abfd, hashtable + (hash * 8));
if (name[0] != h->root.string[0]
|| strcmp (name, h->root.string) != 0)
{
unsigned int srch;
bfd_boolean found;
found = FALSE;
for (srch = (hash + rehash) & (armap_count - 1);
srch != hash;
srch = (srch + rehash) & (armap_count - 1))
{
file_offset = H_GET_32 (abfd, hashtable + (srch * 8) + 4);
if (file_offset == 0)
break;
name = stringbase + H_GET_32 (abfd, hashtable + (srch * 8));
if (name[0] == h->root.string[0]
&& strcmp (name, h->root.string) == 0)
{
found = TRUE;
break;
}
}
if (! found)
{
pundef = &(*pundef)->u.undef.next;
continue;
}
hash = srch;
}
element = (*backend->get_elt_at_filepos) (abfd, (file_ptr) file_offset);
if (element == (bfd *) NULL)
return FALSE;
if (! bfd_check_format (element, bfd_object))
return FALSE;
if (! (*info->callbacks->add_archive_element) (info, element, name))
return FALSE;
if (! ecoff_link_add_object_symbols (element, info))
return FALSE;
pundef = &(*pundef)->u.undef.next;
}
return TRUE;
}
static bfd_boolean
ecoff_link_check_archive_element (abfd, info, pneeded)
bfd *abfd;
struct bfd_link_info *info;
bfd_boolean *pneeded;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
= backend->debug_swap.swap_ext_in;
HDRR *symhdr;
bfd_size_type external_ext_size;
PTR external_ext = NULL;
bfd_size_type esize;
char *ssext = NULL;
char *ext_ptr;
char *ext_end;
*pneeded = FALSE;
if (! ecoff_slurp_symbolic_header (abfd))
goto error_return;
if (bfd_get_symcount (abfd) == 0)
goto successful_return;
symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
external_ext_size = backend->debug_swap.external_ext_size;
esize = symhdr->iextMax * external_ext_size;
external_ext = (PTR) bfd_malloc (esize);
if (external_ext == NULL && esize != 0)
goto error_return;
if (bfd_seek (abfd, (file_ptr) symhdr->cbExtOffset, SEEK_SET) != 0
|| bfd_bread (external_ext, esize, abfd) != esize)
goto error_return;
ssext = (char *) bfd_malloc ((bfd_size_type) symhdr->issExtMax);
if (ssext == NULL && symhdr->issExtMax != 0)
goto error_return;
if (bfd_seek (abfd, (file_ptr) symhdr->cbSsExtOffset, SEEK_SET) != 0
|| (bfd_bread (ssext, (bfd_size_type) symhdr->issExtMax, abfd)
!= (bfd_size_type) symhdr->issExtMax))
goto error_return;
ext_ptr = (char *) external_ext;
ext_end = ext_ptr + esize;
for (; ext_ptr < ext_end; ext_ptr += external_ext_size)
{
EXTR esym;
bfd_boolean def;
const char *name;
struct bfd_link_hash_entry *h;
(*swap_ext_in) (abfd, (PTR) ext_ptr, &esym);
if (esym.asym.st != stGlobal
&& esym.asym.st != stLabel
&& esym.asym.st != stProc)
continue;
switch (esym.asym.sc)
{
case scText:
case scData:
case scBss:
case scAbs:
case scSData:
case scSBss:
case scRData:
case scCommon:
case scSCommon:
case scInit:
case scFini:
case scRConst:
def = TRUE;
break;
default:
def = FALSE;
break;
}
if (! def)
continue;
name = ssext + esym.asym.iss;
h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
if (h == (struct bfd_link_hash_entry *) NULL
|| h->type != bfd_link_hash_undefined)
continue;
if (! (*info->callbacks->add_archive_element) (info, abfd, name))
goto error_return;
if (! ecoff_link_add_externals (abfd, info, external_ext, ssext))
goto error_return;
*pneeded = TRUE;
goto successful_return;
}
successful_return:
if (external_ext != NULL)
free (external_ext);
if (ssext != NULL)
free (ssext);
return TRUE;
error_return:
if (external_ext != NULL)
free (external_ext);
if (ssext != NULL)
free (ssext);
return FALSE;
}
static bfd_boolean
ecoff_link_add_object_symbols (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
HDRR *symhdr;
bfd_size_type external_ext_size;
PTR external_ext = NULL;
bfd_size_type esize;
char *ssext = NULL;
bfd_boolean result;
if (! ecoff_slurp_symbolic_header (abfd))
return FALSE;
if (bfd_get_symcount (abfd) == 0)
return TRUE;
symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
external_ext_size = ecoff_backend (abfd)->debug_swap.external_ext_size;
esize = symhdr->iextMax * external_ext_size;
external_ext = (PTR) bfd_malloc (esize);
if (external_ext == NULL && esize != 0)
goto error_return;
if (bfd_seek (abfd, (file_ptr) symhdr->cbExtOffset, SEEK_SET) != 0
|| bfd_bread (external_ext, esize, abfd) != esize)
goto error_return;
ssext = (char *) bfd_malloc ((bfd_size_type) symhdr->issExtMax);
if (ssext == NULL && symhdr->issExtMax != 0)
goto error_return;
if (bfd_seek (abfd, (file_ptr) symhdr->cbSsExtOffset, SEEK_SET) != 0
|| (bfd_bread (ssext, (bfd_size_type) symhdr->issExtMax, abfd)
!= (bfd_size_type) symhdr->issExtMax))
goto error_return;
result = ecoff_link_add_externals (abfd, info, external_ext, ssext);
if (ssext != NULL)
free (ssext);
if (external_ext != NULL)
free (external_ext);
return result;
error_return:
if (ssext != NULL)
free (ssext);
if (external_ext != NULL)
free (external_ext);
return FALSE;
}
static bfd_boolean
ecoff_link_add_externals (abfd, info, external_ext, ssext)
bfd *abfd;
struct bfd_link_info *info;
PTR external_ext;
char *ssext;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
void (* const swap_ext_in) PARAMS ((bfd *, PTR, EXTR *))
= backend->debug_swap.swap_ext_in;
bfd_size_type external_ext_size = backend->debug_swap.external_ext_size;
unsigned long ext_count;
struct bfd_link_hash_entry **sym_hash;
char *ext_ptr;
char *ext_end;
bfd_size_type amt;
ext_count = ecoff_data (abfd)->debug_info.symbolic_header.iextMax;
amt = ext_count;
amt *= sizeof (struct bfd_link_hash_entry *);
sym_hash = (struct bfd_link_hash_entry **) bfd_alloc (abfd, amt);
if (!sym_hash)
return FALSE;
ecoff_data (abfd)->sym_hashes = (struct ecoff_link_hash_entry **) sym_hash;
ext_ptr = (char *) external_ext;
ext_end = ext_ptr + ext_count * external_ext_size;
for (; ext_ptr < ext_end; ext_ptr += external_ext_size, sym_hash++)
{
EXTR esym;
bfd_boolean skip;
bfd_vma value;
asection *section;
const char *name;
struct ecoff_link_hash_entry *h;
*sym_hash = NULL;
(*swap_ext_in) (abfd, (PTR) ext_ptr, &esym);
skip = FALSE;
switch (esym.asym.st)
{
case stGlobal:
case stStatic:
case stLabel:
case stProc:
case stStaticProc:
break;
default:
skip = TRUE;
break;
}
if (skip)
continue;
value = esym.asym.value;
switch (esym.asym.sc)
{
default:
case scNil:
case scRegister:
case scCdbLocal:
case scBits:
case scCdbSystem:
case scRegImage:
case scInfo:
case scUserStruct:
case scVar:
case scVarRegister:
case scVariant:
case scBasedVar:
case scXData:
case scPData:
section = NULL;
break;
case scText:
section = bfd_make_section_old_way (abfd, ".text");
value -= section->vma;
break;
case scData:
section = bfd_make_section_old_way (abfd, ".data");
value -= section->vma;
break;
case scBss:
section = bfd_make_section_old_way (abfd, ".bss");
value -= section->vma;
break;
case scAbs:
section = bfd_abs_section_ptr;
break;
case scUndefined:
section = bfd_und_section_ptr;
break;
case scSData:
section = bfd_make_section_old_way (abfd, ".sdata");
value -= section->vma;
break;
case scSBss:
section = bfd_make_section_old_way (abfd, ".sbss");
value -= section->vma;
break;
case scRData:
section = bfd_make_section_old_way (abfd, ".rdata");
value -= section->vma;
break;
case scCommon:
if (value > ecoff_data (abfd)->gp_size)
{
section = bfd_com_section_ptr;
break;
}
case scSCommon:
if (ecoff_scom_section.name == NULL)
{
ecoff_scom_section.name = SCOMMON;
ecoff_scom_section.flags = SEC_IS_COMMON;
ecoff_scom_section.output_section = &ecoff_scom_section;
ecoff_scom_section.symbol = &ecoff_scom_symbol;
ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr;
ecoff_scom_symbol.name = SCOMMON;
ecoff_scom_symbol.flags = BSF_SECTION_SYM;
ecoff_scom_symbol.section = &ecoff_scom_section;
ecoff_scom_symbol_ptr = &ecoff_scom_symbol;
}
section = &ecoff_scom_section;
break;
case scSUndefined:
section = bfd_und_section_ptr;
break;
case scInit:
section = bfd_make_section_old_way (abfd, ".init");
value -= section->vma;
break;
case scFini:
section = bfd_make_section_old_way (abfd, ".fini");
value -= section->vma;
break;
case scRConst:
section = bfd_make_section_old_way (abfd, ".rconst");
value -= section->vma;
break;
}
if (section == (asection *) NULL)
continue;
name = ssext + esym.asym.iss;
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, name,
(flagword) (esym.weakext ? BSF_WEAK : BSF_GLOBAL),
section, value, (const char *) NULL, TRUE, TRUE, sym_hash)))
return FALSE;
h = (struct ecoff_link_hash_entry *) *sym_hash;
if (info->hash->creator->flavour == bfd_get_flavour (abfd))
{
if (h->abfd == (bfd *) NULL
|| (! bfd_is_und_section (section)
&& (! bfd_is_com_section (section)
|| (h->root.type != bfd_link_hash_defined
&& h->root.type != bfd_link_hash_defweak))))
{
h->abfd = abfd;
h->esym = esym;
}
if (esym.asym.sc == scSUndefined)
h->small = 1;
if (h->small
&& h->root.type == bfd_link_hash_common
&& strcmp (h->root.u.c.p->section->name, SCOMMON) != 0)
{
h->root.u.c.p->section = bfd_make_section_old_way (abfd,
SCOMMON);
h->root.u.c.p->section->flags = SEC_ALLOC;
if (h->esym.asym.sc == scCommon)
h->esym.asym.sc = scSCommon;
}
}
}
return TRUE;
}
static bfd_boolean ecoff_final_link_debug_accumulate
PARAMS ((bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *,
PTR handle));
static bfd_boolean ecoff_link_write_external
PARAMS ((struct ecoff_link_hash_entry *, PTR));
static bfd_boolean ecoff_indirect_link_order
PARAMS ((bfd *, struct bfd_link_info *, asection *,
struct bfd_link_order *));
static bfd_boolean ecoff_reloc_link_order
PARAMS ((bfd *, struct bfd_link_info *, asection *,
struct bfd_link_order *));
struct extsym_info
{
bfd *abfd;
struct bfd_link_info *info;
};
bfd_boolean
_bfd_ecoff_bfd_final_link (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
struct ecoff_debug_info * const debug = &ecoff_data (abfd)->debug_info;
HDRR *symhdr;
PTR handle;
register bfd *input_bfd;
asection *o;
struct bfd_link_order *p;
struct extsym_info einfo;
symhdr = &debug->symbolic_header;
symhdr->vstamp = 0;
symhdr->ilineMax = 0;
symhdr->cbLine = 0;
symhdr->idnMax = 0;
symhdr->ipdMax = 0;
symhdr->isymMax = 0;
symhdr->ioptMax = 0;
symhdr->iauxMax = 0;
symhdr->issMax = 0;
symhdr->issExtMax = 0;
symhdr->ifdMax = 0;
symhdr->crfd = 0;
symhdr->iextMax = 0;
debug->line = NULL;
debug->external_dnr = NULL;
debug->external_pdr = NULL;
debug->external_sym = NULL;
debug->external_opt = NULL;
debug->external_aux = NULL;
debug->ss = NULL;
debug->ssext = debug->ssext_end = NULL;
debug->external_fdr = NULL;
debug->external_rfd = NULL;
debug->external_ext = debug->external_ext_end = NULL;
handle = bfd_ecoff_debug_init (abfd, debug, &backend->debug_swap, info);
if (handle == (PTR) NULL)
return FALSE;
for (input_bfd = info->input_bfds;
input_bfd != (bfd *) NULL;
input_bfd = input_bfd->link_next)
{
bfd_boolean ret;
if (bfd_get_flavour (input_bfd) == bfd_target_ecoff_flavour)
{
if (symhdr->vstamp == 0)
symhdr->vstamp
= ecoff_data (input_bfd)->debug_info.symbolic_header.vstamp;
ret = ecoff_final_link_debug_accumulate (abfd, input_bfd, info,
handle);
}
else
ret = bfd_ecoff_debug_accumulate_other (handle, abfd,
debug, &backend->debug_swap,
input_bfd, info);
if (! ret)
return FALSE;
ecoff_data (abfd)->gprmask |= ecoff_data (input_bfd)->gprmask;
ecoff_data (abfd)->fprmask |= ecoff_data (input_bfd)->fprmask;
ecoff_data (abfd)->cprmask[0] |= ecoff_data (input_bfd)->cprmask[0];
ecoff_data (abfd)->cprmask[1] |= ecoff_data (input_bfd)->cprmask[1];
ecoff_data (abfd)->cprmask[2] |= ecoff_data (input_bfd)->cprmask[2];
ecoff_data (abfd)->cprmask[3] |= ecoff_data (input_bfd)->cprmask[3];
}
einfo.abfd = abfd;
einfo.info = info;
ecoff_link_hash_traverse (ecoff_hash_table (info),
ecoff_link_write_external,
(PTR) &einfo);
if (info->relocatable)
{
for (o = abfd->sections; o != (asection *) NULL; o = o->next)
{
o->reloc_count = 0;
for (p = o->link_order_head;
p != (struct bfd_link_order *) NULL;
p = p->next)
if (p->type == bfd_indirect_link_order)
o->reloc_count += p->u.indirect.section->reloc_count;
else if (p->type == bfd_section_reloc_link_order
|| p->type == bfd_symbol_reloc_link_order)
++o->reloc_count;
}
}
ecoff_compute_reloc_file_positions (abfd);
if (! bfd_ecoff_write_accumulated_debug (handle, abfd, debug,
&backend->debug_swap, info,
ecoff_data (abfd)->sym_filepos))
return FALSE;
bfd_ecoff_debug_free (handle, abfd, debug, &backend->debug_swap, info);
if (info->relocatable)
{
for (o = abfd->sections; o != (asection *) NULL; o = o->next)
o->reloc_count = 0;
}
if (ecoff_data (abfd)->gp == 0)
{
struct bfd_link_hash_entry *h;
h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE);
if (h != (struct bfd_link_hash_entry *) NULL
&& h->type == bfd_link_hash_defined)
ecoff_data (abfd)->gp = (h->u.def.value
+ h->u.def.section->output_section->vma
+ h->u.def.section->output_offset);
else if (info->relocatable)
{
bfd_vma lo;
lo = (bfd_vma) -1;
for (o = abfd->sections; o != (asection *) NULL; o = o->next)
{
if (o->vma < lo
&& (strcmp (o->name, _SBSS) == 0
|| strcmp (o->name, _SDATA) == 0
|| strcmp (o->name, _LIT4) == 0
|| strcmp (o->name, _LIT8) == 0
|| strcmp (o->name, _LITA) == 0))
lo = o->vma;
}
ecoff_data (abfd)->gp = lo + 0x8000;
}
else
{
}
}
for (o = abfd->sections; o != (asection *) NULL; o = o->next)
{
for (p = o->link_order_head;
p != (struct bfd_link_order *) NULL;
p = p->next)
{
if (p->type == bfd_indirect_link_order
&& (bfd_get_flavour (p->u.indirect.section->owner)
== bfd_target_ecoff_flavour))
{
if (! ecoff_indirect_link_order (abfd, info, o, p))
return FALSE;
}
else if (p->type == bfd_section_reloc_link_order
|| p->type == bfd_symbol_reloc_link_order)
{
if (! ecoff_reloc_link_order (abfd, info, o, p))
return FALSE;
}
else
{
if (! _bfd_default_link_order (abfd, info, o, p))
return FALSE;
}
}
}
bfd_get_symcount (abfd) = symhdr->iextMax + symhdr->isymMax;
ecoff_data (abfd)->linker = TRUE;
return TRUE;
}
static bfd_boolean
ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle)
bfd *output_bfd;
bfd *input_bfd;
struct bfd_link_info *info;
PTR handle;
{
struct ecoff_debug_info * const debug = &ecoff_data (input_bfd)->debug_info;
const struct ecoff_debug_swap * const swap =
&ecoff_backend (input_bfd)->debug_swap;
HDRR *symhdr = &debug->symbolic_header;
bfd_boolean ret;
#define READ(ptr, offset, count, size, type) \
if (symhdr->count == 0) \
debug->ptr = NULL; \
else \
{ \
bfd_size_type amt = (bfd_size_type) size * symhdr->count; \
debug->ptr = (type) bfd_malloc (amt); \
if (debug->ptr == NULL) \
{ \
ret = FALSE; \
goto return_something; \
} \
if (bfd_seek (input_bfd, (file_ptr) symhdr->offset, SEEK_SET) != 0 \
|| bfd_bread (debug->ptr, amt, input_bfd) != amt) \
{ \
ret = FALSE; \
goto return_something; \
} \
}
if (ecoff_data (input_bfd)->raw_syments == NULL)
{
READ (line, cbLineOffset, cbLine, sizeof (unsigned char),
unsigned char *);
READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR);
READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR);
READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR);
READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR);
READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
union aux_ext *);
READ (ss, cbSsOffset, issMax, sizeof (char), char *);
READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR);
READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
}
#undef READ
ret = (bfd_ecoff_debug_accumulate
(handle, output_bfd, &ecoff_data (output_bfd)->debug_info,
&ecoff_backend (output_bfd)->debug_swap,
input_bfd, debug, swap, info));
return_something:
if (ecoff_data (input_bfd)->raw_syments == NULL)
{
if (debug->line != NULL)
free (debug->line);
if (debug->external_dnr != NULL)
free (debug->external_dnr);
if (debug->external_pdr != NULL)
free (debug->external_pdr);
if (debug->external_sym != NULL)
free (debug->external_sym);
if (debug->external_opt != NULL)
free (debug->external_opt);
if (debug->external_aux != NULL)
free (debug->external_aux);
if (debug->ss != NULL)
free (debug->ss);
if (debug->external_fdr != NULL)
free (debug->external_fdr);
if (debug->external_rfd != NULL)
free (debug->external_rfd);
debug->line = NULL;
debug->external_dnr = NULL;
debug->external_pdr = NULL;
debug->external_sym = NULL;
debug->external_opt = NULL;
debug->external_aux = NULL;
debug->ss = NULL;
debug->external_fdr = NULL;
debug->external_rfd = NULL;
}
return ret;
}
static bfd_boolean
ecoff_link_write_external (h, data)
struct ecoff_link_hash_entry *h;
PTR data;
{
struct extsym_info *einfo = (struct extsym_info *) data;
bfd *output_bfd = einfo->abfd;
bfd_boolean strip;
if (h->root.type == bfd_link_hash_warning)
{
h = (struct ecoff_link_hash_entry *) h->root.u.i.link;
if (h->root.type == bfd_link_hash_new)
return TRUE;
}
if (h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak)
strip = FALSE;
else if (einfo->info->strip == strip_all
|| (einfo->info->strip == strip_some
&& bfd_hash_lookup (einfo->info->keep_hash,
h->root.root.string,
FALSE, FALSE) == NULL))
strip = TRUE;
else
strip = FALSE;
if (strip || h->written)
return TRUE;
if (h->abfd == (bfd *) NULL)
{
h->esym.jmptbl = 0;
h->esym.cobol_main = 0;
h->esym.weakext = 0;
h->esym.reserved = 0;
h->esym.ifd = ifdNil;
h->esym.asym.value = 0;
h->esym.asym.st = stGlobal;
if (h->root.type != bfd_link_hash_defined
&& h->root.type != bfd_link_hash_defweak)
h->esym.asym.sc = scAbs;
else
{
asection *output_section;
const char *name;
output_section = h->root.u.def.section->output_section;
name = bfd_section_name (output_section->owner, output_section);
if (strcmp (name, _TEXT) == 0)
h->esym.asym.sc = scText;
else if (strcmp (name, _DATA) == 0)
h->esym.asym.sc = scData;
else if (strcmp (name, _SDATA) == 0)
h->esym.asym.sc = scSData;
else if (strcmp (name, _RDATA) == 0)
h->esym.asym.sc = scRData;
else if (strcmp (name, _BSS) == 0)
h->esym.asym.sc = scBss;
else if (strcmp (name, _SBSS) == 0)
h->esym.asym.sc = scSBss;
else if (strcmp (name, _INIT) == 0)
h->esym.asym.sc = scInit;
else if (strcmp (name, _FINI) == 0)
h->esym.asym.sc = scFini;
else if (strcmp (name, _PDATA) == 0)
h->esym.asym.sc = scPData;
else if (strcmp (name, _XDATA) == 0)
h->esym.asym.sc = scXData;
else if (strcmp (name, _RCONST) == 0)
h->esym.asym.sc = scRConst;
else
h->esym.asym.sc = scAbs;
}
h->esym.asym.reserved = 0;
h->esym.asym.index = indexNil;
}
else if (h->esym.ifd != -1)
{
struct ecoff_debug_info *debug;
debug = &ecoff_data (h->abfd)->debug_info;
BFD_ASSERT (h->esym.ifd >= 0
&& h->esym.ifd < debug->symbolic_header.ifdMax);
h->esym.ifd = debug->ifdmap[h->esym.ifd];
}
switch (h->root.type)
{
default:
case bfd_link_hash_warning:
case bfd_link_hash_new:
abort ();
case bfd_link_hash_undefined:
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;
else if (h->esym.asym.sc == scCommon)
h->esym.asym.sc = scBss;
else if (h->esym.asym.sc == scSCommon)
h->esym.asym.sc = scSBss;
h->esym.asym.value = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
break;
case bfd_link_hash_common:
if (h->esym.asym.sc != scCommon
&& h->esym.asym.sc != scSCommon)
h->esym.asym.sc = scCommon;
h->esym.asym.value = h->root.u.c.size;
break;
case bfd_link_hash_indirect:
return TRUE;
}
h->indx = ecoff_data (output_bfd)->debug_info.symbolic_header.iextMax;
h->written = 1;
return (bfd_ecoff_debug_one_external
(output_bfd, &ecoff_data (output_bfd)->debug_info,
&ecoff_backend (output_bfd)->debug_swap, h->root.root.string,
&h->esym));
}
static bfd_boolean
ecoff_indirect_link_order (output_bfd, info, output_section, link_order)
bfd *output_bfd;
struct bfd_link_info *info;
asection *output_section;
struct bfd_link_order *link_order;
{
asection *input_section;
bfd *input_bfd;
bfd_byte *contents = NULL;
bfd_size_type external_reloc_size;
bfd_size_type external_relocs_size;
PTR external_relocs = NULL;
BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
if (link_order->size == 0)
return TRUE;
input_section = link_order->u.indirect.section;
input_bfd = input_section->owner;
BFD_ASSERT (input_section->output_section == output_section);
BFD_ASSERT (input_section->output_offset == link_order->offset);
BFD_ASSERT (input_section->size == link_order->size);
if (!bfd_malloc_and_get_section (input_bfd, input_section, &contents))
goto error_return;
external_reloc_size = ecoff_backend (input_bfd)->external_reloc_size;
external_relocs_size = external_reloc_size * input_section->reloc_count;
external_relocs = (PTR) bfd_malloc (external_relocs_size);
if (external_relocs == NULL && external_relocs_size != 0)
goto error_return;
if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
|| (bfd_bread (external_relocs, external_relocs_size, input_bfd)
!= external_relocs_size))
goto error_return;
if (! ((*ecoff_backend (input_bfd)->relocate_section)
(output_bfd, info, input_bfd, input_section, contents,
external_relocs)))
goto error_return;
if (! bfd_set_section_contents (output_bfd,
output_section,
contents,
input_section->output_offset,
input_section->size))
goto error_return;
if (info->relocatable)
{
file_ptr pos = (output_section->rel_filepos
+ output_section->reloc_count * external_reloc_size);
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
|| (bfd_bwrite (external_relocs, external_relocs_size, output_bfd)
!= external_relocs_size))
goto error_return;
output_section->reloc_count += input_section->reloc_count;
}
if (contents != NULL)
free (contents);
if (external_relocs != NULL)
free (external_relocs);
return TRUE;
error_return:
if (contents != NULL)
free (contents);
if (external_relocs != NULL)
free (external_relocs);
return FALSE;
}
static bfd_boolean
ecoff_reloc_link_order (output_bfd, info, output_section, link_order)
bfd *output_bfd;
struct bfd_link_info *info;
asection *output_section;
struct bfd_link_order *link_order;
{
enum bfd_link_order_type type;
asection *section;
bfd_vma addend;
arelent rel;
struct internal_reloc in;
bfd_size_type external_reloc_size;
bfd_byte *rbuf;
bfd_boolean ok;
file_ptr pos;
type = link_order->type;
section = NULL;
addend = link_order->u.reloc.p->addend;
rel.address = link_order->offset;
rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
if (rel.howto == 0)
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
if (type == bfd_section_reloc_link_order)
{
section = link_order->u.reloc.p->u.section;
rel.sym_ptr_ptr = section->symbol_ptr_ptr;
}
else
{
struct bfd_link_hash_entry *h;
h = bfd_wrapped_link_hash_lookup (output_bfd, info,
link_order->u.reloc.p->u.name,
FALSE, FALSE, FALSE);
if (h != NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak))
{
type = bfd_section_reloc_link_order;
section = h->u.def.section->output_section;
addend += section->vma + h->u.def.section->output_offset;
}
else
{
rel.sym_ptr_ptr = (asymbol **) NULL;
}
}
BFD_ASSERT (rel.howto->partial_inplace);
if (addend != 0)
{
bfd_size_type size;
bfd_reloc_status_type rstat;
bfd_byte *buf;
size = bfd_get_reloc_size (rel.howto);
buf = (bfd_byte *) bfd_zmalloc (size);
if (buf == (bfd_byte *) NULL)
return FALSE;
rstat = _bfd_relocate_contents (rel.howto, output_bfd,
(bfd_vma) addend, buf);
switch (rstat)
{
case bfd_reloc_ok:
break;
default:
case bfd_reloc_outofrange:
abort ();
case bfd_reloc_overflow:
if (! ((*info->callbacks->reloc_overflow)
(info, NULL,
(link_order->type == bfd_section_reloc_link_order
? bfd_section_name (output_bfd, section)
: link_order->u.reloc.p->u.name),
rel.howto->name, addend, (bfd *) NULL,
(asection *) NULL, (bfd_vma) 0)))
{
free (buf);
return FALSE;
}
break;
}
ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf,
(file_ptr) link_order->offset, size);
free (buf);
if (! ok)
return FALSE;
}
rel.addend = 0;
in.r_vaddr = (rel.address
+ bfd_get_section_vma (output_bfd, output_section));
in.r_type = rel.howto->type;
if (type == bfd_symbol_reloc_link_order)
{
struct ecoff_link_hash_entry *h;
h = ((struct ecoff_link_hash_entry *)
bfd_wrapped_link_hash_lookup (output_bfd, info,
link_order->u.reloc.p->u.name,
FALSE, FALSE, TRUE));
if (h != (struct ecoff_link_hash_entry *) NULL
&& h->indx != -1)
in.r_symndx = h->indx;
else
{
if (! ((*info->callbacks->unattached_reloc)
(info, link_order->u.reloc.p->u.name, (bfd *) NULL,
(asection *) NULL, (bfd_vma) 0)))
return FALSE;
in.r_symndx = 0;
}
in.r_extern = 1;
}
else
{
const char *name;
name = bfd_get_section_name (output_bfd, section);
if (strcmp (name, ".text") == 0)
in.r_symndx = RELOC_SECTION_TEXT;
else if (strcmp (name, ".rdata") == 0)
in.r_symndx = RELOC_SECTION_RDATA;
else if (strcmp (name, ".data") == 0)
in.r_symndx = RELOC_SECTION_DATA;
else if (strcmp (name, ".sdata") == 0)
in.r_symndx = RELOC_SECTION_SDATA;
else if (strcmp (name, ".sbss") == 0)
in.r_symndx = RELOC_SECTION_SBSS;
else if (strcmp (name, ".bss") == 0)
in.r_symndx = RELOC_SECTION_BSS;
else if (strcmp (name, ".init") == 0)
in.r_symndx = RELOC_SECTION_INIT;
else if (strcmp (name, ".lit8") == 0)
in.r_symndx = RELOC_SECTION_LIT8;
else if (strcmp (name, ".lit4") == 0)
in.r_symndx = RELOC_SECTION_LIT4;
else if (strcmp (name, ".xdata") == 0)
in.r_symndx = RELOC_SECTION_XDATA;
else if (strcmp (name, ".pdata") == 0)
in.r_symndx = RELOC_SECTION_PDATA;
else if (strcmp (name, ".fini") == 0)
in.r_symndx = RELOC_SECTION_FINI;
else if (strcmp (name, ".lita") == 0)
in.r_symndx = RELOC_SECTION_LITA;
else if (strcmp (name, "*ABS*") == 0)
in.r_symndx = RELOC_SECTION_ABS;
else if (strcmp (name, ".rconst") == 0)
in.r_symndx = RELOC_SECTION_RCONST;
else
abort ();
in.r_extern = 0;
}
(*ecoff_backend (output_bfd)->adjust_reloc_out) (output_bfd, &rel, &in);
external_reloc_size = ecoff_backend (output_bfd)->external_reloc_size;
rbuf = (bfd_byte *) bfd_malloc (external_reloc_size);
if (rbuf == (bfd_byte *) NULL)
return FALSE;
(*ecoff_backend (output_bfd)->swap_reloc_out) (output_bfd, &in, (PTR) rbuf);
pos = (output_section->rel_filepos
+ output_section->reloc_count * external_reloc_size);
ok = (bfd_seek (output_bfd, pos, SEEK_SET) == 0
&& (bfd_bwrite ((PTR) rbuf, external_reloc_size, output_bfd)
== external_reloc_size));
if (ok)
++output_section->reloc_count;
free (rbuf);
return ok;
}