From e56f61be758d90c463cc220c50ad7f30b955c2af Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Mon, 19 Jul 2004 16:40:52 +0000 Subject: [PATCH] bfd/ 2004-07-19 H.J. Lu * bfd-in.h (dynamic_lib_link_class): Add DYN_NO_ADD_NEEDED and DYN_NO_NEEDED. (bfd_elf_get_dyn_lib_class): New prototype. * elf.c (bfd_elf_get_dyn_lib_class): New function. * elflink.c (elf_link_add_object_symbols): Check DYN_AS_NEEDED, DYN_DT_NEEDED and DYN_NO_NEEDED bits to see if a DT_NEEDED entry is needed. Issue an error if a DT_NEEDED entry is needed for a file marked DYN_NO_NEEDED. (elf_link_check_versioned_symbol): Check the DYN_DT_NEEDED bit for DT_NEEDED tags. * bfd-in2.h: Regenerated. ld/ 2004-07-19 H.J. Lu * emultempl/elf32.em (gld${EMULATION_NAME}_load_symbols): Also check the add_needed field. (dt_needed): New struct. (gld${EMULATION_NAME}_try_needed): Change the first argument to a pointer to struct dt_needed. Check the DYN_NO_ADD_NEEDED bit in the file where the DT_NEEDED entry comes from. (gld${EMULATION_NAME}_search_needed): Change the second argument to a pointer to struct dt_needed. (gld${EMULATION_NAME}_check_ld_so_conf): Updated. (gld${EMULATION_NAME}_after_open): Likewise. * ld.texinfo: Add --add-needed document. * ldlang.c (new_afile): Set p->add_needed. * ldlang.h (lang_input_statement_type): Add add_needed field. * ldmain.h (add_needed): Declare. * ldmain.c (add_needed): New global var. * lexsup.c (option_values): Add OPTION_ADD_NEEDED and OPTION_NO_ADD_NEEDED. (ld_options): Likewise. (parse_args): Handle them. --- bfd/ChangeLog | 16 +++++++++++ bfd/bfd-in.h | 6 +++- bfd/bfd-in2.h | 8 ++++-- bfd/elf.c | 12 ++++++++ bfd/elflink.c | 23 ++++++++++++--- ld/ChangeLog | 23 +++++++++++++++ ld/emultempl/elf32.em | 78 ++++++++++++++++++++++++++++++++++++++++----------- ld/ld.texinfo | 12 ++++++++ ld/ldlang.c | 1 + ld/ldlang.h | 4 +++ ld/ldmain.c | 4 +++ ld/ldmain.h | 1 + ld/lexsup.c | 14 +++++++++ 13 files changed, 179 insertions(+), 23 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index db7ada4..aa3f6f8 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,19 @@ +2004-07-19 H.J. Lu + + * bfd-in.h (dynamic_lib_link_class): Add DYN_NO_ADD_NEEDED and + DYN_NO_NEEDED. + (bfd_elf_get_dyn_lib_class): New prototype. + * elf.c (bfd_elf_get_dyn_lib_class): New function. + + * elflink.c (elf_link_add_object_symbols): Check DYN_AS_NEEDED, + DYN_DT_NEEDED and DYN_NO_NEEDED bits to see if a DT_NEEDED + entry is needed. Issue an error if a DT_NEEDED entry is needed + for a file marked DYN_NO_NEEDED. + (elf_link_check_versioned_symbol): Check the DYN_DT_NEEDED bit + for DT_NEEDED tags. + + * bfd-in2.h: Regenerated. + 2004-07-14 John David Anglin * elflink.c (elf_section_complain_discarded): Don't complain in diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index 97296c8..f48e9d7 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -625,7 +625,9 @@ struct bfd_link_needed_list enum dynamic_lib_link_class { DYN_NORMAL = 0, DYN_AS_NEEDED = 1, - DYN_DT_NEEDED = 2 + DYN_DT_NEEDED = 2, + DYN_NO_ADD_NEEDED = 4, + DYN_NO_NEEDED = 8 }; extern bfd_boolean bfd_elf_record_link_assignment @@ -643,6 +645,8 @@ extern const char *bfd_elf_get_dt_soname (bfd *); extern void bfd_elf_set_dyn_lib_class (bfd *, int); +extern int bfd_elf_get_dyn_lib_class + (bfd *); extern struct bfd_link_needed_list *bfd_elf_get_runpath_list (bfd *, struct bfd_link_info *); extern bfd_boolean bfd_elf_discard_info diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index f3b1761..502a01b 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -632,7 +632,9 @@ struct bfd_link_needed_list enum dynamic_lib_link_class { DYN_NORMAL = 0, DYN_AS_NEEDED = 1, - DYN_DT_NEEDED = 2 + DYN_DT_NEEDED = 2, + DYN_NO_ADD_NEEDED = 4, + DYN_NO_NEEDED = 8 }; extern bfd_boolean bfd_elf_record_link_assignment @@ -650,6 +652,8 @@ extern const char *bfd_elf_get_dt_soname (bfd *); extern void bfd_elf_set_dyn_lib_class (bfd *, int); +extern int bfd_elf_get_dyn_lib_class + (bfd *); extern struct bfd_link_needed_list *bfd_elf_get_runpath_list (bfd *, struct bfd_link_info *); extern bfd_boolean bfd_elf_discard_info @@ -1756,7 +1760,7 @@ enum bfd_architecture #define bfd_mach_avr5 5 bfd_arch_cr16c, /* National Semiconductor CompactRISC. */ #define bfd_mach_cr16c 1 - bfd_arch_crx, /* National Semiconductor CRX. */ + bfd_arch_crx, /* National Semiconductor CRX. */ #define bfd_mach_crx 1 bfd_arch_cris, /* Axis CRIS */ bfd_arch_s390, /* IBM s390 */ diff --git a/bfd/elf.c b/bfd/elf.c index 1cf2dc0..4371f15 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1514,6 +1514,18 @@ bfd_elf_set_dt_needed_name (bfd *abfd, const char *name) elf_dt_name (abfd) = name; } +int +bfd_elf_get_dyn_lib_class (bfd *abfd) +{ + int lib_class; + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + lib_class = elf_dyn_lib_class (abfd); + else + lib_class = 0; + return lib_class; +} + void bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class) { diff --git a/bfd/elflink.c b/bfd/elflink.c index a6dafae..4920d9d 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -3064,8 +3064,13 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) /* If this dynamic lib was specified on the command line with --as-needed in effect, then we don't want to add a DT_NEEDED tag unless the lib is actually used. Similary for libs brought - in by another lib's DT_NEEDED. */ - add_needed = elf_dyn_lib_class (abfd) == DYN_NORMAL; + in by another lib's DT_NEEDED. When --no-add-needed is used + on a dynamic lib, we don't want to add a DT_NEEDED entry for + any dynamic library in DT_NEEDED tags in the dynamic lib at + all. */ + add_needed = (elf_dyn_lib_class (abfd) + & (DYN_AS_NEEDED | DYN_DT_NEEDED + | DYN_NO_NEEDED)) == 0; s = bfd_get_section_by_name (abfd, ".dynamic"); if (s != NULL) @@ -3846,7 +3851,17 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) /* A symbol from a library loaded via DT_NEEDED of some other library is referenced by a regular object. - Add a DT_NEEDED entry for it. */ + Add a DT_NEEDED entry for it. Issue an error if + --no-add-needed is used. */ + if ((elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0) + { + (*_bfd_error_handler) + (_("%s: invalid DSO for symbol `%s' definition"), + bfd_archive_filename (abfd), name); + bfd_set_error (bfd_error_bad_value); + goto error_free_vers; + } + add_needed = TRUE; ret = elf_add_dt_needed_tag (info, soname, add_needed); if (ret < 0) @@ -5818,7 +5833,7 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info, case bfd_link_hash_undefweak: abfd = h->root.u.undef.abfd; if ((abfd->flags & DYNAMIC) == 0 - || elf_dyn_lib_class (abfd) != DYN_DT_NEEDED) + || (elf_dyn_lib_class (abfd) & DYN_DT_NEEDED) == 0) return FALSE; break; diff --git a/ld/ChangeLog b/ld/ChangeLog index a1b679c..e029451 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,26 @@ +2004-07-19 H.J. Lu + + * emultempl/elf32.em (gld${EMULATION_NAME}_load_symbols): Also + check the add_needed field. + (dt_needed): New struct. + (gld${EMULATION_NAME}_try_needed): Change the first argument + to a pointer to struct dt_needed. Check the DYN_NO_ADD_NEEDED + bit in the file where the DT_NEEDED entry comes from. + (gld${EMULATION_NAME}_search_needed): Change the second + argument to a pointer to struct dt_needed. + (gld${EMULATION_NAME}_check_ld_so_conf): Updated. + (gld${EMULATION_NAME}_after_open): Likewise. + + * ld.texinfo: Add --add-needed document. + * ldlang.c (new_afile): Set p->add_needed. + * ldlang.h (lang_input_statement_type): Add add_needed field. + * ldmain.h (add_needed): Declare. + * ldmain.c (add_needed): New global var. + * lexsup.c (option_values): Add OPTION_ADD_NEEDED and + OPTION_NO_ADD_NEEDED. + (ld_options): Likewise. + (parse_args): Handle them. + 2004-07-13 Christof Petig * emultempl/pe.em (make_import_fixup): Use bfd_get_32 to correct diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 8dbd60a..469f054 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -96,14 +96,25 @@ cat >>e${EMULATION_NAME}.c <as_needed - || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0) - return FALSE; + int class = 0; /* Tell the ELF linker that we don't want the output file to have a DT_NEEDED entry for this file, unless it is used to resolve references in a regular object. */ - bfd_elf_set_dyn_lib_class (entry->the_bfd, DYN_AS_NEEDED); + if (entry->as_needed) + class = DYN_AS_NEEDED; + + /* Tell the ELF linker that we don't want the output file to have a + DT_NEEDED entry for any dynamic library in DT_NEEDED tags from + this file at all. */ + if (!entry->add_needed) + class |= DYN_NO_ADD_NEEDED; + + if (!class + || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0) + return FALSE; + + bfd_elf_set_dyn_lib_class (entry->the_bfd, class); /* Continue on with normal load_symbols processing. */ return FALSE; @@ -242,16 +253,24 @@ gld${EMULATION_NAME}_stat_needed (lang_input_statement_type *s) global_needed->name, global_needed->by, soname); } +struct dt_needed +{ + bfd *by; + const char *name; +}; /* This function is called for each possible name for a dynamic object named by a DT_NEEDED entry. The FORCE parameter indicates whether to skip the check for a conflicting version. */ static bfd_boolean -gld${EMULATION_NAME}_try_needed (const char *name, int force) +gld${EMULATION_NAME}_try_needed (struct dt_needed *needed, + int force) { bfd *abfd; + const char *name = needed->name; const char *soname; + int class; abfd = bfd_openr (name, bfd_get_target (output_bfd)); if (abfd == NULL) @@ -364,7 +383,17 @@ cat >>e${EMULATION_NAME}.c <by + && (bfd_elf_get_dyn_lib_class (needed->by) + & DYN_NO_ADD_NEEDED) != 0) + class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED; + + bfd_elf_set_dyn_lib_class (abfd, class); /* Add this file into the symbol table. */ if (! bfd_link_add_symbols (abfd, &link_info)) @@ -377,16 +406,23 @@ cat >>e${EMULATION_NAME}.c <name; size_t len; + struct dt_needed needed; if (name[0] == '/') - return gld${EMULATION_NAME}_try_needed (name, force); + return gld${EMULATION_NAME}_try_needed (n, force); if (path == NULL || *path == '\0') return FALSE; + + needed.by = n->by; + needed.name = n->name; + len = strlen (name); while (1) { @@ -407,7 +443,8 @@ gld${EMULATION_NAME}_search_needed (const char *path, const char *name, int forc } strcpy (sset, name); - if (gld${EMULATION_NAME}_try_needed (filename, force)) + needed.name = filename; + if (gld${EMULATION_NAME}_try_needed (&needed, force)) return TRUE; free (filename); @@ -474,6 +511,7 @@ gld${EMULATION_NAME}_check_ld_so_conf (const char *name, int force) { static bfd_boolean initialized; static char *ld_so_conf; + struct dt_needed needed; if (! initialized) { @@ -548,7 +586,10 @@ gld${EMULATION_NAME}_check_ld_so_conf (const char *name, int force) if (ld_so_conf == NULL) return FALSE; - return gld${EMULATION_NAME}_search_needed (ld_so_conf, name, force); + + needed.by = NULL; + needed.name = name; + return gld${EMULATION_NAME}_search_needed (ld_so_conf, &needed, force); } EOF @@ -631,6 +672,7 @@ gld${EMULATION_NAME}_after_open (void) for (l = needed; l != NULL; l = l->next) { struct bfd_link_needed_list *ll; + struct dt_needed n, nn; int force; /* If we've already seen this file, skip it. */ @@ -647,6 +689,9 @@ gld${EMULATION_NAME}_after_open (void) if (global_found) continue; + n.by = l->by; + n.name = l->name; + nn.by = l->by; if (trace_file_tries) info_msg (_("%s needed by %B\n"), l->name, l->by); @@ -676,13 +721,13 @@ fi cat >>e${EMULATION_NAME}.c <name, force)) + &n, force)) break; EOF if [ "x${USE_LIBPATH}" = xyes ] ; then cat >>e${EMULATION_NAME}.c <name, force)) + &n, force)) break; EOF fi @@ -692,12 +737,12 @@ cat >>e${EMULATION_NAME}.c <name, + if (gld${EMULATION_NAME}_search_needed (lib_path, &n, force)) break; } lib_path = (const char *) getenv ("LD_LIBRARY_PATH"); - if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force)) + if (gld${EMULATION_NAME}_search_needed (lib_path, &n, force)) break; EOF fi @@ -710,7 +755,7 @@ cat >>e${EMULATION_NAME}.c <name); found = (rp->by == l->by && gld${EMULATION_NAME}_search_needed (tmpname, - l->name, + &n, force)); free (tmpname); } @@ -729,7 +774,8 @@ cat >>e${EMULATION_NAME}.c <name) + len + 2); sprintf (filename, "%s/%s", search->name, l->name); - if (gld${EMULATION_NAME}_try_needed (filename, force)) + nn.name = filename; + if (gld${EMULATION_NAME}_try_needed (&nn, force)) break; free (filename); } diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 2b77260..8af0223 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -984,6 +984,18 @@ needed. @option{--as-needed} causes DT_NEEDED tags to only be emitted for libraries that satisfy some reference from regular objects. @option{--no-as-needed} restores the default behaviour. +@kindex --add-needed +@kindex --no-add-needed +@item --add-needed +@itemx --no-add-needed +This option affects the treatment of dynamic libraries from ELF +DT_NEEDED tags in dynamic libraries mentioned on the command line after +the @option{--no-add-needed} option. Normally, the linker will add +a DT_NEEDED tag for each dynamic library from DT_NEEDED tags. +@option{--no-add-needed} causes DT_NEEDED tags will never be emitted +for those libraries from DT_NEEDED tags. @option{--add-needed} restores +the default behaviour. + @kindex -assert @var{keyword} @item -assert @var{keyword} This option is ignored for SunOS compatibility. diff --git a/ld/ldlang.c b/ld/ldlang.c index 8daf9c5..c5cfd5c 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -454,6 +454,7 @@ new_afile (const char *name, p->next = NULL; p->symbol_count = 0; p->dynamic = config.dynamic_link; + p->add_needed = add_needed; p->as_needed = as_needed; p->whole_archive = whole_archive; p->loaded = FALSE; diff --git a/ld/ldlang.h b/ld/ldlang.h index 0b56c27..f7e2fa6 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -266,6 +266,10 @@ typedef struct lang_input_statement_struct /* Whether to search for this entry as a dynamic archive. */ bfd_boolean dynamic; + /* Whether DT_NEEDED tags should be added for dynamic libraries in + DT_NEEDED tags from this entry. */ + bfd_boolean add_needed; + /* Whether this entry should cause a DT_NEEDED tag only when satisfying references from regular files, or always. */ bfd_boolean as_needed; diff --git a/ld/ldmain.c b/ld/ldmain.c index f1804c4..193fd69 100644 --- a/ld/ldmain.c +++ b/ld/ldmain.c @@ -97,6 +97,10 @@ bfd_boolean whole_archive; actually satisfies some reference in a regular object. */ bfd_boolean as_needed; +/* Nonzero means never create DT_NEEDED entries for dynamic libraries + in DT_NEEDED tags. */ +bfd_boolean add_needed = TRUE; + /* TRUE if we should demangle symbol names. */ bfd_boolean demangling; diff --git a/ld/ldmain.h b/ld/ldmain.h index 8cab5fe..976810e 100644 --- a/ld/ldmain.h +++ b/ld/ldmain.h @@ -33,6 +33,7 @@ extern bfd_boolean trace_file_tries; extern bfd_boolean version_printed; extern bfd_boolean whole_archive; extern bfd_boolean as_needed; +extern bfd_boolean add_needed; extern bfd_boolean demangling; extern int g_switch_value; extern const char *output_filename; diff --git a/ld/lexsup.c b/ld/lexsup.c index 55ab5ee..9a599a3 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -112,6 +112,8 @@ enum option_values OPTION_SPLIT_BY_RELOC, OPTION_SPLIT_BY_FILE , OPTION_WHOLE_ARCHIVE, + OPTION_ADD_NEEDED, + OPTION_NO_ADD_NEEDED, OPTION_AS_NEEDED, OPTION_NO_AS_NEEDED, OPTION_WRAP, @@ -482,6 +484,12 @@ static const struct ld_option ld_options[] = { {"whole-archive", no_argument, NULL, OPTION_WHOLE_ARCHIVE}, '\0', NULL, N_("Include all objects from following archives"), TWO_DASHES }, + { {"add-needed", no_argument, NULL, OPTION_ADD_NEEDED}, + '\0', NULL, N_("Set DT_NEEDED tags for DT_NEEDED entries in\n" + "\t\t\t\tfollowing dynamic libs"), TWO_DASHES }, + { {"no-add-needed", no_argument, NULL, OPTION_NO_ADD_NEEDED}, + '\0', NULL, N_("Do not set DT_NEEDED tags for DT_NEEDED entries\n" + "\t\t\t\tin following dynamic libs"), TWO_DASHES }, { {"as-needed", no_argument, NULL, OPTION_AS_NEEDED}, '\0', NULL, N_("Only set DT_NEEDED for following dynamic libs if used"), TWO_DASHES }, @@ -1196,6 +1204,12 @@ parse_args (unsigned argc, char **argv) case OPTION_WHOLE_ARCHIVE: whole_archive = TRUE; break; + case OPTION_ADD_NEEDED: + add_needed = TRUE; + break; + case OPTION_NO_ADD_NEEDED: + add_needed = FALSE; + break; case OPTION_AS_NEEDED: as_needed = TRUE; break; -- 2.7.4