-#include "seclet.h"
-#include "aout/ar.h"
-#include "aout/ranlib.h"
-#include "coff/mips.h"
-#include "coff/internal.h"
-#include "coff/sym.h"
-#include "coff/symconst.h"
-#include "coff/ecoff-ext.h"
-#include "libcoff.h"
-
-/* `Tdata' information kept for ECOFF files. */
-
-#define ecoff_data(abfd) ((abfd)->tdata.ecoff_obj_data)
-
-typedef struct ecoff_tdata
-{
- /* The reloc file position, set by
- ecoff_compute_section_file_positions. */
- file_ptr reloc_filepos;
-
- /* The symbol table file position, set by ecoff_mkobject_hook. */
- file_ptr sym_filepos;
-
- /* The cached gp value. This is used when relocating. */
- bfd_vma gp;
-
- /* The register masks. When linking, all the masks found in the
- input files are combined into the masks of the output file. */
- unsigned long gprmask;
- unsigned long cprmask[4];
-
- /* The size of the unswapped ECOFF symbolic information. */
- bfd_size_type raw_size;
-
- /* The unswapped ECOFF symbolic information. */
- PTR raw_syments;
-
- /* The swapped ECOFF symbolic header. */
- HDRR symbolic_header;
-
- /* Pointers to the unswapped symbolic information. */
- unsigned char *line;
- struct dnr_ext *external_dnr;
- struct pdr_ext *external_pdr;
- struct sym_ext *external_sym;
- struct opt_ext *external_opt;
- union aux_ext *external_aux;
- char *ss;
- char *ssext;
- struct fdr_ext *external_fdr;
- struct rfd_ext *external_rfd;
- struct ext_ext *external_ext;
-
- /* The swapped FDR information. */
- FDR *fdr;
-
- /* The FDR index. This is set for an input BFD to a link so that
- the external symbols can set their FDR index correctly. */
- unsigned int ifdbase;
-
- /* The canonical BFD symbols. */
- struct ecoff_symbol_struct *canonical_symbols;
-
-} ecoff_data_type;
-
-/* Each canonical asymbol really looks like this. */
-
-typedef struct ecoff_symbol_struct
-{
- /* The actual symbol which the rest of BFD works with */
- asymbol symbol;
-
- /* The fdr for this symbol. */
- FDR *fdr;
-
- /* true if this is a local symbol rather than an external one. */
- boolean local;
-
- /* A pointer to the unswapped hidden information for this symbol */
- union
- {
- struct sym_ext *lnative;
- struct ext_ext *enative;
- }
- native;
-} ecoff_symbol_type;
-
-/* We take the address of the first element of a asymbol to ensure that the
- macro is only ever applied to an asymbol. */
-#define ecoffsymbol(asymbol) ((ecoff_symbol_type *) (&((asymbol)->the_bfd)))
-
-/* This is a hack borrowed from coffcode.h; we need to save the index
- of a symbol when we write it out so that can set the symbol index
- correctly when we write out the relocs. */
-#define ecoff_get_sym_index(symbol) ((unsigned long) (symbol)->udata)
-#define ecoff_set_sym_index(symbol, idx) ((symbol)->udata = (PTR) (idx))
-
-/* The page boundary used to align sections in the executable file. */
-#define PAGE_SIZE 0x2000
-
-/* The linker needs a section to hold small common variables while
- linking. There is no convenient way to create it when the linker
- needs it, so we always create one for each BFD. We then avoid
- writing it out. */
-#define SCOMMON ".scommon"
-
-/* MIPS ECOFF has COFF sections, but the debugging information is
- stored in a completely different format. This files uses the some
- of the swapping routines from coffswap.h, and some of the generic
- COFF routines in coffgen.c, but, unlike the real COFF targets, does
- not use coffcode.h itself. */
-\f
-/* Prototypes for static functions. */
-
-static boolean ecoff_bad_format_hook PARAMS ((bfd *abfd, PTR filehdr));
-static asection *ecoff_make_section_hook PARAMS ((bfd *abfd, char *name));
-static boolean ecoff_new_section_hook PARAMS ((bfd *abfd, asection *section));
-static boolean ecoff_mkobject PARAMS ((bfd *abfd));
-static PTR ecoff_mkobject_hook PARAMS ((bfd *abfd, PTR filehdr, PTR aouthdr));
-static boolean ecoff_set_arch_mach_hook PARAMS ((bfd *abfd, PTR filehdr));
-static long ecoff_sec_to_styp_flags PARAMS ((CONST char *name,
- flagword flags));
-static flagword ecoff_styp_to_sec_flags PARAMS ((bfd *abfd, PTR hdr));
-static boolean ecoff_slurp_symbolic_info PARAMS ((bfd *abfd));
-static asymbol *ecoff_make_empty_symbol PARAMS ((bfd *abfd));
-static void ecoff_set_symbol_info PARAMS ((bfd *abfd, SYMR *ecoff_sym,
- asymbol *asym, int ext));
-static boolean ecoff_slurp_symbol_table PARAMS ((bfd *abfd));
-static unsigned int ecoff_get_symtab_upper_bound PARAMS ((bfd *abfd));
-static unsigned int ecoff_get_symtab PARAMS ((bfd *abfd,
- asymbol **alocation));
-static void ecoff_emit_aggregate PARAMS ((bfd *abfd, char *string,
- RNDXR *rndx, long isym,
- CONST char *which));
-static char *ecoff_type_to_string PARAMS ((bfd *abfd, union aux_ext *aux_ptr,
- int indx, int bigendian));
-static void ecoff_print_symbol PARAMS ((bfd *abfd, PTR filep,
- asymbol *symbol,
- bfd_print_symbol_type how));
-static void ecoff_swap_reloc_in PARAMS ((bfd *abfd, RELOC *ext,
- struct internal_reloc *intern));
-static unsigned int ecoff_swap_reloc_out PARAMS ((bfd *abfd, PTR src,
- PTR dst));
-static bfd_reloc_status_type ecoff_generic_reloc PARAMS ((bfd *abfd,
- arelent *reloc,
- asymbol *symbol,
- PTR data,
- asection *section,
- bfd *output_bfd));
-static bfd_reloc_status_type ecoff_refhi_reloc PARAMS ((bfd *abfd,
- arelent *reloc,
- asymbol *symbol,
- PTR data,
- asection *section,
- bfd *output_bfd));
-static bfd_reloc_status_type ecoff_gprel_reloc PARAMS ((bfd *abfd,
- arelent *reloc,
- asymbol *symbol,
- PTR data,
- asection *section,
- bfd *output_bfd));
-static boolean ecoff_slurp_reloc_table PARAMS ((bfd *abfd, asection *section,
- asymbol **symbols));
-static unsigned int ecoff_canonicalize_reloc PARAMS ((bfd *abfd,
- asection *section,
- arelent **relptr,
- asymbol **symbols));
-static boolean ecoff_find_nearest_line PARAMS ((bfd *abfd,
- asection *section,
- asymbol **symbols,
- bfd_vma offset,
- CONST char **filename_ptr,
- CONST char **fnname_ptr,
- unsigned int *retline_ptr));
-static void ecoff_clear_output_flags PARAMS ((bfd *abfd));
-static boolean ecoff_rel PARAMS ((bfd *output_bfd, bfd_seclet_type *seclet,
- asection *output_section, PTR data,
- boolean relocateable));
-static boolean ecoff_dump_seclet PARAMS ((bfd *abfd, bfd_seclet_type *seclet,
- asection *section, PTR data,
- boolean relocateable));
-static long ecoff_add_string PARAMS ((bfd *output_bfd, FDR *fdr,
- CONST char *string, boolean external));
-static boolean ecoff_get_debug PARAMS ((bfd *output_bfd,
- bfd_seclet_type *seclet,
- asection *section,
- boolean relocateable));
-static boolean ecoff_bfd_seclet_link PARAMS ((bfd *abfd, PTR data,
- boolean relocateable));
-static boolean ecoff_set_arch_mach PARAMS ((bfd *abfd,
- enum bfd_architecture arch,
- unsigned long machine));
-static int ecoff_sizeof_headers PARAMS ((bfd *abfd, boolean reloc));
-static void ecoff_compute_section_file_positions PARAMS ((bfd *abfd));
-static boolean ecoff_set_section_contents PARAMS ((bfd *abfd,
- asection *section,
- PTR location,
- file_ptr offset,
- bfd_size_type count));
-static boolean ecoff_write_object_contents PARAMS ((bfd *abfd));
-static unsigned int ecoff_armap_hash PARAMS ((CONST char *s,
- unsigned int *rehash,
- unsigned int size,
- unsigned int hlog));
-static boolean ecoff_slurp_armap PARAMS ((bfd *abfd));
-static boolean ecoff_write_armap PARAMS ((bfd *abfd, unsigned int elength,
- struct orl *map,
- unsigned int orl_count,
- int stridx));
-static bfd_target *ecoff_archive_p PARAMS ((bfd *abfd));
-\f
-/* Get the generic COFF swapping routines, except for the reloc,
- symbol, and lineno ones. Give them ecoff names. */
-#define MIPSECOFF
-#define NO_COFF_RELOCS
-#define NO_COFF_SYMBOLS
-#define NO_COFF_LINENOS
-#define coff_swap_filehdr_in ecoff_swap_filehdr_in
-#define coff_swap_filehdr_out ecoff_swap_filehdr_out
-#define coff_swap_aouthdr_in ecoff_swap_aouthdr_in
-#define coff_swap_aouthdr_out ecoff_swap_aouthdr_out
-#define coff_swap_scnhdr_in ecoff_swap_scnhdr_in
-#define coff_swap_scnhdr_out ecoff_swap_scnhdr_out
-#include "coffswap.h"
-\f
-/* This stuff is somewhat copied from coffcode.h. */
-
-static asection bfd_debug_section = { "*DEBUG*" };
-
-/* See whether the magic number matches. */
-
-static boolean
-ecoff_bad_format_hook (abfd, filehdr)
- bfd *abfd;
- PTR filehdr;
-{
- struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
-
- if (ECOFFBADMAG (*internal_f))
- return false;
-
- return true;
-}
-
-/* This is a hook needed by SCO COFF, but we have nothing to do. */
-
-static asection *
-ecoff_make_section_hook (abfd, name)
- bfd *abfd;
- char *name;
-{
- return (asection *) NULL;
-}
-
-/* Initialize a new section. */
-
-static boolean
-ecoff_new_section_hook (abfd, section)
- bfd *abfd;
- asection *section;
-{
- section->alignment_power = abfd->xvec->align_power_min;
-
- if (strcmp (section->name, _TEXT) == 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)
- 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;
-
- /* Probably any other section name is SEC_NEVER_LOAD, but I'm
- uncertain about .init on some systems and I don't know how shared
- libraries work. */
-
- return true;
-}
-
-/* Set the alignment of a section; we have nothing to do. */
-
-#define ecoff_set_alignment_hook \
- ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void)
-
-/* Create an ECOFF object. */
-
-static boolean
-ecoff_mkobject (abfd)
- bfd *abfd;
-{
- abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *)
- bfd_zalloc (abfd, sizeof(ecoff_data_type)));
- if (abfd->tdata.ecoff_obj_data == NULL)
- {
- bfd_error = no_memory;
- return false;
- }
-
- /* Always create a .scommon section for every BFD. This is a hack so
- that the linker has something to attach scSCommon symbols to. */
- bfd_make_section (abfd, SCOMMON);
-
- return true;
-}
-
-/* Create the ECOFF backend specific information. */
-
-static PTR
-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 (ecoff_mkobject (abfd) == false)
- return NULL;
-
- ecoff = ecoff_data (abfd);
- ecoff->sym_filepos = internal_f->f_symptr;
-
- if (internal_a != (struct internal_aouthdr *) NULL)
- {
- int i;
-
- ecoff->gp = internal_a->gp_value;
- ecoff->gprmask = internal_a->gprmask;
- for (i = 0; i < 4; i++)
- ecoff->cprmask[i] = internal_a->cprmask[i];
- }
-
- return (PTR) ecoff;
-}
-
-/* Determine the machine architecture and type. */
-
-static boolean
-ecoff_set_arch_mach_hook (abfd, filehdr)
- bfd *abfd;
- PTR filehdr;
-{
- struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
- enum bfd_architecture arch;
-
- switch (internal_f->f_magic)
- {
- case MIPS_MAGIC_1:
- case MIPS_MAGIC_2:
- case MIPS_MAGIC_3:
- arch = bfd_arch_mips;
- break;
-
- default:
- arch = bfd_arch_obscure;
- break;
- }
-
- bfd_default_set_arch_mach (abfd, arch, (unsigned long) 0);
-
- return true;
-}
-
-/* Get the section s_flags to use for a section. */
-
-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, _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 (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_TEXT;
- else
- styp = STYP_BSS;
-
- if (flags & SEC_NEVER_LOAD)
- styp |= STYP_NOLOAD;
-
- return styp;
-}
-
-/* Get the BFD flags to use for a section. */
-
-static flagword
-ecoff_styp_to_sec_flags (abfd, hdr)
- bfd *abfd;
- PTR hdr;
-{
- 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;
-
- /* For 386 COFF, at least, an unloadable text or data section is
- actually a shared library section. */
- if (styp_flags & STYP_TEXT)
- {
- if (sec_flags & SEC_NEVER_LOAD)
- sec_flags |= SEC_CODE | SEC_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))
- {
- if (sec_flags & SEC_NEVER_LOAD)
- sec_flags |= SEC_DATA | SEC_SHARED_LIBRARY;
- else
- sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
- if (styp_flags & STYP_RDATA)
- sec_flags |= SEC_READONLY;
- }
- else if ((styp_flags & STYP_BSS)
- || (styp_flags & STYP_SBSS))
- {
- sec_flags |= SEC_ALLOC;
- }
- else if (styp_flags & STYP_INFO)
- {
- sec_flags |= SEC_NEVER_LOAD;
- }
- else if ((styp_flags & STYP_LIT8)
- || (styp_flags & STYP_LIT4))
- {
- sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY;
- }
- else
- {
- sec_flags |= SEC_ALLOC | SEC_LOAD;
- }
-
- return sec_flags;
-}
-\f
-/* Read in and swap the important symbolic information for an ECOFF
- object file. */
-
-static boolean
-ecoff_slurp_symbolic_info (abfd)
- bfd *abfd;
-{
- struct hdr_ext external_symhdr;
- HDRR *internal_symhdr;
- bfd_size_type raw_base;
- bfd_size_type raw_size;
- PTR raw;
- struct fdr_ext *fraw_src;
- struct fdr_ext *fraw_end;
- struct fdr *fdr_ptr;
-
- /* Check whether we've already gotten it, and whether there's any to
- get. */
- if (ecoff_data (abfd)->raw_syments != (PTR) NULL)
- return true;
- if (ecoff_data (abfd)->sym_filepos == 0)
- {
- bfd_get_symcount (abfd) = 0;
- return true;
- }
-
- /* At this point bfd_get_symcount (abfd) holds the number of symbols
- as read from the file header, but on ECOFF this is always the
- size of the symbolic information header. It would be cleaner to
- handle this when we first read the file in coffgen.c. */
- if (bfd_get_symcount (abfd) != sizeof (external_symhdr))
- {
- bfd_error = bad_value;
- return false;
- }
-
- /* Read the symbolic information header. */
- if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) == -1
- || (bfd_read ((PTR) &external_symhdr, sizeof (external_symhdr), 1, abfd)
- != sizeof (external_symhdr)))
- {
- bfd_error = system_call_error;
- return false;
- }
- internal_symhdr = &ecoff_data (abfd)->symbolic_header;
- ecoff_swap_hdr_in (abfd, &external_symhdr, internal_symhdr);
-
- if (internal_symhdr->magic != magicSym)
- {
- bfd_error = bad_value;
- return false;
- }
-
- /* Now we can get the correct number of symbols. */
- bfd_get_symcount (abfd) = (internal_symhdr->isymMax
- + internal_symhdr->iextMax);
-
- /* Read all the symbolic information at once. */
- raw_base = ecoff_data (abfd)->sym_filepos + sizeof (struct hdr_ext);
-
- if (internal_symhdr->cbExtOffset != 0)
- raw_size = (internal_symhdr->cbExtOffset
- - raw_base
- + internal_symhdr->iextMax * sizeof (struct ext_ext));
- else
- {
- long cbline, issmax, issextmax;
-
- cbline = (internal_symhdr->cbLine + 3) &~ 4;
- issmax = (internal_symhdr->issMax + 3) &~ 4;
- issextmax = (internal_symhdr->issExtMax + 3) &~ 4;
- raw_size = (cbline * sizeof (unsigned char)
- + internal_symhdr->idnMax * sizeof (struct dnr_ext)
- + internal_symhdr->ipdMax * sizeof (struct pdr_ext)
- + internal_symhdr->isymMax * sizeof (struct sym_ext)
- + internal_symhdr->ioptMax * sizeof (struct opt_ext)
- + internal_symhdr->iauxMax * sizeof (union aux_ext)
- + issmax * sizeof (char)
- + issextmax * sizeof (char)
- + internal_symhdr->ifdMax * sizeof (struct fdr_ext)
- + internal_symhdr->crfd * sizeof (struct rfd_ext)
- + internal_symhdr->iextMax * sizeof (struct ext_ext));
- }
-
- if (raw_size == 0)
- {
- ecoff_data (abfd)->sym_filepos = 0;
- return true;
- }
- raw = (PTR) bfd_alloc (abfd, raw_size);
- if (raw == NULL)
- {
- bfd_error = no_memory;
- return false;
- }
- if (bfd_read (raw, raw_size, 1, abfd) != raw_size)
- {
- bfd_error = system_call_error;
- bfd_release (abfd, raw);
- return false;
- }
-
- ecoff_data (abfd)->raw_size = raw_size;
- ecoff_data (abfd)->raw_syments = raw;
-
- /* Get pointers for the numeric offsets in the HDRR structure. */
-#define FIX(off1, off2, type) \
- if (internal_symhdr->off1 == 0) \
- ecoff_data (abfd)->off2 = (type *) NULL; \
- else \
- ecoff_data (abfd)->off2 = (type *) ((char *) raw \
- + internal_symhdr->off1 \
- - raw_base)
- FIX (cbLineOffset, line, unsigned char);
- FIX (cbDnOffset, external_dnr, struct dnr_ext);
- FIX (cbPdOffset, external_pdr, struct pdr_ext);
- FIX (cbSymOffset, external_sym, struct sym_ext);
- FIX (cbOptOffset, external_opt, struct opt_ext);
- FIX (cbAuxOffset, external_aux, union aux_ext);
- FIX (cbSsOffset, ss, char);
- FIX (cbSsExtOffset, ssext, char);
- FIX (cbFdOffset, external_fdr, struct fdr_ext);
- FIX (cbRfdOffset, external_rfd, struct rfd_ext);
- FIX (cbExtOffset, external_ext, struct ext_ext);
-#undef FIX
-
- /* I don't want to always swap all the data, because it will just
- waste time and most programs will never look at it. The only
- time the linker needs most of the debugging information swapped
- is when linking big-endian and little-endian MIPS object files
- together, which is not a common occurrence.
-
- We need to look at the fdr to deal with a lot of information in
- the symbols, so we swap them here. */
- ecoff_data (abfd)->fdr = (struct fdr *) bfd_alloc (abfd,
- (internal_symhdr->ifdMax *
- sizeof (struct fdr)));
- if (ecoff_data (abfd)->fdr == NULL)
- {
- bfd_error = no_memory;
- return false;
- }
- fdr_ptr = ecoff_data (abfd)->fdr;
- fraw_src = ecoff_data (abfd)->external_fdr;
- fraw_end = fraw_src + internal_symhdr->ifdMax;
- for (; fraw_src < fraw_end; fraw_src++, fdr_ptr++)
- ecoff_swap_fdr_in (abfd, fraw_src, fdr_ptr);
-
- return true;
-}
-\f
-/* ECOFF symbol table routines. The ECOFF symbol table is described
- in gcc/mips-tfile.c. */
-
-/* ECOFF uses two common sections. One is the usual one, and the
- other is for small objects. All the small objects are kept
- together, and then referenced via the gp pointer, which yields
- faster assembler code. This is what we use for the small common
- section. */
-static asection ecoff_scom_section;
-static asymbol ecoff_scom_symbol;
-static asymbol *ecoff_scom_symbol_ptr;
-
-/* Create an empty symbol. */
-
-static asymbol *
-ecoff_make_empty_symbol (abfd)
- bfd *abfd;
-{
- ecoff_symbol_type *new;
-
- new = (ecoff_symbol_type *) bfd_alloc (abfd, sizeof (ecoff_symbol_type));
- if (new == (ecoff_symbol_type *) NULL)
- {
- bfd_error = no_memory;
- return (asymbol *) NULL;
- }
- new->symbol.section = (asection *) NULL;
- new->fdr = (FDR *) NULL;
- new->local = false;
- new->native.lnative = (struct sym_ext *) NULL;
- new->symbol.the_bfd = abfd;
- return &new->symbol;
-}
-
-/* Set the BFD flags and section for an ECOFF symbol. */
-
-static void
-ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext)
- bfd *abfd;
- SYMR *ecoff_sym;
- asymbol *asym;
- int ext;
-{
- asym->the_bfd = abfd;
- asym->value = ecoff_sym->value;
- asym->section = &bfd_debug_section;
- asym->udata = NULL;
-
- /* Most symbol types are just for debugging. */
- switch (ecoff_sym->st)
- {
- case stGlobal:
- case stStatic:
- case stLabel:
- case stProc:
- case stStaticProc:
- case stBlock:
- case stNil:
- break;
- default:
- asym->flags = BSF_DEBUGGING;
- return;
- }
-
- if (ext)
- asym->flags = BSF_EXPORT | BSF_GLOBAL;
- else
- asym->flags = BSF_LOCAL;
- switch (ecoff_sym->sc)
- {
- case scNil:
- /* Used for compiler generated labels. Leave them in the
- debugging section, and mark them as local. If BSF_DEBUGGING
- is set, then nm does not display them for some reason. If no
- flags are set then the linker whines about them. */
- 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:
- if (ext)
- {
- asym->section = &bfd_com_section;
- asym->flags = 0;
- }
- else
- {
- 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;
- break;
- case scUndefined:
- asym->section = &bfd_und_section;
- 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");
- if (! ext)
- 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:
- /* FIXME: We should take a -G argument, which gives the maximum
- size of objects to be put in the small common section. Until
- we do, we put objects of sizes up to 8 in the small common
- section. The assembler should do this for us, but the native
- assembler seems to get confused. */
- if (asym->value > 8)
- {
- asym->section = &bfd_com_section;
- break;
- }
- /* Fall through. */
- case scSCommon:
- if (ecoff_scom_section.name == NULL)
- {
- /* Initialize the small common section. */
- 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;
- 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;
- default:
- break;
- }
-}
-
-/* Read an ECOFF symbol table. */
-
-static boolean
-ecoff_slurp_symbol_table (abfd)
- bfd *abfd;
-{
- bfd_size_type internal_size;
- ecoff_symbol_type *internal;
- ecoff_symbol_type *internal_ptr;
- struct ext_ext *eraw_src;
- struct ext_ext *eraw_end;
- FDR *fdr_ptr;
- FDR *fdr_end;
-
- /* If we've already read in the symbol table, do nothing. */
- if (ecoff_data (abfd)->canonical_symbols != NULL)
- return true;
-
- /* Get the symbolic information. */
- if (ecoff_slurp_symbolic_info (abfd) == false)
- return false;
- if (bfd_get_symcount (abfd) == 0)
- return true;
-
- internal_size = bfd_get_symcount (abfd) * sizeof (ecoff_symbol_type);
- internal = (ecoff_symbol_type *) bfd_alloc (abfd, internal_size);
- if (internal == NULL)
- {
- bfd_error = no_memory;
- return false;
- }
-
- internal_ptr = internal;
- eraw_src = ecoff_data (abfd)->external_ext;
- eraw_end = eraw_src + ecoff_data (abfd)->symbolic_header.iextMax;
- for (; eraw_src < eraw_end; eraw_src++, internal_ptr++)
- {
- EXTR internal_esym;
-
- ecoff_swap_ext_in (abfd, eraw_src, &internal_esym);
- internal_ptr->symbol.name = (ecoff_data (abfd)->ssext
- + internal_esym.asym.iss);
- ecoff_set_symbol_info (abfd, &internal_esym.asym,
- &internal_ptr->symbol, 1);
- internal_ptr->fdr = ecoff_data (abfd)->fdr + internal_esym.ifd;
- internal_ptr->local = false;
- internal_ptr->native.enative = eraw_src;
- }
-
- /* The local symbols must be accessed via the fdr's, because the
- string and aux indices are relative to the fdr information. */
- fdr_ptr = ecoff_data (abfd)->fdr;
- fdr_end = fdr_ptr + ecoff_data (abfd)->symbolic_header.ifdMax;
- for (; fdr_ptr < fdr_end; fdr_ptr++)
- {
- struct sym_ext *lraw_src;
- struct sym_ext *lraw_end;
-
- lraw_src = ecoff_data (abfd)->external_sym + fdr_ptr->isymBase;
- lraw_end = lraw_src + fdr_ptr->csym;
- for (; lraw_src < lraw_end; lraw_src++, internal_ptr++)
- {
- SYMR internal_sym;
-
- ecoff_swap_sym_in (abfd, lraw_src, &internal_sym);
- internal_ptr->symbol.name = (ecoff_data (abfd)->ss
- + fdr_ptr->issBase
- + internal_sym.iss);
- ecoff_set_symbol_info (abfd, &internal_sym,
- &internal_ptr->symbol, 0);
- internal_ptr->fdr = fdr_ptr;
- internal_ptr->local = true;
- internal_ptr->native.lnative = lraw_src;
- }
- }
-
- ecoff_data (abfd)->canonical_symbols = internal;
-
- return true;
-}
-
-static unsigned int
-ecoff_get_symtab_upper_bound (abfd)
- bfd *abfd;
-{
- if (ecoff_slurp_symbolic_info (abfd) == false
- || bfd_get_symcount (abfd) == 0)
- return 0;
-
- return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *));
-}
-
-static unsigned int
-ecoff_get_symtab (abfd, alocation)
- bfd *abfd;
- asymbol **alocation;
-{
- unsigned int counter = 0;
- ecoff_symbol_type *symbase;
- ecoff_symbol_type **location = (ecoff_symbol_type **) alocation;
-
- if (ecoff_slurp_symbol_table (abfd) == false
- || 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);
-}
-
-/* Turn ECOFF type information into a printable string.
- ecoff_emit_aggregate and ecoff_type_to_string are from
- gcc/mips-tdump.c, with swapping added and used_ptr removed. */
-
-/* Write aggregate information to a string. */
-
-static void
-ecoff_emit_aggregate (abfd, string, rndx, isym, which)
- bfd *abfd;
- char *string;
- RNDXR *rndx;
- long isym;
- CONST char *which;
-{
- int ifd = rndx->rfd;
- int indx = rndx->index;
- int sym_base, ss_base;
- CONST char *name;
-
- if (ifd == 0xfff)
- ifd = isym;
-
- sym_base = ecoff_data (abfd)->fdr[ifd].isymBase;
- ss_base = ecoff_data (abfd)->fdr[ifd].issBase;
-
- if (indx == indexNil)
- name = "/* no name */";
- else
- {
- SYMR sym;
-
- indx += sym_base;
- ecoff_swap_sym_in (abfd,
- ecoff_data (abfd)->external_sym + indx,
- &sym);
- name = ecoff_data (abfd)->ss + ss_base + sym.iss;
- }
-
- sprintf (string,
- "%s %s { ifd = %d, index = %d }",
- which, name, ifd,
- indx + ecoff_data (abfd)->symbolic_header.iextMax);
-}
-
-/* Convert the type information to string format. */
-
-static char *
-ecoff_type_to_string (abfd, aux_ptr, indx, bigendian)
- bfd *abfd;
- union aux_ext *aux_ptr;
- int indx;
- 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;
- static char buffer1[1024];
- static char buffer2[1024];
- char *p1 = buffer1;
- char *p2 = buffer2;
- RNDXR rndx;
-
- 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]) == -1)
- return "-1 (no type)";
- 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;
-
- /*
- * Go get the basic type.
- */
- switch (basic_type)
- {
- case btNil: /* undefined */
- strcpy (p1, "nil");
- break;
-
- case btAdr: /* address - integer same size as pointer */
- strcpy (p1, "address");
- break;
-
- case btChar: /* character */
- strcpy (p1, "char");
- break;
-
- case btUChar: /* unsigned character */
- strcpy (p1, "unsigned char");
- break;
-
- case btShort: /* short */
- strcpy (p1, "short");
- break;
-
- case btUShort: /* unsigned short */
- strcpy (p1, "unsigned short");
- break;
-
- case btInt: /* int */
- strcpy (p1, "int");
- break;
-
- case btUInt: /* unsigned int */
- strcpy (p1, "unsigned int");
- break;
-
- case btLong: /* long */
- strcpy (p1, "long");
- break;
-
- case btULong: /* unsigned long */
- strcpy (p1, "unsigned long");
- break;
-
- case btFloat: /* float (real) */
- strcpy (p1, "float");
- break;
-
- case btDouble: /* Double (real) */
- strcpy (p1, "double");
- break;
-
- /* Structures add 1-2 aux words:
- 1st word is [ST_RFDESCAPE, offset] pointer to struct def;
- 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
-
- case btStruct: /* Structure (Record) */
- ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
- ecoff_emit_aggregate (abfd, p1, &rndx,
- AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
- "struct");
- indx++; /* skip aux words */
- break;
-
- /* Unions add 1-2 aux words:
- 1st word is [ST_RFDESCAPE, offset] pointer to union def;
- 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
-
- case btUnion: /* Union */
- ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
- ecoff_emit_aggregate (abfd, p1, &rndx,
- AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
- "union");
- indx++; /* skip aux words */
- break;
-
- /* Enumerations add 1-2 aux words:
- 1st word is [ST_RFDESCAPE, offset] pointer to enum def;
- 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */
-
- case btEnum: /* Enumeration */
- ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx);
- ecoff_emit_aggregate (abfd, p1, &rndx,
- AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]),
- "enum");
- indx++; /* skip aux words */
- break;
-
- case btTypedef: /* defined via a typedef, isymRef points */
- strcpy (p1, "typedef");
- break;
-
- case btRange: /* subrange of int */
- strcpy (p1, "subrange");
- break;
-
- case btSet: /* pascal sets */
- strcpy (p1, "set");
- break;
-
- case btComplex: /* fortran complex */
- strcpy (p1, "complex");
- break;
-
- case btDComplex: /* fortran double complex */
- strcpy (p1, "double complex");
- break;
-
- case btIndirect: /* forward or unnamed typedef */
- strcpy (p1, "forward/unamed typedef");
- break;
-
- case btFixedDec: /* Fixed Decimal */
- strcpy (p1, "fixed decimal");
- break;
-
- case btFloatDec: /* Float Decimal */
- strcpy (p1, "float decimal");
- break;
-
- case btString: /* Varying Length Character String */
- strcpy (p1, "string");
- break;
-
- case btBit: /* Aligned Bit String */
- strcpy (p1, "bit");
- break;
-
- case btPicture: /* Picture */
- strcpy (p1, "picture");
- break;
-
- case btVoid: /* Void */
- strcpy (p1, "void");
- break;
-
- default:
- sprintf (p1, "Unknown basic type %d", (int) basic_type);
- break;
- }
-
- p1 += strlen (buffer1);
-
- /*
- * If this is a bitfield, get the bitsize.
- */
- if (u.ti.fBitfield)
- {
- int bitsize;
-
- bitsize = AUX_GET_WIDTH (bigendian, &aux_ptr[indx++]);
- sprintf (p1, " : %d", bitsize);
- p1 += strlen (buffer1);
- }
-
-
- /*
- * Deal with any qualifiers.
- */
- if (qualifiers[0].type != tqNil)
- {
- /*
- * Snarf up any array bounds in the correct order. Arrays
- * store 5 successive words in the aux. table:
- * word 0 RNDXR to type of the bounds (ie, int)
- * word 1 Current file descriptor index
- * word 2 low bound
- * word 3 high bound (or -1 if [])
- * word 4 stride size in bits
- */
- 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;
- }
- }
-
- /*
- * Now print out the qualifiers.
- */
- 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;
-
- /* Print array bounds reversed (ie, in the order the C
- programmer writes them). C is such a fun language.... */
-
- 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;
-}
-
-/* Print information about an ECOFF symbol. */
-
-static void
-ecoff_print_symbol (abfd, filep, symbol, how)
- bfd *abfd;
- PTR filep;
- asymbol *symbol;
- bfd_print_symbol_type how;
-{
- 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;
-
- ecoff_swap_sym_in (abfd, ecoffsymbol (symbol)->native.lnative,
- &ecoff_sym);
- fprintf (file, "ecoff local %lx %x %x",
- (unsigned long) ecoff_sym.value,
- (unsigned) ecoff_sym.st, (unsigned) ecoff_sym.sc);
- }
- else
- {
- EXTR ecoff_ext;
-
- ecoff_swap_ext_in (abfd, ecoffsymbol (symbol)->native.enative,
- &ecoff_ext);
- fprintf (file, "ecoff extern %lx %x %x",
- (unsigned long) ecoff_ext.asym.value,
- (unsigned) ecoff_ext.asym.st,
- (unsigned) ecoff_ext.asym.sc);
- }
- break;
- case bfd_print_symbol_nm:
- {
- CONST char *section_name = symbol->section->name;
-
- bfd_print_symbol_vandf ((PTR) file, symbol);
- fprintf (file, " %-5s %s %s",
- section_name,
- ecoffsymbol (symbol)->local ? "l" : "e",
- symbol->name);
- }
- break;
- case bfd_print_symbol_all:
- /* Print out the symbols in a reasonable way */
- {
- char type;
- int pos;
- EXTR ecoff_ext;
- char jmptbl;
- char cobol_main;
- char weakext;
-
- if (ecoffsymbol (symbol)->local)
- {
- ecoff_swap_sym_in (abfd, ecoffsymbol (symbol)->native.lnative,
- &ecoff_ext.asym);
- type = 'l';
- pos = (ecoffsymbol (symbol)->native.lnative
- - ecoff_data (abfd)->external_sym
- + ecoff_data (abfd)->symbolic_header.iextMax);
- jmptbl = ' ';
- cobol_main = ' ';
- weakext = ' ';
- }
- else
- {
- ecoff_swap_ext_in (abfd, ecoffsymbol (symbol)->native.enative,
- &ecoff_ext);
- type = 'e';
- pos = (ecoffsymbol (symbol)->native.enative
- - ecoff_data (abfd)->external_ext);
- jmptbl = ecoff_ext.jmptbl ? 'j' : ' ';
- cobol_main = ecoff_ext.cobol_main ? 'c' : ' ';
- weakext = ecoff_ext.weakext ? 'w' : ' ';
- }
-
- fprintf (file, "[%3d] %c %lx st %x sc %x indx %x %c%c%c %s",
- pos, type, (unsigned long) ecoff_ext.asym.value,
- (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)
- {
- unsigned indx;
- int bigendian;
- long sym_base;
- union aux_ext *aux_base;
-
- indx = ecoff_ext.asym.index;
-
- /* sym_base is used to map the fdr relative indices which
- appear in the file to the position number which we are
- using. */
- sym_base = ecoffsymbol (symbol)->fdr->isymBase;
- if (ecoffsymbol (symbol)->local)
- sym_base += ecoff_data (abfd)->symbolic_header.iextMax;
-
- /* aux_base is the start of the aux entries for this file;
- asym.index is an offset from this. */
- aux_base = (ecoff_data (abfd)->external_aux
- + ecoffsymbol (symbol)->fdr->iauxBase);
-
- /* The aux entries are stored in host byte order; the
- order is indicated by a bit in the fdr. */
- bigendian = ecoffsymbol (symbol)->fdr->fBigendian;
-
- /* This switch is basically from gcc/mips-tdump.c */
- switch (ecoff_ext.asym.st)
- {
- case stNil:
- case stLabel:
- break;
-
- case stFile:
- case stBlock:
- printf ("\n End+1 symbol: %ld", indx + sym_base);
- break;
-
- case stEnd:
- if (ecoff_ext.asym.sc == scText
- || ecoff_ext.asym.sc == scInfo)
- printf ("\n First symbol: %ld", indx + sym_base);
- else
- printf ("\n First symbol: %ld",
- (AUX_GET_ISYM (bigendian,
- &aux_base[ecoff_ext.asym.index])
- + sym_base));
- break;
-
- case stProc:
- case stStaticProc:
- if (MIPS_IS_STAB (&ecoff_ext.asym))
- ;
- else if (ecoffsymbol (symbol)->local)
- printf ("\n End+1 symbol: %-7ld Type: %s",
- (AUX_GET_ISYM (bigendian,
- &aux_base[ecoff_ext.asym.index])
- + sym_base),
- ecoff_type_to_string (abfd, aux_base, indx + 1,
- bigendian));
- else
- printf ("\n Local symbol: %d",
- (indx
- + sym_base
- + ecoff_data (abfd)->symbolic_header.iextMax));
- break;
-
- default:
- if (!MIPS_IS_STAB (&ecoff_ext.asym))
- printf ("\n Type: %s",
- ecoff_type_to_string (abfd, aux_base, indx,
- bigendian));
- break;
- }
- }
- }
- break;
- }
-}
-\f
-/* Reloc handling. MIPS ECOFF relocs are packed into 8 bytes in
- external form. They use a bit which indicates whether the symbol
- is external. */
-
-/* Swap a reloc in. */
-
-static void
-ecoff_swap_reloc_in (abfd, ext, intern)
- bfd *abfd;
- RELOC *ext;
- struct internal_reloc *intern;
-{
- intern->r_vaddr = bfd_h_get_32 (abfd, (bfd_byte *) ext->r_vaddr);
- if (abfd->xvec->header_byteorder_big_p != false)
- {
- intern->r_symndx = (((int) ext->r_bits[0]
- << RELOC_BITS0_SYMNDX_SH_LEFT_BIG)
- | ((int) ext->r_bits[1]
- << RELOC_BITS1_SYMNDX_SH_LEFT_BIG)
- | ((int) ext->r_bits[2]
- << RELOC_BITS2_SYMNDX_SH_LEFT_BIG));
- intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG)
- >> RELOC_BITS3_TYPE_SH_BIG);
- intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0;
- }
- else
- {
- intern->r_symndx = (((int) ext->r_bits[0]
- << RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE)
- | ((int) ext->r_bits[1]
- << RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE)
- | ((int) ext->r_bits[2]
- << RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE));
- intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
- >> RELOC_BITS3_TYPE_SH_LITTLE);
- intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;
- }
-}
-
-/* Swap a reloc out. */
-
-static unsigned int
-ecoff_swap_reloc_out (abfd, src, dst)
- bfd *abfd;
- PTR src;
- PTR dst;
-{
- struct internal_reloc *intern = (struct internal_reloc *) src;
- RELOC *ext = (RELOC *) dst;
-
- bfd_h_put_32 (abfd, intern->r_vaddr, (bfd_byte *) ext->r_vaddr);
- if (abfd->xvec->header_byteorder_big_p != false)
- {
- ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG;
- ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG;
- ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG;
- ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG)
- & RELOC_BITS3_TYPE_BIG)
- | (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0));
- }
- else
- {
- ext->r_bits[0] = intern->r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE;
- ext->r_bits[1] = intern->r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE;
- ext->r_bits[2] = intern->r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE;
- ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE)
- & RELOC_BITS3_TYPE_LITTLE)
- | (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0));
- }
-
- return RELSZ;
-}
-
-/* ECOFF relocs are either against external symbols, or against
- sections. If we are producing relocateable output, and the reloc
- is against an external symbol, the resulting reloc will also be
- against the same symbol. In such a case, we don't want to change
- anything about the way the reloc is handled, since it will all be
- done at final link time. Rather than put special case code into
- bfd_perform_relocation, all the reloc types use this howto
- function. It just short circuits the reloc if producing
- relocateable output against an external symbol. */
-
-static bfd_reloc_status_type
-ecoff_generic_reloc (abfd,
- reloc_entry,
- symbol,
- data,
- input_section,
- output_bfd)
- bfd *abfd;
- arelent *reloc_entry;
- asymbol *symbol;
- PTR data;
- asection *input_section;
- bfd *output_bfd;
-{
- if (output_bfd != (bfd *) NULL
- && (symbol->flags & BSF_SECTION_SYM) == 0)
- {
- reloc_entry->address += input_section->output_offset;
- return bfd_reloc_ok;
- }
-
- return bfd_reloc_continue;
-}
-
-/* Do a REFHI relocation. The next reloc must be the corresponding
- REFLO. This has to be done in a function so that carry is handled
- correctly. */
-
-static bfd_reloc_status_type
-ecoff_refhi_reloc (abfd,
- reloc_entry,
- symbol,
- data,
- input_section,
- output_bfd)
- bfd *abfd;
- arelent *reloc_entry;
- asymbol *symbol;
- PTR data;
- asection *input_section;
- bfd *output_bfd;
-{
- bfd_reloc_status_type ret;
- arelent *rello;
- bfd_vma relocation;
- unsigned long insn;
- unsigned long val;
- unsigned long vallo;
-
- /* If we're relocating, and this an external symbol, we don't want
- to change anything. */
- if (output_bfd != (bfd *) NULL
- && (symbol->flags & BSF_SECTION_SYM) == 0)
- {
- reloc_entry->address += input_section->output_offset;
- return bfd_reloc_ok;
- }
-
- ret = bfd_reloc_ok;
- if (symbol->section == &bfd_und_section
- && output_bfd == (bfd *) NULL)
- ret = bfd_reloc_undefined;
-
- rello = reloc_entry + 1;
- BFD_ASSERT (rello->howto->type == ECOFF_R_REFLO
- && *rello->sym_ptr_ptr == *reloc_entry->sym_ptr_ptr);
-
- if (bfd_is_com_section (symbol->section))
- relocation = 0;
- else
- relocation = symbol->value;
-
- relocation += symbol->section->output_section->vma;
- relocation += symbol->section->output_offset;
- relocation += reloc_entry->addend;
-
- if (reloc_entry->address > input_section->_cooked_size)
- return bfd_reloc_outofrange;
-
- insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
- vallo = bfd_get_32 (abfd, (bfd_byte *) data + rello->address) & 0xffff;
- val = ((insn & 0xffff) << 16) + vallo;
- val += relocation;
-
- /* The low order 16 bits are always treated as a signed value.
- Therefore, a negative value in the low order bits requires an
- adjustment in the high order bits. We need to make this
- adjustment in two ways: once for the bits we took from the data,
- and once for the bits we are putting back in to the data. */
- if ((vallo & 0x8000) != 0)
- val -= 0x10000;
- if ((val & 0x8000) != 0)
- val += 0x10000;
-
- insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff);
- bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
-
- if (output_bfd != (bfd *) NULL)
- reloc_entry->address += input_section->output_offset;
-
- return ret;
-}
-
-/* Do a GPREL relocation. This is a 16 bit value which must become
- the offset from the gp register. */
-
-static bfd_reloc_status_type
-ecoff_gprel_reloc (abfd,
- reloc_entry,
- symbol,
- data,
- input_section,
- output_bfd)
- bfd *abfd;
- arelent *reloc_entry;
- asymbol *symbol;
- PTR data;
- asection *input_section;
- bfd *output_bfd;
-{
- boolean relocateable;
- bfd_vma relocation;
- unsigned long val;
- unsigned long insn;
-
- /* If we're relocating, and this an external symbol, we don't want
- to change anything. */
- if (output_bfd != (bfd *) NULL
- && (symbol->flags & BSF_SECTION_SYM) == 0)
- {
- reloc_entry->address += input_section->output_offset;
- return bfd_reloc_ok;
- }
-
- if (output_bfd != (bfd *) NULL)
- relocateable = true;
- else
- {
- relocateable = false;
- output_bfd = symbol->section->output_section->owner;
- }
-
- if (symbol->section == &bfd_und_section
- && relocateable == false)
- return bfd_reloc_undefined;
-
- /* We have to figure out the gp value, so that we can adjust the
- symbol value correctly. We look up the symbol _gp in the output
- BFD. If we can't find it, we're stuck. We cache it in the ECOFF
- target data. */
- if (ecoff_data (output_bfd)->gp == 0)
- {
- if (relocateable != false)
- {
- /* Make up a value. */
- ecoff_data (output_bfd)->gp =
- symbol->section->output_section->vma + 0x4000;
- }
- else
- {
- unsigned int count;
- asymbol **sym;
- unsigned int i;
-
- count = bfd_get_symcount (output_bfd);
- sym = bfd_get_outsymbols (output_bfd);
-
- /* We should do something more friendly here, but we don't
- have a good reloc status to return. */
- if (sym == (asymbol **) NULL)
- abort ();
-
- for (i = 0; i < count; i++, sym++)
- {
- register CONST char *name;
-
- name = bfd_asymbol_name (*sym);
- if (*name == '_' && strcmp (name, "_gp") == 0)
- {
- ecoff_data (output_bfd)->gp = bfd_asymbol_value (*sym);
- break;
- }
- }
-
- /* We should do something more friendly here, but we don't have
- a good reloc status to return. */
- if (i >= count)
- abort ();
- }
- }
-
- if (bfd_is_com_section (symbol->section))
- relocation = 0;
- else
- relocation = symbol->value;
-
- relocation += symbol->section->output_section->vma;
- relocation += symbol->section->output_offset;
-
- if (reloc_entry->address > input_section->_cooked_size)
- return bfd_reloc_outofrange;
-
- insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
-
- /* Set val to the offset into the section (if we are relocating
- against an external symbol, insn & 0xffff will be zero and so
- will reloc_entry->addend). */
- val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
- if (val & 0x8000)
- val -= 0x10000;
-
- /* Adjust val for the final section location and GP value. */
- val += (relocation - ecoff_data (output_bfd)->gp);
-
- insn = (insn &~ 0xffff) | (val & 0xffff);
- bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
-
- if (relocateable != false)
- reloc_entry->address += input_section->output_offset;