* xcofflink.c (xcoff_link_create_extra_sections): Don't create
	a .loader section for relocatable links.
	(xcoff_need_ldrel_p): New function.
	(xcoff_mark): Use it.
	(bfd_xcoff_link_count_reloc): Only count loader relocs if there's
	a loader section.
	(xcoff_build_ldsym): New function, split out from...
	(xcoff_build_ldsyms): ...here.  Rename to...
	(xcoff_post_gc_symbol): ...this.  Only export symbols, and only
	call xcoff_build_ldsym, if there's a loader section.
	(xcoff_build_loader_section): New function, extracted verbatim from...
	(bfd_xcoff_size_dynamic_sections): ...here.  Only call it if
	there's a loader section.  Only add an __rtinit loader symbol
	if there's a loader section.  Update after above name change.
	(xcoff_symbol_section, xcoff_create_ldrel): New functions.
	(bfd_link_input_bfd): Use xcoff_need_ldrel_p, xcoff_symbol_section
	and xcoff_create_ldrel.
	(xcoff_write_global_symbol): Use xcoff_create_ldrel.
	(xcoff_reloc_link_order): Likewise, but only call it if there's
	a loader section.  Use xcoff_symbol_section.
	(_bfd_xcoff_bfd_final_link): Only use fdinfo.ldrel and fdinfo.ldsym
	if there's a loader section.

ld/testsuite/
	* ld-powerpc/aix-rel-1.s, ld-powerpc/aix-rel-1.od: New test.
	* ld-powerpc/aix52.exp: Run it.
This commit is contained in:
Richard Sandiford
2009-04-01 19:27:38 +00:00
parent 865093a3bf
commit b3d1832c34
4 changed files with 418 additions and 407 deletions

View File

