/* ELF linking support for BFD.
- Copyright 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+ Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
switch (bed->s->arch_size)
{
- case 32: ptralign = 2; break;
- case 64: ptralign = 3; break;
- default: abort();
+ case 32:
+ ptralign = 2;
+ break;
+
+ case 64:
+ ptralign = 3;
+ break;
+
+ default:
+ bfd_set_error (bfd_error_bad_value);
+ return false;
}
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
return false;
}
- /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
- (or .got.plt) section. We don't do this in the linker script
- because we don't want to define the symbol if we are not creating
- a global offset table. */
- h = NULL;
- if (!(_bfd_generic_link_add_one_symbol
- (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s,
- bed->got_symbol_offset, (const char *) NULL, false,
- bed->collect, (struct bfd_link_hash_entry **) &h)))
- return false;
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
- h->type = STT_OBJECT;
+ if (bed->want_got_sym)
+ {
+ /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
+ (or .got.plt) section. We don't do this in the linker script
+ because we don't want to define the symbol if we are not creating
+ a global offset table. */
+ h = NULL;
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s,
+ bed->got_symbol_offset, (const char *) NULL, false,
+ bed->collect, (struct bfd_link_hash_entry **) &h)))
+ return false;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->type = STT_OBJECT;
- if (info->shared
- && ! _bfd_elf_link_record_dynamic_symbol (info, h))
- return false;
+ if (info->shared
+ && ! _bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
- elf_hash_table (info)->hgot = h;
+ elf_hash_table (info)->hgot = h;
+ }
/* The first bit of the global offset table is the header. */
s->_raw_size += bed->got_header_size + bed->got_symbol_offset;
return true;
}
\f
-
/* Create dynamic sections when linking against a dynamic object. */
boolean
flagword flags, pltflags;
register asection *s;
struct elf_backend_data *bed = get_elf_backend_data (abfd);
- int ptralign = 0;
+ int ptralign;
switch (bed->s->arch_size)
{
- case 32: ptralign = 2; break;
- case 64: ptralign = 3; break;
- default: abort();
+ case 32:
+ ptralign = 2;
+ break;
+
+ case 64:
+ ptralign = 3;
+ break;
+
+ default:
+ bfd_set_error (bfd_error_bad_value);
+ return false;
}
/* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
pltflags = flags;
pltflags |= SEC_CODE;
if (bed->plt_not_loaded)
- pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS);
+ pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
if (bed->plt_readonly)
pltflags |= SEC_READONLY;
return false;
}
- s = bfd_make_section (abfd,
+ s = bfd_make_section (abfd,
bed->default_use_rela_p ? ".rela.plt" : ".rel.plt");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
copy relocs. */
if (! info->shared)
{
- s = bfd_make_section (abfd,
- (bed->default_use_rela_p
- ? ".rela.bss" : ".rel.bss"));
+ s = bfd_make_section (abfd,
+ (bed->default_use_rela_p
+ ? ".rela.bss" : ".rel.bss"));
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
|| ! bfd_set_section_alignment (abfd, s, ptralign))
return true;
}
\f
-
/* Record a new dynamic symbol. We record the dynamic symbols as we
read the input files, since we need to have a list of all of them
before we can determine the final sizes of the output sections.
{
if (h->dynindx == -1)
{
- struct bfd_strtab_hash *dynstr;
+ struct elf_strtab_hash *dynstr;
char *p, *alc;
const char *name;
boolean copy;
bfd_size_type indx;
+ /* XXX: The ABI draft says the linker must turn hidden and
+ internal symbols into STB_LOCAL symbols when producing the
+ DSO. However, if ld.so honors st_other in the dynamic table,
+ this would not be necessary. */
+ switch (ELF_ST_VISIBILITY (h->other))
+ {
+ case STV_INTERNAL:
+ case STV_HIDDEN:
+ if (h->root.type != bfd_link_hash_undefined
+ && h->root.type != bfd_link_hash_undefweak)
+ {
+ h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+ return true;
+ }
+
+ default:
+ break;
+ }
+
h->dynindx = elf_hash_table (info)->dynsymcount;
++elf_hash_table (info)->dynsymcount;
if (dynstr == NULL)
{
/* Create a strtab to hold the dynamic symbol names. */
- elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+ elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
if (dynstr == NULL)
return false;
}
}
else
{
- alc = bfd_malloc (p - name + 1);
+ size_t len = p - name + 1;
+
+ alc = bfd_malloc ((bfd_size_type) len);
if (alc == NULL)
return false;
- strncpy (alc, name, p - name);
- alc[p - name] = '\0';
+ memcpy (alc, name, len - 1);
+ alc[len - 1] = '\0';
name = alc;
copy = true;
}
- indx = _bfd_stringtab_add (dynstr, name, true, copy);
+ indx = _bfd_elf_strtab_add (dynstr, name, copy);
if (alc != NULL)
free (alc);
return true;
}
+/* Record a new local dynamic symbol. Returns 0 on failure, 1 on
+ success, and 2 on a failure caused by attempting to record a symbol
+ in a discarded section, eg. a discarded link-once section symbol. */
+
+int
+elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
+ struct bfd_link_info *info;
+ bfd *input_bfd;
+ long input_indx;
+{
+ bfd_size_type amt;
+ struct elf_link_local_dynamic_entry *entry;
+ struct elf_link_hash_table *eht;
+ struct elf_strtab_hash *dynstr;
+ unsigned long dynstr_index;
+ char *name;
+ Elf_External_Sym_Shndx eshndx;
+ char esym[sizeof (Elf64_External_Sym)];
+
+ if (! is_elf_hash_table (info))
+ return 0;
+
+ /* See if the entry exists already. */
+ for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
+ if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
+ return 1;
+
+ amt = sizeof (*entry);
+ entry = (struct elf_link_local_dynamic_entry *) bfd_alloc (input_bfd, amt);
+ if (entry == NULL)
+ return 0;
+
+ /* Go find the symbol, so that we can find it's name. */
+ if (!bfd_elf_get_elf_syms (input_bfd, &elf_tdata (input_bfd)->symtab_hdr,
+ (size_t) 1, (size_t) input_indx,
+ &entry->isym, esym, &eshndx))
+ {
+ bfd_release (input_bfd, entry);
+ return 0;
+ }
+
+ if (entry->isym.st_shndx != SHN_UNDEF
+ && (entry->isym.st_shndx < SHN_LORESERVE
+ || entry->isym.st_shndx > SHN_HIRESERVE))
+ {
+ asection *s;
+
+ s = bfd_section_from_elf_index (input_bfd, entry->isym.st_shndx);
+ if (s == NULL || bfd_is_abs_section (s->output_section))
+ {
+ /* We can still bfd_release here as nothing has done another
+ bfd_alloc. We can't do this later in this function. */
+ bfd_release (input_bfd, entry);
+ return 2;
+ }
+ }
+
+ name = (bfd_elf_string_from_elf_section
+ (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link,
+ entry->isym.st_name));
+
+ dynstr = elf_hash_table (info)->dynstr;
+ if (dynstr == NULL)
+ {
+ /* Create a strtab to hold the dynamic symbol names. */
+ elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
+ if (dynstr == NULL)
+ return 0;
+ }
+
+ dynstr_index = _bfd_elf_strtab_add (dynstr, name, false);
+ if (dynstr_index == (unsigned long) -1)
+ return 0;
+ entry->isym.st_name = dynstr_index;
+
+ eht = elf_hash_table (info);
+
+ entry->next = eht->dynlocal;
+ eht->dynlocal = entry;
+ entry->input_bfd = input_bfd;
+ entry->input_indx = input_indx;
+ eht->dynsymcount++;
+
+ /* Whatever binding the symbol had before, it's now local. */
+ entry->isym.st_info
+ = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info));
+
+ /* The dynindx will be set at the end of size_dynamic_sections. */
+
+ return 1;
+}
+
/* Return the dynindex of a local dynamic symbol. */
long
{
size_t *count = (size_t *) data;
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
if (h->dynindx != -1)
h->dynindx = ++(*count);
return true;
}
-/* Assign dynsym indicies. In a shared library we generate a section
+/* Assign dynsym indices. In a shared library we generate a section
symbol for each output section, which come first. Next come all of
the back-end allocated local dynamic syms, followed by the rest of
the global symbols. */
{
asection *p;
for (p = output_bfd->sections; p ; p = p->next)
- elf_section_data (p)->dynindx = ++dynsymcount;
+ if ((p->flags & SEC_EXCLUDE) == 0)
+ elf_section_data (p)->dynindx = ++dynsymcount;
}
if (elf_hash_table (info)->dynlocal)
if (!lsect)
{
asection *s;
+ bfd_size_type amt = sizeof (elf_linker_section_t);
- lsect = (elf_linker_section_t *)
- bfd_alloc (dynobj, sizeof (elf_linker_section_t));
+ lsect = (elf_linker_section_t *) bfd_alloc (dynobj, amt);
*lsect = *defaults;
elf_linker_section (dynobj, which) = lsect;
s->_raw_size += lsect->hole_size;
if (lsect->hole_offset > lsect->max_hole_offset)
{
- (*_bfd_error_handler) (_("%s: Section %s is already to large to put hole of %ld bytes in"),
+ (*_bfd_error_handler) (_("%s: Section %s is too large to add hole of %ld bytes"),
bfd_get_filename (abfd),
lsect->name,
- (long)lsect->hole_size);
+ (long) lsect->hole_size);
bfd_set_error (bfd_error_bad_value);
return (elf_linker_section_t *)0;
return lsect;
}
-
\f
/* Find a linker generated pointer with a given addend and type. */
elf_linker_section_pointers_t *
_bfd_elf_find_pointer_linker_section (linker_pointers, addend, which)
elf_linker_section_pointers_t *linker_pointers;
- bfd_signed_vma addend;
+ bfd_vma addend;
elf_linker_section_enum_t which;
{
for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next)
return (elf_linker_section_pointers_t *)0;
}
-
\f
/* Make the .rela section corresponding to the generated linker section. */