* xcofflink.c: Numerous changes to get closer to a working XCOFF

linker.
	* libcoff-in.h (struct xcoff_tdata): Add full_aouthdr,
	toc_section, and entry_section fields.
	(struct xcoff_section_tdata): Remove ldrel_count field.
	* libcoff.h: Rebuild.
	* coffcode.h (coff_mkobject_hook): Initialize new xcoff_data
	fields.
	(coff_compute_section_file_positions): If RS6000COFF_C, generate
	full a.out header if full_aouthdr is set in xcoff_data.
	(coff_write_object_contents): Likewise.  Set o_snentry and o_sntoc
	based on sections stored in xcoff_data.
	* coff-rs6000.c (xcoff_copy_private_bfd_data): Copy new xcoff_data
	fields.
	* coffgen.c (coff_get_symbol_info): If fix_value is set, fix the
	value stored in ret rather than returning a pointer value.
This commit is contained in:
Ian Lance Taylor 1995-10-26 18:25:13 +00:00
parent 328e5a48e8
commit 867d923d18
7 changed files with 466 additions and 183 deletions

View File

@ -1,3 +1,22 @@
Thu Oct 26 14:16:47 1995 Ian Lance Taylor <ian@cygnus.com>
* xcofflink.c: Numerous changes to get closer to a working XCOFF
linker.
* libcoff-in.h (struct xcoff_tdata): Add full_aouthdr,
toc_section, and entry_section fields.
(struct xcoff_section_tdata): Remove ldrel_count field.
* libcoff.h: Rebuild.
* coffcode.h (coff_mkobject_hook): Initialize new xcoff_data
fields.
(coff_compute_section_file_positions): If RS6000COFF_C, generate
full a.out header if full_aouthdr is set in xcoff_data.
(coff_write_object_contents): Likewise. Set o_snentry and o_sntoc
based on sections stored in xcoff_data.
* coff-rs6000.c (xcoff_copy_private_bfd_data): Copy new xcoff_data
fields.
* coffgen.c (coff_get_symbol_info): If fix_value is set, fix the
value stored in ret rather than returning a pointer value.
Wed Oct 25 23:10:39 1995 Michael Meissner <meissner@tiktok.cygnus.com> Wed Oct 25 23:10:39 1995 Michael Meissner <meissner@tiktok.cygnus.com>
* config.bfd (powerpc{,le}-{elf,sysv4,eabi,solaris2}): Remove MAC * config.bfd (powerpc{,le}-{elf,sysv4,eabi,solaris2}): Remove MAC

View File

@ -102,7 +102,16 @@ xcoff_copy_private_bfd_data (ibfd, obfd)
return true; return true;
ix = xcoff_data (ibfd); ix = xcoff_data (ibfd);
ox = xcoff_data (obfd); ox = xcoff_data (obfd);
ox->full_aouthdr = ix->full_aouthdr;
ox->toc = ix->toc; ox->toc = ix->toc;
if (ix->toc_section == NULL)
ox->toc_section = NULL;
else
ox->toc_section = ix->toc_section->output_section;
if (ix->entry_section == NULL)
ox->entry_section = NULL;
else
ox->entry_section = ix->entry_section->output_section;
ox->text_align_power = ix->text_align_power; ox->text_align_power = ix->text_align_power;
ox->data_align_power = ix->data_align_power; ox->data_align_power = ix->data_align_power;
ox->modtype = ix->modtype; ox->modtype = ix->modtype;

View File

