/* Intel 80386/80486-specific support for 32-bit ELF
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
default:
return false;
- case 128: /* Linux/MIPS elf_prpsinfo */
+ case 124: /* Linux/i386 elf_prpsinfo */
elf_tdata (abfd)->core_program
= _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
elf_tdata (abfd)->core_command
asection *srelplt;
asection *sdynbss;
asection *srelbss;
+
+ /* Small local sym to section mapping cache. */
+ struct sym_sec_cache sym_sec;
};
/* Get the i386 ELF linker hash table from a link_info structure. */
struct elf_i386_link_hash_table *ret;
bfd_size_type amt = sizeof (struct elf_i386_link_hash_table);
- ret = (struct elf_i386_link_hash_table *) bfd_alloc (abfd, amt);
+ ret = (struct elf_i386_link_hash_table *) bfd_malloc (amt);
if (ret == NULL)
return NULL;
if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc))
{
- bfd_release (abfd, ret);
+ free (ret);
return NULL;
}
ret->srelplt = NULL;
ret->sdynbss = NULL;
ret->srelbss = NULL;
+ ret->sym_sec.abfd = NULL;
return &ret->elf.root;
}
|| (h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR) == 0)))
{
+ struct elf_i386_dyn_relocs *p;
+ struct elf_i386_dyn_relocs **head;
+
/* We must copy these reloc types into the output file.
Create a reloc section in dynobj and make room for
this reloc. */
{
const char *name;
bfd *dynobj;
+ unsigned int strndx = elf_elfheader (abfd)->e_shstrndx;
+ unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name;
- name = (bfd_elf_string_from_elf_section
- (abfd,
- elf_elfheader (abfd)->e_shstrndx,
- elf_section_data (sec)->rel_hdr.sh_name));
+ name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
if (name == NULL)
return false;
relocations we need for this symbol. */
if (h != NULL)
{
- struct elf_i386_link_hash_entry *eh;
- struct elf_i386_dyn_relocs *p;
-
- eh = (struct elf_i386_link_hash_entry *) h;
- p = eh->dyn_relocs;
-
- if (p == NULL || p->sec != sec)
- {
- bfd_size_type amt = sizeof *p;
- p = ((struct elf_i386_dyn_relocs *)
- bfd_alloc (htab->elf.dynobj, amt));
- if (p == NULL)
- return false;
- p->next = eh->dyn_relocs;
- eh->dyn_relocs = p;
- p->sec = sec;
- p->count = 0;
- p->pc_count = 0;
- }
-
- p->count += 1;
- if (ELF32_R_TYPE (rel->r_info) == R_386_PC32)
- p->pc_count += 1;
+ head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs;
}
else
{
- /* Track dynamic relocs needed for local syms too. */
- elf_section_data (sec)->local_dynrel += 1;
+ /* Track dynamic relocs needed for local syms too.
+ We really need local syms available to do this
+ easily. Oh well. */
+
+ asection *s;
+ s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
+ sec, r_symndx);
+ if (s == NULL)
+ return false;
+
+ head = ((struct elf_i386_dyn_relocs **)
+ &elf_section_data (s)->local_dynrel);
}
+
+ p = *head;
+ if (p == NULL || p->sec != sec)
+ {
+ bfd_size_type amt = sizeof *p;
+ p = ((struct elf_i386_dyn_relocs *)
+ bfd_alloc (htab->elf.dynobj, amt));
+ if (p == NULL)
+ return false;
+ p->next = *head;
+ *head = p;
+ p->sec = sec;
+ p->count = 0;
+ p->pc_count = 0;
+ }
+
+ p->count += 1;
+ if (ELF32_R_TYPE (rel->r_info) == R_386_PC32)
+ p->pc_count += 1;
}
break;
}
else
{
- if (!(elf_bad_symtab (abfd)
- && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
- && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
- && sym->st_shndx != SHN_COMMON))
- {
- return bfd_section_from_elf_index (abfd, sym->st_shndx);
- }
+ return bfd_section_from_elf_index (abfd, sym->st_shndx);
}
return NULL;
const Elf_Internal_Rela *rel, *relend;
unsigned long r_symndx;
struct elf_link_hash_entry *h;
- bfd *dynobj;
- elf_section_data (sec)->local_dynrel = 0;
-
- dynobj = elf_hash_table (info)->dynobj;
- if (dynobj == NULL)
- return true;
+ elf_section_data (sec)->local_dynrel = NULL;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
if (h->plt.refcount <= 0
|| (! info->shared
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0))
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0
+ && h->root.type != bfd_link_hash_undefweak
+ && h->root.type != bfd_link_hash_undefined))
{
/* This case can occur if we saw a PLT32 reloc in an input
file, but the symbol was never referred to by a dynamic
struct elf_i386_link_hash_entry *eh;
struct elf_i386_dyn_relocs *p;
- if (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
+ if (h->root.type == bfd_link_hash_indirect)
return true;
+ if (h->root.type == bfd_link_hash_warning)
+ /* When warning symbols are created, they **replace** the "real"
+ entry in the hash table, thus we never get to see the real
+ symbol in a hash traversal. So look at it now. */
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
info = (struct bfd_link_info *) inf;
htab = elf_i386_hash_table (info);
eh->dyn_relocs = NULL;
- keep:
+ keep: ;
}
/* Finally, allocate space. */
struct elf_i386_link_hash_entry *eh;
struct elf_i386_dyn_relocs *p;
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
eh = (struct elf_i386_link_hash_entry *) h;
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
for (s = ibfd->sections; s != NULL; s = s->next)
{
- bfd_size_type count = elf_section_data (s)->local_dynrel;
+ struct elf_i386_dyn_relocs *p;
- if (count != 0)
+ for (p = *((struct elf_i386_dyn_relocs **)
+ &elf_section_data (s)->local_dynrel);
+ p != NULL;
+ p = p->next)
{
- srel = elf_section_data (s)->sreloc;
- srel->_raw_size += count * sizeof (Elf32_External_Rel);
+ if (!bfd_is_abs_section (p->sec)
+ && bfd_is_abs_section (p->sec->output_section))
+ {
+ /* Input section has been discarded, either because
+ it is a copy of a linkonce section or due to
+ linker script /DISCARD/, so we'll be discarding
+ the relocs too. */
+ }
+ else if (p->count != 0)
+ {
+ srel = elf_section_data (p->sec)->sreloc;
+ srel->_raw_size += p->count * sizeof (Elf32_External_Rel);
+ if ((p->sec->output_section->flags & SEC_READONLY) != 0)
+ info->flags |= DF_TEXTREL;
+ }
}
}
/* If any dynamic relocs apply to a read-only section,
then we need a DT_TEXTREL entry. */
- elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, (PTR) info);
+ if ((info->flags & DF_TEXTREL) == 0)
+ elf_link_hash_traverse (&htab->elf, readonly_dynrelocs,
+ (PTR) info);
if ((info->flags & DF_TEXTREL) != 0)
{
relocation = (sec->output_section->vma
+ sec->output_offset
+ sym->st_value);
+ if ((sec->flags & SEC_MERGE)
+ && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ {
+ asection *msec;
+ bfd_vma addend;
+
+ if (howto->src_mask != 0xffffffff)
+ {
+ (*_bfd_error_handler)
+ (_("%s(%s+0x%lx): %s relocation against SEC_MERGE section"),
+ bfd_archive_filename (input_bfd),
+ bfd_get_section_name (input_bfd, input_section),
+ (long) rel->r_offset, howto->name);
+ return false;
+ }
+
+ addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ msec = sec;
+ addend =
+ _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
+ - relocation;
+ addend += msec->output_section->vma + msec->output_offset;
+ bfd_put_32 (input_bfd, addend, contents + rel->r_offset);
+ }
}
else
{
case R_386_32:
case R_386_PC32:
+ /* r_symndx will be zero only for relocs against symbols
+ from removed linkonce sections, or sections discarded by
+ a linker script. */
+ if (r_symndx == 0
+ || (input_section->flags & SEC_ALLOC) == 0)
+ break;
+
if ((info->shared
- && (input_section->flags & SEC_ALLOC) != 0
&& (r_type != R_386_PC32
|| (h != NULL
&& h->dynindx != -1
|| (h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR) == 0))))
|| (!info->shared
- && (input_section->flags & SEC_ALLOC) != 0
&& h != NULL
&& h->dynindx != -1
&& (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
time. */
skip = false;
-
- if (elf_section_data (input_section)->stab_info == NULL)
- outrel.r_offset = rel->r_offset;
- else
- {
- off = (_bfd_stab_section_offset
- (output_bfd, htab->elf.stab_info, input_section,
- &elf_section_data (input_section)->stab_info,
- rel->r_offset));
- if (off == (bfd_vma) -1)
- skip = true;
- outrel.r_offset = off;
- }
-
+ relocate = false;
+
+ outrel.r_offset =
+ _bfd_elf_section_offset (output_bfd, info, input_section,
+ rel->r_offset);
+ if (outrel.r_offset == (bfd_vma) -1)
+ skip = true;
+ else if (outrel.r_offset == (bfd_vma) -2)
+ skip = true, relocate = true;
outrel.r_offset += (input_section->output_section->vma
+ input_section->output_offset);
if (skip)
- {
- memset (&outrel, 0, sizeof outrel);
- relocate = false;
- }
+ memset (&outrel, 0, sizeof outrel);
else if (h != NULL
&& h->dynindx != -1
&& (r_type == R_386_PC32
|| !info->symbolic
|| (h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR) == 0))
-
- {
- relocate = false;
- outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
- }
+ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
else
{
/* This symbol is local, or marked to become local. */
if (! relocate)
continue;
}
-
break;
default:
contents, rel->r_offset,
relocation, (bfd_vma) 0);
- switch (r)
+ if (r != bfd_reloc_ok)
{
- case bfd_reloc_ok:
- break;
+ const char *name;
- case bfd_reloc_overflow:
- {
- const char *name;
-
- if (h != NULL)
- name = h->root.root.string;
- else
- {
- name = bfd_elf_string_from_elf_section (input_bfd,
- symtab_hdr->sh_link,
- sym->st_name);
- if (name == NULL)
- return false;
- if (*name == '\0')
- name = bfd_section_name (input_bfd, sec);
- }
- if (! ((*info->callbacks->reloc_overflow)
- (info, name, howto->name, (bfd_vma) 0,
- input_bfd, input_section, rel->r_offset)))
- return false;
- }
- break;
+ if (h != NULL)
+ name = h->root.root.string;
+ else
+ {
+ name = bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ sym->st_name);
+ if (name == NULL)
+ return false;
+ if (*name == '\0')
+ name = bfd_section_name (input_bfd, sec);
+ }
- default:
- case bfd_reloc_outofrange:
- abort ();
- break;
+ if (r == bfd_reloc_overflow)
+ {
+
+ if (! ((*info->callbacks->reloc_overflow)
+ (info, name, howto->name, (bfd_vma) 0,
+ input_bfd, input_section, rel->r_offset)))
+ return false;
+ }
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%s(%s+0x%lx): reloc against `%s': error %d"),
+ bfd_archive_filename (input_bfd),
+ bfd_get_section_name (input_bfd, input_section),
+ (long) rel->r_offset, name, (int) r);
+ return false;
+ }
}
}