+2004-07-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * 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 <dave.anglin@nrc-cnrc.gc.ca>
* elflink.c (elf_section_complain_discarded): Don't complain in
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
(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
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
(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
#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 */
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)
{
/* 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)
/* 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)
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;
+2004-07-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * 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 <christof@petig-baender.de>
* emultempl/pe.em (make_import_fixup): Use bfd_get_32 to correct
static bfd_boolean
gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry)
{
- if (!entry->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;
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)
/* 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 (abfd, DYN_DT_NEEDED);
+ class = DYN_DT_NEEDED;
+
+ /* Tell the ELF linker that we don't want the output file to have a
+ DT_NEEDED entry for this file at all if the entry is from a file
+ with DYN_NO_ADD_NEEDED. */
+ if (needed->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))
/* Search for a needed file in a path. */
static bfd_boolean
-gld${EMULATION_NAME}_search_needed (const char *path, const char *name, int force)
+gld${EMULATION_NAME}_search_needed (const char *path,
+ struct dt_needed *n, int force)
{
const char *s;
+ const char *name = n->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)
{
}
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);
{
static bfd_boolean initialized;
static char *ld_so_conf;
+ struct dt_needed needed;
if (! initialized)
{
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
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. */
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);
cat >>e${EMULATION_NAME}.c <<EOF
if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
- l->name, force))
+ &n, force))
break;
EOF
if [ "x${USE_LIBPATH}" = xyes ] ; then
cat >>e${EMULATION_NAME}.c <<EOF
if (gld${EMULATION_NAME}_search_needed (command_line.rpath,
- l->name, force))
+ &n, force))
break;
EOF
fi
&& command_line.rpath == NULL)
{
lib_path = (const char *) getenv ("LD_RUN_PATH");
- if (gld${EMULATION_NAME}_search_needed (lib_path, l->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
char *tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name);
found = (rp->by == l->by
&& gld${EMULATION_NAME}_search_needed (tmpname,
- l->name,
+ &n,
force));
free (tmpname);
}
continue;
filename = (char *) xmalloc (strlen (search->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);
}
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.
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;
/* 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;
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;
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;
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,
{ {"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 },
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;