@ -1002,7 +1002,18 @@ coff_mkobject_hook (abfd, filehdr, aouthdr)
struct xcoff_tdata *xcoff; struct xcoff_tdata *xcoff;
xcoff = xcoff_data (abfd); xcoff = xcoff_data (abfd);
xcoff->full_aouthdr = true;
xcoff->toc = internal_a->o_toc; xcoff->toc = internal_a->o_toc;
if (internal_a->o_sntoc == 0)
xcoff->toc_section = NULL;
else
xcoff->toc_section =
coff_section_from_bfd_index (abfd, internal_a->o_sntoc);
if (internal_a->o_snentry == 0)
xcoff->entry_section = NULL;
else
xcoff->entry_section =
coff_section_from_bfd_index (abfd, internal_a->o_snentry);
xcoff->text_align_power = internal_a->o_algntext; xcoff->text_align_power = internal_a->o_algntext;
xcoff->data_align_power = internal_a->o_algndata; xcoff->data_align_power = internal_a->o_algndata;
xcoff->modtype = internal_a->o_modtype; xcoff->modtype = internal_a->o_modtype;
@ -1764,6 +1775,8 @@ coff_compute_section_file_positions (abfd)
if (abfd->flags & EXEC_P) if (abfd->flags & EXEC_P)
sofar += AOUTSZ; sofar += AOUTSZ;
#ifdef RS6000COFF_C #ifdef RS6000COFF_C
else if (xcoff_data (abfd)->full_aouthdr)
sofar += AOUTSZ;
else else
sofar += SMALL_AOUTSZ; sofar += SMALL_AOUTSZ;
#endif #endif
@ -2003,7 +2016,10 @@ coff_write_object_contents (abfd)
{ {
scn_base = FILHSZ; scn_base = FILHSZ;
#ifdef RS6000COFF_C #ifdef RS6000COFF_C
scn_base += SMALL_AOUTSZ; if (xcoff_data (abfd)->full_aouthdr)
scn_base += AOUTSZ;
else
scn_base += SMALL_AOUTSZ;
#endif #endif
} }
@ -2135,8 +2151,10 @@ coff_write_object_contents (abfd)
{ {
internal_f.f_opthdr = 0; internal_f.f_opthdr = 0;
#ifdef RS6000COFF_C #ifdef RS6000COFF_C
/* XCOFF seems to always write at least a small a.out header. */ if (xcoff_data (abfd)->full_aouthdr)
internal_f.f_opthdr = SMALL_AOUTSZ; internal_f.f_opthdr = AOUTSZ;
else
internal_f.f_opthdr = SMALL_AOUTSZ;
#endif #endif
} }
@ -2311,22 +2329,20 @@ coff_write_object_contents (abfd)
internal_f.f_nsyms = obj_raw_syment_count (abfd); internal_f.f_nsyms = obj_raw_syment_count (abfd);
#ifdef RS6000COFF_C #ifdef RS6000COFF_C
if ((abfd->flags & EXEC_P) != 0) if (xcoff_data (abfd)->full_aouthdr)
{ {
bfd_vma entry, toc; bfd_vma toc;
asection *loader_sec; asection *loader_sec;
entry = bfd_get_start_address (abfd); if (xcoff_data (abfd)->entry_section != NULL)
if (text_sec != NULL internal_a.o_snentry = xcoff_data (abfd)->entry_section->target_index;
&& entry >= text_sec->vma
&& entry < text_sec->vma + bfd_section_size (abfd, text_sec))
internal_a.o_snentry = text_sec->target_index;
else if (data_sec != NULL
&& entry >= data_sec->vma
&& entry < data_sec->vma + bfd_section_size (abfd, data_sec))
internal_a.o_snentry = data_sec->target_index;
else else
internal_a.o_snentry = 0; {
internal_a.o_snentry = 0;
if (internal_a.entry == 0)
internal_a.entry = (bfd_vma) -1;
}
if (text_sec != NULL) if (text_sec != NULL)
{ {
internal_a.o_sntext = text_sec->target_index; internal_a.o_sntext = text_sec->target_index;
@ -2359,16 +2375,10 @@ coff_write_object_contents (abfd)
toc = xcoff_data (abfd)->toc; toc = xcoff_data (abfd)->toc;
internal_a.o_toc = toc; internal_a.o_toc = toc;
if (text_sec != NULL if (xcoff_data (abfd)->toc_section == NULL)
&& toc >= text_sec->vma
&& toc < text_sec->vma + bfd_section_size (abfd, text_sec))
internal_a.o_sntoc = text_sec->target_index;
else if (data_sec != NULL
&& toc >= data_sec->vma
&& toc < data_sec->vma + bfd_section_size (abfd, data_sec))
internal_a.o_sntoc = data_sec->target_index;
else
internal_a.o_sntoc = 0; internal_a.o_sntoc = 0;
else
internal_a.o_sntoc = xcoff_data (abfd)->toc_section->target_index;
internal_a.o_modtype = xcoff_data (abfd)->modtype; internal_a.o_modtype = xcoff_data (abfd)->modtype;
if (xcoff_data (abfd)->cputype != -1) if (xcoff_data (abfd)->cputype != -1)
@ -2415,9 +2425,15 @@ coff_write_object_contents (abfd)
else else
{ {
AOUTHDR buff; AOUTHDR buff;
size_t size;
/* XCOFF seems to always write at least a small a.out header. */ /* XCOFF seems to always write at least a small a.out header. */
coff_swap_aouthdr_out (abfd, (PTR) &internal_a, (PTR) &buff); coff_swap_aouthdr_out (abfd, (PTR) &internal_a, (PTR) &buff);
if (bfd_write ((PTR) &buff, 1, SMALL_AOUTSZ, abfd) != SMALL_AOUTSZ) if (xcoff_data (abfd)->full_aouthdr)
size = AOUTSZ;
else
size = SMALL_AOUTSZ;
if (bfd_write ((PTR) &buff, 1, size, abfd) != size)
return false; return false;
} }
#endif #endif

View File

@ -329,6 +329,147 @@ coff_get_symtab (abfd, alocation)
return bfd_get_symcount (abfd); return bfd_get_symcount (abfd);
} }
/* Get the name of a symbol. The caller must pass in a buffer of size
>= SYMNMLEN + 1. */
const char *
_bfd_coff_internal_syment_name (abfd, sym, buf)
bfd *abfd;
const struct internal_syment *sym;
char *buf;
{
/* FIXME: It's not clear this will work correctly if sizeof
(_n_zeroes) != 4. */
if (sym->_n._n_n._n_zeroes != 0
|| sym->_n._n_n._n_offset == 0)
{
memcpy (buf, sym->_n._n_name, SYMNMLEN);
buf[SYMNMLEN] = '\0';
return buf;
}
else
{
const char *strings;
BFD_ASSERT (sym->_n._n_n._n_offset >= STRING_SIZE_SIZE);
strings = obj_coff_strings (abfd);
if (strings == NULL)
{
strings = _bfd_coff_read_string_table (abfd);
if (strings == NULL)
return NULL;
}
return strings + sym->_n._n_n._n_offset;
}
}
/* Read in and swap the relocs. This returns a buffer holding the
relocs for section SEC in file ABFD. If CACHE is true and
INTERNAL_RELOCS is NULL, the relocs read in will be saved in case
the function is called again. If EXTERNAL_RELOCS is not NULL, it
is a buffer large enough to hold the unswapped relocs. If
INTERNAL_RELOCS is not NULL, it is a buffer large enough to hold
the swapped relocs. If REQUIRE_INTERNAL is true, then the return
value must be INTERNAL_RELOCS. The function returns NULL on error. */
struct internal_reloc *
_bfd_coff_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;
{
bfd_size_type relsz;
bfd_byte *free_external = NULL;
struct internal_reloc *free_internal = NULL;
bfd_byte *erel;
bfd_byte *erel_end;
struct internal_reloc *irel;
if (coff_section_data (abfd, sec) != NULL
&& coff_section_data (abfd, sec)->relocs != NULL)
{
if (! require_internal)
return coff_section_data (abfd, sec)->relocs;
memcpy (internal_relocs, coff_section_data (abfd, sec)->relocs,
sec->reloc_count * sizeof (struct internal_reloc));
return internal_relocs;
}
relsz = bfd_coff_relsz (abfd);
if (external_relocs == NULL)
{
free_external = (bfd_byte *) malloc (sec->reloc_count * relsz);
if (free_external == NULL && sec->reloc_count > 0)
{
bfd_set_error (bfd_error_no_memory);
goto error_return;
}
external_relocs = free_external;
}
if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
|| (bfd_read (external_relocs, relsz, sec->reloc_count, abfd)
!= relsz * sec->reloc_count))
goto error_return;
if (internal_relocs == NULL)
{
free_internal = ((struct internal_reloc *)
malloc (sec->reloc_count
* sizeof (struct internal_reloc)));
if (free_internal == NULL && sec->reloc_count > 0)
{
bfd_set_error (bfd_error_no_memory);
goto error_return;
}
internal_relocs = free_internal;
}
/* Swap in the relocs. */
erel = external_relocs;
erel_end = erel + relsz * sec->reloc_count;
irel = internal_relocs;
for (; erel < erel_end; erel += relsz, irel++)
bfd_coff_swap_reloc_in (abfd, (PTR) erel, (PTR) irel);
if (free_external != NULL)
{
free (free_external);
free_external = NULL;
}
if (cache && free_internal != NULL)
{
if (coff_section_data (abfd, sec) == NULL)
{
sec->used_by_bfd =
(PTR) bfd_zalloc (abfd,
sizeof (struct coff_section_tdata));
if (sec->used_by_bfd == NULL)
{
bfd_set_error (bfd_error_no_memory);
goto error_return;
}
coff_section_data (abfd, sec)->contents = NULL;
}
coff_section_data (abfd, sec)->relocs = free_internal;
}
return internal_relocs;
error_return:
if (free_external != NULL)
free (free_external);
if (free_internal != NULL)
free (free_internal);
return NULL;
}
/* Set lineno_count for the output sections of a COFF file. */ /* Set lineno_count for the output sections of a COFF file. */
int int
@ -1688,6 +1829,15 @@ coff_get_symbol_info (abfd, symbol, ret)
symbol_info *ret; symbol_info *ret;
{ {
bfd_symbol_info (symbol, ret); bfd_symbol_info (symbol, ret);
if (coffsymbol (symbol)->native != NULL
&& coffsymbol (symbol)->native->fix_value)
{
combined_entry_type *psym;
psym = ((combined_entry_type *)
coffsymbol (symbol)->native->u.syment.n_value);
ret->value = (bfd_vma) (psym - obj_raw_syments (abfd));
}
} }
/* Print out information about COFF symbol. */ /* Print out information about COFF symbol. */
@ -1974,7 +2124,7 @@ coff_find_nearest_line (abfd, section, ignore_symbols, offset, filename_ptr,
section->used_by_bfd = section->used_by_bfd =
((PTR) bfd_zalloc (abfd, ((PTR) bfd_zalloc (abfd,
sizeof (struct coff_section_tdata))); sizeof (struct coff_section_tdata)));
sec_data = section->used_by_bfd; sec_data = (struct coff_section_tdata *) section->used_by_bfd;
} }
if (sec_data != NULL) if (sec_data != NULL)
{ {

View File

@ -105,9 +105,18 @@ struct xcoff_tdata
/* Basic COFF information. */ /* Basic COFF information. */
coff_data_type coff; coff_data_type coff;
/* True if a large a.out header should be generated. */
boolean full_aouthdr;
/* TOC value. */ /* TOC value. */
bfd_vma toc; bfd_vma toc;
/* Section holding TOC. */
asection *toc_section;
/* Section holding entry point. */
asection *entry_section;
/* .text alignment from optional header. */ /* .text alignment from optional header. */
int text_align_power; int text_align_power;
@ -178,8 +187,6 @@ struct xcoff_section_tdata
by this csect. */ by this csect. */
unsigned long first_symndx; unsigned long first_symndx;
unsigned long last_symndx; unsigned long last_symndx;
/* The number of .loader relocs in this csect. */
size_t ldrel_count;
}; };
/* An accessor macro the xcoff_section_tdata structure. */ /* An accessor macro the xcoff_section_tdata structure. */

