From b3d1832c347fbfdf0c816aaa8910fc327c929b02 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 1 Apr 2009 19:27:38 +0000 Subject: [PATCH] bfd/ * 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. --- bfd/xcofflink.c | 794 +++++++++++++-------------- ld/testsuite/ld-powerpc/aix-rel-1.od | 22 + ld/testsuite/ld-powerpc/aix-rel-1.s | 5 + ld/testsuite/ld-powerpc/aix52.exp | 4 + 4 files changed, 418 insertions(+), 407 deletions(-) create mode 100644 ld/testsuite/ld-powerpc/aix-rel-1.od create mode 100644 ld/testsuite/ld-powerpc/aix-rel-1.s diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c index ac0f529f640..6905a3a8153 100644 --- a/bfd/xcofflink.c +++ b/bfd/xcofflink.c @@ -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; - 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; + 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; - } - } + if (r_symndx == -1) + 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,49 +5563,13 @@ 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; - } - } - 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; + if (!xcoff_create_ldrel (output_bfd, finfo, output_section, + output_bfd, irel, hsec, h)) + return FALSE; } - 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; diff --git a/ld/testsuite/ld-powerpc/aix-rel-1.od b/ld/testsuite/ld-powerpc/aix-rel-1.od new file mode 100644 index 00000000000..0d9f2bb9b8c --- /dev/null +++ b/ld/testsuite/ld-powerpc/aix-rel-1.od @@ -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 + + diff --git a/ld/testsuite/ld-powerpc/aix-rel-1.s b/ld/testsuite/ld-powerpc/aix-rel-1.s new file mode 100644 index 00000000000..9891ba824fb --- /dev/null +++ b/ld/testsuite/ld-powerpc/aix-rel-1.s @@ -0,0 +1,5 @@ + .globl foo + .csect foo[RW] +foo: + .long .puts + .long foobar diff --git a/ld/testsuite/ld-powerpc/aix52.exp b/ld/testsuite/ld-powerpc/aix52.exp index fb2307a6fdc..c88ba9b5101 100644 --- a/ld/testsuite/ld-powerpc/aix52.exp +++ b/ld/testsuite/ld-powerpc/aix52.exp @@ -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}} -- 2.30.2