/* 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.
PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
static void elf_i386_info_to_howto_rel
PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
-static boolean elf_i386_is_local_label_name PARAMS ((bfd *, const char *));
-static struct bfd_hash_entry *elf_i386_link_hash_newfunc
+static boolean elf_i386_is_local_label_name
+ PARAMS ((bfd *, const char *));
+static boolean elf_i386_grok_prstatus
+ PARAMS ((bfd *abfd, Elf_Internal_Note *note));
+static boolean elf_i386_grok_psinfo
+ PARAMS ((bfd *abfd, Elf_Internal_Note *note));
+static struct bfd_hash_entry *link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
static struct bfd_link_hash_table *elf_i386_link_hash_table_create
PARAMS ((bfd *));
-static boolean create_got_section PARAMS((bfd *, struct bfd_link_info *));
+static boolean create_got_section
+ PARAMS((bfd *, struct bfd_link_info *));
static boolean elf_i386_create_dynamic_sections
PARAMS((bfd *, struct bfd_link_info *));
+static void elf_i386_copy_indirect_symbol
+ PARAMS ((struct elf_link_hash_entry *, struct elf_link_hash_entry *));
+static int elf_i386_tls_transition
+ PARAMS ((struct bfd_link_info *, int, int));
+
+static boolean elf_i386_mkobject
+ PARAMS((bfd *));
+static boolean elf_i386_object_p
+ PARAMS((bfd *));
static boolean elf_i386_check_relocs
PARAMS ((bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *));
+static asection *elf_i386_gc_mark_hook
+ PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
+ struct elf_link_hash_entry *, Elf_Internal_Sym *));
+static boolean elf_i386_gc_sweep_hook
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *));
static boolean elf_i386_adjust_dynamic_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
-static boolean allocate_plt_and_got_and_discard_relocs
+static boolean allocate_dynrelocs
+ PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean readonly_dynrelocs
PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_i386_fake_sections
+ PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
static boolean elf_i386_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
+static bfd_vma dtpoff_base
+ PARAMS ((struct bfd_link_info *));
+static bfd_vma tpoff
+ PARAMS ((struct bfd_link_info *, bfd_vma));
static boolean elf_i386_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
static boolean elf_i386_finish_dynamic_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
Elf_Internal_Sym *));
+static enum elf_reloc_type_class elf_i386_reloc_type_class
+ PARAMS ((const Elf_Internal_Rela *));
static boolean elf_i386_finish_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
R_386_ext_offset is the value to subtract from a reloc type of
R_386_16 thru R_386_PC8 to form an index into this table. */
#define R_386_standard ((unsigned int) R_386_GOTPC + 1)
-#define R_386_ext_offset ((unsigned int) R_386_16 - R_386_standard)
+#define R_386_ext_offset ((unsigned int) R_386_TLS_LE - R_386_standard)
/* The remaining relocs are a GNU extension. */
+ HOWTO(R_386_TLS_LE, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_LE",
+ true, 0xffffffff, 0xffffffff, false),
+ HOWTO(R_386_TLS_GD, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_GD",
+ true, 0xffffffff, 0xffffffff, false),
+ HOWTO(R_386_TLS_LDM, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_LDM",
+ true, 0xffffffff, 0xffffffff, false),
HOWTO(R_386_16, 0, 1, 16, false, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_386_16",
true, 0xffff, 0xffff, false),
bfd_elf_generic_reloc, "R_386_PC8",
true, 0xff, 0xff, true),
- /* Another gap. */
#define R_386_ext ((unsigned int) R_386_PC8 + 1 - R_386_ext_offset)
-#define R_386_vt_offset ((unsigned int) R_386_GNU_VTINHERIT - R_386_ext)
+#define R_386_tls_offset ((unsigned int) R_386_TLS_LDO_32 - R_386_ext)
+ /* These are common with Solaris TLS implementation. */
+ HOWTO(R_386_TLS_LDO_32, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_LDO_32",
+ true, 0xffffffff, 0xffffffff, false),
+ HOWTO(R_386_TLS_IE_32, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_IE_32",
+ true, 0xffffffff, 0xffffffff, false),
+ HOWTO(R_386_TLS_LE_32, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_LE_32",
+ true, 0xffffffff, 0xffffffff, false),
+ HOWTO(R_386_TLS_DTPMOD32, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_DTPMOD32",
+ true, 0xffffffff, 0xffffffff, false),
+ HOWTO(R_386_TLS_DTPOFF32, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_DTPOFF32",
+ true, 0xffffffff, 0xffffffff, false),
+ HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_TPOFF32",
+ true, 0xffffffff, 0xffffffff, false),
+
+ /* Another gap. */
+#define R_386_tls ((unsigned int) R_386_TLS_TPOFF32 + 1 - R_386_tls_offset)
+#define R_386_vt_offset ((unsigned int) R_386_GNU_VTINHERIT - R_386_tls)
/* GNU extension to record C++ vtable hierarchy. */
HOWTO (R_386_GNU_VTINHERIT, /* type */
false, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
- false),
+ false), /* pcrel_offset */
/* GNU extension to record C++ vtable member usage. */
HOWTO (R_386_GNU_VTENTRY, /* type */
false, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
- false)
+ false) /* pcrel_offset */
#define R_386_vt ((unsigned int) R_386_GNU_VTENTRY + 1 - R_386_vt_offset)
return &elf_howto_table[(unsigned int) R_386_GOTPC ];
/* The remaining relocs are a GNU extension. */
+ case BFD_RELOC_386_TLS_LE:
+ TRACE ("BFD_RELOC_386_TLS_LE");
+ return &elf_howto_table[(unsigned int) R_386_TLS_LE - R_386_ext_offset];
+
+ case BFD_RELOC_386_TLS_GD:
+ TRACE ("BFD_RELOC_386_TLS_GD");
+ return &elf_howto_table[(unsigned int) R_386_TLS_GD - R_386_ext_offset];
+
+ case BFD_RELOC_386_TLS_LDM:
+ TRACE ("BFD_RELOC_386_TLS_LDM");
+ return &elf_howto_table[(unsigned int) R_386_TLS_LDM - R_386_ext_offset];
+
case BFD_RELOC_16:
TRACE ("BFD_RELOC_16");
return &elf_howto_table[(unsigned int) R_386_16 - R_386_ext_offset];
TRACE ("BFD_RELOC_8_PCREL");
return &elf_howto_table[(unsigned int) R_386_PC8 - R_386_ext_offset];
+ /* Common with Sun TLS implementation. */
+ case BFD_RELOC_386_TLS_LDO_32:
+ TRACE ("BFD_RELOC_386_TLS_LDO_32");
+ return &elf_howto_table[(unsigned int) R_386_TLS_LDO_32 - R_386_tls_offset];
+
+ case BFD_RELOC_386_TLS_IE_32:
+ TRACE ("BFD_RELOC_386_TLS_IE_32");
+ return &elf_howto_table[(unsigned int) R_386_TLS_IE_32 - R_386_tls_offset];
+
+ case BFD_RELOC_386_TLS_LE_32:
+ TRACE ("BFD_RELOC_386_TLS_LE_32");
+ return &elf_howto_table[(unsigned int) R_386_TLS_LE_32 - R_386_tls_offset];
+
+ case BFD_RELOC_386_TLS_DTPMOD32:
+ TRACE ("BFD_RELOC_386_TLS_DTPMOD32");
+ return &elf_howto_table[(unsigned int) R_386_TLS_DTPMOD32 - R_386_tls_offset];
+
+ case BFD_RELOC_386_TLS_DTPOFF32:
+ TRACE ("BFD_RELOC_386_TLS_DTPOFF32");
+ return &elf_howto_table[(unsigned int) R_386_TLS_DTPOFF32 - R_386_tls_offset];
+
+ case BFD_RELOC_386_TLS_TPOFF32:
+ TRACE ("BFD_RELOC_386_TLS_TPOFF32");
+ return &elf_howto_table[(unsigned int) R_386_TLS_TPOFF32 - R_386_tls_offset];
+
case BFD_RELOC_VTABLE_INHERIT:
TRACE ("BFD_RELOC_VTABLE_INHERIT");
return &elf_howto_table[(unsigned int) R_386_GNU_VTINHERIT
if ((indx = r_type) >= R_386_standard
&& ((indx = r_type - R_386_ext_offset) - R_386_standard
>= R_386_ext - R_386_standard)
- && ((indx = r_type - R_386_vt_offset) - R_386_ext
- >= R_386_vt - R_386_ext))
+ && ((indx = r_type - R_386_tls_offset) - R_386_ext
+ >= R_386_tls - R_386_ext)
+ && ((indx = r_type - R_386_vt_offset) - R_386_tls
+ >= R_386_vt - R_386_tls))
{
(*_bfd_error_handler) (_("%s: invalid relocation type %d"),
- bfd_get_filename (abfd), (int) r_type);
+ bfd_archive_filename (abfd), (int) r_type);
indx = (unsigned int) R_386_NONE;
}
cache_ptr->howto = &elf_howto_table[indx];
return _bfd_elf_is_local_label_name (abfd, name);
}
\f
-/* Functions for the i386 ELF linker. */
+/* Support for core dump NOTE sections. */
+static boolean
+elf_i386_grok_prstatus (abfd, note)
+ bfd *abfd;
+ Elf_Internal_Note *note;
+{
+ int offset;
+ size_t raw_size;
+
+ switch (note->descsz)
+ {
+ default:
+ return false;
+
+ case 144: /* Linux/i386 */
+ /* pr_cursig */
+ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+
+ /* pr_pid */
+ elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
+
+ /* pr_reg */
+ offset = 72;
+ raw_size = 68;
+
+ break;
+ }
+
+ /* Make a ".reg/999" section. */
+ return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+ raw_size, note->descpos + offset);
+}
+
+static boolean
+elf_i386_grok_psinfo (abfd, note)
+ bfd *abfd;
+ Elf_Internal_Note *note;
+{
+ switch (note->descsz)
+ {
+ default:
+ return false;
+
+ case 124: /* Linux/i386 elf_prpsinfo */
+ elf_tdata (abfd)->core_program
+ = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
+ elf_tdata (abfd)->core_command
+ = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
+ }
+
+ /* Note that for some reason, a spurious space is tacked
+ onto the end of the args in some (at least one anyway)
+ implementations, so strip it off if it exists. */
+
+ {
+ char *command = elf_tdata (abfd)->core_command;
+ int n = strlen (command);
+
+ if (0 < n && command[n - 1] == ' ')
+ command[n - 1] = '\0';
+ }
+
+ return true;
+}
+\f
+/* Functions for the i386 ELF linker.
+
+ In order to gain some understanding of code in this file without
+ knowing all the intricate details of the linker, note the
+ following:
+
+ Functions named elf_i386_* are called by external routines, other
+ functions are only called locally. elf_i386_* functions appear
+ in this file more or less in the order in which they are called
+ from external routines. eg. elf_i386_check_relocs is called
+ early in the link process, elf_i386_finish_dynamic_sections is
+ one of the last functions. */
+
/* The name of the dynamic interpreter. This is put in the .interp
section. */
};
/* The i386 linker needs to keep track of the number of relocs that it
- decides to copy in check_relocs for each symbol. This is so that
- it can discard PC relative relocs if it doesn't need them when
- linking with -Bsymbolic. We store the information in a field
- extending the regular ELF linker hash table. */
-
-/* This structure keeps track of the number of PC relative relocs we
- have copied for a given symbol. */
+ decides to copy as dynamic relocs in check_relocs for each symbol.
+ This is so that it can later discard them if they are found to be
+ unnecessary. We store the information in a field extending the
+ regular ELF linker hash table. */
-struct elf_i386_pcrel_relocs_copied
+struct elf_i386_dyn_relocs
{
- /* Next section. */
- struct elf_i386_pcrel_relocs_copied *next;
- /* A section in dynobj. */
- asection *section;
- /* Number of relocs copied in this section. */
+ struct elf_i386_dyn_relocs *next;
+
+ /* The input section of the reloc. */
+ asection *sec;
+
+ /* Total number of relocs copied for the input section. */
bfd_size_type count;
+
+ /* Number of pc-relative relocs copied for the input section. */
+ bfd_size_type pc_count;
};
/* i386 ELF linker hash entry. */
struct elf_i386_link_hash_entry
{
- struct elf_link_hash_entry root;
+ struct elf_link_hash_entry elf;
+
+ /* Track dynamic relocs copied for this symbol. */
+ struct elf_i386_dyn_relocs *dyn_relocs;
+
+ enum {
+ GOT_UNKNOWN = 0, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE
+ } tls_type;
+};
+
+#define elf_i386_hash_entry(ent) ((struct elf_i386_link_hash_entry *)(ent))
+
+struct elf_i386_obj_tdata
+{
+ struct elf_obj_tdata root;
- /* Number of PC relative relocs copied for this symbol. */
- struct elf_i386_pcrel_relocs_copied *pcrel_relocs_copied;
+ /* tls_type for each local got entry. */
+ char *local_got_tls_type;
};
+#define elf_i386_tdata(abfd) \
+ ((struct elf_i386_obj_tdata *) (abfd)->tdata.any)
+
+#define elf_i386_local_got_tls_type(abfd) \
+ (elf_i386_tdata (abfd)->local_got_tls_type)
+
+static boolean
+elf_i386_mkobject (abfd)
+ bfd *abfd;
+{
+ bfd_size_type amt = sizeof (struct elf_i386_obj_tdata);
+ abfd->tdata.any = bfd_zalloc (abfd, amt);
+ if (abfd->tdata.any == NULL)
+ return false;
+ return true;
+}
+
+static boolean
+elf_i386_object_p (abfd)
+ bfd *abfd;
+{
+ /* Allocate our special target data. */
+ struct elf_i386_obj_tdata *new_tdata;
+ bfd_size_type amt = sizeof (struct elf_i386_obj_tdata);
+ new_tdata = bfd_zalloc (abfd, amt);
+ if (new_tdata == NULL)
+ return false;
+ new_tdata->root = *abfd->tdata.elf_obj_data;
+ abfd->tdata.any = new_tdata;
+ return true;
+}
+
/* i386 ELF linker hash table. */
struct elf_i386_link_hash_table
{
- struct elf_link_hash_table root;
+ struct elf_link_hash_table elf;
/* Short-cuts to get to dynamic linker sections. */
asection *sgot;
asection *srelplt;
asection *sdynbss;
asection *srelbss;
+
+ union {
+ bfd_signed_vma refcount;
+ bfd_vma offset;
+ } tls_ldm_got;
+
+ /* 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. */
/* Create an entry in an i386 ELF linker hash table. */
static struct bfd_hash_entry *
-elf_i386_link_hash_newfunc (entry, table, string)
+link_hash_newfunc (entry, table, string)
struct bfd_hash_entry *entry;
struct bfd_hash_table *table;
const char *string;
{
- struct elf_i386_link_hash_entry *ret =
- (struct elf_i386_link_hash_entry *) entry;
-
/* Allocate the structure if it has not already been allocated by a
subclass. */
- if (ret == (struct elf_i386_link_hash_entry *) NULL)
- ret = ((struct elf_i386_link_hash_entry *)
- bfd_hash_allocate (table,
- sizeof (struct elf_i386_link_hash_entry)));
- if (ret == (struct elf_i386_link_hash_entry *) NULL)
- return (struct bfd_hash_entry *) ret;
+ if (entry == NULL)
+ {
+ entry = bfd_hash_allocate (table,
+ sizeof (struct elf_i386_link_hash_entry));
+ if (entry == NULL)
+ return entry;
+ }
/* Call the allocation method of the superclass. */
- ret = ((struct elf_i386_link_hash_entry *)
- _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
- table, string));
- if (ret != (struct elf_i386_link_hash_entry *) NULL)
+ entry = _bfd_elf_link_hash_newfunc (entry, table, string);
+ if (entry != NULL)
{
- ret->pcrel_relocs_copied = NULL;
+ struct elf_i386_link_hash_entry *eh;
+
+ eh = (struct elf_i386_link_hash_entry *) entry;
+ eh->dyn_relocs = NULL;
+ eh->tls_type = GOT_UNKNOWN;
}
- return (struct bfd_hash_entry *) ret;
+ return entry;
}
/* Create an i386 ELF linker hash table. */
bfd *abfd;
{
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, sizeof (struct elf_i386_link_hash_table)));
- if (ret == (struct elf_i386_link_hash_table *) NULL)
+ ret = (struct elf_i386_link_hash_table *) bfd_malloc (amt);
+ if (ret == NULL)
return NULL;
- if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
- elf_i386_link_hash_newfunc))
+ 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->root.root;
+ return &ret->elf.root;
}
/* Create .got, .gotplt, and .rel.got sections in DYNOBJ, and set up
return true;
}
+/* Copy the extra info we tack onto an elf_link_hash_entry. */
+
+static void
+elf_i386_copy_indirect_symbol (dir, ind)
+ struct elf_link_hash_entry *dir, *ind;
+{
+ struct elf_i386_link_hash_entry *edir, *eind;
+
+ edir = (struct elf_i386_link_hash_entry *) dir;
+ eind = (struct elf_i386_link_hash_entry *) ind;
+
+ if (eind->dyn_relocs != NULL)
+ {
+ if (edir->dyn_relocs != NULL)
+ {
+ struct elf_i386_dyn_relocs **pp;
+ struct elf_i386_dyn_relocs *p;
+
+ if (ind->root.type == bfd_link_hash_indirect)
+ abort ();
+
+ /* Add reloc counts against the weak sym to the strong sym
+ list. Merge any entries against the same section. */
+ for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
+ {
+ struct elf_i386_dyn_relocs *q;
+
+ for (q = edir->dyn_relocs; q != NULL; q = q->next)
+ if (q->sec == p->sec)
+ {
+ q->pc_count += p->pc_count;
+ q->count += p->count;
+ *pp = p->next;
+ break;
+ }
+ if (q == NULL)
+ pp = &p->next;
+ }
+ *pp = edir->dyn_relocs;
+ }
+
+ edir->dyn_relocs = eind->dyn_relocs;
+ eind->dyn_relocs = NULL;
+ }
+
+ _bfd_elf_link_hash_copy_indirect (dir, ind);
+}
+
+static int
+elf_i386_tls_transition (info, r_type, is_local)
+ struct bfd_link_info *info;
+ int r_type;
+ int is_local;
+{
+ if (info->shared)
+ return r_type;
+
+ switch (r_type)
+ {
+ case R_386_TLS_GD:
+ case R_386_TLS_IE_32:
+ if (is_local)
+ return R_386_TLS_LE_32;
+ return R_386_TLS_IE_32;
+ case R_386_TLS_LDM:
+ return R_386_TLS_LE_32;
+ }
+
+ return r_type;
+}
+
/* Look through the relocs for a section during the first phase, and
- allocate space in the global offset table or procedure linkage
- table. */
+ calculate needed space in the global offset table, procedure linkage
+ table, and dynamic reloc sections. */
static boolean
elf_i386_check_relocs (abfd, info, sec, relocs)
const Elf_Internal_Rela *relocs;
{
struct elf_i386_link_hash_table *htab;
- bfd *dynobj;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
- bfd_signed_vma *local_got_refcounts;
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
asection *sreloc;
return true;
htab = elf_i386_hash_table (info);
- dynobj = htab->root.dynobj;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
- local_got_refcounts = elf_local_got_refcounts (abfd);
sreloc = NULL;
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
+ unsigned int r_type;
unsigned long r_symndx;
struct elf_link_hash_entry *h;
r_symndx = ELF32_R_SYM (rel->r_info);
+ r_type = ELF32_R_TYPE (rel->r_info);
if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
{
- if (abfd->my_archive)
- (*_bfd_error_handler) (_("%s(%s): bad symbol index: %d"),
- bfd_get_filename (abfd->my_archive),
- bfd_get_filename (abfd),
- r_symndx);
- else
- (*_bfd_error_handler) (_("%s: bad symbol index: %d"),
- bfd_get_filename (abfd),
- r_symndx);
+ (*_bfd_error_handler) (_("%s: bad symbol index: %d"),
+ bfd_archive_filename (abfd),
+ r_symndx);
return false;
}
else
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- /* Some relocs require a global offset table. */
- if (htab->sgot == NULL)
- {
- switch (ELF32_R_TYPE (rel->r_info))
- {
- case R_386_GOT32:
- case R_386_GOTOFF:
- case R_386_GOTPC:
- if (dynobj == NULL)
- htab->root.dynobj = dynobj = abfd;
- if (!create_got_section (dynobj, info))
- return false;
- break;
-
- default:
- break;
- }
- }
+ r_type = elf_i386_tls_transition (info, r_type, h == NULL);
- switch (ELF32_R_TYPE (rel->r_info))
+ switch (r_type)
{
+ case R_386_TLS_IE_32:
+ if (info->shared)
+ info->flags |= DF_STATIC_TLS;
+ /* FALLTHROUGH */
case R_386_GOT32:
+ case R_386_TLS_GD:
/* This symbol requires a global offset table entry. */
- if (h != NULL)
- {
- if (h->got.refcount == -1)
- {
- /* Make sure this symbol is output as a dynamic symbol. */
- if (h->dynindx == -1)
- {
- if (! bfd_elf32_link_record_dynamic_symbol (info, h))
- return false;
- }
- h->got.refcount = 1;
- }
- else
+ {
+ int tls_type, old_tls_type;
+
+ switch (r_type)
+ {
+ default:
+ case R_386_GOT32: tls_type = GOT_NORMAL; break;
+ case R_386_TLS_GD: tls_type = GOT_TLS_GD; break;
+ case R_386_TLS_IE_32: tls_type = GOT_TLS_IE; break;
+ }
+
+ if (h != NULL)
+ {
h->got.refcount += 1;
- }
- else
- {
- /* This is a global offset table entry for a local symbol. */
- if (local_got_refcounts == NULL)
- {
- size_t size;
+ old_tls_type = elf_i386_hash_entry(h)->tls_type;
+ }
+ else
+ {
+ bfd_signed_vma *local_got_refcounts;
- size = symtab_hdr->sh_info * sizeof (bfd_signed_vma);
- local_got_refcounts = ((bfd_signed_vma *)
- bfd_alloc (abfd, size));
- if (local_got_refcounts == NULL)
- return false;
- elf_local_got_refcounts (abfd) = local_got_refcounts;
- memset (local_got_refcounts, -1, size);
- }
- if (local_got_refcounts[r_symndx] == -1)
- local_got_refcounts[r_symndx] = 1;
- else
+ /* This is a global offset table entry for a local symbol. */
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+ if (local_got_refcounts == NULL)
+ {
+ bfd_size_type size;
+
+ size = symtab_hdr->sh_info;
+ size *= (sizeof (bfd_signed_vma) + sizeof(char));
+ local_got_refcounts = ((bfd_signed_vma *)
+ bfd_zalloc (abfd, size));
+ if (local_got_refcounts == NULL)
+ return false;
+ elf_local_got_refcounts (abfd) = local_got_refcounts;
+ elf_i386_local_got_tls_type (abfd)
+ = (char *) (local_got_refcounts + symtab_hdr->sh_info);
+ }
local_got_refcounts[r_symndx] += 1;
+ old_tls_type = elf_i386_local_got_tls_type (abfd) [r_symndx];
+ }
+
+ /* If a TLS symbol is accessed using IE at least once,
+ there is no point to use dynamic model for it. */
+ if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
+ && (old_tls_type != GOT_TLS_GD || tls_type != GOT_TLS_IE))
+ {
+ if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD)
+ tls_type = GOT_TLS_IE;
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%s: `%s' accessed both as normal and thread local symbol"),
+ bfd_archive_filename (abfd), h->root.root.string);
+ return false;
+ }
+ }
+
+ if (old_tls_type != tls_type)
+ {
+ if (h != NULL)
+ elf_i386_hash_entry (h)->tls_type = tls_type;
+ else
+ elf_i386_local_got_tls_type (abfd) [r_symndx] = tls_type;
+ }
+ }
+ /* Fall through */
+
+ case R_386_GOTOFF:
+ case R_386_GOTPC:
+ create_got:
+ if (htab->sgot == NULL)
+ {
+ if (htab->elf.dynobj == NULL)
+ htab->elf.dynobj = abfd;
+ if (!create_got_section (htab->elf.dynobj, info))
+ return false;
}
break;
+ case R_386_TLS_LDM:
+ htab->tls_ldm_got.refcount += 1;
+ goto create_got;
+
case R_386_PLT32:
/* This symbol requires a procedure linkage table entry. We
- actually build the entry in adjust_dynamic_symbol,
- because this might be a case of linking PIC code which is
- never referenced by a dynamic object, in which case we
- don't need to generate a procedure linkage table entry
- after all. */
+ actually build the entry in adjust_dynamic_symbol,
+ because this might be a case of linking PIC code which is
+ never referenced by a dynamic object, in which case we
+ don't need to generate a procedure linkage table entry
+ after all. */
/* If this is a local symbol, we resolve it directly without
- creating a procedure linkage table entry. */
+ creating a procedure linkage table entry. */
if (h == NULL)
continue;
- if (h->plt.refcount == -1)
- {
- h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
- h->plt.refcount = 1;
- }
- else
- h->plt.refcount += 1;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ h->plt.refcount += 1;
break;
case R_386_32:
if (h != NULL && !info->shared)
{
/* If this reloc is in a read-only section, we might
- need a copy reloc. */
- if ((sec->flags & SEC_READONLY) != 0)
- h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
+ need a copy reloc. We can't check reliably at this
+ stage whether the section is read-only, as input
+ sections have not yet been mapped to output sections.
+ Tentatively set the flag for now, and correct in
+ adjust_dynamic_symbol. */
+ h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
/* We may need a .plt entry if the function this reloc
refers to is in a shared lib. */
- if (h->plt.refcount == -1)
- h->plt.refcount = 1;
- else
- h->plt.refcount += 1;
+ h->plt.refcount += 1;
}
/* If we are creating a shared library, and this is a reloc
possible that DEF_REGULAR is not set now but will be set
later (it is never cleared). In case of a weak definition,
DEF_REGULAR may be cleared later by a strong definition in
- a shared library. We account for that possibility below by
+ a shared library. We account for that possibility below by
storing information in the relocs_copied field of the hash
table entry. A similar situation occurs when creating
shared libraries and symbol visibility changes render the
symbol local.
+
If on the other hand, we are creating an executable, we
may need to keep relocations for symbols satisfied by a
dynamic library if we manage to avoid copy relocs for the
symbol. */
if ((info->shared
&& (sec->flags & SEC_ALLOC) != 0
- && (ELF32_R_TYPE (rel->r_info) != R_386_PC32
+ && (r_type != R_386_PC32
|| (h != NULL
&& (! info->symbolic
|| h->root.type == bfd_link_hash_defweak
|| (!info->shared
&& (sec->flags & SEC_ALLOC) != 0
&& h != NULL
- && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
&& (h->root.type == bfd_link_hash_defweak
|| (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. */
- if (dynobj == NULL)
- htab->root.dynobj = dynobj = abfd;
if (sreloc == NULL)
{
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;
|| strcmp (bfd_get_section_name (abfd, sec),
name + 4) != 0)
{
- if (abfd->my_archive)
- (*_bfd_error_handler) (_("%s(%s): bad relocation section name `%s\'"),
- bfd_get_filename (abfd->my_archive),
- bfd_get_filename (abfd),
- name);
- else
- (*_bfd_error_handler) (_("%s: bad relocation section name `%s\'"),
- bfd_get_filename (abfd),
- name);
+ (*_bfd_error_handler)
+ (_("%s: bad relocation section name `%s\'"),
+ bfd_archive_filename (abfd), name);
}
+ if (htab->elf.dynobj == NULL)
+ htab->elf.dynobj = abfd;
+
+ dynobj = htab->elf.dynobj;
sreloc = bfd_get_section_by_name (dynobj, name);
if (sreloc == NULL)
{
|| ! bfd_set_section_alignment (dynobj, sreloc, 2))
return false;
}
+ elf_section_data (sec)->sreloc = sreloc;
}
- sreloc->_raw_size += sizeof (Elf32_External_Rel);
-
- /* If this is a global symbol, we count the number of PC
- relative relocations we have entered for this symbol,
- so that we can discard them later as necessary. Note
- that this function is only called if we are using an
- elf_i386 linker hash table, which means that h is
- really a pointer to an elf_i386_link_hash_entry. */
- if (!info->shared
- || (h != NULL
- && ELF32_R_TYPE (rel->r_info) == R_386_PC32))
+ /* If this is a global symbol, we count the number of
+ relocations we need for this symbol. */
+ if (h != NULL)
{
- struct elf_i386_link_hash_entry *eh;
- struct elf_i386_pcrel_relocs_copied *p;
-
- eh = (struct elf_i386_link_hash_entry *) h;
+ head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs;
+ }
+ else
+ {
+ /* 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;
- for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next)
- if (p->section == sreloc)
- break;
+ 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)
- {
- p = ((struct elf_i386_pcrel_relocs_copied *)
- bfd_alloc (dynobj, sizeof *p));
- if (p == NULL)
- return false;
- p->next = eh->pcrel_relocs_copied;
- eh->pcrel_relocs_copied = p;
- p->section = sreloc;
- p->count = 0;
- }
-
- ++p->count;
+ return false;
+ p->next = *head;
+ *head = p;
+ p->sec = sec;
+ p->count = 0;
+ p->pc_count = 0;
}
- }
+ p->count += 1;
+ if (r_type == R_386_PC32)
+ p->pc_count += 1;
+ }
break;
/* This relocation describes the C++ object vtable hierarchy.
return false;
break;
+ case R_386_TLS_LE_32:
+ case R_386_TLS_LE:
+ if (info->shared)
+ {
+ (*_bfd_error_handler) (_("%s: TLS local exec code cannot be linked into shared objects"),
+ bfd_archive_filename (abfd));
+ return false;
+ }
+ break;
+
default:
break;
}
relocation. */
static asection *
-elf_i386_gc_mark_hook (abfd, info, rel, h, sym)
- bfd *abfd;
+elf_i386_gc_mark_hook (sec, info, rel, h, sym)
+ asection *sec;
struct bfd_link_info *info ATTRIBUTE_UNUSED;
Elf_Internal_Rela *rel;
struct elf_link_hash_entry *h;
}
}
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 (sec->owner, sym->st_shndx);
return NULL;
}
const Elf_Internal_Rela *rel, *relend;
unsigned long r_symndx;
struct elf_link_hash_entry *h;
- bfd *dynobj;
- 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);
relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; rel++)
- switch (ELF32_R_TYPE (rel->r_info))
+ switch (elf_i386_tls_transition (info, ELF32_R_TYPE (rel->r_info),
+ ELF32_R_SYM (rel->r_info)
+ >= symtab_hdr->sh_info))
{
+ case R_386_TLS_LDM:
+ if (elf_i386_hash_table (info)->tls_ldm_got.refcount > 0)
+ elf_i386_hash_table (info)->tls_ldm_got.refcount -= 1;
+ break;
+
+ case R_386_TLS_GD:
+ case R_386_TLS_IE_32:
case R_386_GOT32:
- case R_386_GOTOFF:
- case R_386_GOTPC:
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx >= symtab_hdr->sh_info)
{
case R_386_32:
case R_386_PC32:
- if (info->shared)
- break;
- /* Fall through. */
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ struct elf_i386_link_hash_entry *eh;
+ struct elf_i386_dyn_relocs **pp;
+ struct elf_i386_dyn_relocs *p;
+
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+ if (!info->shared && h->plt.refcount > 0)
+ h->plt.refcount -= 1;
+
+ eh = (struct elf_i386_link_hash_entry *) h;
+
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+ if (p->sec == sec)
+ {
+ if (ELF32_R_TYPE (rel->r_info) == R_386_PC32)
+ p->pc_count -= 1;
+ p->count -= 1;
+ if (p->count == 0)
+ *pp = p->next;
+ break;
+ }
+ }
+ break;
case R_386_PLT32:
r_symndx = ELF32_R_SYM (rel->r_info);
struct elf_link_hash_entry *h;
{
struct elf_i386_link_hash_table *htab;
- bfd *dynobj;
+ struct elf_i386_link_hash_entry * eh;
+ struct elf_i386_dyn_relocs *p;
asection *s;
unsigned int power_of_two;
- htab = elf_i386_hash_table (info);
- dynobj = htab->root.dynobj;
-
- /* Make sure we know what is going on here. */
- BFD_ASSERT (dynobj != NULL
- && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
- || h->weakdef != NULL
- || ((h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_REF_REGULAR) != 0
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0)));
-
/* If this is a function, put it in the procedure linkage table. We
will fill in the contents of the procedure linkage table later,
when we know the address of the .got section. */
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
object, or if all references were garbage collected. In
such a case, we don't actually need to build a procedure
linkage table, and we can just do a PC32 reloc instead. */
- h->plt.refcount = (bfd_vma) -1;
+ h->plt.offset = (bfd_vma) -1;
h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
- return true;
- }
-
- /* Make sure this symbol is output as a dynamic symbol. */
- if (h->dynindx == -1)
- {
- if (! bfd_elf32_link_record_dynamic_symbol (info, h))
- return false;
}
return true;
check_relocs. We can't decide accurately between function and
non-function syms in check-relocs; Objects loaded later in
the link may change h->type. So fix it now. */
- h->plt.refcount = (bfd_vma) -1;
+ h->plt.offset = (bfd_vma) -1;
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0)
return true;
- /* We must allocate the symbol in our .dynbss section, which will
- become part of the .bss section of the executable. There will be
- an entry for this symbol in the .dynsym section. The dynamic
- object will contain position independent code, so all references
- from the dynamic object to this symbol will go through the global
- offset table. The dynamic linker will use the .dynsym entry to
- determine the address it must put in the global offset table, so
- both the dynamic object and the regular object will refer to the
- same memory location for the variable. */
-
- s = htab->sdynbss;
- BFD_ASSERT (s != NULL);
+ /* If -z nocopyreloc was given, we won't generate them either. */
+ if (info->nocopyreloc)
+ {
+ h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
+ return true;
+ }
+
+ eh = (struct elf_i386_link_hash_entry *) h;
+ for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ {
+ s = p->sec->output_section;
+ if (s != NULL && (s->flags & SEC_READONLY) != 0)
+ break;
+ }
+
+ /* If we didn't find any dynamic relocs in read-only sections, then
+ we'll be keeping the dynamic relocs and avoiding the copy reloc. */
+ if (p == NULL)
+ {
+ h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
+ return true;
+ }
+
+ /* We must allocate the symbol in our .dynbss section, which will
+ become part of the .bss section of the executable. There will be
+ an entry for this symbol in the .dynsym section. The dynamic
+ object will contain position independent code, so all references
+ from the dynamic object to this symbol will go through the global
+ offset table. The dynamic linker will use the .dynsym entry to
+ determine the address it must put in the global offset table, so
+ both the dynamic object and the regular object will refer to the
+ same memory location for the variable. */
+
+ htab = elf_i386_hash_table (info);
/* We must generate a R_386_COPY reloc to tell the dynamic linker to
copy the initial value out of the dynamic object and into the
- runtime process image. We need to remember the offset into the
- .rel.bss section we are going to use. */
+ runtime process image. */
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
{
- asection *srel;
-
- srel = htab->srelbss;
- BFD_ASSERT (srel != NULL);
- srel->_raw_size += sizeof (Elf32_External_Rel);
+ htab->srelbss->_raw_size += sizeof (Elf32_External_Rel);
h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
}
power_of_two = 3;
/* Apply the required alignment. */
- s->_raw_size = BFD_ALIGN (s->_raw_size,
- (bfd_size_type) (1 << power_of_two));
- if (power_of_two > bfd_get_section_alignment (dynobj, s))
+ s = htab->sdynbss;
+ s->_raw_size = BFD_ALIGN (s->_raw_size, (bfd_size_type) (1 << power_of_two));
+ if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s))
{
- if (! bfd_set_section_alignment (dynobj, s, power_of_two))
+ if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two))
return false;
}
|| ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0))
/* Allocate space in .plt, .got and associated reloc sections for
- global syms. Also discards space allocated for relocs in the
- check_relocs function that we subsequently have found to be
- unneeded. */
+ dynamic relocs. */
static boolean
-allocate_plt_and_got_and_discard_relocs (h, inf)
+allocate_dynrelocs (h, inf)
struct elf_link_hash_entry *h;
PTR inf;
{
struct bfd_link_info *info;
struct elf_i386_link_hash_table *htab;
- asection *s;
+ 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);
- if (htab->root.dynamic_sections_created
+ if (htab->elf.dynamic_sections_created
&& h->plt.refcount > 0)
{
- s = htab->splt;
- BFD_ASSERT (s != NULL);
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1
+ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ {
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+ }
- /* If this is the first .plt entry, make room for the special
- first entry. */
- if (s->_raw_size == 0)
- s->_raw_size += PLT_ENTRY_SIZE;
+ if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
+ {
+ asection *s = htab->splt;
- h->plt.offset = s->_raw_size;
+ /* If this is the first .plt entry, make room for the special
+ first entry. */
+ if (s->_raw_size == 0)
+ s->_raw_size += PLT_ENTRY_SIZE;
- /* If this symbol is not defined in a regular file, and we are
- not generating a shared library, then set the symbol to this
- location in the .plt. This is required to make function
- pointers compare as equal between the normal executable and
- the shared library. */
- if (! info->shared
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
- {
- h->root.u.def.section = s;
- h->root.u.def.value = h->plt.offset;
- }
+ h->plt.offset = s->_raw_size;
- /* Make room for this entry. */
- s->_raw_size += PLT_ENTRY_SIZE;
+ /* If this symbol is not defined in a regular file, and we are
+ not generating a shared library, then set the symbol to this
+ location in the .plt. This is required to make function
+ pointers compare as equal between the normal executable and
+ the shared library. */
+ if (! info->shared
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = h->plt.offset;
+ }
- /* We also need to make an entry in the .got.plt section, which
- will be placed in the .got section by the linker script. */
- s = htab->sgotplt;
- BFD_ASSERT (s != NULL);
- s->_raw_size += 4;
+ /* Make room for this entry. */
+ s->_raw_size += PLT_ENTRY_SIZE;
+
+ /* We also need to make an entry in the .got.plt section, which
+ will be placed in the .got section by the linker script. */
+ htab->sgotplt->_raw_size += 4;
- if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
- {
/* We also need to make an entry in the .rel.plt section. */
- s = htab->srelplt;
- BFD_ASSERT (s != NULL);
- s->_raw_size += sizeof (Elf32_External_Rel);
+ htab->srelplt->_raw_size += sizeof (Elf32_External_Rel);
+ }
+ else
+ {
+ h->plt.offset = (bfd_vma) -1;
+ h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
}
}
else
h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
}
- if (h->got.refcount > 0)
+ /* If R_386_TLS_IE_32 symbol is now local to the binary,
+ make it a R_386_TLS_LE_32 requiring no TLS entry. */
+ if (h->got.refcount > 0
+ && !info->shared
+ && h->dynindx == -1
+ && elf_i386_hash_entry(h)->tls_type == GOT_TLS_IE)
+ h->got.offset = (bfd_vma) -1;
+ else if (h->got.refcount > 0)
{
+ asection *s;
boolean dyn;
+ int tls_type = elf_i386_hash_entry(h)->tls_type;
+
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1
+ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ {
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+ }
s = htab->sgot;
h->got.offset = s->_raw_size;
s->_raw_size += 4;
- dyn = htab->root.dynamic_sections_created;
- if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
+ /* R_386_TLS_GD needs 2 consecutive GOT slots. */
+ if (tls_type == GOT_TLS_GD)
+ s->_raw_size += 4;
+ dyn = htab->elf.dynamic_sections_created;
+ /* R_386_TLS_IE_32 needs one dynamic relocation,
+ R_386_TLS_GD needs one if local symbol and two if global. */
+ if ((tls_type == GOT_TLS_GD && h->dynindx == -1)
+ || tls_type == GOT_TLS_IE)
+ htab->srelgot->_raw_size += sizeof (Elf32_External_Rel);
+ else if (tls_type == GOT_TLS_GD)
+ htab->srelgot->_raw_size += 2 * sizeof (Elf32_External_Rel);
+ else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
htab->srelgot->_raw_size += sizeof (Elf32_External_Rel);
}
else
h->got.offset = (bfd_vma) -1;
- /* In the shared -Bsymbolic case, discard space allocated to copy
- PC relative relocs against symbols which turn out to be defined
- in regular objects. For the normal shared case, discard space
- for relocs that have become local due to symbol visibility
- changes. For the non-shared case, discard space for symbols
- which turn out to need copy relocs or are not dynamic. */
-
- if ((info->shared
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
- && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
- || info->symbolic))
- || (!info->shared
- && ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) != 0
- || h->dynindx == -1)))
+ eh = (struct elf_i386_link_hash_entry *) h;
+ if (eh->dyn_relocs == NULL)
+ return true;
+
+ /* In the shared -Bsymbolic case, discard space allocated for
+ dynamic pc-relative relocs against symbols which turn out to be
+ defined in regular objects. For the normal shared case, discard
+ space for pc-relative relocs that have become local due to symbol
+ visibility changes. */
+
+ if (info->shared)
{
- struct elf_i386_link_hash_entry *eh;
- struct elf_i386_pcrel_relocs_copied *c;
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+ && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
+ || info->symbolic))
+ {
+ struct elf_i386_dyn_relocs **pp;
- eh = (struct elf_i386_link_hash_entry *) h;
- for (c = eh->pcrel_relocs_copied; c != NULL; c = c->next)
- c->section->_raw_size -= c->count * sizeof (Elf32_External_Rel);
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+ {
+ p->count -= p->pc_count;
+ p->pc_count = 0;
+ if (p->count == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
+ }
+ }
+ else
+ {
+ /* For the non-shared case, discard space for relocs against
+ symbols which turn out to need copy relocs or are not
+ dynamic. */
+
+ if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
+ && (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ || (htab->elf.dynamic_sections_created
+ && (h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_undefined))))
+ {
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (h->dynindx == -1
+ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ {
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ /* If that succeeded, we know we'll be keeping all the
+ relocs. */
+ if (h->dynindx != -1)
+ goto keep;
+ }
+
+ eh->dyn_relocs = NULL;
+
+ keep: ;
+ }
+
+ /* Finally, allocate space. */
+ for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ {
+ asection *sreloc = elf_section_data (p->sec)->sreloc;
+ sreloc->_raw_size += p->count * sizeof (Elf32_External_Rel);
}
return true;
}
+/* Find any dynamic relocs that apply to read-only sections. */
+
+static boolean
+readonly_dynrelocs (h, inf)
+ struct elf_link_hash_entry *h;
+ PTR inf;
+{
+ 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)
+ {
+ asection *s = p->sec->output_section;
+
+ if (s != NULL && (s->flags & SEC_READONLY) != 0)
+ {
+ struct bfd_link_info *info = (struct bfd_link_info *) inf;
+
+ info->flags |= DF_TEXTREL;
+
+ /* Not an error, just cut short the traversal. */
+ return false;
+ }
+ }
+ return true;
+}
+
/* Set the sizes of the dynamic sections. */
static boolean
elf_i386_size_dynamic_sections (output_bfd, info)
- bfd *output_bfd;
+ bfd *output_bfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
{
struct elf_i386_link_hash_table *htab;
bfd *dynobj;
asection *s;
boolean relocs;
- boolean reltext;
- bfd *i;
+ bfd *ibfd;
htab = elf_i386_hash_table (info);
- dynobj = htab->root.dynobj;
- BFD_ASSERT (dynobj != NULL);
+ dynobj = htab->elf.dynobj;
+ if (dynobj == NULL)
+ abort ();
- if (htab->root.dynamic_sections_created)
+ if (htab->elf.dynamic_sections_created)
{
/* Set the contents of the .interp section to the interpreter. */
if (! info->shared)
{
s = bfd_get_section_by_name (dynobj, ".interp");
- BFD_ASSERT (s != NULL);
+ if (s == NULL)
+ abort ();
s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
}
}
- /* Set up .got offsets for local syms. */
- for (i = info->input_bfds; i; i = i->link_next)
+ /* Set up .got offsets for local syms, and space for local dynamic
+ relocs. */
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
bfd_signed_vma *local_got;
bfd_signed_vma *end_local_got;
+ char *local_tls_type;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
- if (bfd_get_flavour (i) != bfd_target_elf_flavour)
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
continue;
- local_got = elf_local_got_refcounts (i);
+ for (s = ibfd->sections; s != NULL; s = s->next)
+ {
+ struct elf_i386_dyn_relocs *p;
+
+ for (p = *((struct elf_i386_dyn_relocs **)
+ &elf_section_data (s)->local_dynrel);
+ p != NULL;
+ p = p->next)
+ {
+ 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;
+ }
+ }
+ }
+
+ local_got = elf_local_got_refcounts (ibfd);
if (!local_got)
continue;
- symtab_hdr = &elf_tdata (i)->symtab_hdr;
+ symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
+ local_tls_type = elf_i386_local_got_tls_type (ibfd);
s = htab->sgot;
srel = htab->srelgot;
- for (; local_got < end_local_got; ++local_got)
+ for (; local_got < end_local_got; ++local_got, ++local_tls_type)
{
if (*local_got > 0)
{
*local_got = s->_raw_size;
s->_raw_size += 4;
- if (info->shared)
+ if (*local_tls_type == GOT_TLS_GD)
+ s->_raw_size += 4;
+ if (info->shared
+ || *local_tls_type == GOT_TLS_GD
+ || *local_tls_type == GOT_TLS_IE)
srel->_raw_size += sizeof (Elf32_External_Rel);
}
else
}
}
- /* Allocate global sym .plt and .got entries. Also discard all
- unneeded relocs. */
- elf_link_hash_traverse (&htab->root,
- allocate_plt_and_got_and_discard_relocs,
- (PTR) info);
+ if (htab->tls_ldm_got.refcount > 0)
+ {
+ /* Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM
+ relocs. */
+ htab->tls_ldm_got.offset = htab->sgot->_raw_size;
+ htab->sgot->_raw_size += 8;
+ htab->srelgot->_raw_size += sizeof (Elf32_External_Rel);
+ }
+ else
+ htab->tls_ldm_got.offset = -1;
- /* The check_relocs and adjust_dynamic_symbol entry points have
- determined the sizes of the various dynamic sections. Allocate
- memory for them. */
+ /* Allocate global sym .plt and .got entries, and space for global
+ sym dynamic relocs. */
+ elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
+
+ /* We now have determined the sizes of the various dynamic sections.
+ Allocate memory for them. */
relocs = false;
- reltext = false;
for (s = dynobj->sections; s != NULL; s = s->next)
{
if ((s->flags & SEC_LINKER_CREATED) == 0)
}
else if (strncmp (bfd_get_section_name (dynobj, s), ".rel", 4) == 0)
{
- if (s->_raw_size == 0)
- {
- /* If we don't need this section, strip it from the
- output file. This is mostly to handle .rel.bss and
- .rel.plt. We must create both sections in
- create_dynamic_sections, because they must be created
- before the linker maps input sections to output
- sections. The linker does that before
- adjust_dynamic_symbol is called, and it is that
- function which decides whether anything needs to go
- into these sections. */
- }
- else
- {
- asection *target;
-
- /* Remember whether there are any reloc sections other
- than .rel.plt. */
- if (s != htab->srelplt)
- {
- const char *outname;
-
- relocs = true;
-
- /* If this relocation section applies to a read only
- section, then we probably need a DT_TEXTREL
- entry. The entries in the .rel.plt section
- really apply to the .got section, which we
- created ourselves and so know is not readonly. */
- outname = bfd_get_section_name (output_bfd,
- s->output_section);
- target = bfd_get_section_by_name (output_bfd, outname + 4);
- if (target != NULL
- && (target->flags & SEC_READONLY) != 0
- && (target->flags & SEC_ALLOC) != 0)
- reltext = true;
- }
+ if (s->_raw_size != 0 && s != htab->srelplt)
+ relocs = true;
- /* We use the reloc_count field as a counter if we need
- to copy relocs into the output file. */
- s->reloc_count = 0;
- }
+ /* We use the reloc_count field as a counter if we need
+ to copy relocs into the output file. */
+ s->reloc_count = 0;
}
else
{
if (s->_raw_size == 0)
{
+ /* If we don't need this section, strip it from the
+ output file. This is mostly to handle .rel.bss and
+ .rel.plt. We must create both sections in
+ create_dynamic_sections, because they must be created
+ before the linker maps input sections to output
+ sections. The linker does that before
+ adjust_dynamic_symbol is called, and it is that
+ function which decides whether anything needs to go
+ into these sections. */
+
_bfd_strip_section_from_output (info, s);
continue;
}
return false;
}
- if (htab->root.dynamic_sections_created)
+ if (htab->elf.dynamic_sections_created)
{
/* Add some entries to the .dynamic section. We fill in the
values later, in elf_i386_finish_dynamic_sections, but we
must add the entries now so that we get the correct size for
the .dynamic section. The DT_DEBUG entry is filled in by the
dynamic linker and used by the debugger. */
+#define add_dynamic_entry(TAG, VAL) \
+ bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
if (! info->shared)
{
- if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0))
+ if (!add_dynamic_entry (DT_DEBUG, 0))
return false;
}
if (htab->splt->_raw_size != 0)
{
- if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
- || ! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
- || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_REL)
- || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0))
+ if (!add_dynamic_entry (DT_PLTGOT, 0)
+ || !add_dynamic_entry (DT_PLTRELSZ, 0)
+ || !add_dynamic_entry (DT_PLTREL, DT_REL)
+ || !add_dynamic_entry (DT_JMPREL, 0))
return false;
}
if (relocs)
{
- if (! bfd_elf32_add_dynamic_entry (info, DT_REL, 0)
- || ! bfd_elf32_add_dynamic_entry (info, DT_RELSZ, 0)
- || ! bfd_elf32_add_dynamic_entry (info, DT_RELENT,
- sizeof (Elf32_External_Rel)))
+ if (!add_dynamic_entry (DT_REL, 0)
+ || !add_dynamic_entry (DT_RELSZ, 0)
+ || !add_dynamic_entry (DT_RELENT, sizeof (Elf32_External_Rel)))
return false;
- }
- if (reltext)
- {
- if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
- return false;
- info->flags |= DF_TEXTREL;
+ /* If any dynamic relocs apply to a read-only section,
+ then we need a DT_TEXTREL entry. */
+ if ((info->flags & DF_TEXTREL) == 0)
+ elf_link_hash_traverse (&htab->elf, readonly_dynrelocs,
+ (PTR) info);
+
+ if ((info->flags & DF_TEXTREL) != 0)
+ {
+ if (!add_dynamic_entry (DT_TEXTREL, 0))
+ return false;
+ }
}
}
+#undef add_dynamic_entry
return true;
}
+/* Set the correct type for an x86 ELF section. We do this by the
+ section name, which is a hack, but ought to work. */
+
+static boolean
+elf_i386_fake_sections (abfd, hdr, sec)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ Elf32_Internal_Shdr *hdr;
+ asection *sec;
+{
+ register const char *name;
+
+ name = bfd_get_section_name (abfd, sec);
+
+ /* This is an ugly, but unfortunately necessary hack that is
+ needed when producing EFI binaries on x86. It tells
+ elf.c:elf_fake_sections() not to consider ".reloc" as a section
+ containing ELF relocation info. We need this hack in order to
+ be able to generate ELF binaries that can be translated into
+ EFI applications (which are essentially COFF objects). Those
+ files contain a COFF ".reloc" section inside an ELFNN object,
+ which would normally cause BFD to segfault because it would
+ attempt to interpret this section as containing relocation
+ entries for section "oc". With this hack enabled, ".reloc"
+ will be treated as a normal data section, which will avoid the
+ segfault. However, you won't be able to create an ELFNN binary
+ with a section named "oc" that needs relocations, but that's
+ the kind of ugly side-effects you get when detecting section
+ types based on their names... In practice, this limitation is
+ unlikely to bite. */
+ if (strcmp (name, ".reloc") == 0)
+ hdr->sh_type = SHT_PROGBITS;
+
+ return true;
+}
+
+/* Return the base VMA address which should be subtracted from real addresses
+ when resolving @dtpoff relocation.
+ This is PT_TLS segment p_vaddr. */
+
+static bfd_vma
+dtpoff_base (info)
+ struct bfd_link_info *info;
+{
+ BFD_ASSERT (elf_hash_table (info)->tls_segment != NULL);
+ return elf_hash_table (info)->tls_segment->start;
+}
+
+/* Return the relocation value for @tpoff relocation
+ if STT_TLS virtual address is ADDRESS. */
+
+static bfd_vma
+tpoff (info, address)
+ struct bfd_link_info *info;
+ bfd_vma address;
+{
+ struct elf_link_tls_segment *tls_segment
+ = elf_hash_table (info)->tls_segment;
+
+ BFD_ASSERT (tls_segment != NULL);
+ return (align_power (tls_segment->size, tls_segment->align)
+ + tls_segment->start - address);
+}
+
/* Relocate an i386 ELF section. */
static boolean
asection **local_sections;
{
struct elf_i386_link_hash_table *htab;
- bfd *dynobj;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
bfd_vma *local_got_offsets;
- asection *sreloc;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
htab = elf_i386_hash_table (info);
- dynobj = htab->root.dynobj;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
local_got_offsets = elf_local_got_offsets (input_bfd);
- sreloc = NULL;
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
{
- int r_type;
+ unsigned int r_type;
reloc_howto_type *howto;
unsigned long r_symndx;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
asection *sec;
+ bfd_vma off;
bfd_vma relocation;
+ boolean unresolved_reloc;
bfd_reloc_status_type r;
unsigned int indx;
+ int tls_type;
r_type = ELF32_R_TYPE (rel->r_info);
if (r_type == (int) R_386_GNU_VTINHERIT
continue;
if ((indx = (unsigned) r_type) >= R_386_standard
- && ((indx = (unsigned) r_type - R_386_ext_offset) - R_386_standard
- >= R_386_ext - R_386_standard))
+ && ((indx = r_type - R_386_ext_offset) - R_386_standard
+ >= R_386_ext - R_386_standard)
+ && ((indx = r_type - R_386_tls_offset) - R_386_ext
+ >= R_386_tls - R_386_ext))
{
bfd_set_error (bfd_error_bad_value);
return false;
if (info->relocateable)
{
- /* This is a relocateable link. We don't have to change
+ bfd_vma val;
+ bfd_byte *where;
+
+ /* This is a relocatable link. We don't have to change
anything, unless the reloc is against a section symbol,
in which case we have to adjust according to where the
section symbol winds up in the output section. */
- if (r_symndx < symtab_hdr->sh_info)
- {
- sym = local_syms + r_symndx;
- if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
- {
- bfd_vma val;
+ if (r_symndx >= symtab_hdr->sh_info)
+ continue;
- sec = local_sections[r_symndx];
- val = bfd_get_32 (input_bfd, contents + rel->r_offset);
- val += sec->output_offset + sym->st_value;
- bfd_put_32 (input_bfd, val, contents + rel->r_offset);
- }
- }
+ sym = local_syms + r_symndx;
+ if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+ continue;
+ sec = local_sections[r_symndx];
+ val = sec->output_offset;
+ if (val == 0)
+ continue;
+
+ where = contents + rel->r_offset;
+ switch (howto->size)
+ {
+ /* FIXME: overflow checks. */
+ case 0:
+ val += bfd_get_8 (input_bfd, where);
+ bfd_put_8 (input_bfd, val, where);
+ break;
+ case 1:
+ val += bfd_get_16 (input_bfd, where);
+ bfd_put_16 (input_bfd, val, where);
+ break;
+ case 2:
+ val += bfd_get_32 (input_bfd, where);
+ bfd_put_32 (input_bfd, val, where);
+ break;
+ default:
+ abort ();
+ }
continue;
}
h = NULL;
sym = NULL;
sec = NULL;
+ unresolved_reloc = false;
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
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;
+ bfd_byte *where = contents + rel->r_offset;
+
+ switch (howto->size)
+ {
+ case 0:
+ addend = bfd_get_8 (input_bfd, where);
+ if (howto->pc_relative)
+ {
+ addend = (addend ^ 0x80) - 0x80;
+ addend += 1;
+ }
+ break;
+ case 1:
+ addend = bfd_get_16 (input_bfd, where);
+ if (howto->pc_relative)
+ {
+ addend = (addend ^ 0x8000) - 0x8000;
+ addend += 2;
+ }
+ break;
+ case 2:
+ addend = bfd_get_32 (input_bfd, where);
+ if (howto->pc_relative)
+ {
+ addend = (addend ^ 0x80000000) - 0x80000000;
+ addend += 4;
+ }
+ break;
+ default:
+ abort ();
+ }
+
+ msec = sec;
+ addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
+ addend -= relocation;
+ addend += msec->output_section->vma + msec->output_offset;
+
+ switch (howto->size)
+ {
+ case 0:
+ /* FIXME: overflow checks. */
+ if (howto->pc_relative)
+ addend -= 1;
+ bfd_put_8 (input_bfd, addend, where);
+ break;
+ case 1:
+ if (howto->pc_relative)
+ addend -= 2;
+ bfd_put_16 (input_bfd, addend, where);
+ break;
+ case 2:
+ if (howto->pc_relative)
+ addend -= 4;
+ bfd_put_32 (input_bfd, addend, where);
+ break;
+ }
+ }
}
else
{
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
relocation = 0;
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
sec = h->root.u.def.section;
- if (r_type == R_386_GOTPC
- || (r_type == R_386_PLT32
- && htab->splt != NULL
- && h->plt.offset != (bfd_vma) -1)
- || (r_type == R_386_GOT32
- && (WILL_CALL_FINISH_DYNAMIC_SYMBOL
- (htab->root.dynamic_sections_created, info, h))
- && !(info->shared
- && (info->symbolic
- || h->dynindx == -1
- || (h->elf_link_hash_flags
- & ELF_LINK_FORCED_LOCAL))
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR)))
- || ((r_type == R_386_32
- || r_type == R_386_PC32)
- && ((info->shared
- && ((!info->symbolic && h->dynindx != -1)
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0))
- || (!info->shared
- && h->dynindx != -1
- && (h->elf_link_hash_flags
- & ELF_LINK_NON_GOT_REF) == 0
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0))
- && ((input_section->flags & SEC_ALLOC) != 0
- /* DWARF will emit R_386_32 relocations in its
- sections against symbols defined externally
- in shared libraries. We can't do anything
- with them here. */
- || ((input_section->flags & SEC_DEBUGGING) != 0
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_DYNAMIC) != 0))))
- /* In these cases, we don't need the relocation
- value. We check specially because in some
- obscure cases sec->output_section will be NULL. */
- ;
- else if (sec->output_section == NULL)
- (*_bfd_error_handler)
- (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
- bfd_get_filename (input_bfd),
- bfd_get_section_name (input_bfd, input_section),
- (long) rel->r_offset,
- h->root.root.string);
+ if (sec->output_section == NULL)
+ /* Set a flag that will be cleared later if we find a
+ relocation value for this symbol. output_section
+ is typically NULL for symbols satisfied by a shared
+ library. */
+ unresolved_reloc = true;
else
relocation = (h->root.u.def.value
+ sec->output_section->vma
}
else if (h->root.type == bfd_link_hash_undefweak)
;
- else if (info->shared && !info->symbolic
+ else if (info->shared
+ && (!info->symbolic || info->allow_shlib_undefined)
&& !info->no_undefined
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
;
case R_386_GOT32:
/* Relocation is to the entry for this symbol in the global
offset table. */
- BFD_ASSERT (htab->sgot != NULL);
+ if (htab->sgot == NULL)
+ abort ();
if (h != NULL)
{
- bfd_vma off;
boolean dyn;
off = h->got.offset;
- BFD_ASSERT (off != (bfd_vma) -1);
-
- dyn = htab->root.dynamic_sections_created;
+ dyn = htab->elf.dynamic_sections_created;
if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)
|| (info->shared
&& (info->symbolic
h->got.offset |= 1;
}
}
-
- relocation = htab->sgot->output_offset + off;
+ else
+ unresolved_reloc = false;
}
else
{
- bfd_vma off;
-
- BFD_ASSERT (local_got_offsets != NULL
- && local_got_offsets[r_symndx] != (bfd_vma) -1);
+ if (local_got_offsets == NULL)
+ abort ();
off = local_got_offsets[r_symndx];
/* The offset must always be a multiple of 4. We use
- the least significant bit to record whether we have
- already generated the necessary reloc. */
+ the least significant bit to record whether we have
+ already generated the necessary reloc. */
if ((off & 1) != 0)
off &= ~1;
else
{
asection *srelgot;
Elf_Internal_Rel outrel;
+ Elf32_External_Rel *loc;
srelgot = htab->srelgot;
- BFD_ASSERT (srelgot != NULL);
+ if (srelgot == NULL)
+ abort ();
outrel.r_offset = (htab->sgot->output_section->vma
+ htab->sgot->output_offset
+ off);
outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
- bfd_elf32_swap_reloc_out (output_bfd, &outrel,
- (((Elf32_External_Rel *)
- srelgot->contents)
- + srelgot->reloc_count));
- ++srelgot->reloc_count;
+ loc = (Elf32_External_Rel *) srelgot->contents;
+ loc += srelgot->reloc_count++;
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
}
local_got_offsets[r_symndx] |= 1;
}
-
- relocation = htab->sgot->output_offset + off;
}
+ if (off >= (bfd_vma) -2)
+ abort ();
+
+ relocation = htab->sgot->output_offset + off;
break;
case R_386_GOTOFF:
permitted by the ABI, we might have to change this
calculation. */
relocation -= htab->sgot->output_section->vma;
-
break;
case R_386_GOTPC:
/* Use global offset table as symbol value. */
relocation = htab->sgot->output_section->vma;
+ unresolved_reloc = false;
break;
case R_386_PLT32:
procedure linkage table. */
/* Resolve a PLT32 reloc against a local symbol directly,
- without using the procedure linkage table. */
+ without using the procedure linkage table. */
if (h == NULL)
break;
|| htab->splt == NULL)
{
/* We didn't make a PLT entry for this symbol. This
- happens when statically linking PIC code, or when
- using -Bsymbolic. */
+ happens when statically linking PIC code, or when
+ using -Bsymbolic. */
break;
}
relocation = (htab->splt->output_section->vma
+ htab->splt->output_offset
+ h->plt.offset);
-
+ unresolved_reloc = false;
break;
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
- && (h->root.type == bfd_link_hash_defweak
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+ && (((h->elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+ && (h->elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ || h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_undefined)))
{
Elf_Internal_Rel outrel;
boolean skip, relocate;
+ asection *sreloc;
+ Elf32_External_Rel *loc;
/* When generating a shared object, these relocations
are copied into the output file to be resolved at run
time. */
- if (sreloc == NULL)
+ skip = false;
+ 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);
+ else if (h != NULL
+ && h->dynindx != -1
+ && (r_type == R_386_PC32
+ || !info->shared
+ || !info->symbolic
+ || (h->elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) == 0))
+ outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+ else
{
- const char *name;
+ /* This symbol is local, or marked to become local. */
+ relocate = true;
+ outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
+ }
- name = (bfd_elf_string_from_elf_section
- (input_bfd,
- elf_elfheader (input_bfd)->e_shstrndx,
- elf_section_data (input_section)->rel_hdr.sh_name));
- if (name == NULL)
- return false;
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (sreloc == NULL)
+ abort ();
- if (strncmp (name, ".rel", 4) != 0
- || strcmp (bfd_get_section_name (input_bfd,
- input_section),
- name + 4) != 0)
+ loc = (Elf32_External_Rel *) sreloc->contents;
+ loc += sreloc->reloc_count++;
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+
+ /* If this reloc is against an external symbol, we do
+ not want to fiddle with the addend. Otherwise, we
+ need to include the symbol value so that it becomes
+ an addend for the dynamic reloc. */
+ if (! relocate)
+ continue;
+ }
+ break;
+
+ case R_386_TLS_GD:
+ case R_386_TLS_IE_32:
+ r_type = elf_i386_tls_transition (info, r_type, h == NULL);
+ tls_type = GOT_UNKNOWN;
+ if (h == NULL && local_got_offsets)
+ tls_type = elf_i386_local_got_tls_type (input_bfd) [r_symndx];
+ else if (h != NULL)
+ {
+ tls_type = elf_i386_hash_entry(h)->tls_type;
+ if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE)
+ r_type = R_386_TLS_LE_32;
+ }
+ if (r_type == R_386_TLS_GD && tls_type == GOT_TLS_IE)
+ r_type = R_386_TLS_IE_32;
+
+ if (r_type == R_386_TLS_LE_32)
+ {
+ BFD_ASSERT (! unresolved_reloc);
+ if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
+ {
+ unsigned int val, type;
+ bfd_vma roff;
+
+ /* GD->LE transition. */
+ BFD_ASSERT (rel->r_offset >= 2);
+ type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
+ BFD_ASSERT (type == 0x8d || type == 0x04);
+ BFD_ASSERT (rel->r_offset + 9 <= input_section->_raw_size);
+ BFD_ASSERT (bfd_get_8 (input_bfd,
+ contents + rel->r_offset + 4)
+ == 0xe8);
+ BFD_ASSERT (rel + 1 < relend);
+ BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
+ roff = rel->r_offset + 5;
+ val = bfd_get_8 (input_bfd,
+ contents + rel->r_offset - 1);
+ if (type == 0x04)
+ {
+ /* leal foo(,%reg,1), %eax; call ___tls_get_addr
+ Change it into:
+ movl %gs:0, %eax; subl $foo@tpoff, %eax
+ (6 byte form of subl). */
+ BFD_ASSERT (rel->r_offset >= 3);
+ BFD_ASSERT (bfd_get_8 (input_bfd,
+ contents + rel->r_offset - 3)
+ == 0x8d);
+ BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3));
+ memcpy (contents + rel->r_offset - 3,
+ "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+ }
+ else
{
- if (input_bfd->my_archive)
- (*_bfd_error_handler) (_("%s(%s): bad relocation section name `%s\'"),
- bfd_get_filename (input_bfd->my_archive),
- bfd_get_filename (input_bfd),
- name);
+ BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
+ if (rel->r_offset + 10 <= input_section->_raw_size
+ && bfd_get_8 (input_bfd,
+ contents + rel->r_offset + 9) == 0x90)
+ {
+ /* leal foo(%reg), %eax; call ___tls_get_addr; nop
+ Change it into:
+ movl %gs:0, %eax; subl $foo@tpoff, %eax
+ (6 byte form of subl). */
+ memcpy (contents + rel->r_offset - 2,
+ "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+ roff = rel->r_offset + 6;
+ }
else
- (*_bfd_error_handler) (_("%s: bad relocation section name `%s\'"),
- bfd_get_filename (input_bfd),
- name);
- return false;
+ {
+ /* leal foo(%reg), %eax; call ___tls_get_addr
+ Change it into:
+ movl %gs:0, %eax; subl $foo@tpoff, %eax
+ (5 byte form of subl). */
+ memcpy (contents + rel->r_offset - 2,
+ "\x65\xa1\0\0\0\0\x2d\0\0\0", 11);
+ }
}
-
- sreloc = bfd_get_section_by_name (dynobj, name);
- BFD_ASSERT (sreloc != NULL);
+ bfd_put_32 (output_bfd, tpoff (info, relocation),
+ contents + roff);
+ /* Skip R_386_PLT32. */
+ rel++;
+ continue;
}
-
- skip = false;
-
- if (elf_section_data (input_section)->stab_info == NULL)
- outrel.r_offset = rel->r_offset;
else
{
- bfd_vma off;
-
- off = (_bfd_stab_section_offset
- (output_bfd, htab->root.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;
+ unsigned int val, type;
+
+ /* IE->LE transition:
+ Originally it can be either:
+ subl foo(%reg1), %reg2
+ or
+ movl foo(%reg1), %reg2
+ We change it into:
+ subl $foo, %reg2
+ or
+ movl $foo, %reg2 (6 byte form) */
+ BFD_ASSERT (rel->r_offset >= 2);
+ type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
+ val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
+ BFD_ASSERT (rel->r_offset + 4 <= input_section->_raw_size);
+ if (type == 0x8b)
+ {
+ /* movl */
+ BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4);
+ bfd_put_8 (output_bfd, 0xc7,
+ contents + rel->r_offset - 2);
+ bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7),
+ contents + rel->r_offset - 1);
+ }
+ else if (type == 0x2b)
+ {
+ /* subl */
+ BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4);
+ bfd_put_8 (output_bfd, 0x81,
+ contents + rel->r_offset - 2);
+ bfd_put_8 (output_bfd, 0xe8 | ((val >> 3) & 7),
+ contents + rel->r_offset - 1);
+ }
+ else
+ BFD_FAIL ();
+ bfd_put_32 (output_bfd, tpoff (info, relocation),
+ contents + rel->r_offset);
+ continue;
}
+ }
- outrel.r_offset += (input_section->output_section->vma
- + input_section->output_offset);
+ if (htab->sgot == NULL)
+ abort ();
- if (skip)
- {
- memset (&outrel, 0, sizeof outrel);
- relocate = false;
- }
- else if (r_type == R_386_PC32)
- {
- BFD_ASSERT (h != NULL && h->dynindx != -1);
- relocate = false;
- outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_PC32);
- }
+ if (h != NULL)
+ off = h->got.offset;
+ else
+ {
+ if (local_got_offsets == NULL)
+ abort ();
+
+ off = local_got_offsets[r_symndx];
+ }
+
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ Elf_Internal_Rel outrel;
+ Elf32_External_Rel *loc;
+ int dr_type, indx;
+
+ if (htab->srelgot == NULL)
+ abort ();
+
+ outrel.r_offset = (htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off);
+
+ bfd_put_32 (output_bfd, 0,
+ htab->sgot->contents + off);
+ indx = h && h->dynindx != -1 ? h->dynindx : 0;
+ if (r_type == R_386_TLS_GD)
+ dr_type = R_386_TLS_DTPMOD32;
else
+ dr_type = R_386_TLS_TPOFF32;
+ outrel.r_info = ELF32_R_INFO (indx, dr_type);
+ loc = (Elf32_External_Rel *) htab->srelgot->contents;
+ loc += htab->srelgot->reloc_count++;
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+
+ if (r_type == R_386_TLS_GD)
{
- /* h->dynindx may be -1 if this symbol was marked to
- become local. */
- if (h == NULL
- || (info->shared
- && (info->symbolic || h->dynindx == -1)
- && (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) != 0))
+ if (indx == 0)
{
- relocate = true;
- outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
+ BFD_ASSERT (! unresolved_reloc);
+ bfd_put_32 (output_bfd,
+ relocation - dtpoff_base (info),
+ htab->sgot->contents + off + 4);
}
else
{
- BFD_ASSERT (h->dynindx != -1);
- relocate = false;
- outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_32);
+ bfd_put_32 (output_bfd, 0,
+ htab->sgot->contents + off + 4);
+ outrel.r_info = ELF32_R_INFO (indx,
+ R_386_TLS_DTPOFF32);
+ outrel.r_offset += 4;
+ htab->srelgot->reloc_count++;
+ loc++;
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel,
+ loc);
}
}
- bfd_elf32_swap_reloc_out (output_bfd, &outrel,
- (((Elf32_External_Rel *)
- sreloc->contents)
- + sreloc->reloc_count));
- ++sreloc->reloc_count;
+ if (h != NULL)
+ h->got.offset |= 1;
+ else
+ local_got_offsets[r_symndx] |= 1;
+ }
- /* If this reloc is against an external symbol, we do
- not want to fiddle with the addend. Otherwise, we
- need to include the symbol value so that it becomes
- an addend for the dynamic reloc. */
- if (! relocate)
- continue;
+ if (off >= (bfd_vma) -2)
+ abort ();
+ if (r_type == ELF32_R_TYPE (rel->r_info))
+ {
+ relocation = htab->sgot->output_offset + off;
+ unresolved_reloc = false;
+ }
+ else
+ {
+ unsigned int val, type;
+ bfd_vma roff;
+
+ /* GD->IE transition. */
+ BFD_ASSERT (rel->r_offset >= 2);
+ type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
+ BFD_ASSERT (type == 0x8d || type == 0x04);
+ BFD_ASSERT (rel->r_offset + 9 <= input_section->_raw_size);
+ BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
+ == 0xe8);
+ BFD_ASSERT (rel + 1 < relend);
+ BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
+ roff = rel->r_offset - 3;
+ val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
+ if (type == 0x04)
+ {
+ /* leal foo(,%reg,1), %eax; call ___tls_get_addr
+ Change it into:
+ movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */
+ BFD_ASSERT (rel->r_offset >= 3);
+ BFD_ASSERT (bfd_get_8 (input_bfd,
+ contents + rel->r_offset - 3)
+ == 0x8d);
+ BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3));
+ val >>= 3;
+ }
+ else
+ {
+ /* leal foo(%reg), %eax; call ___tls_get_addr; nop
+ Change it into:
+ movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */
+ BFD_ASSERT (rel->r_offset + 10 <= input_section->_raw_size);
+ BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
+ BFD_ASSERT (bfd_get_8 (input_bfd,
+ contents + rel->r_offset + 9)
+ == 0x90);
+ roff = rel->r_offset - 2;
+ }
+ memcpy (contents + roff,
+ "\x65\xa1\0\0\0\0\x2b\x80\0\0\0", 12);
+ contents[roff + 7] = 0x80 | (val & 7);
+ bfd_put_32 (output_bfd, htab->sgot->output_offset + off,
+ contents + roff + 8);
+ /* Skip R_386_PLT32. */
+ rel++;
+ continue;
}
+ break;
+ case R_386_TLS_LDM:
+ if (! info->shared)
+ {
+ unsigned int val;
+
+ /* LD->LE transition:
+ Ensure it is:
+ leal foo(%reg), %eax; call ___tls_get_addr.
+ We change it into:
+ movl %gs:0, %eax; nop; leal 0(%esi,1), %esi. */
+ BFD_ASSERT (rel->r_offset >= 2);
+ BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2)
+ == 0x8d);
+ val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
+ BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
+ BFD_ASSERT (rel->r_offset + 9 <= input_section->_raw_size);
+ BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
+ == 0xe8);
+ BFD_ASSERT (rel + 1 < relend);
+ BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
+ memcpy (contents + rel->r_offset - 2,
+ "\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11);
+ /* Skip R_386_PLT32. */
+ rel++;
+ continue;
+ }
+
+ if (htab->sgot == NULL)
+ abort ();
+
+ off = htab->tls_ldm_got.offset;
+ if (off & 1)
+ off &= ~1;
+ else
+ {
+ Elf_Internal_Rel outrel;
+ Elf32_External_Rel *loc;
+
+ if (htab->srelgot == NULL)
+ abort ();
+
+ outrel.r_offset = (htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off);
+
+ bfd_put_32 (output_bfd, 0,
+ htab->sgot->contents + off);
+ bfd_put_32 (output_bfd, 0,
+ htab->sgot->contents + off + 4);
+ outrel.r_info = ELF32_R_INFO (0, R_386_TLS_DTPMOD32);
+ loc = (Elf32_External_Rel *) htab->srelgot->contents;
+ loc += htab->srelgot->reloc_count++;
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+ htab->tls_ldm_got.offset |= 1;
+ }
+ relocation = htab->sgot->output_offset + off;
+ unresolved_reloc = false;
+ break;
+
+ case R_386_TLS_LDO_32:
+ if (info->shared)
+ relocation -= dtpoff_base (info);
+ else
+ /* When converting LDO to LE, we must negate. */
+ relocation = -tpoff (info, relocation);
+ break;
+
+ case R_386_TLS_LE_32:
+ relocation = tpoff (info, relocation);
+ break;
+
+ case R_386_TLS_LE:
+ relocation = -tpoff (info, relocation);
break;
default:
break;
}
+ /* FIXME: Why do we allow debugging sections to escape this error?
+ More importantly, why do we not emit dynamic relocs for
+ R_386_32 above in debugging sections (which are ! SEC_ALLOC)?
+ If we had emitted the dynamic reloc, we could remove the
+ fudge here. */
+ if (unresolved_reloc
+ && !(info->shared
+ && (input_section->flags & SEC_DEBUGGING) != 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
+ (*_bfd_error_handler)
+ (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
+ bfd_archive_filename (input_bfd),
+ bfd_get_section_name (input_bfd, input_section),
+ (long) rel->r_offset,
+ h->root.root.string);
+
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, (bfd_vma) 0);
if (r != bfd_reloc_ok)
{
- switch (r)
+ const char *name;
+
+ if (h != NULL)
+ name = h->root.root.string;
+ else
{
- default:
- case bfd_reloc_outofrange:
- abort ();
- case bfd_reloc_overflow:
- {
- const char *name;
+ 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 (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 (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;
}
}
}
Elf_Internal_Sym *sym;
{
struct elf_i386_link_hash_table *htab;
- bfd *dynobj;
htab = elf_i386_hash_table (info);
- dynobj = htab->root.dynobj;
if (h->plt.offset != (bfd_vma) -1)
{
bfd_vma plt_index;
bfd_vma got_offset;
Elf_Internal_Rel rel;
+ Elf32_External_Rel *loc;
/* This symbol has an entry in the procedure linkage table. Set
it up. */
- BFD_ASSERT (h->dynindx != -1
- && htab->splt != NULL
- && htab->sgotplt != NULL
- && htab->srelplt != NULL);
+ if (h->dynindx == -1
+ || htab->splt == NULL
+ || htab->sgotplt == NULL
+ || htab->srelplt == NULL)
+ abort ();
/* Get the index in the procedure linkage table which
corresponds to this symbol. This is the index of this symbol
+ htab->sgotplt->output_offset
+ got_offset);
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT);
- bfd_elf32_swap_reloc_out (output_bfd, &rel,
- ((Elf32_External_Rel *) htab->srelplt->contents
- + plt_index));
+ loc = (Elf32_External_Rel *) htab->srelplt->contents + plt_index;
+ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
{
/* Mark the symbol as undefined, rather than as defined in
- the .plt section. Leave the value alone. */
+ the .plt section. Leave the value alone. This is a clue
+ for the dynamic linker, to make function pointer
+ comparisons work between an application and shared
+ library. */
sym->st_shndx = SHN_UNDEF;
}
}
- if (h->got.offset != (bfd_vma) -1)
+ if (h->got.offset != (bfd_vma) -1
+ && elf_i386_hash_entry(h)->tls_type != GOT_TLS_GD
+ && elf_i386_hash_entry(h)->tls_type != GOT_TLS_IE)
{
Elf_Internal_Rel rel;
+ Elf32_External_Rel *loc;
/* This symbol has an entry in the global offset table. Set it
up. */
- BFD_ASSERT (htab->sgot != NULL && htab->srelgot != NULL);
+ if (htab->sgot == NULL || htab->srelgot == NULL)
+ abort ();
rel.r_offset = (htab->sgot->output_section->vma
+ htab->sgot->output_offset
- + (h->got.offset &~ 1));
+ + (h->got.offset & ~(bfd_vma) 1));
/* If this is a static link, or it is a -Bsymbolic link and the
symbol is defined locally or was forced to be local because
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT);
}
- bfd_elf32_swap_reloc_out (output_bfd, &rel,
- ((Elf32_External_Rel *) htab->srelgot->contents
- + htab->srelgot->reloc_count));
- ++htab->srelgot->reloc_count;
+ loc = (Elf32_External_Rel *) htab->srelgot->contents;
+ loc += htab->srelgot->reloc_count++;
+ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
}
if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
{
Elf_Internal_Rel rel;
+ Elf32_External_Rel *loc;
/* This symbol needs a copy reloc. Set it up. */
- BFD_ASSERT (h->dynindx != -1
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && htab->srelbss != NULL);
+ if (h->dynindx == -1
+ || (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ || htab->srelbss == NULL)
+ abort ();
rel.r_offset = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY);
- bfd_elf32_swap_reloc_out (output_bfd, &rel,
- ((Elf32_External_Rel *) htab->srelbss->contents
- + htab->srelbss->reloc_count));
- ++htab->srelbss->reloc_count;
+ loc = (Elf32_External_Rel *) htab->srelbss->contents;
+ loc += htab->srelbss->reloc_count++;
+ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
}
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
return true;
}
+/* Used to decide how to sort relocs in an optimal manner for the
+ dynamic linker, before writing them out. */
+
+static enum elf_reloc_type_class
+elf_i386_reloc_type_class (rela)
+ const Elf_Internal_Rela *rela;
+{
+ switch ((int) ELF32_R_TYPE (rela->r_info))
+ {
+ case R_386_RELATIVE:
+ return reloc_class_relative;
+ case R_386_JUMP_SLOT:
+ return reloc_class_plt;
+ case R_386_COPY:
+ return reloc_class_copy;
+ default:
+ return reloc_class_normal;
+ }
+}
+
/* Finish up the dynamic sections. */
static boolean
asection *sdyn;
htab = elf_i386_hash_table (info);
- dynobj = htab->root.dynobj;
+ dynobj = htab->elf.dynobj;
sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
- if (htab->root.dynamic_sections_created)
+ if (htab->elf.dynamic_sections_created)
{
Elf32_External_Dyn *dyncon, *dynconend;
- BFD_ASSERT (sdyn != NULL && htab->sgot != NULL);
+ if (sdyn == NULL || htab->sgot == NULL)
+ abort ();
dyncon = (Elf32_External_Dyn *) sdyn->contents;
dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
for (; dyncon < dynconend; dyncon++)
{
Elf_Internal_Dyn dyn;
+ asection *s;
bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
switch (dyn.d_tag)
{
default:
- break;
+ continue;
case DT_PLTGOT:
dyn.d_un.d_ptr = htab->sgot->output_section->vma;
- bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
case DT_JMPREL:
dyn.d_un.d_ptr = htab->srelplt->output_section->vma;
- bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
case DT_PLTRELSZ:
- if (htab->srelplt->output_section->_cooked_size != 0)
- dyn.d_un.d_val = htab->srelplt->output_section->_cooked_size;
+ s = htab->srelplt->output_section;
+ if (s->_cooked_size != 0)
+ dyn.d_un.d_val = s->_cooked_size;
else
- dyn.d_un.d_val = htab->srelplt->output_section->_raw_size;
- bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ dyn.d_un.d_val = s->_raw_size;
break;
case DT_RELSZ:
about changing the DT_REL entry. */
if (htab->srelplt != NULL)
{
- if (htab->srelplt->output_section->_cooked_size != 0)
- dyn.d_un.d_val -= htab->srelplt->output_section->_cooked_size;
+ s = htab->srelplt->output_section;
+ if (s->_cooked_size != 0)
+ dyn.d_un.d_val -= s->_cooked_size;
else
- dyn.d_un.d_val -= htab->srelplt->output_section->_raw_size;
+ dyn.d_un.d_val -= s->_raw_size;
}
- bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
}
+
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
}
/* Fill in the first entry in the procedure linkage table. */
return true;
}
-/* Set the correct type for an x86 ELF section. We do this by the
- section name, which is a hack, but ought to work. */
-
-static boolean
-elf_i386_fake_sections (abfd, hdr, sec)
- bfd *abfd ATTRIBUTE_UNUSED;
- Elf32_Internal_Shdr *hdr;
- asection *sec;
-{
- register const char *name;
-
- name = bfd_get_section_name (abfd, sec);
-
- if (strcmp (name, ".reloc") == 0)
- /*
- * This is an ugly, but unfortunately necessary hack that is
- * needed when producing EFI binaries on x86. It tells
- * elf.c:elf_fake_sections() not to consider ".reloc" as a section
- * containing ELF relocation info. We need this hack in order to
- * be able to generate ELF binaries that can be translated into
- * EFI applications (which are essentially COFF objects). Those
- * files contain a COFF ".reloc" section inside an ELFNN object,
- * which would normally cause BFD to segfault because it would
- * attempt to interpret this section as containing relocation
- * entries for section "oc". With this hack enabled, ".reloc"
- * will be treated as a normal data section, which will avoid the
- * segfault. However, you won't be able to create an ELFNN binary
- * with a section named "oc" that needs relocations, but that's
- * the kind of ugly side-effects you get when detecting section
- * types based on their names... In practice, this limitation is
- * unlikely to bite.
- */
- hdr->sh_type = SHT_PROGBITS;
-
- return true;
-}
-
-
#define TARGET_LITTLE_SYM bfd_elf32_i386_vec
#define TARGET_LITTLE_NAME "elf32-i386"
#define ELF_ARCH bfd_arch_i386
#define ELF_MAXPAGESIZE 0x1000
#define elf_backend_can_gc_sections 1
+#define elf_backend_can_refcount 1
#define elf_backend_want_got_plt 1
#define elf_backend_plt_readonly 1
#define elf_backend_want_plt_sym 0
#define elf_info_to_howto elf_i386_info_to_howto
#define elf_info_to_howto_rel elf_i386_info_to_howto_rel
+#define bfd_elf32_mkobject elf_i386_mkobject
+#define elf_backend_object_p elf_i386_object_p
+
#define bfd_elf32_bfd_is_local_label_name elf_i386_is_local_label_name
#define bfd_elf32_bfd_link_hash_table_create elf_i386_link_hash_table_create
#define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup
#define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol
#define elf_backend_check_relocs elf_i386_check_relocs
+#define elf_backend_copy_indirect_symbol elf_i386_copy_indirect_symbol
#define elf_backend_create_dynamic_sections elf_i386_create_dynamic_sections
+#define elf_backend_fake_sections elf_i386_fake_sections
#define elf_backend_finish_dynamic_sections elf_i386_finish_dynamic_sections
#define elf_backend_finish_dynamic_symbol elf_i386_finish_dynamic_symbol
#define elf_backend_gc_mark_hook elf_i386_gc_mark_hook
#define elf_backend_gc_sweep_hook elf_i386_gc_sweep_hook
+#define elf_backend_grok_prstatus elf_i386_grok_prstatus
+#define elf_backend_grok_psinfo elf_i386_grok_psinfo
+#define elf_backend_reloc_type_class elf_i386_reloc_type_class
#define elf_backend_relocate_section elf_i386_relocate_section
#define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections
-#define elf_backend_fake_sections elf_i386_fake_sections
+#ifndef ELF32_I386_C_INCLUDED
#include "elf32-target.h"
+#endif