@@ -814,7 +814,8 @@ xcoff_link_create_extra_sections (bfd * abfd, struct bfd_link_info *info)
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)
if (!info->relocatable
&& xcoff_hash_table (info)->loader_section == NULL)
{
asection *lsec;
flagword flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY;
@@ -2409,6 +2410,59 @@ xcoff_auto_export_p (struct xcoff_link_hash_entry *h,
return FALSE;
}
/* Return true if relocation REL needs to be copied to the .loader section.
If REL is against a global symbol, H is that symbol, otherwise it
is null. */
static bfd_boolean
xcoff_need_ldrel_p (struct bfd_link_info *info, struct internal_reloc *rel,
struct xcoff_link_hash_entry *h)
{
if (!xcoff_hash_table (info)->loader_section)
return FALSE;
switch (rel->r_type)
{
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. */
return FALSE;
default:
/* In this case, relocations against defined symbols can be resolved
statically. */
if (h == NULL
|| h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak
|| h->root.type == bfd_link_hash_common)
return FALSE;
/* We will always provide a local definition of function symbols,
even if we don't have one yet. */
if ((h->flags & XCOFF_CALLED) != 0)
return FALSE;
return TRUE;
case R_POS:
case R_NEG:
case R_RL:
case R_RLA:
/* Absolute relocations against absolute symbols can be
resolved statically. */
if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& bfd_is_abs_section (h->root.u.def.section))
return FALSE;
return TRUE;
}
}
/* Mark a symbol as not being garbage, including the section in which
it is defined. */
@@ -2681,39 +2735,11 @@ xcoff_mark (struct bfd_link_info *info, asection *sec)
/* See if this reloc needs to be copied into the .loader
section. */
switch (rel->r_type)
if (xcoff_need_ldrel_p (info, rel, h))
{
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
/* We will always provide a local definition of
function symbols. */
|| (h->flags & XCOFF_CALLED) != 0)
break;
/* Fall through. */
case R_POS:
case R_NEG:
case R_RL:
case R_RLA:
if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& bfd_is_abs_section (h->root.u.def.section))
break;
++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;
}
}
@@ -2941,8 +2967,12 @@ bfd_xcoff_link_count_reloc (bfd *output_bfd,
return FALSE;
}
h->flags |= XCOFF_REF_REGULAR | XCOFF_LDREL;
++xcoff_hash_table (info)->ldrel_count;
h->flags |= XCOFF_REF_REGULAR;
if (xcoff_hash_table (info)->loader_section)
{
h->flags |= XCOFF_LDREL;
++xcoff_hash_table (info)->ldrel_count;
}
/* Mark the symbol to avoid garbage collection. */
if (! xcoff_mark_symbol (info, h))
@@ -3024,101 +3054,34 @@ xcoff_final_definition_p (bfd *input_bfd, struct xcoff_link_hash_entry *h,
}
}
/* See if H should have a loader symbol associated with it. */
static bfd_boolean
xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p)
xcoff_build_ldsym (struct xcoff_loader_info *ldinfo,
struct xcoff_link_hash_entry *h)
{
struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p;
bfd_size_type amt;
if (h->root.type == bfd_link_hash_warning)
h = (struct xcoff_link_hash_entry *) h->root.u.i.link;
/* __rtinit, this symbol has special handling. */
if (h->flags & XCOFF_RTINIT)
return TRUE;
/* If this is a final link, and the symbol was defined as a common
symbol in a regular object file, and there was no definition in
any dynamic object, then the linker will have allocated space for
the symbol in a common section but the XCOFF_DEF_REGULAR flag
will not have been set. */
if (h->root.type == bfd_link_hash_defined
&& (h->flags & XCOFF_DEF_REGULAR) == 0
&& (h->flags & XCOFF_REF_REGULAR) != 0
&& (h->flags & XCOFF_DEF_DYNAMIC) == 0
&& (bfd_is_abs_section (h->root.u.def.section)
|| (h->root.u.def.section->owner->flags & DYNAMIC) == 0))
h->flags |= XCOFF_DEF_REGULAR;
/* If all defined symbols should be exported, mark them now. We
don't want to export the actual functions, just the function
descriptors. */
if (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
h->flags |= XCOFF_EXPORT;
/* We don't want to garbage collect symbols which are not defined in
XCOFF files. This is a convenient place to mark them. */
if (xcoff_hash_table (ldinfo->info)->gc
&& (h->flags & XCOFF_MARK) == 0
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& (h->root.u.def.section->owner == NULL
|| (h->root.u.def.section->owner->xvec
!= ldinfo->info->output_bfd->xvec)))
h->flags |= XCOFF_MARK;
/* If this symbol is exported, but not defined, we need to try to
define it. */
/* Warn if this symbol is exported but not defined. */
if ((h->flags & XCOFF_EXPORT) != 0
&& (h->flags & XCOFF_WAS_UNDEFINED) != 0)
{
(*_bfd_error_handler)
(_("warning: attempt to export undefined symbol `%s'"),
h->root.root.string);
h->ldsym = NULL;
return TRUE;
}
/* If this is still a common symbol, and it wasn't garbage
collected, we need to actually allocate space for it in the .bss
section. */
if (h->root.type == bfd_link_hash_common
&& (! xcoff_hash_table (ldinfo->info)->gc
|| (h->flags & XCOFF_MARK) != 0)
&& h->root.u.c.p->section->size == 0)
{
BFD_ASSERT (bfd_is_com_section (h->root.u.c.p->section));
h->root.u.c.p->section->size = h->root.u.c.size;
}
/* 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
not defined or common, or if it is the entry point, or if it is
being exported. */
if (((h->flags & XCOFF_LDREL) == 0
|| h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak
|| h->root.type == bfd_link_hash_common)
&& (h->flags & XCOFF_ENTRY) == 0
&& (h->flags & XCOFF_EXPORT) == 0)
{
h->ldsym = NULL;
return TRUE;
}
/* We don't need to add this symbol if we did garbage collection and
we did not mark this symbol. */
if (xcoff_hash_table (ldinfo->info)->gc
&& (h->flags & XCOFF_MARK) == 0)
{
h->ldsym = NULL;
return TRUE;
}
/* We may have already processed this symbol due to the recursive
call above. */
if ((h->flags & XCOFF_BUILT_LDSYM) != 0)
return TRUE;
/* We need to add this symbol to the .loader symbols. */
@@ -3151,6 +3114,71 @@ xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p)
return FALSE;
h->flags |= XCOFF_BUILT_LDSYM;
return TRUE;
}
/* An xcoff_htab_traverse callback that is called for each symbol
once garbage collection is complete. */
static bfd_boolean
xcoff_post_gc_symbol (struct xcoff_link_hash_entry *h, void * p)
{
struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p;
if (h->root.type == bfd_link_hash_warning)
h = (struct xcoff_link_hash_entry *) h->root.u.i.link;
/* __rtinit, this symbol has special handling. */
if (h->flags & XCOFF_RTINIT)
return TRUE;
/* If this is a final link, and the symbol was defined as a common
symbol in a regular object file, and there was no definition in
any dynamic object, then the linker will have allocated space for
the symbol in a common section but the XCOFF_DEF_REGULAR flag
will not have been set. */
if (h->root.type == bfd_link_hash_defined
&& (h->flags & XCOFF_DEF_REGULAR) == 0
&& (h->flags & XCOFF_REF_REGULAR) != 0
&& (h->flags & XCOFF_DEF_DYNAMIC) == 0
&& (bfd_is_abs_section (h->root.u.def.section)
|| (h->root.u.def.section->owner->flags & DYNAMIC) == 0))
h->flags |= XCOFF_DEF_REGULAR;
/* We don't want to garbage collect symbols which are not defined in
XCOFF files. This is a convenient place to mark them. */
if (xcoff_hash_table (ldinfo->info)->gc
&& (h->flags & XCOFF_MARK) == 0
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& (h->root.u.def.section->owner == NULL
|| (h->root.u.def.section->owner->xvec
!= ldinfo->info->output_bfd->xvec)))
h->flags |= XCOFF_MARK;
/* Skip discarded symbols. */
if (xcoff_hash_table (ldinfo->info)->gc
&& (h->flags & XCOFF_MARK) == 0)
return TRUE;
/* If this is still a common symbol, and it wasn't garbage
collected, we need to actually allocate space for it in the .bss
section. */
if (h->root.type == bfd_link_hash_common
&& h->root.u.c.p->section->size == 0)
{
BFD_ASSERT (bfd_is_com_section (h->root.u.c.p->section));
h->root.u.c.p->section->size = h->root.u.c.size;
}
if (xcoff_hash_table (ldinfo->info)->loader_section)
{
if (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
h->flags |= XCOFF_EXPORT;
if (!xcoff_build_ldsym (ldinfo, h))
return FALSE;
}
return TRUE;
}
@@ -3246,6 +3274,119 @@ xcoff_keep_symbol_p (struct bfd_link_info *info, bfd *input_bfd,
return 1;
}
/* Lay out the .loader section, filling in the header and the import paths.
LIBPATH is as for bfd_xcoff_size_dynamic_sections. */
static bfd_boolean
xcoff_build_loader_section (struct xcoff_loader_info *ldinfo,
const char *libpath)
{
bfd *output_bfd;
struct xcoff_link_hash_table *htab;
struct internal_ldhdr *ldhdr;
struct xcoff_import_file *fl;
bfd_size_type stoff;
size_t impsize, impcount;
asection *lsec;
char *out;
/* Work out the size of the import file names. Each import file ID
consists of three null terminated strings: the path, the file
name, and the archive member name. The first entry in the list
of names is the path to use to find objects, which the linker has
passed in as the libpath argument. For some reason, the path
entry in the other import file names appears to always be empty. */
output_bfd = ldinfo->output_bfd;
htab = xcoff_hash_table (ldinfo->info);
impsize = strlen (libpath) + 3;
impcount = 1;
for (fl = htab->imports; fl != NULL; fl = fl->next)
{
++impcount;
impsize += (strlen (fl->path)
+ strlen (fl->file)
+ strlen (fl->member)
+ 3);
}
/* Set up the .loader section header. */
ldhdr = &htab->ldhdr;
ldhdr->l_version = bfd_xcoff_ldhdr_version(output_bfd);
ldhdr->l_nsyms = ldinfo->ldsym_count;
ldhdr->l_nreloc = htab->ldrel_count;
ldhdr->l_istlen = impsize;
ldhdr->l_nimpid = impcount;
ldhdr->l_impoff = (bfd_xcoff_ldhdrsz (output_bfd)
+ ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd)
+ ldhdr->l_nreloc * bfd_xcoff_ldrelsz (output_bfd));
ldhdr->l_stlen = ldinfo->string_size;
stoff = ldhdr->l_impoff + impsize;
if (ldinfo->string_size == 0)
ldhdr->l_stoff = 0;
else
ldhdr->l_stoff = stoff;
/* 64 bit elements to ldhdr
The swap out routine for 32 bit will ignore them.
Nothing fancy, symbols come after the header and relocs come
after symbols. */
ldhdr->l_symoff = bfd_xcoff_ldhdrsz (output_bfd);
ldhdr->l_rldoff = (bfd_xcoff_ldhdrsz (output_bfd)
+ ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd));
/* We now know the final size of the .loader section. Allocate
space for it. */
lsec = htab->loader_section;
lsec->size = stoff + ldhdr->l_stlen;
lsec->contents = bfd_zalloc (output_bfd, lsec->size);
if (lsec->contents == NULL)
return FALSE;
/* Set up the header. */
bfd_xcoff_swap_ldhdr_out (output_bfd, ldhdr, lsec->contents);
/* Set up the import file names. */
out = (char *) lsec->contents + ldhdr->l_impoff;
strcpy (out, libpath);
out += strlen (libpath) + 1;
*out++ = '\0';
*out++ = '\0';
for (fl = htab->imports; fl != NULL; fl = fl->next)
{
const char *s;
s = fl->path;
while ((*out++ = *s++) != '\0')
;
s = fl->file;
while ((*out++ = *s++) != '\0')
;
s = fl->member;
while ((*out++ = *s++) != '\0')
;
}
BFD_ASSERT ((bfd_size_type) ((bfd_byte *) out - lsec->contents) == stoff);
/* Set up the symbol string table. */
if (ldinfo->string_size > 0)
{
memcpy (out, ldinfo->strings, ldinfo->string_size);
free (ldinfo->strings);
ldinfo->strings = NULL;
}
/* We can't set up the symbol table or the relocs yet, because we
don't yet know the final position of the various sections. The
.loader symbols are written out when the corresponding normal
symbols are written out in xcoff_link_input_bfd or
xcoff_write_global_symbol. The .loader relocs are written out
when the corresponding normal relocs are handled in
xcoff_link_input_bfd. */
return TRUE;
}
/* Build the .loader section. This is called by the XCOFF linker
emulation before_allocation routine. We must set the size of the
.loader section before the linker lays out the output file.
@@ -3277,14 +3418,8 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
asection **special_sections,
bfd_boolean rtld)
{
asection *lsec;
struct xcoff_loader_info ldinfo;
int i;
size_t impsize, impcount;
struct xcoff_import_file *fl;
struct internal_ldhdr *ldhdr;
bfd_size_type stoff;
char *out;
asection *sec;
bfd *sub;
struct bfd_strtab_hash *debug_strtab;
@@ -3316,7 +3451,8 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
xcoff_hash_table (info)->rtld = rtld;
/* __rtinit */
if (info->init_function || info->fini_function || rtld)
if (xcoff_hash_table (info)->loader_section
&& (info->init_function || info->fini_function || rtld))
{
struct xcoff_link_hash_entry *hsym;
struct internal_ldsym *ldsym;
@@ -3432,103 +3568,15 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
/* I'm not sure what to do in this bizarre case. */
return TRUE;
xcoff_link_hash_traverse (xcoff_hash_table (info), xcoff_build_ldsyms,
xcoff_link_hash_traverse (xcoff_hash_table (info), xcoff_post_gc_symbol,
(void *) &ldinfo);
if (ldinfo.failed)
goto error_return;
/* Work out the size of the import file names. Each import file ID
consists of three null terminated strings: the path, the file
name, and the archive member name. The first entry in the list
of names is the path to use to find objects, which the linker has
passed in as the libpath argument. For some reason, the path
entry in the other import file names appears to always be empty. */
impsize = strlen (libpath) + 3;
impcount = 1;
for (fl = xcoff_hash_table (info)->imports; fl != NULL; fl = fl->next)
{
++impcount;
impsize += (strlen (fl->path)
+ strlen (fl->file)
+ strlen (fl->member)
+ 3);
}
/* Set up the .loader section header. */
ldhdr = &xcoff_hash_table (info)->ldhdr;
ldhdr->l_version = bfd_xcoff_ldhdr_version(output_bfd);
ldhdr->l_nsyms = ldinfo.ldsym_count;
ldhdr->l_nreloc = xcoff_hash_table (info)->ldrel_count;
ldhdr->l_istlen = impsize;
ldhdr->l_nimpid = impcount;
ldhdr->l_impoff = (bfd_xcoff_ldhdrsz(output_bfd)
+ ldhdr->l_nsyms * bfd_xcoff_ldsymsz(output_bfd)
+ ldhdr->l_nreloc * bfd_xcoff_ldrelsz(output_bfd));
ldhdr->l_stlen = ldinfo.string_size;
stoff = ldhdr->l_impoff + impsize;
if (ldinfo.string_size == 0)
ldhdr->l_stoff = 0;
else
ldhdr->l_stoff = stoff;
/* 64 bit elements to ldhdr
The swap out routine for 32 bit will ignore them.
Nothing fancy, symbols come after the header and relocs come
after symbols. */
ldhdr->l_symoff = bfd_xcoff_ldhdrsz (output_bfd);
ldhdr->l_rldoff = (bfd_xcoff_ldhdrsz (output_bfd)
+ ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd));
/* We now know the final size of the .loader section. Allocate
space for it. */
lsec = xcoff_hash_table (info)->loader_section;
lsec->size = stoff + ldhdr->l_stlen;
lsec->contents = bfd_zalloc (output_bfd, lsec->size);
if (lsec->contents == NULL)
if (xcoff_hash_table (info)->loader_section
&& !xcoff_build_loader_section (&ldinfo, libpath))
goto error_return;
/* Set up the header. */
bfd_xcoff_swap_ldhdr_out (output_bfd, ldhdr, lsec->contents);
/* Set up the import file names. */
out = (char *) lsec->contents + ldhdr->l_impoff;
strcpy (out, libpath);
out += strlen (libpath) + 1;
*out++ = '\0';
*out++ = '\0';
for (fl = xcoff_hash_table (info)->imports; fl != NULL; fl = fl->next)
{
const char *s;
s = fl->path;
while ((*out++ = *s++) != '\0')
;
s = fl->file;
while ((*out++ = *s++) != '\0')
;
s = fl->member;
while ((*out++ = *s++) != '\0')
;
}
BFD_ASSERT ((bfd_size_type) ((bfd_byte *) out - lsec->contents) == stoff);
/* Set up the symbol string table. */
if (ldinfo.string_size > 0)
{
memcpy (out, ldinfo.strings, ldinfo.string_size);
free (ldinfo.strings);
ldinfo.strings = NULL;
}
/* We can't set up the symbol table or the relocs yet, because we
don't yet know the final position of the various sections. The
.loader symbols are written out when the corresponding normal
symbols are written out in xcoff_link_input_bfd or
xcoff_write_global_symbol. The .loader relocs are written out
when the corresponding normal relocs are handled in
xcoff_link_input_bfd. */
/* Allocate space for the magic sections. */
sec = xcoff_hash_table (info)->linkage_section;
if (sec->size > 0)
@@ -3743,6 +3791,91 @@ bfd_xcoff_link_generate_rtinit (bfd *abfd,
return TRUE;
}
/* Return the section that defines H. Return null if no section does. */
static asection *
xcoff_symbol_section (struct xcoff_link_hash_entry *h)
{
switch (h->root.type)
{
case bfd_link_hash_defined:
case bfd_link_hash_defweak:
return h->root.u.def.section;
case bfd_link_hash_common:
return h->root.u.c.p->section;
default:
return NULL;
}
}
/* Add a .loader relocation for input relocation IREL. If the loader
relocation should be against an output section, HSEC points to the
input section that IREL is against, otherwise HSEC is null. H is the
symbol that IREL is against, or null if it isn't against a global symbol.
REFERENCE_BFD is the bfd to use in error messages about the relocation. */
static bfd_boolean
xcoff_create_ldrel (bfd *output_bfd, struct xcoff_final_link_info *finfo,
asection *output_section, bfd *reference_bfd,
struct internal_reloc *irel, asection *hsec,
struct xcoff_link_hash_entry *h)
{
struct internal_ldrel ldrel;
ldrel.l_vaddr = irel->r_vaddr;
if (hsec != NULL)
{
const char *secname;
secname = hsec->output_section->name;
if (strcmp (secname, ".text") == 0)
ldrel.l_symndx = 0;
else if (strcmp (secname, ".data") == 0)
ldrel.l_symndx = 1;
else if (strcmp (secname, ".bss") == 0)
ldrel.l_symndx = 2;
else
{
(*_bfd_error_handler)
(_("%B: loader reloc in unrecognized section `%s'"),
reference_bfd, secname);
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
}
else if (h != NULL)
{
if (h->ldindx < 0)
{
(*_bfd_error_handler)
(_("%B: `%s' in loader reloc but not loader sym"),
reference_bfd, h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
ldrel.l_symndx = h->ldindx;
}
else
ldrel.l_symndx = -(bfd_size_type) 1;
ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
ldrel.l_rsecnm = output_section->target_index;
if (xcoff_hash_table (finfo->info)->textro
&& strcmp (output_section->name, ".text") == 0)
{
(*_bfd_error_handler)
(_("%B: loader reloc in read-only section %A"),
reference_bfd, output_section);
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
finfo->ldrel += bfd_xcoff_ldrelsz (output_bfd);
return TRUE;
}
/* Link an input file into the linker output file. This function
handles all the sections and relocations of the input file at once. */
@@ -4455,7 +4588,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
for (; irel < irelend; irel++, rel_hash++)
{
struct xcoff_link_hash_entry *h = NULL;
struct internal_ldrel ldrel;
*rel_hash = NULL;
@@ -4588,97 +4720,20 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
}
}
switch (irel->r_type)
if (xcoff_need_ldrel_p (finfo->info, irel, h))
{
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:
if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& bfd_is_abs_section (h->root.u.def.section))
break;
/* This reloc needs to be copied into the .loader
section. */
ldrel.l_vaddr = irel->r_vaddr;
asection *sec;
if (r_symndx == -1)
ldrel.l_symndx = -(bfd_size_type ) 1;
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;
if (h == NULL)
sec = xcoff_data (input_bfd)->csects[r_symndx];
else if (h->root.type == bfd_link_hash_common)
sec = h->root.u.c.p->section;
else
sec = h->root.u.def.section;
sec = sec->output_section;
if (strcmp (sec->name, ".text") == 0)
ldrel.l_symndx = 0;
else if (strcmp (sec->name, ".data") == 0)
ldrel.l_symndx = 1;
else if (strcmp (sec->name, ".bss") == 0)
ldrel.l_symndx = 2;
else
{
(*_bfd_error_handler)
(_("%B: loader reloc in unrecognized section `%A'"),
input_bfd, sec);
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
}
sec = NULL;
else if (h == NULL)
sec = xcoff_data (input_bfd)->csects[r_symndx];
else
{
if (h->ldindx < 0)
{
(*_bfd_error_handler)
(_("%B: `%s' in loader reloc but not loader sym"),
input_bfd,
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
ldrel.l_symndx = h->ldindx;
}
ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
ldrel.l_rsecnm = o->output_section->target_index;
if (xcoff_hash_table (finfo->info)->textro
&& strcmp (o->output_section->name, ".text") == 0)
{
(*_bfd_error_handler)
(_("%B: loader reloc in read-only section %A"),
input_bfd, o->output_section);
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel,
finfo->ldrel);
finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
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;
sec = xcoff_symbol_section (h);
if (!xcoff_create_ldrel (output_bfd, finfo,
o->output_section, input_bfd,
irel, sec, h))
return FALSE;
}
}
@@ -5035,7 +5090,6 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf)
asection *osec;
int oindx;
struct internal_reloc *irel;
struct internal_ldrel ldrel;
struct internal_syment irsym;
union internal_auxent iraux;
@@ -5088,12 +5142,9 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf)
finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
++osec->reloc_count;
ldrel.l_vaddr = irel->r_vaddr;
ldrel.l_symndx = h->ldindx;
ldrel.l_rtype = (irel->r_size << 8) | R_POS;
ldrel.l_rsecnm = oindx;
bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
if (!xcoff_create_ldrel (output_bfd, finfo, osec,
output_bfd, irel, NULL, h))
return FALSE;
/* We need to emit a symbol to define a csect which holds
the reloc. */
@@ -5159,7 +5210,6 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf)
struct xcoff_link_hash_entry *hentry;
asection *esec;
struct internal_reloc *irel;
struct internal_ldrel ldrel;
asection *tsec;
unsigned int reloc_size, byte_size;
@@ -5197,26 +5247,9 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf)
finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
++osec->reloc_count;
ldrel.l_vaddr = irel->r_vaddr;
if (strcmp (esec->output_section->name, ".text") == 0)
ldrel.l_symndx = 0;
else if (strcmp (esec->output_section->name, ".data") == 0)
ldrel.l_symndx = 1;
else if (strcmp (esec->output_section->name, ".bss") == 0)
ldrel.l_symndx = 2;
else
{
(*_bfd_error_handler)
(_("%s: loader reloc in unrecognized section `%s'"),
bfd_get_filename (output_bfd),
esec->output_section->name);
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
ldrel.l_rtype = (reloc_size << 8) | R_POS;
ldrel.l_rsecnm = oindx;
bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
if (!xcoff_create_ldrel (output_bfd, finfo, osec,
output_bfd, irel, esec, NULL))
return FALSE;
/* There are three items to write out,
the address of the code
@@ -5259,26 +5292,9 @@ xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf)
finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
++osec->reloc_count;
ldrel.l_vaddr = irel->r_vaddr;
if (strcmp (tsec->output_section->name, ".text") == 0)
ldrel.l_symndx = 0;
else if (strcmp (tsec->output_section->name, ".data") == 0)
ldrel.l_symndx = 1;
else if (strcmp (tsec->output_section->name, ".bss") == 0)
ldrel.l_symndx = 2;
else
{
(*_bfd_error_handler)
(_("%s: loader reloc in unrecognized section `%s'"),
bfd_get_filename (output_bfd),
tsec->output_section->name);
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
ldrel.l_rtype = (reloc_size << 8) | R_POS;
ldrel.l_rsecnm = oindx;
bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
if (!xcoff_create_ldrel (output_bfd, finfo, osec,
output_bfd, irel, tsec, NULL))
return FALSE;
}
if (h->indx >= 0 || finfo->info->strip == strip_all)
@@ -5440,7 +5456,6 @@ xcoff_reloc_link_order (bfd *output_bfd,
bfd_vma addend;
struct internal_reloc *irel;
struct xcoff_link_hash_entry **rel_hash_ptr;
struct internal_ldrel ldrel;
if (link_order->type == bfd_section_reloc_link_order)
/* We need to somehow locate a symbol in the right section. The
@@ -5468,22 +5483,12 @@ xcoff_reloc_link_order (bfd *output_bfd,
return TRUE;
}
if (h->root.type == bfd_link_hash_common)
{
hsec = h->root.u.c.p->section;
hval = 0;
}
else if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
hsec = h->root.u.def.section;
hval = h->root.u.def.value;
}
hsec = xcoff_symbol_section (h);
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
hval = h->root.u.def.value;
else
{
hsec = NULL;
hval = 0;
}
hval = 0;
addend = link_order->u.reloc.p->addend;
if (hsec != NULL)
@@ -5558,48 +5563,12 @@ xcoff_reloc_link_order (bfd *output_bfd,
++output_section->reloc_count;
/* Now output the reloc to the .loader section. */
ldrel.l_vaddr = irel->r_vaddr;
if (hsec != NULL)
if (xcoff_hash_table (finfo->info)->loader_section)
{
const char *secname;
secname = hsec->output_section->name;
if (strcmp (secname, ".text") == 0)
ldrel.l_symndx = 0;
else if (strcmp (secname, ".data") == 0)
ldrel.l_symndx = 1;
else if (strcmp (secname, ".bss") == 0)
ldrel.l_symndx = 2;
else
{
(*_bfd_error_handler)
(_("%s: loader reloc in unrecognized section `%s'"),
bfd_get_filename (output_bfd), secname);
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
if (!xcoff_create_ldrel (output_bfd, finfo, output_section,
output_bfd, irel, hsec, h))
return FALSE;
}
else
{
if (h->ldindx < 0)
{
(*_bfd_error_handler)
(_("%s: `%s' in loader reloc but not loader sym"),
bfd_get_filename (output_bfd),
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
ldrel.l_symndx = h->ldindx;
}
ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
ldrel.l_rsecnm = output_section->target_index;
bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
return TRUE;
}
@@ -5646,12 +5615,20 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
finfo.contents = NULL;
finfo.external_relocs = NULL;
finfo.ldsym = (xcoff_hash_table (info)->loader_section->contents
+ bfd_xcoff_ldhdrsz (abfd));
finfo.ldrel = (xcoff_hash_table (info)->loader_section->contents
+ bfd_xcoff_ldhdrsz(abfd)
+ (xcoff_hash_table (info)->ldhdr.l_nsyms
* bfd_xcoff_ldsymsz(abfd)));
if (xcoff_hash_table (info)->loader_section)
{
finfo.ldsym = (xcoff_hash_table (info)->loader_section->contents
+ bfd_xcoff_ldhdrsz (abfd));
finfo.ldrel = (xcoff_hash_table (info)->loader_section->contents
+ bfd_xcoff_ldhdrsz (abfd)
+ (xcoff_hash_table (info)->ldhdr.l_nsyms
* bfd_xcoff_ldsymsz (abfd)));
}
else
{
finfo.ldsym = NULL;
finfo.ldrel = NULL;
}
xcoff_data (abfd)->coff.link_info = info;
@@ -6138,13 +6115,16 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
}
/* Write out the loader section contents. */
BFD_ASSERT ((bfd_byte *) finfo.ldrel
== (xcoff_hash_table (info)->loader_section->contents
+ xcoff_hash_table (info)->ldhdr.l_impoff));
o = xcoff_hash_table (info)->loader_section;
if (! bfd_set_section_contents (abfd, o->output_section, o->contents,
(file_ptr) o->output_offset, o->size))
goto error_return;
if (o)
{
BFD_ASSERT ((bfd_byte *) finfo.ldrel
== (xcoff_hash_table (info)->loader_section->contents
+ xcoff_hash_table (info)->ldhdr.l_impoff));
if (!bfd_set_section_contents (abfd, o->output_section, o->contents,
(file_ptr) o->output_offset, o->size))
goto error_return;
}
/* Write out the magic sections. */
o = xcoff_hash_table (info)->linkage_section;

View File

@@ -0,0 +1,22 @@
.*
# It doesn't matter whether .text, .bss and .debug are listed, as long as
# they're empty. The important thing is that .loader shouldn't appear
# at all.
Sections:
*Idx Name * Size .*
*0 \.text * 0+0 .*
*ALLOC, LOAD, CODE
*1 \.data * 0+8 .*
*CONTENTS, ALLOC, LOAD, RELOC, DATA
*2 \.bss * 0+0 .*
*ALLOC
*3 \.debug * 0+0 .*
RELOCATION RECORDS FOR \[\.data\]:
OFFSET * TYPE * VALUE
0+0 R_POS(|_32) * \.puts
0+4 R_POS(|_32) * foobar

View File

@@ -0,0 +1,5 @@
.globl foo
.csect foo[RW]
foo:
.long .puts
.long foobar

View File

@@ -171,6 +171,10 @@ set aix52tests {
{{objdump -d aix-glink-2-SIZE.dd}}
"aix-glink-2"}
{"Relocatable test 1" "-r"
"" {aix-rel-1.s}
{{objdump -hr aix-rel-1.od}} "aix-rel-1.ro"}
{"Weak test 1 (rel)" "-r"
"" {aix-weak-1a.s aix-weak-1b.s}
{{nm {} aix-weak-1-rel.nd} {objdump -h aix-weak-1-rel.hd}}