/* ELF linker support.
- Copyright 1995, 1996 Free Software Foundation, Inc.
+ Copyright 1995, 1996, 1997 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf_link_add_archive_symbols
PARAMS ((bfd *, struct bfd_link_info *));
-static Elf_Internal_Rela *elf_link_read_relocs
- PARAMS ((bfd *, asection *, PTR, Elf_Internal_Rela *, boolean));
static boolean elf_export_symbol
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_adjust_dynamic_symbol
{
boolean failed;
struct bfd_link_info *info;
-};
+};
/* Given an ELF BFD, add symbols to the global hash table as
appropriate. */
goto error_return;
if (! (_bfd_generic_link_add_one_symbol
- (info, abfd,
+ (info, abfd,
name + sizeof ".gnu.warning." - 1,
BSF_WARNING, s, (bfd_vma) 0, msg, false, collect,
(struct bfd_link_hash_entry **) NULL)))
/* Find the name to use in a DT_NEEDED entry that refers to this
object. If the object has a DT_SONAME entry, we use it.
Otherwise, if the generic linker stuck something in
- elf_dt_needed_name, we use that. Otherwise, we just use the
- file name. If the generic linker put a null string into
- elf_dt_needed_name, we don't make a DT_NEEDED entry at all,
- even if there is a DT_SONAME entry. */
+ elf_dt_name, we use that. Otherwise, we just use the file
+ name. If the generic linker put a null string into
+ elf_dt_name, we don't make a DT_NEEDED entry at all, even if
+ there is a DT_SONAME entry. */
add_needed = true;
name = bfd_get_filename (abfd);
- if (elf_dt_needed_name (abfd) != NULL)
+ if (elf_dt_name (abfd) != NULL)
{
- name = elf_dt_needed_name (abfd);
+ name = elf_dt_name (abfd);
if (*name == '\0')
add_needed = false;
}
Elf_Internal_Dyn dyn;
elf_swap_dyn_in (abfd, extdyn, &dyn);
- if (add_needed && dyn.d_tag == DT_SONAME)
+ if (dyn.d_tag == DT_SONAME)
{
name = bfd_elf_string_from_elf_section (abfd, link,
dyn.d_un.d_val);
if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
goto error_return;
}
+
+ /* Save the SONAME, if there is one, because sometimes the
+ linker emulation code will need to know it. */
+ if (*name == '\0')
+ name = bfd_get_filename (abfd);
+ elf_dt_name (abfd) = name;
}
if (bfd_seek (abfd,
the dynamic object handling right. We pass the hash
table entry in to _bfd_generic_link_add_one_symbol so
that it does not have to look it up again. */
- h = elf_link_hash_lookup (elf_hash_table (info), name,
- true, false, false);
+ if (! bfd_is_und_section (sec))
+ h = elf_link_hash_lookup (elf_hash_table (info), name,
+ true, false, false);
+ else
+ h = ((struct elf_link_hash_entry *)
+ bfd_wrapped_link_hash_lookup (abfd, info, name, true,
+ false, false));
if (h == NULL)
goto error_return;
*sym_hash = h;
by some other object. If it has, we want to use the
existing definition, and we do not want to report a
multiple symbol definition error; we do this by
- clobbering sec to be bfd_und_section_ptr. */
+ clobbering sec to be bfd_und_section_ptr. We treat a
+ common symbol as a definition if the symbol in the shared
+ library is a function, since common symbols always
+ represent variables; this can cause confusion in
+ principle, but any such confusion would seem to indicate
+ an erroneous program or shared library. */
if (dynamic && definition)
{
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak
|| (h->root.type == bfd_link_hash_common
- && bind == STB_WEAK))
+ && (bind == STB_WEAK
+ || ELF_ST_TYPE (sym.st_info) == STT_FUNC)))
{
sec = bfd_und_section_ptr;
definition = false;
size_change_ok = true;
+ if (h->root.type == bfd_link_hash_common)
+ type_change_ok = true;
}
}
objects, even if they are defined after the dynamic
object in the link. */
if (! dynamic
- && definition
+ && (definition
+ || (bfd_is_com_section (sec)
+ && (h->root.type == bfd_link_hash_defweak
+ || h->type == STT_FUNC)))
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
h->root.type = bfd_link_hash_undefined;
h->root.u.undef.abfd = h->root.u.def.section->owner;
size_change_ok = true;
+ if (bfd_is_com_section (sec))
+ type_change_ok = true;
}
}
h->type = ELF_ST_TYPE (sym.st_info);
}
+ if (sym.st_other != 0
+ && (definition || h->other == 0))
+ h->other = sym.st_other;
+
/* Set a flag in the hash table entry indicating the type of
reference or definition we just found. Keep a count of
the number of dynamic symbols we find. A dynamic symbol
is one which is referenced or defined by both a regular
- object and a shared object, or one which is referenced or
- defined by more than one shared object. */
+ object and a shared object. */
old_flags = h->elf_link_hash_flags;
dynsym = false;
if (! dynamic)
new_flag = ELF_LINK_HASH_REF_DYNAMIC;
else
new_flag = ELF_LINK_HASH_DEF_DYNAMIC;
- if ((old_flags & new_flag) != 0
- || (old_flags & (ELF_LINK_HASH_DEF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR)) != 0
+ if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR
+ | ELF_LINK_HASH_REF_REGULAR)) != 0
|| (h->weakdef != NULL
- && (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC
- | ELF_LINK_HASH_REF_DYNAMIC)) != 0))
+ && ! new_weakdef
+ && h->weakdef->dynindx != -1))
dynsym = true;
}
goto error_return;
}
+ /* If the real definition is in the list of dynamic
+ symbols, make sure the weak definition is put there
+ as well. If we don't do this, then the dynamic
+ loader might not merge the entries for the real
+ definition and the weak definition. */
+ if (h->dynindx != -1
+ && hlook->dynindx == -1)
+ {
+ if (! _bfd_elf_link_record_dynamic_symbol (info, hlook))
+ goto error_return;
+ }
+
break;
}
}
|| o->reloc_count == 0)
continue;
- /* I believe we can ignore the relocs for any section which
- does not form part of the final process image, such as a
- debugging section. */
- if ((o->flags & SEC_ALLOC) == 0)
- continue;
-
- internal_relocs = elf_link_read_relocs (abfd, o, (PTR) NULL,
- (Elf_Internal_Rela *) NULL,
- info->keep_memory);
+ internal_relocs = (NAME(_bfd_elf,link_read_relocs)
+ (abfd, o, (PTR) NULL,
+ (Elf_Internal_Rela *) NULL,
+ info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
}
}
+ /* If this is a non-traditional, non-relocateable link, try to
+ optimize the handling of the .stab/.stabstr sections. */
+ if (! dynamic
+ && ! info->relocateable
+ && ! info->traditional_format
+ && info->hash->creator->flavour == bfd_target_elf_flavour
+ && (info->strip != strip_all && info->strip != strip_debugger))
+ {
+ asection *stab, *stabstr;
+
+ stab = bfd_get_section_by_name (abfd, ".stab");
+ if (stab != NULL)
+ {
+ stabstr = bfd_get_section_by_name (abfd, ".stabstr");
+
+ if (stabstr != NULL)
+ {
+ struct bfd_elf_section_data *secdata;
+
+ secdata = elf_section_data (stab);
+ if (! _bfd_link_section_stabs (abfd,
+ &elf_hash_table (info)->stab_info,
+ stab, stabstr,
+ &secdata->stab_info))
+ goto error_return;
+ }
+ }
+ }
+
return true;
error_return:
/* Note that we set the SEC_IN_MEMORY flag for all of these
sections. */
- flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
/* A dynamically linked executable has a .interp section, but a
shared library does not. */
value is allocated using either malloc or bfd_alloc, according to
the KEEP_MEMORY argument. */
-static Elf_Internal_Rela *
-elf_link_read_relocs (abfd, o, external_relocs, internal_relocs, keep_memory)
+Elf_Internal_Rela *
+NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
+ keep_memory)
bfd *abfd;
asection *o;
PTR external_relocs;
/* Cache the results for next time, if we can. */
if (keep_memory)
elf_section_data (o)->relocs = internal_relocs;
-
+
if (alloc1 != NULL)
free (alloc1);
based on the number of symbols there are. If there are fewer than
3 symbols we use 1 bucket, fewer than 17 symbols we use 3 buckets,
fewer than 37 we use 17 buckets, and so forth. We never use more
- than 521 buckets. */
+ than 32771 buckets. */
static const size_t elf_buckets[] =
{
- 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 0
+ 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771, 0
};
/* Set up the sizes and contents of the ELF dynamic sections. This is
boolean
NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
- export_dynamic, info, sinterpptr)
+ export_dynamic, filter_shlib,
+ auxiliary_filters, info, sinterpptr)
bfd *output_bfd;
const char *soname;
const char *rpath;
boolean export_dynamic;
+ const char *filter_shlib;
+ const char * const *auxiliary_filters;
struct bfd_link_info *info;
asection **sinterpptr;
{
if (info->hash->creator->flavour != bfd_target_elf_flavour)
return true;
+ /* The backend may have to create some sections regardless of whether
+ we're dynamic or not. */
+ bed = get_elf_backend_data (output_bfd);
+ if (bed->elf_backend_always_size_sections
+ && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
+ return false;
+
dynobj = elf_hash_table (info)->dynobj;
/* If there were no dynamic objects in the link, there is nothing to
if (indx == (bfd_size_type) -1
|| ! elf_add_dynamic_entry (info, DT_SONAME, indx))
return false;
- }
+ }
if (info->symbolic)
{
return false;
}
+ if (filter_shlib != NULL)
+ {
+ bfd_size_type indx;
+
+ indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+ filter_shlib, true, true);
+ if (indx == (bfd_size_type) -1
+ || ! elf_add_dynamic_entry (info, DT_FILTER, indx))
+ return false;
+ }
+
+ if (auxiliary_filters != NULL)
+ {
+ const char * const *p;
+
+ for (p = auxiliary_filters; *p != NULL; p++)
+ {
+ bfd_size_type indx;
+
+ indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+ *p, true, true);
+ if (indx == (bfd_size_type) -1
+ || ! elf_add_dynamic_entry (info, DT_AUXILIARY, indx))
+ return false;
+ }
+ }
+
/* Find all symbols which were defined in a dynamic object and make
the backend pick a reasonable value for them. */
eif.failed = false;
/* The backend must work out the sizes of all the other dynamic
sections. */
- bed = get_elf_backend_data (output_bfd);
if (! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
return false;
}
}
+ /* 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 ELF_LINK_HASH_DEF_REGULAR
+ flag will not have been set. */
+ if (h->root.type == bfd_link_hash_defined
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+ && (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+
/* If -Bsymbolic was used (which means to bind references to global
symbols to the definition within the shared object), and this
symbol was defined in a regular object, then it actually doesn't
{
boolean failed;
struct elf_final_link_info *finfo;
-};
+};
/* Do the final step of an ELF link. */
sec = p->u.indirect.section;
+ /* Mark all sections which are to be included in the
+ link. This will normally be every section. We need
+ to do this so that we can identify any sections which
+ the linker has decided to not include. */
+ sec->linker_mark = true;
+
if (info->relocateable)
o->reloc_count += sec->reloc_count;
zero. This is done in elf_fake_sections as well, but forcing
the VMA to 0 here will ensure that relocs against these
sections are handled correctly. */
- if ((o->flags & SEC_ALLOC) == 0)
+ if ((o->flags & SEC_ALLOC) == 0
+ && ! o->user_set_vma)
o->vma = 0;
}
{
if (*rel_hash == NULL)
continue;
-
+
BFD_ASSERT ((*rel_hash)->indx >= 0);
if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
if ((o->flags & SEC_HAS_CONTENTS) == 0
|| o->_raw_size == 0)
continue;
- if ((o->flags & SEC_IN_MEMORY) == 0)
+ if ((o->flags & SEC_LINKER_CREATED) == 0)
{
/* At this point, we are only interested in sections
- created by elf_link_create_dynamic_sections. FIXME:
- This test is fragile. */
+ created by elf_link_create_dynamic_sections. */
continue;
}
if ((elf_section_data (o->output_section)->this_hdr.sh_type
}
}
+ /* If we have optimized stabs strings, output them. */
+ if (elf_hash_table (info)->stab_info != NULL)
+ {
+ if (! _bfd_write_stab_strings (abfd, &elf_hash_table (info)->stab_info))
+ goto error_return;
+ }
+
if (finfo.symstrtab != NULL)
_bfd_stringtab_free (finfo.symstrtab);
if (finfo.contents != NULL)
sym.st_value = 0;
sym.st_size = h->size;
- sym.st_other = 0;
+ sym.st_other = h->other;
if (h->root.type == bfd_link_hash_undefweak
|| h->root.type == bfd_link_hash_defweak)
sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
Elf_Internal_Shdr *symtab_hdr;
size_t locsymcount;
size_t extsymoff;
+ Elf_External_Sym *external_syms;
Elf_External_Sym *esym;
Elf_External_Sym *esymend;
Elf_Internal_Sym *isym;
}
/* Read the local symbols. */
- if (locsymcount > 0
- && (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
- || (bfd_read (finfo->external_syms, sizeof (Elf_External_Sym),
+ if (symtab_hdr->contents != NULL)
+ external_syms = (Elf_External_Sym *) symtab_hdr->contents;
+ else if (locsymcount == 0)
+ external_syms = NULL;
+ else
+ {
+ external_syms = finfo->external_syms;
+ if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+ || (bfd_read (external_syms, sizeof (Elf_External_Sym),
locsymcount, input_bfd)
- != locsymcount * sizeof (Elf_External_Sym))))
- return false;
+ != locsymcount * sizeof (Elf_External_Sym)))
+ return false;
+ }
/* Swap in the local symbols and write out the ones which we know
are going into the output file. */
- esym = finfo->external_syms;
+ esym = external_syms;
esymend = esym + locsymcount;
isym = finfo->internal_syms;
pindex = finfo->indices;
*ppsection = isec;
/* Don't output the first, undefined, symbol. */
- if (esym == finfo->external_syms)
+ if (esym == external_syms)
continue;
/* If we are stripping all symbols, we don't want to output this
/* Relocate the contents of each section. */
for (o = input_bfd->sections; o != NULL; o = o->next)
{
- if ((o->flags & SEC_HAS_CONTENTS) == 0)
+ bfd_byte *contents;
+
+ if (! o->linker_mark)
+ {
+ /* This section was omitted from the link. */
+ continue;
+ }
+
+ if ((o->flags & SEC_HAS_CONTENTS) == 0
+ || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0))
continue;
- if ((o->flags & SEC_IN_MEMORY) != 0
- && input_bfd == elf_hash_table (finfo->info)->dynobj)
+ if ((o->flags & SEC_LINKER_CREATED) != 0)
{
- /* Section was created by elf_link_create_dynamic_sections.
- FIXME: This test is fragile. */
+ /* Section was created by elf_link_create_dynamic_sections
+ or somesuch. */
continue;
}
- /* Read the contents of the section. */
- if (! bfd_get_section_contents (input_bfd, o, finfo->contents,
- (file_ptr) 0, o->_raw_size))
- return false;
+ /* Get the contents of the section. They have been cached by a
+ relaxation routine. Note that o is a section in an input
+ file, so the contents field will not have been set by any of
+ the routines which work on output files. */
+ if (elf_section_data (o)->this_hdr.contents != NULL)
+ contents = elf_section_data (o)->this_hdr.contents;
+ else
+ {
+ contents = finfo->contents;
+ if (! bfd_get_section_contents (input_bfd, o, contents,
+ (file_ptr) 0, o->_raw_size))
+ return false;
+ }
if ((o->flags & SEC_RELOC) != 0)
{
Elf_Internal_Rela *internal_relocs;
/* Get the swapped relocs. */
- internal_relocs = elf_link_read_relocs (input_bfd, o,
- finfo->external_relocs,
- finfo->internal_relocs,
- false);
+ internal_relocs = (NAME(_bfd_elf,link_read_relocs)
+ (input_bfd, o, finfo->external_relocs,
+ finfo->internal_relocs, false));
if (internal_relocs == NULL
&& o->reloc_count > 0)
return false;
the addend to be adjusted. */
if (! (*relocate_section) (output_bfd, finfo->info,
- input_bfd, o,
- finfo->contents,
+ input_bfd, o, contents,
internal_relocs,
finfo->internal_syms,
finfo->sections))
}
/* Write out the modified section contents. */
- if (! bfd_set_section_contents (output_bfd, o->output_section,
- finfo->contents, o->output_offset,
- (o->_cooked_size != 0
- ? o->_cooked_size
- : o->_raw_size)))
- return false;
+ if (elf_section_data (o)->stab_info == NULL)
+ {
+ if (! bfd_set_section_contents (output_bfd, o->output_section,
+ contents, o->output_offset,
+ (o->_cooked_size != 0
+ ? o->_cooked_size
+ : o->_raw_size)))
+ return false;
+ }
+ else
+ {
+ if (! _bfd_write_section_stabs (output_bfd, o,
+ &elf_section_data (o)->stab_info,
+ contents))
+ return false;
+ }
}
return true;
/* Treat a reloc against a defined symbol as though it were
actually against the section. */
- h = elf_link_hash_lookup (elf_hash_table (info),
- link_order->u.reloc.p->u.name,
- false, false, true);
+ h = ((struct elf_link_hash_entry *)
+ bfd_wrapped_link_hash_lookup (output_bfd, info,
+ link_order->u.reloc.p->u.name,
+ false, false, true));
if (h != NULL
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak))
linker_section_ptr->written_address_p = false;
*ptr_linker_section_ptr = linker_section_ptr;
+#if 0
if (lsect->hole_size && lsect->hole_offset < lsect->max_hole_offset)
{
- linker_section_ptr->offset = lsect->section->_raw_size - lsect->hole_size;
+ linker_section_ptr->offset = lsect->section->_raw_size - lsect->hole_size + (ARCH_SIZE / 8);
lsect->hole_offset += ARCH_SIZE / 8;
lsect->sym_offset += ARCH_SIZE / 8;
if (lsect->sym_hash) /* Bump up symbol value if needed */
- lsect->sym_hash->root.u.def.value += ARCH_SIZE / 8;
+ {
+ lsect->sym_hash->root.u.def.value += ARCH_SIZE / 8;
+#ifdef DEBUG
+ fprintf (stderr, "Bump up %s by %ld, current value = %ld\n",
+ lsect->sym_hash->root.root.string,
+ (long)ARCH_SIZE / 8,
+ (long)lsect->sym_hash->root.u.def.value);
+#endif
+ }
}
else
+#endif
linker_section_ptr->offset = lsect->section->_raw_size;
lsect->section->_raw_size += ARCH_SIZE / 8;