View File

@ -105,9 +105,18 @@ struct xcoff_tdata
/* Basic COFF information. */ /* Basic COFF information. */
coff_data_type coff; coff_data_type coff;
/* True if a large a.out header should be generated. */
boolean full_aouthdr;
/* TOC value. */ /* TOC value. */
bfd_vma toc; bfd_vma toc;
/* Section holding TOC. */
asection *toc_section;
/* Section holding entry point. */
asection *entry_section;
/* .text alignment from optional header. */ /* .text alignment from optional header. */
int text_align_power; int text_align_power;
@ -178,8 +187,6 @@ struct xcoff_section_tdata
by this csect. */ by this csect. */
unsigned long first_symndx; unsigned long first_symndx;
unsigned long last_symndx; unsigned long last_symndx;
/* The number of .loader relocs in this csect. */
size_t ldrel_count;
}; };
/* An accessor macro the xcoff_section_tdata structure. */ /* An accessor macro the xcoff_section_tdata structure. */

View File

@ -25,10 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "coff/internal.h" #include "coff/internal.h"
#include "libcoff.h" #include "libcoff.h"
/* This file holds the XCOFF linker code. A lot of it is very similar /* This file holds the XCOFF linker code. */
to the COFF linker code. However, it is different enough that I
chose to avoid trying to hack up the COFF code to support XCOFF.
That leads to a certain amount of duplicated code, alas. */
#define STRING_SIZE_SIZE (4) #define STRING_SIZE_SIZE (4)
@ -1216,34 +1213,47 @@ xcoff_link_add_symbols (abfd, info)
relbuf); relbuf);
if (relname == NULL) if (relname == NULL)
goto error_return; goto error_return;
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 /* We only merge TOC entries if the TC name is
bfd_link_hash_new. That should be OK, since the same as the symbol name. This handles
we know for sure that we will come across the normal case, but not common cases like
this symbol as we step through the file. */ SYM.P4 which gcc generates to store SYM + 4
in the TOC. FIXME. */
/* We store h in *sym_hash for the convenience if (strcmp (name, relname) == 0)
of the relocate_section function. */
*sym_hash = h;
if (h->toc_section != NULL)
{ {
/* We already have a TOC entry for this copy = (! info->keep_memory
symbol, so we can just ignore this one. */ || relsym._n._n_n._n_zeroes != 0
*rel_csect = bfd_und_section_ptr; || relsym._n._n_n._n_offset == 0);
break; h = xcoff_link_hash_lookup (xcoff_hash_table (info),
} relname, true, copy,
false);
if (h == NULL)
goto error_return;
/* We are about to create a TOC entry for this /* At this point h->root.type could be
symbol. */ bfd_link_hash_new. That should be OK,
set_toc = h; 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)
{
/* We already have a TOC entry for this
symbol, so we can just ignore this
one. */
*rel_csect = bfd_und_section_ptr;
break;
}
/* We are about to create a TOC entry for
this symbol. */
set_toc = h;
}
} }
} }
} }
@ -1431,7 +1441,7 @@ xcoff_link_add_symbols (abfd, info)
csect = bfd_make_section_anyway (abfd, ".bss"); csect = bfd_make_section_anyway (abfd, ".bss");
if (csect == NULL) if (csect == NULL)
goto error_return; goto error_return;
csect->vma = 0; csect->vma = sym.n_value;
csect->_raw_size = aux.x_csect.x_scnlen.l; csect->_raw_size = aux.x_csect.x_scnlen.l;
csect->flags |= SEC_ALLOC; csect->flags |= SEC_ALLOC;
csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp); csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp);
@ -1524,6 +1534,21 @@ xcoff_link_add_symbols (abfd, info)
(struct bfd_link_hash_entry **) sym_hash))) (struct bfd_link_hash_entry **) sym_hash)))
goto error_return; goto error_return;
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) if (info->hash->creator == abfd->xvec)
{ {
int flag; int flag;
@ -1574,75 +1599,49 @@ xcoff_link_add_symbols (abfd, info)
goto error_return; goto error_return;
} }
/* We need to copy all relocs which are not PC relative /* We identify all symbols which are called, so that we
and not TOC relative into the .loader section. can create glue code for calls to functions imported
from dynamic objects. */
We also 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 if (info->hash->creator == abfd->xvec
&& *rel_csect != bfd_und_section_ptr) && *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; struct xcoff_link_hash_entry *h;
switch (rel->r_type) 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)
{ {
default: struct xcoff_link_hash_entry *hds;
break;
case R_POS:
case R_NEG:
case R_RL:
case R_RLA:
++xcoff_hash_table (info)->ldrel_count;
++xcoff_section_data (abfd, *rel_csect)->ldrel_count;
h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx];
if (h != NULL)
h->flags |= XCOFF_LDREL;
break;
case R_BR:
case R_RBR:
h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx];
if (h != NULL)
{
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 hds = xcoff_link_hash_lookup (xcoff_hash_table (info),
(xcoff_hash_table (info), h->root.root.string + 1,
h->root.root.string + 1, true, false, true, false, true);
true)); if (hds == NULL)
if (hds == NULL) goto error_return;
goto error_return; if (hds->root.type == bfd_link_hash_new)
if (hds->root.type == bfd_link_hash_new) {
{ if (! (_bfd_generic_link_add_one_symbol
if (! (_bfd_generic_link_add_one_symbol (info, abfd, hds->root.root.string,
(info, abfd, hds->root.root.string, (flagword) 0, bfd_und_section_ptr,
(flagword) 0, bfd_und_section_ptr, (bfd_vma) 0, (const char *) NULL, false,
(bfd_vma) 0, (const char *) NULL, false,
false, false, (struct bfd_link_hash_entry **) NULL)))
((struct bfd_link_hash_entry **) goto error_return;
NULL))))
goto error_return;
}
h->descriptor = hds;
}
} }
break; h->descriptor = hds;
} }
} }
} }
@ -1773,10 +1772,12 @@ xcoff_link_add_dynamic_symbols (abfd, info)
/* If the symbol is undefined, and the current BFD is /* If the symbol is undefined, and the current BFD is
not a dynamic object, change the BFD to this dynamic not a dynamic object, change the BFD to this dynamic
object, so that we can get the import file ID object, so that we can get the correct import file
correctly. */ ID. */
if (h->root.u.undef.abfd == NULL if ((h->root.type == bfd_link_hash_undefined
|| (h->root.u.undef.abfd->flags & DYNAMIC) == 0) || 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; h->root.u.undef.abfd = abfd;
if (h->smclas == XMC_UA if (h->smclas == XMC_UA
@ -2024,7 +2025,13 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
hentry = xcoff_link_hash_lookup (xcoff_hash_table (info), entry, hentry = xcoff_link_hash_lookup (xcoff_hash_table (info), entry,
false, false, true); false, false, true);
if (hentry != NULL) if (hentry != NULL)
hentry->flags |= XCOFF_ENTRY; {
hentry->flags |= XCOFF_ENTRY;
if (hentry->root.type == bfd_link_hash_defined
|| hentry->root.type == bfd_link_hash_defweak)
xcoff_data (output_bfd)->entry_section =
hentry->root.u.def.section->output_section;
}
/* Garbage collect unused sections. */ /* Garbage collect unused sections. */
if (info->relocateable if (info->relocateable
@ -2035,6 +2042,22 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
{ {
gc = false; gc = false;
xcoff_hash_table (info)->gc = false; xcoff_hash_table (info)->gc = false;
/* We still need to call xcoff_mark, in order to set ldrel_count
correctly. */
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
asection *o;
for (o = sub->sections; o != NULL; o = o->next)
{
if ((o->flags & SEC_MARK) == 0)
{
if (! xcoff_mark (info, o))
goto error_return;
}
}
}
} }
else else
{ {
@ -2284,7 +2307,10 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
} }
/* The mark phase of garbage collection. For a given section, mark /* The mark phase of garbage collection. For a given section, mark
it, and all the sections which define symbols to which it refers. */ 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 static boolean
xcoff_mark (info, sec) xcoff_mark (info, sec)
@ -2393,6 +2419,35 @@ xcoff_mark (info, sec)
if (! xcoff_mark (info, rsec)) if (! xcoff_mark (info, rsec))
return false; return false;
} }
/* See if this reloc needs to be copied into the .loader
section. */
switch (rel->r_type)
{
default:
if (h == NULL
|| h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak
|| h->root.type == bfd_link_hash_common)
break;
/* Fall through. */
case R_POS:
case R_NEG:
case R_RL:
case R_RLA:
++xcoff_hash_table (info)->ldrel_count;
if (h != NULL)
h->flags |= XCOFF_LDREL;
break;
case R_TOC:
case R_GL:
case R_TCL:
case R_TRL:
case R_TRLA:
/* We should never need a .loader reloc for a TOC
relative reloc. */
break;
}
} }
if (! info->keep_memory if (! info->keep_memory
@ -2441,10 +2496,6 @@ xcoff_sweep (info)
o->_raw_size = 0; o->_raw_size = 0;
o->reloc_count = 0; o->reloc_count = 0;
o->lineno_count = 0; o->lineno_count = 0;
if (coff_section_data (sub, o) != NULL
&& xcoff_section_data (sub, o) != NULL)
xcoff_hash_table (info)->ldrel_count -=
xcoff_section_data (sub, o)->ldrel_count;
} }
} }
} }
@ -2520,11 +2571,12 @@ xcoff_build_ldsyms (h, p)
/* We need to add a symbol to the .loader section if it is mentioned /* We need to add a symbol to the .loader section if it is mentioned
in a reloc which we are copying to the .loader section and it was in a reloc which we are copying to the .loader section and it was
not defined, or if it is the entry point. */ not defined or common, or if it is the entry point. */
if (((h->flags & XCOFF_LDREL) == 0 if (((h->flags & XCOFF_LDREL) == 0
|| h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak) || h->root.type == bfd_link_hash_defweak
|| h->root.type == bfd_link_hash_common)
&& (h->flags & XCOFF_ENTRY) == 0) && (h->flags & XCOFF_ENTRY) == 0)
{ {
h->ldsym = NULL; h->ldsym = NULL;
@ -2660,6 +2712,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
+ xcoff_hash_table (info)->ldhdr.l_nsyms * LDSYMSZ)); + xcoff_hash_table (info)->ldhdr.l_nsyms * LDSYMSZ));
xcoff_data (abfd)->coff.link_info = info; xcoff_data (abfd)->coff.link_info = info;
xcoff_data (abfd)->full_aouthdr = true;
finfo.strtab = _bfd_stringtab_init (); finfo.strtab = _bfd_stringtab_init ();
if (finfo.strtab == NULL) if (finfo.strtab == NULL)
@ -2728,13 +2781,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
code knows what compute_section_file_positions is going code knows what compute_section_file_positions is going
to do. */ to do. */
sofar = bfd_coff_filhsz (abfd); sofar = bfd_coff_filhsz (abfd);
if ((abfd->flags & EXEC_P) != 0) sofar += bfd_coff_aoutsz (abfd);
sofar += bfd_coff_aoutsz (abfd);
else
{
/* FIXME. */
sofar += 28;
}
sofar += abfd->section_count * bfd_coff_scnhsz (abfd); sofar += abfd->section_count * bfd_coff_scnhsz (abfd);
for (o = abfd->sections; o != NULL; o = o->next) for (o = abfd->sections; o != NULL; o = o->next)
@ -3420,6 +3467,8 @@ xcoff_link_input_bfd (finfo, input_bfd)
+ (*csectpp)->output_offset + (*csectpp)->output_offset
+ isym.n_value + isym.n_value
- (*csectpp)->vma); - (*csectpp)->vma);
xcoff_data (finfo->output_bfd)->toc_section =
(*csectpp)->output_section;
require = true; require = true;
} }
} }
@ -3441,7 +3490,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
if (! skip if (! skip
&& isym.n_sclass == C_EXT && isym.n_sclass == C_EXT
&& smtyp == XTY_CM && smtyp == XTY_CM
&& ((*sym_hash)->flags & XCOFF_DEF_REGULAR) != 0) && (*sym_hash)->root.type != bfd_link_hash_common)
skip = true; skip = true;
/* Skip local symbols if we are discarding them. */ /* Skip local symbols if we are discarding them. */
@ -3531,26 +3580,9 @@ xcoff_link_input_bfd (finfo, input_bfd)
} }
} }
if (isym.n_sclass == C_BSTAT) if (isym.n_sclass != C_BSTAT
{ && isym.n_sclass != C_ESTAT
unsigned long indx; && isym.n_scnum > 0)
/* The value of a C_BSTAT symbol is the symbol table
index of the containing csect. */
indx = isym.n_value;
if (indx < obj_raw_syment_count (input_bfd))
{
long symindx;
symindx = finfo->sym_indices[indx];
if (symindx < 0)
isym.n_value = 0;
else
isym.n_value = symindx;
}
}
else if (isym.n_scnum > 0)
{ {
isym.n_scnum = (*csectpp)->output_section->target_index; isym.n_scnum = (*csectpp)->output_section->target_index;
isym.n_value += ((*csectpp)->output_section->vma isym.n_value += ((*csectpp)->output_section->vma
@ -3635,9 +3667,10 @@ xcoff_link_input_bfd (finfo, input_bfd)
*indexp++ = -1; *indexp++ = -1;
} }
/* Fix up the aux entries. This must be done in a separate pass, /* Fix up the aux entries and the C_BSTAT symbols. This must be
because we don't know the correct symbol indices until we have done in a separate pass, because we don't know the correct symbol
already decided which symbols we are going to keep. */ indices until we have already decided which symbols we are going
to keep. */
esym = (bfd_byte *) obj_coff_external_syms (input_bfd); esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
@ -3657,6 +3690,27 @@ xcoff_link_input_bfd (finfo, input_bfd)
{ {
int i; int i;
if (isymp->n_sclass == C_BSTAT)
{
unsigned long indx;
/* The value of a C_BSTAT symbol is the symbol table
index of the containing csect. */
indx = isymp->n_value;
if (indx < obj_raw_syment_count (input_bfd))
{
long symindx;
symindx = finfo->sym_indices[indx];
if (symindx < 0)
isymp->n_value = 0;
else
isymp->n_value = symindx;
bfd_coff_swap_sym_out (output_bfd, (PTR) isymp,
(PTR) outsym);
}
}
esym += isymesz; esym += isymesz;
outsym += osymesz; outsym += osymesz;
@ -4066,7 +4120,12 @@ xcoff_link_input_bfd (finfo, input_bfd)
switch (irel->r_type) switch (irel->r_type)
{ {
default: default:
break; if (h == NULL
|| h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak
|| h->root.type == bfd_link_hash_common)
break;
/* Fall through. */
case R_POS: case R_POS:
case R_NEG: case R_NEG:
case R_RL: case R_RL:
@ -4076,30 +4135,36 @@ xcoff_link_input_bfd (finfo, input_bfd)
ldrel.l_vaddr = irel->r_vaddr; ldrel.l_vaddr = irel->r_vaddr;
if (r_symndx == -1) if (r_symndx == -1)
ldrel.l_symndx = -1; ldrel.l_symndx = -1;
else if (h == NULL) else if (h == NULL
|| (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak
|| h->root.type == bfd_link_hash_common))
{ {
asection *sec; asection *sec;
sec = xcoff_data (input_bfd)->csects[r_symndx]; if (h == NULL)
if ((sec->flags & SEC_CODE) != 0) sec = xcoff_data (input_bfd)->csects[r_symndx];
ldrel.l_symndx = 0; else if (h->root.type == bfd_link_hash_common)
else if ((sec->flags & SEC_HAS_CONTENTS) != 0) sec = h->root.u.c.p->section;
ldrel.l_symndx = 1;
else else
ldrel.l_symndx = 2; sec = h->root.u.def.section;
} sec = sec->output_section;
else if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
asection *sec;
sec = h->root.u.def.section->output_section; if (strcmp (sec->name, ".text") == 0)
if ((sec->flags & SEC_CODE) != 0)
ldrel.l_symndx = 0; ldrel.l_symndx = 0;
else if ((sec->flags & SEC_HAS_CONTENTS) != 0) else if (strcmp (sec->name, ".data") == 0)
ldrel.l_symndx = 1; ldrel.l_symndx = 1;
else else if (strcmp (sec->name, ".bss") == 0)
ldrel.l_symndx = 2; ldrel.l_symndx = 2;
else
{
(*_bfd_error_handler)
("%s: loader reloc in unrecognized section `%s'",
bfd_get_filename (input_bfd),
sec->name);
bfd_set_error (bfd_error_nonrepresentable_section);
return false;
}
} }
else else
{ {
@ -4117,7 +4182,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
ldrel.l_rtype = (irel->r_size << 8) | irel->r_type; ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
ldrel.l_rsecnm = o->output_section->target_index; ldrel.l_rsecnm = o->output_section->target_index;
if (xcoff_hash_table (finfo->info)->textro if (xcoff_hash_table (finfo->info)->textro
&& (o->output_section->flags & SEC_CODE) != 0) && strcmp (o->output_section->name, ".text") == 0)
{ {
(*_bfd_error_handler) (*_bfd_error_handler)
("%s: loader reloc in read-only section %s", ("%s: loader reloc in read-only section %s",
@ -4131,6 +4196,16 @@ xcoff_link_input_bfd (finfo, input_bfd)
finfo->ldrel); finfo->ldrel);
BFD_ASSERT (sizeof (struct external_ldrel) == LDRELSZ); BFD_ASSERT (sizeof (struct external_ldrel) == LDRELSZ);
++finfo->ldrel; ++finfo->ldrel;
break;
case R_TOC:
case R_GL:
case R_TCL:
case R_TRL:
case R_TRLA:
/* We should never need a .loader reloc for a TOC
relative reloc. */
break;
} }
} }