blob: 5580e9b35439119c13131e8e5325b86fcd639c09 [file] [log] [blame]
/* POWER/PowerPC XCOFF linker support.
Copyright 1995, 1996, 1997, 1998, 1999, 2000
Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "coff/internal.h"
#include "libcoff.h"
/* This file holds the XCOFF linker code. */
#define STRING_SIZE_SIZE (4)
/* Get the XCOFF hash table entries for a BFD. */
#define obj_xcoff_sym_hashes(bfd) \
((struct xcoff_link_hash_entry **) obj_coff_sym_hashes (bfd))
/* XCOFF relocation types. These probably belong in a header file
somewhere. The relocations are described in the function
_bfd_ppc_xcoff_relocate_section in this file. */
#define R_POS (0x00)
#define R_NEG (0x01)
#define R_REL (0x02)
#define R_TOC (0x03)
#define R_RTB (0x04)
#define R_GL (0x05)
#define R_TCL (0x06)
#define R_BA (0x08)
#define R_BR (0x0a)
#define R_RL (0x0c)
#define R_RLA (0x0d)
#define R_REF (0x0f)
#define R_TRL (0x12)
#define R_TRLA (0x13)
#define R_RRTBI (0x14)
#define R_RRTBA (0x15)
#define R_CAI (0x16)
#define R_CREL (0x17)
#define R_RBA (0x18)
#define R_RBAC (0x19)
#define R_RBR (0x1a)
#define R_RBRC (0x1b)
/* The first word of global linkage code. This must be modified by
filling in the correct TOC offset. */
#define XCOFF_GLINK_FIRST (0x81820000) /* lwz r12,0(r2) */
/* The remaining words of global linkage code. */
static unsigned long xcoff_glink_code[] = {
0x90410014, /* stw r2,20(r1) */
0x800c0000, /* lwz r0,0(r12) */
0x804c0004, /* lwz r2,4(r12) */
0x7c0903a6, /* mtctr r0 */
0x4e800420, /* bctr */
0x0, /* start of traceback table */
0x000c8000, /* traceback table */
0x0 /* traceback table */
};
#define XCOFF_GLINK_SIZE \
(((sizeof xcoff_glink_code / sizeof xcoff_glink_code[0]) * 4) + 4)
/* We reuse the SEC_ROM flag as a mark flag for garbage collection.
This flag will only be used on input sections. */
#define SEC_MARK (SEC_ROM)
/* The ldhdr structure. This appears at the start of the .loader
section. */
struct internal_ldhdr {
/* The version number: currently always 1. */
unsigned long l_version;
/* The number of symbol table entries. */
bfd_size_type l_nsyms;
/* The number of relocation table entries. */
bfd_size_type l_nreloc;
/* The length of the import file string table. */
bfd_size_type l_istlen;
/* The number of import files. */
bfd_size_type l_nimpid;
/* The offset from the start of the .loader section to the first
entry in the import file table. */
bfd_size_type l_impoff;
/* The length of the string table. */
bfd_size_type l_stlen;
/* The offset from the start of the .loader section to the first
entry in the string table. */
bfd_size_type l_stoff;
};
struct external_ldhdr {
bfd_byte l_version[4];
bfd_byte l_nsyms[4];
bfd_byte l_nreloc[4];
bfd_byte l_istlen[4];
bfd_byte l_nimpid[4];
bfd_byte l_impoff[4];
bfd_byte l_stlen[4];
bfd_byte l_stoff[4];
};
#define LDHDRSZ (8 * 4)
/* The ldsym structure. This is used to represent a symbol in the
.loader section. */
struct internal_ldsym {
union {
/* The symbol name if <= SYMNMLEN characters. */
char _l_name[SYMNMLEN];
struct {
/* Zero if the symbol name is more than SYMNMLEN characters. */
long _l_zeroes;
/* The offset in the string table if the symbol name is more
than SYMNMLEN characters. */
long _l_offset;
} _l_l;
} _l;
/* The symbol value. */
bfd_vma l_value;
/* The symbol section number. */
short l_scnum;
/* The symbol type and flags. */
char l_smtype;
/* The symbol storage class. */
char l_smclas;
/* The import file ID. */
bfd_size_type l_ifile;
/* Offset to the parameter type check string. */
bfd_size_type l_parm;
};
struct external_ldsym {
union {
bfd_byte _l_name[SYMNMLEN];
struct {
bfd_byte _l_zeroes[4];
bfd_byte _l_offset[4];
} _l_l;
} _l;
bfd_byte l_value[4];
bfd_byte l_scnum[2];
bfd_byte l_smtype[1];
bfd_byte l_smclas[1];
bfd_byte l_ifile[4];
bfd_byte l_parm[4];
};
#define LDSYMSZ (8 + 3 * 4 + 2 + 2)
/* These flags are for the l_smtype field (the lower three bits are an
XTY_* value). */
/* Imported symbol. */
#define L_IMPORT (0x40)
/* Entry point. */
#define L_ENTRY (0x20)
/* Exported symbol. */
#define L_EXPORT (0x10)
/* The ldrel structure. This is used to represent a reloc in the
.loader section. */
struct internal_ldrel {
/* The reloc address. */
bfd_vma l_vaddr;
/* The symbol table index in the .loader section symbol table. */
bfd_size_type l_symndx;
/* The relocation type and size. */
short l_rtype;
/* The section number this relocation applies to. */
short l_rsecnm;
};
struct external_ldrel {
bfd_byte l_vaddr[4];
bfd_byte l_symndx[4];
bfd_byte l_rtype[2];
bfd_byte l_rsecnm[2];
};
#define LDRELSZ (2 * 4 + 2 * 2)
/* The list of import files. */
struct xcoff_import_file {
/* The next entry in the list. */
struct xcoff_import_file *next;
/* The path. */
const char *path;
/* The file name. */
const char *file;
/* The member name. */
const char *member;
};
/* An entry in the XCOFF linker hash table. */
struct xcoff_link_hash_entry {
struct bfd_link_hash_entry root;
/* Symbol index in output file. Set to -1 initially. Set to -2 if
there is a reloc against this symbol. */
long indx;
/* If we have created a TOC entry for this symbol, this is the .tc
section which holds it. */
asection *toc_section;
union {
/* If we have created a TOC entry (the XCOFF_SET_TOC flag is set),
this is the offset in toc_section. */
bfd_vma toc_offset;
/* If the TOC entry comes from an input file, this is set to the
symbol index of the C_HIDEXT XMC_TC or XMC_TD symbol. */
long toc_indx;
} u;
/* If this symbol is a function entry point which is called, this
field holds a pointer to the function descriptor. If this symbol
is a function descriptor, this field holds a pointer to the
function entry point. */
struct xcoff_link_hash_entry *descriptor;
/* The .loader symbol table entry, if there is one. */
struct internal_ldsym *ldsym;
/* If XCOFF_BUILT_LDSYM is set, this is the .loader symbol table
index. If XCOFF_BUILD_LDSYM is clear, and XCOFF_IMPORT is set,
this is the l_ifile value. */
long ldindx;
/* Some linker flags. */
unsigned short flags;
/* Symbol is referenced by a regular object. */
#define XCOFF_REF_REGULAR (01)
/* Symbol is defined by a regular object. */
#define XCOFF_DEF_REGULAR (02)
/* Symbol is defined by a dynamic object. */
#define XCOFF_DEF_DYNAMIC (04)
/* Symbol is used in a reloc being copied into the .loader section. */
#define XCOFF_LDREL (010)
/* Symbol is the entry point. */
#define XCOFF_ENTRY (020)
/* Symbol is called; this is, it appears in a R_BR reloc. */
#define XCOFF_CALLED (040)
/* Symbol needs the TOC entry filled in. */
#define XCOFF_SET_TOC (0100)
/* Symbol is explicitly imported. */
#define XCOFF_IMPORT (0200)
/* Symbol is explicitly exported. */
#define XCOFF_EXPORT (0400)
/* Symbol has been processed by xcoff_build_ldsyms. */
#define XCOFF_BUILT_LDSYM (01000)
/* Symbol is mentioned by a section which was not garbage collected. */
#define XCOFF_MARK (02000)
/* Symbol size is recorded in size_list list from hash table. */
#define XCOFF_HAS_SIZE (04000)
/* Symbol is a function descriptor. */
#define XCOFF_DESCRIPTOR (010000)
/* Multiple definitions have been for the symbol. */
#define XCOFF_MULTIPLY_DEFINED (020000)
/* The storage mapping class. */
unsigned char smclas;
};
/* The XCOFF linker hash table. */
struct xcoff_link_hash_table {
struct bfd_link_hash_table root;
/* The .debug string hash table. We need to compute this while
reading the input files, so that we know how large the .debug
section will be before we assign section positions. */
struct bfd_strtab_hash *debug_strtab;
/* The .debug section we will use for the final output. */
asection *debug_section;
/* The .loader section we will use for the final output. */
asection *loader_section;
/* A count of non TOC relative relocs which will need to be
allocated in the .loader section. */
size_t ldrel_count;
/* The .loader section header. */
struct internal_ldhdr ldhdr;
/* The .gl section we use to hold global linkage code. */
asection *linkage_section;
/* The .tc section we use to hold toc entries we build for global
linkage code. */
asection *toc_section;
/* The .ds section we use to hold function descriptors which we
create for exported symbols. */
asection *descriptor_section;
/* The list of import files. */
struct xcoff_import_file *imports;
/* Required alignment of sections within the output file. */
unsigned long file_align;
/* Whether the .text section must be read-only. */
boolean textro;
/* Whether garbage collection was done. */
boolean gc;
/* A linked list of symbols for which we have size information. */
struct xcoff_link_size_list {
struct xcoff_link_size_list *next;
struct xcoff_link_hash_entry *h;
bfd_size_type size;
} *size_list;
/* Magic sections: _text, _etext, _data, _edata, _end, end. */
asection *special_sections[6];
};
/* Information we keep for each section in the output file during the
final link phase. */
struct xcoff_link_section_info {
/* The relocs to be output. */
struct internal_reloc *relocs;
/* For each reloc against a global symbol whose index was not known
when the reloc was handled, the global hash table entry. */
struct xcoff_link_hash_entry **rel_hashes;
/* If there is a TOC relative reloc against a global symbol, and the
index of the TOC symbol is not known when the reloc was handled,
an entry is added to this linked list. This is not an array,
like rel_hashes, because this case is quite uncommon. */
struct xcoff_toc_rel_hash {
struct xcoff_toc_rel_hash *next;
struct xcoff_link_hash_entry *h;
struct internal_reloc *rel;
} *toc_rel_hashes;
};
/* Information that we pass around while doing the final link step. */
struct xcoff_final_link_info {
/* General link information. */
struct bfd_link_info *info;
/* Output BFD. */
bfd *output_bfd;
/* Hash table for long symbol names. */
struct bfd_strtab_hash *strtab;
/* Array of information kept for each output section, indexed by the
target_index field. */
struct xcoff_link_section_info *section_info;
/* Symbol index of last C_FILE symbol (-1 if none). */
long last_file_index;
/* Contents of last C_FILE symbol. */
struct internal_syment last_file;
/* Symbol index of TOC symbol. */
long toc_symindx;
/* Start of .loader symbols. */
struct external_ldsym *ldsym;
/* Next .loader reloc to swap out. */
struct external_ldrel *ldrel;
/* File position of start of line numbers. */
file_ptr line_filepos;
/* Buffer large enough to hold swapped symbols of any input file. */
struct internal_syment *internal_syms;
/* Buffer large enough to hold output indices of symbols of any
input file. */
long *sym_indices;
/* Buffer large enough to hold output symbols for any input file. */
bfd_byte *outsyms;
/* Buffer large enough to hold external line numbers for any input
section. */
bfd_byte *linenos;
/* Buffer large enough to hold any input section. */
bfd_byte *contents;
/* Buffer large enough to hold external relocs of any input section. */
bfd_byte *external_relocs;
};
static void xcoff_swap_ldhdr_in
PARAMS ((bfd *, const struct external_ldhdr *, struct internal_ldhdr *));
static void xcoff_swap_ldhdr_out
PARAMS ((bfd *, const struct internal_ldhdr *, struct external_ldhdr *));
static void xcoff_swap_ldsym_in
PARAMS ((bfd *, const struct external_ldsym *, struct internal_ldsym *));
static void xcoff_swap_ldsym_out
PARAMS ((bfd *, const struct internal_ldsym *, struct external_ldsym *));
static void xcoff_swap_ldrel_in
PARAMS ((bfd *, const struct external_ldrel *, struct internal_ldrel *));
static void xcoff_swap_ldrel_out
PARAMS ((bfd *, const struct internal_ldrel *, struct external_ldrel *));
static struct bfd_hash_entry *xcoff_link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
static boolean xcoff_get_section_contents PARAMS ((bfd *, asection *));
static struct internal_reloc *xcoff_read_internal_relocs
PARAMS ((bfd *, asection *, boolean, bfd_byte *, boolean,
struct internal_reloc *));
static boolean xcoff_link_add_object_symbols
PARAMS ((bfd *, struct bfd_link_info *));
static boolean xcoff_link_check_archive_element
PARAMS ((bfd *, struct bfd_link_info *, boolean *));
static boolean xcoff_link_check_ar_symbols
PARAMS ((bfd *, struct bfd_link_info *, boolean *));
static boolean xcoff_link_check_dynamic_ar_symbols
PARAMS ((bfd *, struct bfd_link_info *, boolean *));
static bfd_size_type xcoff_find_reloc
PARAMS ((struct internal_reloc *, bfd_size_type, bfd_vma));
static boolean xcoff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
static boolean xcoff_link_add_dynamic_symbols
PARAMS ((bfd *, struct bfd_link_info *));
static boolean xcoff_mark_symbol
PARAMS ((struct bfd_link_info *, struct xcoff_link_hash_entry *));
static boolean xcoff_mark PARAMS ((struct bfd_link_info *, asection *));
static void xcoff_sweep PARAMS ((struct bfd_link_info *));
static boolean xcoff_build_ldsyms
PARAMS ((struct xcoff_link_hash_entry *, PTR));
static boolean xcoff_link_input_bfd
PARAMS ((struct xcoff_final_link_info *, bfd *));
static boolean xcoff_write_global_symbol
PARAMS ((struct xcoff_link_hash_entry *, PTR));
static boolean xcoff_reloc_link_order
PARAMS ((bfd *, struct xcoff_final_link_info *, asection *,
struct bfd_link_order *));
static int xcoff_sort_relocs PARAMS ((const PTR, const PTR));
/* Routines to swap information in the XCOFF .loader section. If we
ever need to write an XCOFF loader, this stuff will need to be
moved to another file shared by the linker (which XCOFF calls the
``binder'') and the loader. */
/* Swap in the ldhdr structure. */
static void
xcoff_swap_ldhdr_in (abfd, src, dst)
bfd *abfd;
const struct external_ldhdr *src;
struct internal_ldhdr *dst;
{
dst->l_version = bfd_get_32 (abfd, src->l_version);
dst->l_nsyms = bfd_get_32 (abfd, src->l_nsyms);
dst->l_nreloc = bfd_get_32 (abfd, src->l_nreloc);
dst->l_istlen = bfd_get_32 (abfd, src->l_istlen);
dst->l_nimpid = bfd_get_32 (abfd, src->l_nimpid);
dst->l_impoff = bfd_get_32 (abfd, src->l_impoff);
dst->l_stlen = bfd_get_32 (abfd, src->l_stlen);
dst->l_stoff = bfd_get_32 (abfd, src->l_stoff);
}
/* Swap out the ldhdr structure. */
static void
xcoff_swap_ldhdr_out (abfd, src, dst)
bfd *abfd;
const struct internal_ldhdr *src;
struct external_ldhdr *dst;
{
bfd_put_32 (abfd, src->l_version, dst->l_version);
bfd_put_32 (abfd, src->l_nsyms, dst->l_nsyms);
bfd_put_32 (abfd, src->l_nreloc, dst->l_nreloc);
bfd_put_32 (abfd, src->l_istlen, dst->l_istlen);
bfd_put_32 (abfd, src->l_nimpid, dst->l_nimpid);
bfd_put_32 (abfd, src->l_impoff, dst->l_impoff);
bfd_put_32 (abfd, src->l_stlen, dst->l_stlen);
bfd_put_32 (abfd, src->l_stoff, dst->l_stoff);
}
/* Swap in the ldsym structure. */
static void
xcoff_swap_ldsym_in (abfd, src, dst)
bfd *abfd;
const struct external_ldsym *src;
struct internal_ldsym *dst;
{
if (bfd_get_32 (abfd, src->_l._l_l._l_zeroes) != 0)
memcpy (dst->_l._l_name, src->_l._l_name, SYMNMLEN);
else
{
dst->_l._l_l._l_zeroes = 0;
dst->_l._l_l._l_offset = bfd_get_32 (abfd, src->_l._l_l._l_offset);
}
dst->l_value = bfd_get_32 (abfd, src->l_value);
dst->l_scnum = bfd_get_16 (abfd, src->l_scnum);
dst->l_smtype = bfd_get_8 (abfd, src->l_smtype);
dst->l_smclas = bfd_get_8 (abfd, src->l_smclas);
dst->l_ifile = bfd_get_32 (abfd, src->l_ifile);
dst->l_parm = bfd_get_32 (abfd, src->l_parm);
}
/* Swap out the ldsym structure. */
static void
xcoff_swap_ldsym_out (abfd, src, dst)
bfd *abfd;
const struct internal_ldsym *src;
struct external_ldsym *dst;
{
if (src->_l._l_l._l_zeroes != 0)
memcpy (dst->_l._l_name, src->_l._l_name, SYMNMLEN);
else
{
bfd_put_32 (abfd, 0, dst->_l._l_l._l_zeroes);
bfd_put_32 (abfd, src->_l._l_l._l_offset, dst->_l._l_l._l_offset);
}
bfd_put_32 (abfd, src->l_value, dst->l_value);
bfd_put_16 (abfd, src->l_scnum, dst->l_scnum);
bfd_put_8 (abfd, src->l_smtype, dst->l_smtype);
bfd_put_8 (abfd, src->l_smclas, dst->l_smclas);
bfd_put_32 (abfd, src->l_ifile, dst->l_ifile);
bfd_put_32 (abfd, src->l_parm, dst->l_parm);
}
/* Swap in the ldrel structure. */
static void
xcoff_swap_ldrel_in (abfd, src, dst)
bfd *abfd;
const struct external_ldrel *src;
struct internal_ldrel *dst;
{
dst->l_vaddr = bfd_get_32 (abfd, src->l_vaddr);
dst->l_symndx = bfd_get_32 (abfd, src->l_symndx);
dst->l_rtype = bfd_get_16 (abfd, src->l_rtype);
dst->l_rsecnm = bfd_get_16 (abfd, src->l_rsecnm);
}
/* Swap out the ldrel structure. */
static void
xcoff_swap_ldrel_out (abfd, src, dst)
bfd *abfd;
const struct internal_ldrel *src;
struct external_ldrel *dst;
{
bfd_put_32 (abfd, src->l_vaddr, dst->l_vaddr);
bfd_put_32 (abfd, src->l_symndx, dst->l_symndx);
bfd_put_16 (abfd, src->l_rtype, dst->l_rtype);
bfd_put_16 (abfd, src->l_rsecnm, dst->l_rsecnm);
}
/* Routines to read XCOFF dynamic information. This don't really
belong here, but we already have the ldsym manipulation routines
here. */
/* Read the contents of a section. */
static boolean
xcoff_get_section_contents (abfd, sec)
bfd *abfd;
asection *sec;
{
if (coff_section_data (abfd, sec) == NULL)
{
sec->used_by_bfd = bfd_zalloc (abfd,
sizeof (struct coff_section_tdata));
if (sec->used_by_bfd == NULL)
return false;
}
if (coff_section_data (abfd, sec)->contents == NULL)
{
coff_section_data (abfd, sec)->contents =
(bfd_byte *) bfd_malloc (sec->_raw_size);
if (coff_section_data (abfd, sec)->contents == NULL)
return false;
if (! bfd_get_section_contents (abfd, sec,
coff_section_data (abfd, sec)->contents,
(file_ptr) 0, sec->_raw_size))
return false;
}
return true;
}
/* Get the size required to hold the dynamic symbols. */
long
_bfd_xcoff_get_dynamic_symtab_upper_bound (abfd)
bfd *abfd;
{
asection *lsec;
bfd_byte *contents;
struct internal_ldhdr ldhdr;
if ((abfd->flags & DYNAMIC) == 0)
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
lsec = bfd_get_section_by_name (abfd, ".loader");
if (lsec == NULL)
{
bfd_set_error (bfd_error_no_symbols);
return -1;
}
if (! xcoff_get_section_contents (abfd, lsec))
return -1;
contents = coff_section_data (abfd, lsec)->contents;
xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
return (ldhdr.l_nsyms + 1) * sizeof (asymbol *);
}
/* Get the dynamic symbols. */
long
_bfd_xcoff_canonicalize_dynamic_symtab (abfd, psyms)
bfd *abfd;
asymbol **psyms;
{
asection *lsec;
bfd_byte *contents;
struct internal_ldhdr ldhdr;
const char *strings;
struct external_ldsym *elsym, *elsymend;
coff_symbol_type *symbuf;
if ((abfd->flags & DYNAMIC) == 0)
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
lsec = bfd_get_section_by_name (abfd, ".loader");
if (lsec == NULL)
{
bfd_set_error (bfd_error_no_symbols);
return -1;
}
if (! xcoff_get_section_contents (abfd, lsec))
return -1;
contents = coff_section_data (abfd, lsec)->contents;
coff_section_data (abfd, lsec)->keep_contents = true;
xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
strings = (char *) contents + ldhdr.l_stoff;
symbuf = ((coff_symbol_type *)
bfd_zalloc (abfd, ldhdr.l_nsyms * sizeof (coff_symbol_type)));
if (symbuf == NULL)
return -1;
elsym = (struct external_ldsym *) (contents + LDHDRSZ);
elsymend = elsym + ldhdr.l_nsyms;
for (; elsym < elsymend; elsym++, symbuf++, psyms++)
{
struct internal_ldsym ldsym;
xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
symbuf->symbol.the_bfd = abfd;
if (ldsym._l._l_l._l_zeroes == 0)
symbuf->symbol.name = strings + ldsym._l._l_l._l_offset;
else
{
int i;
for (i = 0; i < SYMNMLEN; i++)
if (ldsym._l._l_name[i] == '\0')
break;
if (i < SYMNMLEN)
symbuf->symbol.name = (char *) elsym->_l._l_name;
else
{
char *c;
c = bfd_alloc (abfd, SYMNMLEN + 1);
if (c == NULL)
return -1;
memcpy (c, ldsym._l._l_name, SYMNMLEN);
c[SYMNMLEN] = '\0';
symbuf->symbol.name = c;
}
}
if (ldsym.l_smclas == XMC_XO)
symbuf->symbol.section = bfd_abs_section_ptr;
else
symbuf->symbol.section = coff_section_from_bfd_index (abfd,
ldsym.l_scnum);
symbuf->symbol.value = ldsym.l_value - symbuf->symbol.section->vma;
symbuf->symbol.flags = BSF_NO_FLAGS;
if ((ldsym.l_smtype & L_EXPORT) != 0)
symbuf->symbol.flags |= BSF_GLOBAL;
/* FIXME: We have no way to record the other information stored
with the loader symbol. */
*psyms = (asymbol *) symbuf;
}
*psyms = NULL;
return ldhdr.l_nsyms;
}
/* Get the size required to hold the dynamic relocs. */
long
_bfd_xcoff_get_dynamic_reloc_upper_bound (abfd)
bfd *abfd;
{
asection *lsec;
bfd_byte *contents;
struct internal_ldhdr ldhdr;
if ((abfd->flags & DYNAMIC) == 0)
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
lsec = bfd_get_section_by_name (abfd, ".loader");
if (lsec == NULL)
{
bfd_set_error (bfd_error_no_symbols);
return -1;
}
if (! xcoff_get_section_contents (abfd, lsec))
return -1;
contents = coff_section_data (abfd, lsec)->contents;
xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
return (ldhdr.l_nreloc + 1) * sizeof (arelent *);
}
/* The typical dynamic reloc. */
static reloc_howto_type xcoff_dynamic_reloc =
HOWTO (0, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
0, /* special_function */
"R_POS", /* name */
true, /* partial_inplace */
0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
false); /* pcrel_offset */
/* Get the dynamic relocs. */
long
_bfd_xcoff_canonicalize_dynamic_reloc (abfd, prelocs, syms)
bfd *abfd;
arelent **prelocs;
asymbol **syms;
{
asection *lsec;
bfd_byte *contents;
struct internal_ldhdr ldhdr;
arelent *relbuf;
struct external_ldrel *elrel, *elrelend;
if ((abfd->flags & DYNAMIC) == 0)
{
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
lsec = bfd_get_section_by_name (abfd, ".loader");
if (lsec == NULL)
{
bfd_set_error (bfd_error_no_symbols);
return -1;
}
if (! xcoff_get_section_contents (abfd, lsec))
return -1;
contents = coff_section_data (abfd, lsec)->contents;
xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
relbuf = (arelent *) bfd_alloc (abfd, ldhdr.l_nreloc * sizeof (arelent));
if (relbuf == NULL)
return -1;
elrel = ((struct external_ldrel *)
(contents + LDHDRSZ + ldhdr.l_nsyms * LDSYMSZ));
elrelend = elrel + ldhdr.l_nreloc;
for (; elrel < elrelend; elrel++, relbuf++, prelocs++)
{
struct internal_ldrel ldrel;
xcoff_swap_ldrel_in (abfd, elrel, &ldrel);
if (ldrel.l_symndx >= 3)
relbuf->sym_ptr_ptr = syms + (ldrel.l_symndx - 3);
else
{
const char *name;
asection *sec;
switch (ldrel.l_symndx)
{
case 0:
name = ".text";
break;
case 1:
name = ".data";
break;
case 2:
name = ".bss";
break;
default:
abort ();
break;
}
sec = bfd_get_section_by_name (abfd, name);
if (sec == NULL)
{
bfd_set_error (bfd_error_bad_value);
return -1;
}
relbuf->sym_ptr_ptr = sec->symbol_ptr_ptr;
}
relbuf->address = ldrel.l_vaddr;
relbuf->addend = 0;
/* Most dynamic relocs have the same type. FIXME: This is only
correct if ldrel.l_rtype == 0. In other cases, we should use
a different howto. */
relbuf->howto = &xcoff_dynamic_reloc;
/* FIXME: We have no way to record the l_rsecnm field. */
*prelocs = relbuf;
}
*prelocs = NULL;
return ldhdr.l_nreloc;
}
/* Routine to create an entry in an XCOFF link hash table. */
static struct bfd_hash_entry *
xcoff_link_hash_newfunc (entry, table, string)
struct bfd_hash_entry *entry;
struct bfd_hash_table *table;
const char *string;
{
struct xcoff_link_hash_entry *ret = (struct xcoff_link_hash_entry *) entry;
/* Allocate the structure if it has not already been allocated by a
subclass. */
if (ret == (struct xcoff_link_hash_entry *) NULL)
ret = ((struct xcoff_link_hash_entry *)
bfd_hash_allocate (table, sizeof (struct xcoff_link_hash_entry)));
if (ret == (struct xcoff_link_hash_entry *) NULL)
return (struct bfd_hash_entry *) ret;
/* Call the allocation method of the superclass. */
ret = ((struct xcoff_link_hash_entry *)
_bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
if (ret != NULL)
{
/* Set local fields. */
ret->indx = -1;
ret->toc_section = NULL;
ret->u.toc_indx = -1;
ret->descriptor = NULL;
ret->ldsym = NULL;
ret->ldindx = -1;
ret->flags = 0;
ret->smclas = XMC_UA;
}
return (struct bfd_hash_entry *) ret;
}
/* Create a XCOFF link hash table. */
struct bfd_link_hash_table *
_bfd_xcoff_bfd_link_hash_table_create (abfd)
bfd *abfd;
{
struct xcoff_link_hash_table *ret;
ret = ((struct xcoff_link_hash_table *)
bfd_alloc (abfd, sizeof (struct xcoff_link_hash_table)));
if (ret == (struct xcoff_link_hash_table *) NULL)
return (struct bfd_link_hash_table *) NULL;
if (! _bfd_link_hash_table_init (&ret->root, abfd, xcoff_link_hash_newfunc))
{
bfd_release (abfd, ret);
return (struct bfd_link_hash_table *) NULL;
}
ret->debug_strtab = _bfd_xcoff_stringtab_init ();
ret->debug_section = NULL;
ret->loader_section = NULL;
ret->ldrel_count = 0;
memset (&ret->ldhdr, 0, sizeof (struct internal_ldhdr));
ret->linkage_section = NULL;
ret->toc_section = NULL;
ret->descriptor_section = NULL;
ret->imports = NULL;
ret->file_align = 0;
ret->textro = false;
ret->gc = false;
memset (ret->special_sections, 0, sizeof ret->special_sections);
/* The linker will always generate a full a.out header. We need to
record that fact now, before the sizeof_headers routine could be
called. */
xcoff_data (abfd)->full_aouthdr = true;
return &ret->root;
}
/* Look up an entry in an XCOFF link hash table. */
#define xcoff_link_hash_lookup(table, string, create, copy, follow) \
((struct xcoff_link_hash_entry *) \
bfd_link_hash_lookup (&(table)->root, (string), (create), (copy),\
(follow)))
/* Traverse an XCOFF link hash table. */
#define xcoff_link_hash_traverse(table, func, info) \
(bfd_link_hash_traverse \
(&(table)->root, \
(boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \
(info)))
/* Get the XCOFF link hash table from the info structure. This is
just a cast. */
#define xcoff_hash_table(p) ((struct xcoff_link_hash_table *) ((p)->hash))
/* Read internal relocs for an XCOFF csect. This is a wrapper around
_bfd_coff_read_internal_relocs which tries to take advantage of any
relocs which may have been cached for the enclosing section. */
static struct internal_reloc *
xcoff_read_internal_relocs (abfd, sec, cache, external_relocs,
require_internal, internal_relocs)
bfd *abfd;
asection *sec;
boolean cache;
bfd_byte *external_relocs;
boolean require_internal;
struct internal_reloc *internal_relocs;
{
if (coff_section_data (abfd, sec) != NULL
&& coff_section_data (abfd, sec)->relocs == NULL
&& xcoff_section_data (abfd, sec) != NULL)
{
asection *enclosing;
enclosing = xcoff_section_data (abfd, sec)->enclosing;
if (enclosing != NULL
&& (coff_section_data (abfd, enclosing) == NULL
|| coff_section_data (abfd, enclosing)->relocs == NULL)
&& cache
&& enclosing->reloc_count > 0)
{
if (_bfd_coff_read_internal_relocs (abfd, enclosing, true,
external_relocs, false,
(struct internal_reloc *) NULL)
== NULL)
return NULL;
}
if (enclosing != NULL
&& coff_section_data (abfd, enclosing) != NULL
&& coff_section_data (abfd, enclosing)->relocs != NULL)
{
size_t off;
off = ((sec->rel_filepos - enclosing->rel_filepos)
/ bfd_coff_relsz (abfd));
if (! require_internal)
return coff_section_data (abfd, enclosing)->relocs + off;
memcpy (internal_relocs,
coff_section_data (abfd, enclosing)->relocs + off,
sec->reloc_count * sizeof (struct internal_reloc));
return internal_relocs;
}
}
return _bfd_coff_read_internal_relocs (abfd, sec, cache, external_relocs,
require_internal, internal_relocs);
}
/* Given an XCOFF BFD, add symbols to the global hash table as
appropriate. */
boolean
_bfd_xcoff_bfd_link_add_symbols (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
switch (bfd_get_format (abfd))
{
case bfd_object:
return xcoff_link_add_object_symbols (abfd, info);
case bfd_archive:
/* If the archive has a map, do the usual search. We then need
to check the archive for stripped dynamic objects, because
they will not appear in the archive map even though they
should, perhaps, be included. If the archive has no map, we
just consider each object file in turn, since that apparently
is what the AIX native linker does. */
if (bfd_has_map (abfd))
{
if (! (_bfd_generic_link_add_archive_symbols
(abfd, info, xcoff_link_check_archive_element)))
return false;
}
{
bfd *member;
member = bfd_openr_next_archived_file (abfd, (bfd *) NULL);
while (member != NULL)
{
if (bfd_check_format (member, bfd_object)
&& (! bfd_has_map (abfd)
|| ((member->flags & DYNAMIC) != 0
&& (member->flags & HAS_SYMS) == 0)))
{
boolean needed;
if (! xcoff_link_check_archive_element (member, info, &needed))
return false;
if (needed)
member->archive_pass = -1;
}
member = bfd_openr_next_archived_file (abfd, member);
}
}
return true;
default:
bfd_set_error (bfd_error_wrong_format);
return false;
}
}
/* Add symbols from an XCOFF object file. */
static boolean
xcoff_link_add_object_symbols (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
if (! _bfd_coff_get_external_symbols (abfd))
return false;
if (! xcoff_link_add_symbols (abfd, info))
return false;
if (! info->keep_memory)
{
if (! _bfd_coff_free_symbols (abfd))
return false;
}
return true;
}
/* Check a single archive element to see if we need to include it in
the link. *PNEEDED is set according to whether this element is
needed in the link or not. This is called via
_bfd_generic_link_add_archive_symbols. */
static boolean
xcoff_link_check_archive_element (abfd, info, pneeded)
bfd *abfd;
struct bfd_link_info *info;
boolean *pneeded;
{
if (! _bfd_coff_get_external_symbols (abfd))
return false;
if (! xcoff_link_check_ar_symbols (abfd, info, pneeded))
return false;
if (*pneeded)
{
if (! xcoff_link_add_symbols (abfd, info))
return false;
}
if (! info->keep_memory || ! *pneeded)
{
if (! _bfd_coff_free_symbols (abfd))
return false;
}
return true;
}
/* Look through the symbols to see if this object file should be
included in the link. */
static boolean
xcoff_link_check_ar_symbols (abfd, info, pneeded)
bfd *abfd;
struct bfd_link_info *info;
boolean *pneeded;
{
bfd_size_type symesz;
bfd_byte *esym;
bfd_byte *esym_end;
*pneeded = false;
if ((abfd->flags & DYNAMIC) != 0
&& ! info->static_link
&& info->hash->creator == abfd->xvec)
return xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded);
symesz = bfd_coff_symesz (abfd);
esym = (bfd_byte *) obj_coff_external_syms (abfd);
esym_end = esym + obj_raw_syment_count (abfd) * symesz;
while (esym < esym_end)
{
struct internal_syment sym;
bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
if (sym.n_sclass == C_EXT && sym.n_scnum != N_UNDEF)
{
const char *name;
char buf[SYMNMLEN + 1];
struct bfd_link_hash_entry *h;
/* This symbol is externally visible, and is defined by this
object file. */
name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
if (name == NULL)
return false;
h = bfd_link_hash_lookup (info->hash, name, false, false, true);
/* We are only interested in symbols that are currently
undefined. If a symbol is currently known to be common,
XCOFF linkers do not bring in an object file which
defines it. We also don't bring in symbols to satisfy
undefined references in shared objects. */
if (h != (struct bfd_link_hash_entry *) NULL
&& h->type == bfd_link_hash_undefined
&& (info->hash->creator != abfd->xvec
|| (((struct xcoff_link_hash_entry *) h)->flags
& XCOFF_DEF_DYNAMIC) == 0))
{
if (! (*info->callbacks->add_archive_element) (info, abfd, name))
return false;
*pneeded = true;
return true;
}
}
esym += (sym.n_numaux + 1) * symesz;
}
/* We do not need this object file. */
return true;
}
/* Look through the loader symbols to see if this dynamic object
should be included in the link. The native linker uses the loader
symbols, not the normal symbol table, so we do too. */
static boolean
xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded)
bfd *abfd;
struct bfd_link_info *info;
boolean *pneeded;
{
asection *lsec;
bfd_byte *buf;
struct internal_ldhdr ldhdr;
const char *strings;
struct external_ldsym *elsym, *elsymend;
*pneeded = false;
lsec = bfd_get_section_by_name (abfd, ".loader");
if (lsec == NULL)
{
/* There are no symbols, so don't try to include it. */
return true;
}
if (! xcoff_get_section_contents (abfd, lsec))
return false;
buf = coff_section_data (abfd, lsec)->contents;
xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) buf, &ldhdr);
strings = (char *) buf + ldhdr.l_stoff;
elsym = (struct external_ldsym *) (buf + LDHDRSZ);
elsymend = elsym + ldhdr.l_nsyms;
for (; elsym < elsymend; elsym++)
{
struct internal_ldsym ldsym;
char nambuf[SYMNMLEN + 1];
const char *name;
struct bfd_link_hash_entry *h;
xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
/* We are only interested in exported symbols. */
if ((ldsym.l_smtype & L_EXPORT) == 0)
continue;
if (ldsym._l._l_l._l_zeroes == 0)
name = strings + ldsym._l._l_l._l_offset;
else
{
memcpy (nambuf, ldsym._l._l_name, SYMNMLEN);
nambuf[SYMNMLEN] = '\0';
name = nambuf;
}
h = bfd_link_hash_lookup (info->hash, name, false, false, true);
/* We are only interested in symbols that are currently
undefined. At this point we know that we are using an XCOFF
hash table. */
if (h != NULL
&& h->type == bfd_link_hash_undefined
&& (((struct xcoff_link_hash_entry *) h)->flags
& XCOFF_DEF_DYNAMIC) == 0)
{
if (! (*info->callbacks->add_archive_element) (info, abfd, name))
return false;
*pneeded = true;
return true;
}
}
/* We do not need this shared object. */
if (buf != NULL && ! coff_section_data (abfd, lsec)->keep_contents)
{
free (coff_section_data (abfd, lsec)->contents);
coff_section_data (abfd, lsec)->contents = NULL;
}
return true;
}
/* Returns the index of reloc in RELOCS with the least address greater
than or equal to ADDRESS. The relocs are sorted by address. */
static bfd_size_type
xcoff_find_reloc (relocs, count, address)
struct internal_reloc *relocs;
bfd_size_type count;
bfd_vma address;
{
bfd_size_type min, max, this;
if (count < 2)
{
if (count == 1 && relocs[0].r_vaddr < address)
return 1;
else
return 0;
}
min = 0;
max = count;
/* Do a binary search over (min,max]. */
while (min + 1 < max)
{
bfd_vma raddr;
this = (max + min) / 2;
raddr = relocs[this].r_vaddr;
if (raddr > address)
max = this;
else if (raddr < address)
min = this;
else
{
min = this;
break;
}
}
if (relocs[min].r_vaddr < address)
return min + 1;
while (min > 0
&& relocs[min - 1].r_vaddr == address)
--min;
return min;
}
/* Add all the symbols from an object file to the hash table.
XCOFF is a weird format. A normal XCOFF .o files will have three
COFF sections--.text, .data, and .bss--but each COFF section will
contain many csects. These csects are described in the symbol
table. From the linker's point of view, each csect must be
considered a section in its own right. For example, a TOC entry is
handled as a small XMC_TC csect. The linker must be able to merge
different TOC entries together, which means that it must be able to
extract the XMC_TC csects from the .data section of the input .o
file.
From the point of view of our linker, this is, of course, a hideous
nightmare. We cope by actually creating sections for each csect,
and discarding the original sections. We then have to handle the
relocation entries carefully, since the only way to tell which
csect they belong to is to examine the address. */
static boolean
xcoff_link_add_symbols (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
unsigned int n_tmask;
unsigned int n_btshft;
boolean default_copy;
bfd_size_type symcount;
struct xcoff_link_hash_entry **sym_hash;
asection **csect_cache;
bfd_size_type linesz;
asection *o;
asection *last_real;
boolean keep_syms;
asection *csect;
unsigned int csect_index;
asection *first_csect;
bfd_size_type symesz;
bfd_byte *esym;
bfd_byte *esym_end;
struct reloc_info_struct
{
struct internal_reloc *relocs;
asection **csects;
bfd_byte *linenos;
} *reloc_info = NULL;
keep_syms = obj_coff_keep_syms (abfd);
if ((abfd->flags & DYNAMIC) != 0
&& ! info->static_link)
{
if (! xcoff_link_add_dynamic_symbols (abfd, info))
return false;
}
if (info->hash->creator == abfd->xvec)
{
/* We need to build a .loader section, so we do it here. This
won't work if we're producing an XCOFF output file with no
XCOFF input files. FIXME. */
if (xcoff_hash_table (info)->loader_section == NULL)
{
asection *lsec;
lsec = bfd_make_section_anyway (abfd, ".loader");
if (lsec == NULL)
goto error_return;
xcoff_hash_table (info)->loader_section = lsec;
lsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY;
}
/* Likewise for the linkage section. */
if (xcoff_hash_table (info)->linkage_section == NULL)
{
asection *lsec;
lsec = bfd_make_section_anyway (abfd, ".gl");
if (lsec == NULL)
goto error_return;
xcoff_hash_table (info)->linkage_section = lsec;
lsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
| SEC_IN_MEMORY);
lsec->alignment_power = 2;
}
/* Likewise for the TOC section. */
if (xcoff_hash_table (info)->toc_section == NULL)
{
asection *tsec;
tsec = bfd_make_section_anyway (abfd, ".tc");
if (tsec == NULL)
goto error_return;
xcoff_hash_table (info)->toc_section = tsec;
tsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
| SEC_IN_MEMORY);
tsec->alignment_power = 2;
}
/* Likewise for the descriptor section. */
if (xcoff_hash_table (info)->descriptor_section == NULL)
{
asection *dsec;
dsec = bfd_make_section_anyway (abfd, ".ds");
if (dsec == NULL)
goto error_return;
xcoff_hash_table (info)->descriptor_section = dsec;
dsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
| SEC_IN_MEMORY);
dsec->alignment_power = 2;
}
/* Likewise for the .debug section. */
if (xcoff_hash_table (info)->debug_section == NULL
&& info->strip != strip_all)
{
asection *dsec;
dsec = bfd_make_section_anyway (abfd, ".debug");
if (dsec == NULL)
goto error_return;
xcoff_hash_table (info)->debug_section = dsec;
dsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY;
}
}
if ((abfd->flags & DYNAMIC) != 0
&& ! info->static_link)
return true;
n_tmask = coff_data (abfd)->local_n_tmask;
n_btshft = coff_data (abfd)->local_n_btshft;
/* Define macros so that ISFCN, et. al., macros work correctly. */
#define N_TMASK n_tmask
#define N_BTSHFT n_btshft
if (info->keep_memory)
default_copy = false;
else
default_copy = true;
symcount = obj_raw_syment_count (abfd);
/* We keep a list of the linker hash table entries that correspond
to each external symbol. */
sym_hash = ((struct xcoff_link_hash_entry **)
bfd_alloc (abfd,
(symcount
* sizeof (struct xcoff_link_hash_entry *))));
if (sym_hash == NULL && symcount != 0)
goto error_return;
coff_data (abfd)->sym_hashes = (struct coff_link_hash_entry **) sym_hash;
memset (sym_hash, 0,
(size_t) symcount * sizeof (struct xcoff_link_hash_entry *));
/* Because of the weird stuff we are doing with XCOFF csects, we can
not easily determine which section a symbol is in, so we store
the information in the tdata for the input file. */
csect_cache = ((asection **)
bfd_alloc (abfd, symcount * sizeof (asection *)));
if (csect_cache == NULL && symcount != 0)
goto error_return;
xcoff_data (abfd)->csects = csect_cache;
memset (csect_cache, 0, (size_t) symcount * sizeof (asection *));
/* While splitting sections into csects, we need to assign the
relocs correctly. The relocs and the csects must both be in
order by VMA within a given section, so we handle this by
scanning along the relocs as we process the csects. We index
into reloc_info using the section target_index. */
reloc_info = ((struct reloc_info_struct *)
bfd_malloc ((abfd->section_count + 1)
* sizeof (struct reloc_info_struct)));
if (reloc_info == NULL)
goto error_return;
memset ((PTR) reloc_info, 0,
(abfd->section_count + 1) * sizeof (struct reloc_info_struct));
/* Read in the relocs and line numbers for each section. */
linesz = bfd_coff_linesz (abfd);
last_real = NULL;
for (o = abfd->sections; o != NULL; o = o->next)
{
last_real = o;
if ((o->flags & SEC_RELOC) != 0)
{
reloc_info[o->target_index].relocs =
xcoff_read_internal_relocs (abfd, o, true, (bfd_byte *) NULL,
false, (struct internal_reloc *) NULL);
reloc_info[o->target_index].csects =
(asection **) bfd_malloc (o->reloc_count * sizeof (asection *));
if (reloc_info[o->target_index].csects == NULL)
goto error_return;
memset (reloc_info[o->target_index].csects, 0,
o->reloc_count * sizeof (asection *));
}
if ((info->strip == strip_none || info->strip == strip_some)
&& o->lineno_count > 0)
{
bfd_byte *linenos;
linenos = (bfd_byte *) bfd_malloc (o->lineno_count * linesz);
if (linenos == NULL)
goto error_return;
reloc_info[o->target_index].linenos = linenos;
if (bfd_seek (abfd, o->line_filepos, SEEK_SET) != 0
|| (bfd_read (linenos, linesz, o->lineno_count, abfd)
!= linesz * o->lineno_count))
goto error_return;
}
}
/* Don't let the linker relocation routines discard the symbols. */
obj_coff_keep_syms (abfd) = true;
csect = NULL;
csect_index = 0;
first_csect = NULL;
symesz = bfd_coff_symesz (abfd);
BFD_ASSERT (symesz == bfd_coff_auxesz (abfd));
esym = (bfd_byte *) obj_coff_external_syms (abfd);
esym_end = esym + symcount * symesz;
while (esym < esym_end)
{
struct internal_syment sym;
union internal_auxent aux;
const char *name;
char buf[SYMNMLEN + 1];
int smtyp;
flagword flags;
asection *section;
bfd_vma value;
struct xcoff_link_hash_entry *set_toc;
bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &sym);
/* In this pass we are only interested in symbols with csect
information. */
if (sym.n_sclass != C_EXT && sym.n_sclass != C_HIDEXT)
{
if (sym.n_sclass == C_FILE && csect != NULL)
{
xcoff_section_data (abfd, csect)->last_symndx =
((esym
- (bfd_byte *) obj_coff_external_syms (abfd))
/ symesz);
csect = NULL;
}
if (csect != NULL)
*csect_cache = csect;
else if (first_csect == NULL || sym.n_sclass == C_FILE)
*csect_cache = coff_section_from_bfd_index (abfd, sym.n_scnum);
else
*csect_cache = NULL;
esym += (sym.n_numaux + 1) * symesz;
sym_hash += sym.n_numaux + 1;
csect_cache += sym.n_numaux + 1;
continue;
}
name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
if (name == NULL)
goto error_return;
/* If this symbol has line number information attached to it,
and we're not stripping it, count the number of entries and
add them to the count for this csect. In the final link pass
we are going to attach line number information by symbol,
rather than by section, in order to more easily handle
garbage collection. */
if ((info->strip == strip_none || info->strip == strip_some)
&& sym.n_numaux > 1
&& csect != NULL
&& ISFCN (sym.n_type))
{
union internal_auxent auxlin;
bfd_coff_swap_aux_in (abfd, (PTR) (esym + symesz),
sym.n_type, sym.n_sclass,
0, sym.n_numaux, (PTR) &auxlin);
if (auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr != 0)
{
asection *enclosing;
bfd_size_type linoff;
enclosing = xcoff_section_data (abfd, csect)->enclosing;
if (enclosing == NULL)
{
(*_bfd_error_handler)
(_("%s: `%s' has line numbers but no enclosing section"),
bfd_get_filename (abfd), name);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
linoff = (auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr
- enclosing->line_filepos);
if (linoff < enclosing->lineno_count * linesz)
{
struct internal_lineno lin;
bfd_byte *linpstart;
linpstart = (reloc_info[enclosing->target_index].linenos
+ linoff);
bfd_coff_swap_lineno_in (abfd, (PTR) linpstart, (PTR) &lin);
if (lin.l_lnno == 0
&& ((bfd_size_type) lin.l_addr.l_symndx
== ((esym
- (bfd_byte *) obj_coff_external_syms (abfd))
/ symesz)))
{
bfd_byte *linpend, *linp;
linpend = (reloc_info[enclosing->target_index].linenos
+ enclosing->lineno_count * linesz);
for (linp = linpstart + linesz;
linp < linpend;
linp += linesz)
{
bfd_coff_swap_lineno_in (abfd, (PTR) linp,
(PTR) &lin);
if (lin.l_lnno == 0)
break;
}
csect->lineno_count += (linp - linpstart) / linesz;
/* The setting of line_filepos will only be
useful if all the line number entries for a
csect are contiguous; this only matters for
error reporting. */
if (csect->line_filepos == 0)
csect->line_filepos =
auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr;
}
}
}
}
/* Pick up the csect auxiliary information. */
if (sym.n_numaux == 0)
{
(*_bfd_error_handler)
(_("%s: class %d symbol `%s' has no aux entries"),
bfd_get_filename (abfd), sym.n_sclass, name);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
bfd_coff_swap_aux_in (abfd,
(PTR) (esym + symesz * sym.n_numaux),
sym.n_type, sym.n_sclass,
sym.n_numaux - 1, sym.n_numaux,
(PTR) &aux);
smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp);
flags = BSF_GLOBAL;
section = NULL;
value = 0;
set_toc = NULL;
switch (smtyp)
{
default:
(*_bfd_error_handler)
(_("%s: symbol `%s' has unrecognized csect type %d"),
bfd_get_filename (abfd), name, smtyp);
bfd_set_error (bfd_error_bad_value);
goto error_return;
case XTY_ER:
/* This is an external reference. */
if (sym.n_sclass == C_HIDEXT
|| sym.n_scnum != N_UNDEF
|| aux.x_csect.x_scnlen.l != 0)
{
(*_bfd_error_handler)
(_("%s: bad XTY_ER symbol `%s': class %d scnum %d scnlen %d"),
bfd_get_filename (abfd), name, sym.n_sclass, sym.n_scnum,
aux.x_csect.x_scnlen.l);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
/* An XMC_XO external reference is actually a reference to
an absolute location. */
if (aux.x_csect.x_smclas != XMC_XO)
section = bfd_und_section_ptr;
else
{
section = bfd_abs_section_ptr;
value = sym.n_value;
}
break;
case XTY_SD:
/* This is a csect definition. */
if (csect != NULL)
{
xcoff_section_data (abfd, csect)->last_symndx =
((esym
- (bfd_byte *) obj_coff_external_syms (abfd))
/ symesz);
}
csect = NULL;
csect_index = -1;
/* When we see a TOC anchor, we record the TOC value. */
if (aux.x_csect.x_smclas == XMC_TC0)
{
if (sym.n_sclass != C_HIDEXT
|| aux.x_csect.x_scnlen.l != 0)
{
(*_bfd_error_handler)
(_("%s: XMC_TC0 symbol `%s' is class %d scnlen %d"),
bfd_get_filename (abfd), name, sym.n_sclass,
aux.x_csect.x_scnlen.l);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
xcoff_data (abfd)->toc = sym.n_value;
}
/* We must merge TOC entries for the same symbol. We can
merge two TOC entries if they are both C_HIDEXT, they
both have the same name, they are both 4 bytes long, and
they both have a relocation table entry for an external
symbol with the same name. Unfortunately, this means
that we must look through the relocations. Ick. */
if (aux.x_csect.x_smclas == XMC_TC
&& sym.n_sclass == C_HIDEXT
&& aux.x_csect.x_scnlen.l == 4
&& info->hash->creator == abfd->xvec)
{
asection *enclosing;
struct internal_reloc *relocs;
bfd_size_type relindx;
struct internal_reloc *rel;
enclosing = coff_section_from_bfd_index (abfd, sym.n_scnum);
if (enclosing == NULL)
goto error_return;
relocs = reloc_info[enclosing->target_index].relocs;
relindx = xcoff_find_reloc (relocs, enclosing->reloc_count,
sym.n_value);
rel = relocs + relindx;
if (relindx < enclosing->reloc_count
&& rel->r_vaddr == (bfd_vma) sym.n_value
&& rel->r_size == 31
&& rel->r_type == R_POS)
{
bfd_byte *erelsym;
struct internal_syment relsym;
erelsym = ((bfd_byte *) obj_coff_external_syms (abfd)
+ rel->r_symndx * symesz);
bfd_coff_swap_sym_in (abfd, (PTR) erelsym, (PTR) &relsym);
if (relsym.n_sclass == C_EXT)
{
const char *relname;
char relbuf[SYMNMLEN + 1];
boolean copy;
struct xcoff_link_hash_entry *h;
/* At this point we know that the TOC entry is
for an externally visible symbol. */
relname = _bfd_coff_internal_syment_name (abfd, &relsym,
relbuf);
if (relname == NULL)
goto error_return;
/* We only merge TOC entries if the TC name is
the same as the symbol name. This handles
the normal case, but not common cases like
SYM.P4 which gcc generates to store SYM + 4
in the TOC. FIXME. */
if (strcmp (name, relname) == 0)
{
copy = (! info->keep_memory
|| relsym._n._n_n._n_zeroes != 0
|| relsym._n._n_n._n_offset == 0);
h = xcoff_link_hash_lookup (xcoff_hash_table (info),
relname, true, copy,
false);
if (h == NULL)
goto error_return;
/* At this point h->root.type could be
bfd_link_hash_new. That should be OK,
since we know for sure that we will come
across this symbol as we step through the
file. */
/* We store h in *sym_hash for the
convenience of the relocate_section
function. */
*sym_hash = h;
if (h->toc_section != NULL)
{
asection **rel_csects;
/* We already have a TOC entry for this
symbol, so we can just ignore this
one. */
rel_csects =
reloc_info[enclosing->target_index].csects;
rel_csects[relindx] = bfd_und_section_ptr;
break;
}
/* We are about to create a TOC entry for
this symbol. */
set_toc = h;
}
}
}
}
/* We need to create a new section. We get the name from
the csect storage mapping class, so that the linker can
accumulate similar csects together. */
{
static const char *csect_name_by_class[] = {
".pr", ".ro", ".db", ".tc", ".ua", ".rw", ".gl", ".xo",
".sv", ".bs", ".ds", ".uc", ".ti", ".tb", NULL, ".tc0",
".td"
};
const char *csect_name;
asection *enclosing;
if ((aux.x_csect.x_smclas >=
sizeof csect_name_by_class / sizeof csect_name_by_class[0])
|| csect_name_by_class[aux.x_csect.x_smclas] == NULL)
{
(*_bfd_error_handler)
(_("%s: symbol `%s' has unrecognized smclas %d"),
bfd_get_filename (abfd), name, aux.x_csect.x_smclas);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
csect_name = csect_name_by_class[aux.x_csect.x_smclas];
csect = bfd_make_section_anyway (abfd, csect_name);
if (csect == NULL)
goto error_return;
enclosing = coff_section_from_bfd_index (abfd, sym.n_scnum);
if (enclosing == NULL)
goto error_return;
if (! bfd_is_abs_section (enclosing)
&& ((bfd_vma) sym.n_value < enclosing->vma
|| ((bfd_vma) sym.n_value + aux.x_csect.x_scnlen.l
> enclosing->vma + enclosing->_raw_size)))
{
(*_bfd_error_handler)
(_("%s: csect `%s' not in enclosing section"),
bfd_get_filename (abfd), name);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
csect->vma = sym.n_value;
csect->filepos = (enclosing->filepos
+ sym.n_value
- enclosing->vma);
csect->_raw_size = aux.x_csect.x_scnlen.l;
csect->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS;
csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp);
/* Record the enclosing section in the tdata for this new
section. */
csect->used_by_bfd =
(PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata));
if (csect->used_by_bfd == NULL)
goto error_return;
coff_section_data (abfd, csect)->tdata =
bfd_zalloc (abfd, sizeof (struct xcoff_section_tdata));
if (coff_section_data (abfd, csect)->tdata == NULL)
goto error_return;
xcoff_section_data (abfd, csect)->enclosing = enclosing;
xcoff_section_data (abfd, csect)->lineno_count =
enclosing->lineno_count;
if (enclosing->owner == abfd)
{
struct internal_reloc *relocs;
bfd_size_type relindx;
struct internal_reloc *rel;
asection **rel_csect;
relocs = reloc_info[enclosing->target_index].relocs;
relindx = xcoff_find_reloc (relocs, enclosing->reloc_count,
csect->vma);
rel = relocs + relindx;
rel_csect = (reloc_info[enclosing->target_index].csects
+ relindx);
csect->rel_filepos = (enclosing->rel_filepos
+ relindx * bfd_coff_relsz (abfd));
while (relindx < enclosing->reloc_count
&& *rel_csect == NULL
&& rel->r_vaddr < csect->vma + csect->_raw_size)
{
*rel_csect = csect;
csect->flags |= SEC_RELOC;
++csect->reloc_count;
++relindx;
++rel;
++rel_csect;
}
}
/* There are a number of other fields and section flags
which we do not bother to set. */
csect_index = ((esym
- (bfd_byte *) obj_coff_external_syms (abfd))
/ symesz);
xcoff_section_data (abfd, csect)->first_symndx = csect_index;
if (first_csect == NULL)
first_csect = csect;
/* If this symbol is C_EXT, we treat it as starting at the
beginning of the newly created section. */
if (sym.n_sclass == C_EXT)
{
section = csect;
value = 0;
}
/* If this is a TOC section for a symbol, record it. */
if (set_toc != NULL)
set_toc->toc_section = csect;
}
break;
case XTY_LD:
/* This is a label definition. The x_scnlen field is the
symbol index of the csect. I believe that this must
always follow the appropriate XTY_SD symbol, so I will
insist on it. */
{
boolean bad;
bad = false;
if (aux.x_csect.x_scnlen.l < 0
|| (aux.x_csect.x_scnlen.l
>= esym - (bfd_byte *) obj_coff_external_syms (abfd)))
bad = true;
if (! bad)
{
section = xcoff_data (abfd)->csects[aux.x_csect.x_scnlen.l];
if (section == NULL
|| (section->flags & SEC_HAS_CONTENTS) == 0)
bad = true;
}
if (bad)
{
(*_bfd_error_handler)
(_("%s: misplaced XTY_LD `%s'"),
bfd_get_filename (abfd), name);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
value = sym.n_value - csect->vma;
}
break;
case XTY_CM:
/* This is an unitialized csect. We could base the name on
the storage mapping class, but we don't bother except for
an XMC_TD symbol. If this csect is externally visible,
it is a common symbol. We put XMC_TD symbols in sections
named .tocbss, and rely on the linker script to put that
in the TOC area. */
if (csect != NULL)
{
xcoff_section_data (abfd, csect)->last_symndx =
((esym
- (bfd_byte *) obj_coff_external_syms (abfd))
/ symesz);
}
if (aux.x_csect.x_smclas == XMC_TD)
csect = bfd_make_section_anyway (abfd, ".tocbss");
else
csect = bfd_make_section_anyway (abfd, ".bss");
if (csect == NULL)
goto error_return;
csect->vma = sym.n_value;
csect->_raw_size = aux.x_csect.x_scnlen.l;
csect->flags |= SEC_ALLOC;
csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp);
/* There are a number of other fields and section flags
which we do not bother to set. */
csect_index = ((esym
- (bfd_byte *) obj_coff_external_syms (abfd))
/ symesz);
csect->used_by_bfd =
(PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata));
if (csect->used_by_bfd == NULL)
goto error_return;
coff_section_data (abfd, csect)->tdata =
bfd_zalloc (abfd, sizeof (struct xcoff_section_tdata));
if (coff_section_data (abfd, csect)->tdata == NULL)
goto error_return;
xcoff_section_data (abfd, csect)->first_symndx = csect_index;
if (first_csect == NULL)
first_csect = csect;
if (sym.n_sclass == C_EXT)
{
csect->flags |= SEC_IS_COMMON;
csect->_raw_size = 0;
section = csect;
value = aux.x_csect.x_scnlen.l;
}
break;
}
/* Check for magic symbol names. */
if ((smtyp == XTY_SD || smtyp == XTY_CM)
&& aux.x_csect.x_smclas != XMC_TC
&& aux.x_csect.x_smclas != XMC_TD)
{
int i;
i = -1;
if (name[0] == '_')
{
if (strcmp (name, "_text") == 0)
i = 0;
else if (strcmp (name, "_etext") == 0)
i = 1;
else if (strcmp (name, "_data") == 0)
i = 2;
else if (strcmp (name, "_edata") == 0)
i = 3;
else if (strcmp (name, "_end") == 0)
i = 4;
}
else if (name[0] == 'e' && strcmp (name, "end") == 0)
i = 5;
if (i != -1)
xcoff_hash_table (info)->special_sections[i] = csect;
}
/* Now we have enough information to add the symbol to the
linker hash table. */
if (sym.n_sclass == C_EXT)
{
boolean copy;
BFD_ASSERT (section != NULL);
/* We must copy the name into memory if we got it from the
syment itself, rather than the string table. */
copy = default_copy;
if (sym._n._n_n._n_zeroes != 0
|| sym._n._n_n._n_offset == 0)
copy = true;
/* The AIX linker appears to only detect multiple symbol
definitions when there is a reference to the symbol. If
a symbol is defined multiple times, and the only
references are from the same object file, the AIX linker
appears to permit it. It does not merge the different
definitions, but handles them independently. On the
other hand, if there is a reference, the linker reports
an error.
This matters because the AIX <net/net_globals.h> header
file actually defines an initialized array, so we have to
actually permit that to work.
Just to make matters even more confusing, the AIX linker
appears to permit multiple symbol definitions whenever
the second definition is in an archive rather than an
object file. This may be a consequence of the manner in
which it handles archives: I think it may load the entire
archive in as separate csects, and then let garbage
collection discard symbols.
We also have to handle the case of statically linking a
shared object, which will cause symbol redefinitions,
although this is an easier case to detect. */
if (info->hash->creator == abfd->xvec)
{
if (! bfd_is_und_section (section))
*sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info),
name, true, copy, false);
else
*sym_hash = ((struct xcoff_link_hash_entry *)
bfd_wrapped_link_hash_lookup (abfd, info, name,
true, copy, false));
if (*sym_hash == NULL)
goto error_return;
if (((*sym_hash)->root.type == bfd_link_hash_defined
|| (*sym_hash)->root.type == bfd_link_hash_defweak)
&& ! bfd_is_und_section (section)
&& ! bfd_is_com_section (section))
{
/* This is a second definition of a defined symbol. */
if ((abfd->flags & DYNAMIC) != 0
&& ((*sym_hash)->smclas != XMC_GL
|| aux.x_csect.x_smclas == XMC_GL
|| ((*sym_hash)->root.u.def.section->owner->flags
& DYNAMIC) == 0))
{
/* The new symbol is from a shared library, and
either the existing symbol is not global
linkage code or this symbol is global linkage
code. If the existing symbol is global
linkage code and the new symbol is not, then
we want to use the new symbol. */
section = bfd_und_section_ptr;
value = 0;
}
else if (((*sym_hash)->root.u.def.section->owner->flags
& DYNAMIC) != 0)
{
/* The existing symbol is from a shared library.
Replace it. */
(*sym_hash)->root.type = bfd_link_hash_undefined;
(*sym_hash)->root.u.undef.abfd =
(*sym_hash)->root.u.def.section->owner;
}
else if (abfd->my_archive != NULL)
{
/* This is a redefinition in an object contained
in an archive. Just ignore it. See the
comment above. */
section = bfd_und_section_ptr;
value = 0;
}
else if ((*sym_hash)->root.next != NULL
|| info->hash->undefs_tail == &(*sym_hash)->root)
{
/* This symbol has been referenced. In this
case, we just continue and permit the
multiple definition error. See the comment
above about the behaviour of the AIX linker. */
}
else if ((*sym_hash)->smclas == aux.x_csect.x_smclas)
{
/* The symbols are both csects of the same
class. There is at least a chance that this
is a semi-legitimate redefinition. */
section = bfd_und_section_ptr;
value = 0;
(*sym_hash)->flags |= XCOFF_MULTIPLY_DEFINED;
}
}
else if (((*sym_hash)->flags & XCOFF_MULTIPLY_DEFINED) != 0
&& ((*sym_hash)->root.type == bfd_link_hash_defined
|| (*sym_hash)->root.type == bfd_link_hash_defweak)
&& (bfd_is_und_section (section)
|| bfd_is_com_section (section)))
{
/* This is a reference to a multiply defined symbol.
Report the error now. See the comment above
about the behaviour of the AIX linker. We could
also do this with warning symbols, but I'm not
sure the XCOFF linker is wholly prepared to
handle them, and that would only be a warning,
not an error. */
if (! ((*info->callbacks->multiple_definition)
(info, (*sym_hash)->root.root.string,
(bfd *) NULL, (asection *) NULL, 0,
(*sym_hash)->root.u.def.section->owner,
(*sym_hash)->root.u.def.section,
(*sym_hash)->root.u.def.value)))
goto error_return;
/* Try not to give this error too many times. */
(*sym_hash)->flags &= ~XCOFF_MULTIPLY_DEFINED;
}
}
/* _bfd_generic_link_add_one_symbol may call the linker to
generate an error message, and the linker may try to read
the symbol table to give a good error. Right now, the
line numbers are in an inconsistent state, since they are
counted both in the real sections and in the new csects.
We need to leave the count in the real sections so that
the linker can report the line number of the error
correctly, so temporarily clobber the link to the csects
so that the linker will not try to read the line numbers
a second time from the csects. */
BFD_ASSERT (last_real->next == first_csect);
last_real->next = NULL;
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, name, flags, section, value,
(const char *) NULL, copy, true,
(struct bfd_link_hash_entry **) sym_hash)))
goto error_return;
last_real->next = first_csect;
if (smtyp == XTY_CM)
{
if ((*sym_hash)->root.type != bfd_link_hash_common
|| (*sym_hash)->root.u.c.p->section != csect)
{
/* We don't need the common csect we just created. */
csect->_raw_size = 0;
}
else
{
(*sym_hash)->root.u.c.p->alignment_power
= csect->alignment_power;
}
}
if (info->hash->creator == abfd->xvec)
{
int flag;
if (smtyp == XTY_ER || smtyp == XTY_CM)
flag = XCOFF_REF_REGULAR;
else
flag = XCOFF_DEF_REGULAR;
(*sym_hash)->flags |= flag;
if ((*sym_hash)->smclas == XMC_UA
|| flag == XCOFF_DEF_REGULAR)
(*sym_hash)->smclas = aux.x_csect.x_smclas;
}
}
*csect_cache = csect;
esym += (sym.n_numaux + 1) * symesz;
sym_hash += sym.n_numaux + 1;
csect_cache += sym.n_numaux + 1;
}
BFD_ASSERT (last_real == NULL || last_real->next == first_csect);
/* Make sure that we have seen all the relocs. */
for (o = abfd->sections; o != first_csect; o = o->next)
{
/* Reset the section size and the line number count, since the
data is now attached to the csects. Don't reset the size of
the .debug section, since we need to read it below in
bfd_xcoff_size_dynamic_sections. */
if (strcmp (bfd_get_section_name (abfd, o), ".debug") != 0)
o->_raw_size = 0;
o->lineno_count = 0;
if ((o->flags & SEC_RELOC) != 0)
{
bfd_size_type i;
struct internal_reloc *rel;
asection **rel_csect;
rel = reloc_info[o->target_index].relocs;
rel_csect = reloc_info[o->target_index].csects;
for (i = 0; i < o->reloc_count; i++, rel++, rel_csect++)
{
if (*rel_csect == NULL)
{
(*_bfd_error_handler)
(_("%s: reloc %s:%d not in csect"),
bfd_get_filename (abfd), o->name, i);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
/* We identify all symbols which are called, so that we
can create glue code for calls to functions imported
from dynamic objects. */
if (info->hash->creator == abfd->xvec
&& *rel_csect != bfd_und_section_ptr
&& (rel->r_type == R_BR
|| rel->r_type == R_RBR)
&& obj_xcoff_sym_hashes (abfd)[rel->r_symndx] != NULL)
{
struct xcoff_link_hash_entry *h;
h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx];
h->flags |= XCOFF_CALLED;
/* If the symbol name starts with a period, it is
the code of a function. If the symbol is
currently undefined, then add an undefined symbol
for the function descriptor. This should do no
harm, because any regular object that defines the
function should also define the function
descriptor. It helps, because it means that we
will identify the function descriptor with a
dynamic object if a dynamic object defines it. */
if (h->root.root.string[0] == '.'
&& h->descriptor == NULL)
{
struct xcoff_link_hash_entry *hds;
hds = xcoff_link_hash_lookup (xcoff_hash_table (info),
h->root.root.string + 1,
true, false, true);
if (hds == NULL)
goto error_return;
if (hds->root.type == bfd_link_hash_new)
{
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, hds->root.root.string,
(flagword) 0, bfd_und_section_ptr,
(bfd_vma) 0, (const char *) NULL, false,
true,
(struct bfd_link_hash_entry **) &hds)))
goto error_return;
}
hds->flags |= XCOFF_DESCRIPTOR;
BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0
&& (h->flags & XCOFF_DESCRIPTOR) == 0);
hds->descriptor = h;
h->descriptor = hds;
}
}
}
free (reloc_info[o->target_index].csects);
reloc_info[o->target_index].csects = NULL;
/* Reset SEC_RELOC and the reloc_count, since the reloc
information is now attached to the csects. */
o->flags &= ~SEC_RELOC;
o->reloc_count = 0;
/* If we are not keeping memory, free the reloc information. */
if (! info->keep_memory
&& coff_section_data (abfd, o) != NULL
&& coff_section_data (abfd, o)->relocs != NULL
&& ! coff_section_data (abfd, o)->keep_relocs)
{
free (coff_section_data (abfd, o)->relocs);
coff_section_data (abfd, o)->relocs = NULL;
}
}
/* Free up the line numbers. FIXME: We could cache these
somewhere for the final link, to avoid reading them again. */
if (reloc_info[o->target_index].linenos != NULL)
{
free (reloc_info[o->target_index].linenos);
reloc_info[o->target_index].linenos = NULL;
}
}
free (reloc_info);
obj_coff_keep_syms (abfd) = keep_syms;
return true;
error_return:
if (reloc_info != NULL)
{
for (o = abfd->sections; o != NULL; o = o->next)
{
if (reloc_info[o->target_index].csects != NULL)
free (reloc_info[o->target_index].csects);
if (reloc_info[o->target_index].linenos != NULL)
free (reloc_info[o->target_index].linenos);
}
free (reloc_info);
}
obj_coff_keep_syms (abfd) = keep_syms;
return false;
}
#undef N_TMASK
#undef N_BTSHFT
/* This function is used to add symbols from a dynamic object to the
global symbol table. */
static boolean
xcoff_link_add_dynamic_symbols (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
asection *lsec;
bfd_byte *buf;
struct internal_ldhdr ldhdr;
const char *strings;
struct external_ldsym *elsym, *elsymend;
struct xcoff_import_file *n;
const char *bname;
const char *mname;
const char *s;
unsigned int c;
struct xcoff_import_file **pp;
/* We can only handle a dynamic object if we are generating an XCOFF
output file. */
if (info->hash->creator != abfd->xvec)
{
(*_bfd_error_handler)
(_("%s: XCOFF shared object when not producing XCOFF output"),
bfd_get_filename (abfd));
bfd_set_error (bfd_error_invalid_operation);
return false;
}
/* The symbols we use from a dynamic object are not the symbols in
the normal symbol table, but, rather, the symbols in the export
table. If there is a global symbol in a dynamic object which is
not in the export table, the loader will not be able to find it,
so we don't want to find it either. Also, on AIX 4.1.3, shr.o in
libc.a has symbols in the export table which are not in the
symbol table. */
/* Read in the .loader section. FIXME: We should really use the
o_snloader field in the a.out header, rather than grabbing the
section by name. */
lsec = bfd_get_section_by_name (abfd, ".loader");
if (lsec == NULL)
{
(*_bfd_error_handler)
(_("%s: dynamic object with no .loader section"),
bfd_get_filename (abfd));
bfd_set_error (bfd_error_no_symbols);
return false;
}
if (! xcoff_get_section_contents (abfd, lsec))
return false;
buf = coff_section_data (abfd, lsec)->contents;
/* Remove the sections from this object, so that they do not get
included in the link. */
abfd->sections = NULL;
xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) buf, &ldhdr);
strings = (char *) buf + ldhdr.l_stoff;
elsym = (struct external_ldsym *) (buf + LDHDRSZ);
elsymend = elsym + ldhdr.l_nsyms;
BFD_ASSERT (sizeof (struct external_ldsym) == LDSYMSZ);
for (; elsym < elsymend; elsym++)
{
struct internal_ldsym ldsym;
char nambuf[SYMNMLEN + 1];
const char *name;
struct xcoff_link_hash_entry *h;
xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
/* We are only interested in exported symbols. */
if ((ldsym.l_smtype & L_EXPORT) == 0)
continue;
if (ldsym._l._l_l._l_zeroes == 0)
name = strings + ldsym._l._l_l._l_offset;
else
{
memcpy (nambuf, ldsym._l._l_name, SYMNMLEN);
nambuf[SYMNMLEN] = '\0';
name = nambuf;
}
/* Normally we could not call xcoff_link_hash_lookup in an add
symbols routine, since we might not be using an XCOFF hash
table. However, we verified above that we are using an XCOFF
hash table. */
h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true,
true, true);
if (h == NULL)
return false;
h->flags |= XCOFF_DEF_DYNAMIC;
/* If the symbol is undefined, and the BFD it was found in is
not a dynamic object, change the BFD to this dynamic object,
so that we can get the correct import file ID. */
if ((h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak)
&& (h->root.u.undef.abfd == NULL
|| (h->root.u.undef.abfd->flags & DYNAMIC) == 0))
h->root.u.undef.abfd = abfd;
if (h->root.type == bfd_link_hash_new)
{
h->root.type = bfd_link_hash_undefined;
h->root.u.undef.abfd = abfd;
/* We do not want to add this to the undefined symbol list. */
}
if (h->smclas == XMC_UA
|| h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak)
h->smclas = ldsym.l_smclas;
/* Unless this is an XMC_XO symbol, we don't bother to actually
define it, since we don't have a section to put it in anyhow.
Instead, the relocation routines handle the DEF_DYNAMIC flag
correctly. */
if (h->smclas == XMC_XO
&& (h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak))
{
/* This symbol has an absolute value. */
h->root.type = bfd_link_hash_defined;
h->root.u.def.section = bfd_abs_section_ptr;
h->root.u.def.value = ldsym.l_value;
}
/* If this symbol defines a function descriptor, then it
implicitly defines the function code as well. */
if (h->smclas == XMC_DS
|| (h->smclas == XMC_XO && name[0] != '.'))
h->flags |= XCOFF_DESCRIPTOR;
if ((h->flags & XCOFF_DESCRIPTOR) != 0)
{
struct xcoff_link_hash_entry *hds;
hds = h->descriptor;
if (hds == NULL)
{
char *dsnm;
dsnm = bfd_malloc (strlen (name) + 2);
if (dsnm == NULL)
return false;
dsnm[0] = '.';
strcpy (dsnm + 1, name);
hds = xcoff_link_hash_lookup (xcoff_hash_table (info), dsnm,
true, true, true);
free (dsnm);
if (hds == NULL)
return false;
if (hds->root.type == bfd_link_hash_new)
{
hds->root.type = bfd_link_hash_undefined;
hds->root.u.undef.abfd = abfd;
/* We do not want to add this to the undefined
symbol list. */
}
hds->descriptor = h;
h->descriptor = hds;
}
hds->flags |= XCOFF_DEF_DYNAMIC;
if (hds->smclas == XMC_UA)
hds->smclas = XMC_PR;
/* An absolute symbol appears to actually define code, not a
function descriptor. This is how some math functions are
implemented on AIX 4.1. */
if (h->smclas == XMC_XO
&& (hds->root.type == bfd_link_hash_undefined
|| hds->root.type == bfd_link_hash_undefweak))
{
hds->smclas = XMC_XO;
hds->root.type = bfd_link_hash_defined;
hds->root.u.def.section = bfd_abs_section_ptr;
hds->root.u.def.value = ldsym.l_value;
}
}
}
if (buf != NULL && ! coff_section_data (abfd, lsec)->keep_contents)
{
free (coff_section_data (abfd, lsec)->contents);
coff_section_data (abfd, lsec)->contents = NULL;
}
/* Record this file in the import files. */
n = ((struct xcoff_import_file *)
bfd_alloc (abfd, sizeof (struct xcoff_import_file)));
if (n == NULL)
return false;
n->next = NULL;
/* For some reason, the path entry in the import file list for a
shared object appears to always be empty. The file name is the
base name. */
n->path = "";
if (abfd->my_archive == NULL)
{
bname = bfd_get_filename (abfd);
mname = "";
}
else
{
bname = bfd_get_filename (abfd->my_archive);
mname = bfd_get_filename (abfd);
}
s = strrchr (bname, '/');
if (s != NULL)
bname = s + 1;
n->file = bname;
n->member = mname;
/* We start c at 1 because the first import file number is reserved
for LIBPATH. */
for (pp = &xcoff_hash_table (info)->imports, c = 1;
*pp != NULL;
pp = &(*pp)->next, ++c)
;
*pp = n;
xcoff_data (abfd)->import_file_id = c;
return true;
}
/* Routines that are called after all the input files have been
handled, but before the sections are laid out in memory. */
/* Mark a symbol as not being garbage, including the section in which
it is defined. */
static INLINE boolean
xcoff_mark_symbol (info, h)
struct bfd_link_info *info;
struct xcoff_link_hash_entry *h;
{
if ((h->flags & XCOFF_MARK) != 0)
return true;
h->flags |= XCOFF_MARK;
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
asection *hsec;
hsec = h->root.u.def.section;
if (! bfd_is_abs_section (hsec)
&& (hsec->flags & SEC_MARK) == 0)
{
if (! xcoff_mark (info, hsec))
return false;
}
}
if (h->toc_section != NULL
&& (h->toc_section->flags & SEC_MARK) == 0)
{
if (! xcoff_mark (info, h->toc_section))
return false;
}
return true;
}
/* The mark phase of garbage collection. For a given section, mark
it, and all the sections which define symbols to which it refers.
Because this function needs to look at the relocs, we also count
the number of relocs which need to be copied into the .loader
section. */
static boolean
xcoff_mark (info, sec)
struct bfd_link_info *info;
asection *sec;
{
if (bfd_is_abs_section (sec)
|| (sec->flags & SEC_MARK) != 0)
return true;
sec->flags |= SEC_MARK;
if (sec->owner->xvec == info->hash->creator
&& coff_section_data (sec->owner, sec) != NULL
&& xcoff_section_data (sec->owner, sec) != NULL)
{
register struct xcoff_link_hash_entry **hp, **hpend;
struct internal_reloc *rel, *relend;
/* Mark all the symbols in this section. */
hp = (obj_xcoff_sym_hashes (sec->owner)
+ xcoff_section_data (sec->owner, sec)->first_symndx);
hpend = (obj_xcoff_sym_hashes (sec->owner)
+ xcoff_section_data (sec->owner, sec)->last_symndx);
for (; hp < hpend; hp++)
{
register struct xcoff_link_hash_entry *h;
h = *hp;
if (h != NULL
&& (h->flags & XCOFF_MARK) == 0)
{
if (! xcoff_mark_symbol (info, h))
return false;
}
}
/* Look through the section relocs. */
if ((sec->flags & SEC_RELOC) != 0
&& sec->reloc_count > 0)
{
rel = xcoff_read_internal_relocs (sec->owner, sec, true,
(bfd_byte *) NULL, false,
(struct internal_reloc *) NULL);
if (rel == NULL)
return false;
relend = rel + sec->reloc_count;
for (; rel < relend; rel++)
{
asection *rsec;
struct xcoff_link_hash_entry *h;
if ((unsigned int) rel->r_symndx
> obj_raw_syment_count (sec->owner))