From 1876a542175ef438d6aaafeccb479024994b938d Mon Sep 17 00:00:00 2001 From: Cl?ment Chigot Date: Wed, 20 Apr 2022 15:07:50 +0100 Subject: [PATCH] Stubs (added in a later patch) will generate new .loader symbols, once the allocations have been done. Thus, the .loader section cannot be layout before that. bfd/ChangeLog: * coff-rs6000.c (_bfd_xcoff_put_ldsymbol_name): Write len in ldinfo->strings instead of directly in the output_bfd. * coff64-rs6000.c (_bfd_xcoff64_put_ldsymbol_name): Likewise. * xcofflink.c (struct xcoff_link_hash_table): Remove ldrel_count field. Add ldinfo field. (xcoff_mark_symbol): Adjust to new ldinfo field. (xcoff_mark): Likewise. (bfd_xcoff_link_count_reloc): Likewise. (xcoff_build_loader_section): Split into two functions: one that build the loader section (this function) and one that only size it... (xcoff_size_loader_section): ... (this function). (bfd_xcoff_size_dynamic_sections): Adapt to new ldinfo field. Move the part where the dynamic sections are build to ... (bfd_xcoff_build_dynamic_sections): ... this function. * xcofflink.h: Add bfd_xcoff_build_dynamic_sections prototype. include/ChangeLog: * coff/xcoff.h (struct xcoff_loader_info): Add ldrel_count and libpath fields. ld/ChangeLog: * emultempl/aix.em (_after_allocation): New function. --- bfd/ChangeLog | 19 +++ bfd/coff-rs6000.c | 4 +- bfd/coff64-rs6000.c | 4 +- bfd/xcofflink.c | 268 +++++++++++++++++++++++++++---------------- bfd/xcofflink.h | 2 + include/ChangeLog | 5 + include/coff/xcoff.h | 7 ++ ld/ChangeLog | 4 + ld/emultempl/aix.em | 9 ++ 9 files changed, 218 insertions(+), 104 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 02656703ce6..06c44a3d150 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +2022-04-20 Clément Chigot + + * coff-rs6000.c (_bfd_xcoff_put_ldsymbol_name): Write len in + ldinfo->strings instead of directly in the output_bfd. + * coff64-rs6000.c (_bfd_xcoff64_put_ldsymbol_name): Likewise. + * xcofflink.c (struct xcoff_link_hash_table): Remove ldrel_count + field. Add ldinfo field. + (xcoff_mark_symbol): Adjust to new ldinfo field. + (xcoff_mark): Likewise. + (bfd_xcoff_link_count_reloc): Likewise. + (xcoff_build_loader_section): Split into two functions: one that + build the loader section (this function) and one that only size + it... + (xcoff_size_loader_section): ... (this function). + (bfd_xcoff_size_dynamic_sections): Adapt to new ldinfo field. + Move the part where the dynamic sections are build to ... + (bfd_xcoff_build_dynamic_sections): ... this function. + * xcofflink.h: Add bfd_xcoff_build_dynamic_sections prototype. + 2022-04-13 Alexander von Gluck IV * config.bfd (x86-haiku): Add i386_pei_vec as a selectable format. diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c index 97e84a443b0..8656dfdb4c4 100644 --- a/bfd/coff-rs6000.c +++ b/bfd/coff-rs6000.c @@ -3881,8 +3881,8 @@ _bfd_xcoff_put_ldsymbol_name (bfd *abfd ATTRIBUTE_UNUSED, ldinfo->strings = newstrings; } - bfd_put_16 (ldinfo->output_bfd, (bfd_vma) (len + 1), - ldinfo->strings + ldinfo->string_size); + ldinfo->strings[ldinfo->string_size] = ((len + 1) >> 8) & 0xff; + ldinfo->strings[ldinfo->string_size + 1] = ((len + 1)) & 0xff; strcpy (ldinfo->strings + ldinfo->string_size + 2, name); ldsym->_l._l_l._l_zeroes = 0; ldsym->_l._l_l._l_offset = ldinfo->string_size + 2; diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c index 01326d4503d..95abbb9e957 100644 --- a/bfd/coff64-rs6000.c +++ b/bfd/coff64-rs6000.c @@ -623,8 +623,8 @@ _bfd_xcoff64_put_ldsymbol_name (bfd *abfd ATTRIBUTE_UNUSED, ldinfo->strings = newstrings; } - bfd_put_16 (ldinfo->output_bfd, (bfd_vma) (len + 1), - ldinfo->strings + ldinfo->string_size); + ldinfo->strings[ldinfo->string_size] = ((len + 1) >> 8) & 0xff; + ldinfo->strings[ldinfo->string_size + 1] = ((len + 1)) & 0xff; strcpy (ldinfo->strings + ldinfo->string_size + 2, name); ldsym->_l._l_l._l_zeroes = 0; ldsym->_l._l_l._l_offset = ldinfo->string_size + 2; diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c index 70d371e4aed..6d4abdd1eda 100644 --- a/bfd/xcofflink.c +++ b/bfd/xcofflink.c @@ -104,9 +104,8 @@ struct xcoff_link_hash_table /* The .loader section we will use for the final output. */ asection *loader_section; - /* A count of non TOC relative relocs which will need to be - allocated in the .loader section. */ - size_t ldrel_count; + /* The structure holding information about the .loader section. */ + struct xcoff_loader_info ldinfo; /* The .loader section header. */ struct internal_ldhdr ldhdr; @@ -2841,7 +2840,7 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h) /* A function descriptor uses two relocs: one for the associated code, and one for the TOC address. */ - xcoff_hash_table (info)->ldrel_count += 2; + xcoff_hash_table (info)->ldinfo.ldrel_count += 2; sec->reloc_count += 2; /* Mark the function itself. */ @@ -2913,7 +2912,7 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h) /* Allocate room for a static and dynamic R_TOC relocation. */ - ++xcoff_hash_table (info)->ldrel_count; + ++xcoff_hash_table (info)->ldinfo.ldrel_count; ++hds->toc_section->reloc_count; /* Set the index to -2 to force this symbol to @@ -3077,7 +3076,7 @@ xcoff_mark (struct bfd_link_info *info, asection *sec) if ((sec->flags & SEC_DEBUGGING) == 0 && xcoff_need_ldrel_p (info, rel, h, sec)) { - ++xcoff_hash_table (info)->ldrel_count; + ++xcoff_hash_table (info)->ldinfo.ldrel_count; if (h != NULL) h->flags |= XCOFF_LDREL; } @@ -3341,7 +3340,7 @@ bfd_xcoff_link_count_reloc (bfd *output_bfd, if (xcoff_hash_table (info)->loader_section) { h->flags |= XCOFF_LDREL; - ++xcoff_hash_table (info)->ldrel_count; + ++xcoff_hash_table (info)->ldinfo.ldrel_count; } /* Mark the symbol to avoid garbage collection. */ @@ -3632,12 +3631,11 @@ 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. */ +/* Compute the current size of the .loader section. Start filling + its header but it will be finalized in xcoff_build_loader_section. */ static bool -xcoff_build_loader_section (struct xcoff_loader_info *ldinfo, - const char *libpath) +xcoff_size_loader_section (struct xcoff_loader_info *ldinfo) { bfd *output_bfd; struct xcoff_link_hash_table *htab; @@ -3646,7 +3644,18 @@ xcoff_build_loader_section (struct xcoff_loader_info *ldinfo, bfd_size_type stoff; size_t impsize, impcount; asection *lsec; - char *out; + + output_bfd = ldinfo->output_bfd; + htab = xcoff_hash_table (ldinfo->info); + ldhdr = &htab->ldhdr; + + /* If this function has already been called (ie l_version is set) + and the number of symbols or relocations haven't changed since + last call, the size is already known. */ + if (ldhdr->l_version != 0 + && ldhdr->l_nsyms == ldinfo->ldsym_count + && ldhdr->l_nreloc == ldinfo->ldrel_count) + return true; /* Work out the size of the import file names. Each import file ID consists of three null terminated strings: the path, the file @@ -3654,31 +3663,31 @@ xcoff_build_loader_section (struct xcoff_loader_info *ldinfo, 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) + if (ldhdr->l_nimpid == 0) { - ++impcount; - impsize += (strlen (fl->path) - + strlen (fl->file) - + strlen (fl->member) - + 3); + impsize = strlen (ldinfo->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); + } + ldhdr->l_istlen = impsize; + ldhdr->l_nimpid = impcount; } /* 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_nreloc = ldinfo->ldrel_count; 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; + stoff = ldhdr->l_impoff + ldhdr->l_istlen; if (ldinfo->string_size == 0) ldhdr->l_stoff = 0; else @@ -3692,62 +3701,19 @@ xcoff_build_loader_section (struct xcoff_loader_info *ldinfo, 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. */ + /* Save the size of the .loader section. */ 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 +/* Prepare 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. + .loader section before the linker lays out the output file. However, + some symbols or relocations might be append to the .loader section + when processing the addresses, thus it's not layout right now and + its size might change. LIBPATH is the library path to search for shared objects; this is normally built from the -L arguments passed to the linker. ENTRY is the name of the entry point symbol (the -e linker option). @@ -3776,12 +3742,10 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, asection **special_sections, bool rtld) { - struct xcoff_loader_info ldinfo; + struct xcoff_loader_info *ldinfo; int i; asection *sec; bfd *sub; - struct bfd_strtab_hash *debug_strtab; - bfd_byte *debug_contents = NULL; size_t amt; if (bfd_get_flavour (output_bfd) != bfd_target_xcoff_flavour) @@ -3791,14 +3755,18 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, return true; } - ldinfo.failed = false; - ldinfo.output_bfd = output_bfd; - ldinfo.info = info; - ldinfo.auto_export_flags = auto_export_flags; - ldinfo.ldsym_count = 0; - ldinfo.string_size = 0; - ldinfo.strings = NULL; - ldinfo.string_alc = 0; + /* Setup ldinfo. */ + ldinfo = &(xcoff_hash_table (info)->ldinfo); + + ldinfo->failed = false; + ldinfo->output_bfd = output_bfd; + ldinfo->info = info; + ldinfo->auto_export_flags = auto_export_flags; + ldinfo->ldsym_count = 0; + ldinfo->string_size = 0; + ldinfo->strings = NULL; + ldinfo->string_alc = 0; + ldinfo->libpath = libpath; xcoff_data (output_bfd)->maxstack = maxstack; xcoff_data (output_bfd)->maxdata = maxdata; @@ -3843,13 +3811,13 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, The first 3 symbol table indices are reserved to indicate the data, text and bss sections. */ - BFD_ASSERT (0 == ldinfo.ldsym_count); + BFD_ASSERT (0 == ldinfo->ldsym_count); hsym->ldindx = 3; - ldinfo.ldsym_count = 1; + ldinfo->ldsym_count = 1; hsym->ldsym = ldsym; - if (! bfd_xcoff_put_ldsymbol_name (ldinfo.output_bfd, &ldinfo, + if (! bfd_xcoff_put_ldsymbol_name (ldinfo->output_bfd, ldinfo, hsym->ldsym, hsym->root.root.string)) return false; @@ -3901,8 +3869,8 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, if (auto_export_flags != 0) { xcoff_link_hash_traverse (xcoff_hash_table (info), - xcoff_mark_auto_exports, &ldinfo); - if (ldinfo.failed) + xcoff_mark_auto_exports, ldinfo); + if (ldinfo->failed) goto error_return; } xcoff_sweep (info); @@ -3927,35 +3895,136 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, return true; xcoff_link_hash_traverse (xcoff_hash_table (info), xcoff_post_gc_symbol, - (void *) &ldinfo); - if (ldinfo.failed) + (void *) ldinfo); + if (ldinfo->failed) goto error_return; if (xcoff_hash_table (info)->loader_section - && !xcoff_build_loader_section (&ldinfo, libpath)) + && !xcoff_size_loader_section (ldinfo)) goto error_return; + return true; + + error_return: + free (ldinfo->strings); + return false; +} + +/* Lay out the .loader section, finalizing its header and + filling the import paths */ +static bool +xcoff_build_loader_section (struct xcoff_loader_info *ldinfo) +{ + bfd *output_bfd; + asection *lsec; + struct xcoff_link_hash_table *htab; + struct internal_ldhdr *ldhdr; + struct xcoff_import_file *fl; + char *out; + + output_bfd = ldinfo->output_bfd; + htab = xcoff_hash_table (ldinfo->info); + lsec = htab->loader_section; + ldhdr = &htab->ldhdr; + + /* We could have called xcoff_size_loader_section one more time. + However, this function is called once all the addresses have + been layout thus the .loader section shouldn't be changed + anymore. */ + BFD_ASSERT (ldhdr->l_nsyms == ldinfo->ldsym_count); + BFD_ASSERT (ldhdr->l_nreloc == ldinfo->ldrel_count); + + /* We now know the final size of the .loader section. Allocate + space for it. */ + 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, ldinfo->libpath); + out += strlen (ldinfo->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) == ldhdr->l_impoff + ldhdr->l_istlen); + + /* 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; +} + + +/* Lay out the .loader section and allocate the space for + the other dynamic sections of XCOFF. */ +bool +bfd_xcoff_build_dynamic_sections (bfd *output_bfd, + struct bfd_link_info *info) +{ + struct xcoff_loader_info *ldinfo; + struct bfd_strtab_hash *debug_strtab; + bfd_byte *debug_contents = NULL; + bfd *sub; + asection *sec; + + ldinfo = &(xcoff_hash_table (info)->ldinfo); + + if (xcoff_hash_table (info)->loader_section + && !xcoff_build_loader_section (ldinfo)) + return false; + /* Allocate space for the magic sections. */ sec = xcoff_hash_table (info)->linkage_section; if (sec->size > 0) { sec->contents = bfd_zalloc (output_bfd, sec->size); if (sec->contents == NULL) - goto error_return; + return false; } sec = xcoff_hash_table (info)->toc_section; if (sec->size > 0) { sec->contents = bfd_zalloc (output_bfd, sec->size); if (sec->contents == NULL) - goto error_return; + return false; } sec = xcoff_hash_table (info)->descriptor_section; if (sec->size > 0) { sec->contents = bfd_zalloc (output_bfd, sec->size); if (sec->contents == NULL) - goto error_return; + return false; } /* Now that we've done garbage collection, decide which symbols to keep, @@ -4051,7 +4120,7 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, keep_p = xcoff_keep_symbol_p (info, sub, &sym, &aux, *sym_hash, csect, name); if (keep_p < 0) - return false; + goto error_return; if (!keep_p) /* Use a debug_index of -2 to record that a symbol should @@ -4110,7 +4179,6 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, return true; error_return: - free (ldinfo.strings); free (debug_contents); return false; } diff --git a/bfd/xcofflink.h b/bfd/xcofflink.h index cd35676b08f..92feeb58958 100644 --- a/bfd/xcofflink.h +++ b/bfd/xcofflink.h @@ -37,5 +37,7 @@ extern bool bfd_xcoff_size_dynamic_sections (bfd *, struct bfd_link_info *, const char *, const char *, unsigned long, unsigned long, unsigned long, bool, int, bool, unsigned int, struct bfd_section **, bool); +extern bool bfd_xcoff_build_dynamic_sections + (bfd *, struct bfd_link_info *); extern bool bfd_xcoff_link_generate_rtinit (bfd *, const char *, const char *, bool); diff --git a/include/ChangeLog b/include/ChangeLog index c40136eb520..5cf3fa7041a 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2022-04-20 Clément Chigot + + * coff/xcoff.h (struct xcoff_loader_info): Add ldrel_count and + libpath fields. + 2022-04-07 Mark Harmstone * coff/i386.h: Define R_SECTION. diff --git a/include/coff/xcoff.h b/include/coff/xcoff.h index acadf54d4a1..0770d04b5f6 100644 --- a/include/coff/xcoff.h +++ b/include/coff/xcoff.h @@ -432,6 +432,10 @@ struct xcoff_loader_info /* Number of ldsym structures. */ size_t ldsym_count; + /* A count of non TOC relative relocs which will need to be + allocated in the .loader section. */ + size_t ldrel_count; + /* Size of string table. */ size_t string_size; @@ -440,6 +444,9 @@ struct xcoff_loader_info /* Allocated size of string table. */ size_t string_alc; + + /* The libpath being used. */ + const char *libpath; }; /* In case we're on a 32-bit machine, construct a 64-bit "-1" value diff --git a/ld/ChangeLog b/ld/ChangeLog index 1538f42516c..285aae94202 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,7 @@ +2022-04-20 Clément Chigot + + * emultempl/aix.em (_after_allocation): New function. + 2022-04-07 Mark Harmstone * testsuite/ld-pe/secidx1.s: New test source file. diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em index 6807aaee1c8..3878d58bb32 100644 --- a/ld/emultempl/aix.em +++ b/ld/emultempl/aix.em @@ -1009,6 +1009,14 @@ gld${EMULATION_NAME}_before_allocation (void) before_allocation_default (); } +static void +gld${EMULATION_NAME}_after_allocation (void) +{ + /* Now that everything is in place, finalize the dynamic sections. */ + if (!bfd_xcoff_build_dynamic_sections (link_info.output_bfd, &link_info)) + einfo (_("%F%P: failed to layout dynamic sections: %E\n")); +} + static char * gld${EMULATION_NAME}_choose_target (int argc, char **argv) { @@ -1607,6 +1615,7 @@ LDEMUL_AFTER_OPEN=gld${EMULATION_NAME}_after_open LDEMUL_SET_OUTPUT_ARCH=gld${EMULATION_NAME}_set_output_arch LDEMUL_CHOOSE_TARGET=gld${EMULATION_NAME}_choose_target LDEMUL_BEFORE_ALLOCATION=gld${EMULATION_NAME}_before_allocation +LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=gld${EMULATION_NAME}_create_output_section_statements LDEMUL_OPEN_DYNAMIC_ARCHIVE=gld${EMULATION_NAME}_open_dynamic_archive LDEMUL_PARSE_ARGS=gld${EMULATION_NAME}_parse_args -- 2.30.2