/* IA-64 support for 64-bit ELF
- Copyright 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of BFD, the Binary File Descriptor library.
#include "opcode/ia64.h"
#include "elf/ia64.h"
-
/*
* THE RULES for all the stuff the linker creates --
*
/* The symbol table entry, if any, that this was derrived from. */
struct elf_link_hash_entry *h;
-
+
/* Used to count non-got, non-plt relocations for delayed sizing
of relocation sections. */
struct elfNN_ia64_dyn_reloc_entry
static boolean elfNN_ia64_relax_section
PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
boolean *again));
+static boolean is_unwind_section_name
+ PARAMS ((const char *));
static boolean elfNN_ia64_section_from_shdr
PARAMS ((bfd *, ElfNN_Internal_Shdr *, char *));
static boolean elfNN_ia64_fake_sections
PARAMS ((bfd *abfd, ElfNN_Internal_Shdr *hdr, asection *sec));
+static void elfNN_ia64_final_write_processing
+ PARAMS ((bfd *abfd, boolean linker));
static boolean elfNN_ia64_add_symbol_hook
PARAMS ((bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Sym *sym,
const char **namep, flagword *flagsp, asection **secp,
bfd_vma *valp));
+static boolean elfNN_ia64_aix_vec
+ PARAMS ((const bfd_target *vec));
+static boolean elfNN_ia64_aix_add_symbol_hook
+ PARAMS ((bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Sym *sym,
+ const char **namep, flagword *flagsp, asection **secp,
+ bfd_vma *valp));
+static boolean elfNN_ia64_aix_link_add_symbols
+ PARAMS ((bfd *abfd, struct bfd_link_info *info));
static int elfNN_ia64_additional_program_headers
PARAMS ((bfd *abfd));
static boolean elfNN_ia64_is_local_label_name
boolean create, boolean copy));
static void elfNN_ia64_dyn_sym_traverse
PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
- boolean (*func)(struct elfNN_ia64_dyn_sym_info *, PTR),
+ boolean (*func) (struct elfNN_ia64_dyn_sym_info *, PTR),
PTR info));
static boolean elfNN_ia64_create_dynamic_sections
PARAMS ((bfd *abfd, struct bfd_link_info *info));
PARAMS ((bfd *ibfd, bfd *obfd));
static boolean elfNN_ia64_print_private_bfd_data
PARAMS ((bfd *abfd, PTR ptr));
-
\f
/* ia64-specific relocation */
static bfd_reloc_status_type
elfNN_ia64_reloc (abfd, reloc, sym, data, input_section,
output_bfd, error_message)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc;
- asymbol *sym;
- PTR data;
+ asymbol *sym ATTRIBUTE_UNUSED;
+ PTR data ATTRIBUTE_UNUSED;
asection *input_section;
bfd *output_bfd;
char **error_message;
IA64_HOWTO (R_IA64_LTOFF_FPTR64MSB, "LTOFF_FPTR64MSB", 4, false, true),
IA64_HOWTO (R_IA64_LTOFF_FPTR64LSB, "LTOFF_FPTR64LSB", 4, false, true),
- IA64_HOWTO (R_IA64_SEGBASE, "SEGBASE", 4, false, true),
IA64_HOWTO (R_IA64_SEGREL32MSB, "SEGREL32MSB", 2, false, true),
IA64_HOWTO (R_IA64_SEGREL32LSB, "SEGREL32LSB", 2, false, true),
IA64_HOWTO (R_IA64_SEGREL64MSB, "SEGREL64MSB", 4, false, true),
IA64_HOWTO (R_IA64_IPLTMSB, "IPLTMSB", 4, false, true),
IA64_HOWTO (R_IA64_IPLTLSB, "IPLTLSB", 4, false, true),
- IA64_HOWTO (R_IA64_EPLTMSB, "EPLTMSB", 4, false, true),
- IA64_HOWTO (R_IA64_EPLTLSB, "EPLTLSB", 4, false, true),
IA64_HOWTO (R_IA64_COPY, "COPY", 4, false, true),
IA64_HOWTO (R_IA64_LTOFF22X, "LTOFF22X", 0, false, true),
IA64_HOWTO (R_IA64_LDXMOV, "LDXMOV", 0, false, true),
static reloc_howto_type*
elfNN_ia64_reloc_type_lookup (abfd, bfd_code)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
bfd_reloc_code_real_type bfd_code;
{
unsigned int rtype;
case BFD_RELOC_IA64_LTOFF_FPTR64MSB: rtype = R_IA64_LTOFF_FPTR64MSB; break;
case BFD_RELOC_IA64_LTOFF_FPTR64LSB: rtype = R_IA64_LTOFF_FPTR64LSB; break;
- case BFD_RELOC_IA64_SEGBASE: rtype = R_IA64_SEGBASE; break;
case BFD_RELOC_IA64_SEGREL32MSB: rtype = R_IA64_SEGREL32MSB; break;
case BFD_RELOC_IA64_SEGREL32LSB: rtype = R_IA64_SEGREL32LSB; break;
case BFD_RELOC_IA64_SEGREL64MSB: rtype = R_IA64_SEGREL64MSB; break;
case BFD_RELOC_IA64_IPLTMSB: rtype = R_IA64_IPLTMSB; break;
case BFD_RELOC_IA64_IPLTLSB: rtype = R_IA64_IPLTLSB; break;
- case BFD_RELOC_IA64_EPLTMSB: rtype = R_IA64_EPLTMSB; break;
- case BFD_RELOC_IA64_EPLTLSB: rtype = R_IA64_EPLTLSB; break;
case BFD_RELOC_IA64_COPY: rtype = R_IA64_COPY; break;
case BFD_RELOC_IA64_LTOFF22X: rtype = R_IA64_LTOFF22X; break;
case BFD_RELOC_IA64_LDXMOV: rtype = R_IA64_LDXMOV; break;
static void
elfNN_ia64_info_to_howto (abfd, bfd_reloc, elf_reloc)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
arelent *bfd_reloc;
ElfNN_Internal_Rela *elf_reloc;
{
};
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
+#define AIX_DYNAMIC_INTERPRETER "/usr/lib/ia64l64/libc.so.1"
+#define DYNAMIC_INTERPRETER(abfd) \
+ (elfNN_ia64_aix_vec (abfd->xvec) ? AIX_DYNAMIC_INTERPRETER : ELF_DYNAMIC_INTERPRETER)
/* Select out of range branch fixup type. Note that Itanium does
not support brl, and so it gets emulated by the kernel. */
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Rela *internal_relocs;
- Elf_Internal_Rela *free_relocs;
+ Elf_Internal_Rela *free_relocs = NULL;
Elf_Internal_Rela *irel, *irelend;
bfd_byte *contents;
- bfd_byte *free_contents;
+ bfd_byte *free_contents = NULL;
ElfNN_External_Sym *extsyms;
- ElfNN_External_Sym *free_extsyms;
+ ElfNN_External_Sym *free_extsyms = NULL;
struct elfNN_ia64_link_hash_table *ia64_info;
struct one_fixup *fixups = NULL;
boolean changed_contents = false;
link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
- free_relocs = NULL;
+
if (! link_info->keep_memory)
free_relocs = internal_relocs;
}
/* Get the section contents. */
- free_contents = NULL;
if (elf_section_data (sec)->this_hdr.contents != NULL)
contents = elf_section_data (sec)->this_hdr.contents;
else
}
/* Read this BFD's symbols. */
- free_extsyms = NULL;
if (symtab_hdr->contents != NULL)
extsyms = (ElfNN_External_Sym *) symtab_hdr->contents;
else
tsec = bfd_com_section_ptr;
else if (isym.st_shndx > 0 && isym.st_shndx < SHN_LORESERVE)
tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
- else
- continue; /* who knows. */
+ else
+ continue; /* who knows. */
toff = isym.st_value;
}
return false;
}
\f
+/* Return true if NAME is an unwind table section name. */
+
+static inline boolean
+is_unwind_section_name (name)
+ const char *name;
+{
+ size_t len1, len2, len3;
+
+ len1 = sizeof (ELF_STRING_ia64_unwind) - 1;
+ len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1;
+ len3 = sizeof (ELF_STRING_ia64_unwind_once) - 1;
+ return ((strncmp (name, ELF_STRING_ia64_unwind, len1) == 0
+ && strncmp (name, ELF_STRING_ia64_unwind_info, len2) != 0)
+ || strncmp (name, ELF_STRING_ia64_unwind_once, len3) == 0);
+}
+
/* Handle an IA-64 specific section when reading an object file. This
is called when elfcode.h finds a section with an unknown type. */
switch (hdr->sh_type)
{
case SHT_IA_64_UNWIND:
- if (strcmp (name, ELF_STRING_ia64_unwind) != 0)
- return false;
break;
case SHT_IA_64_EXT:
static boolean
elfNN_ia64_fake_sections (abfd, hdr, sec)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
ElfNN_Internal_Shdr *hdr;
asection *sec;
{
name = bfd_get_section_name (abfd, sec);
- if (strcmp (name, ELF_STRING_ia64_unwind) == 0)
- hdr->sh_type = SHT_IA_64_UNWIND;
+ if (is_unwind_section_name (name))
+ {
+ /* We don't have the sections numbered at this point, so sh_info
+ is set later, in elfNN_ia64_final_write_processing. */
+ hdr->sh_type = SHT_IA_64_UNWIND;
+ hdr->sh_flags |= SHF_LINK_ORDER;
+ }
else if (strcmp (name, ELF_STRING_ia64_archext) == 0)
hdr->sh_type = SHT_IA_64_EXT;
else if (strcmp (name, ".reloc") == 0)
return true;
}
+/* The final processing done just before writing out an IA-64 ELF
+ object file. */
+
+static void
+elfNN_ia64_final_write_processing (abfd, linker)
+ bfd *abfd;
+ boolean linker ATTRIBUTE_UNUSED;
+{
+ Elf_Internal_Shdr *hdr;
+ const char *sname;
+ asection *text_sect, *s;
+ size_t len;
+
+ for (s = abfd->sections; s; s = s->next)
+ {
+ hdr = &elf_section_data (s)->this_hdr;
+ switch (hdr->sh_type)
+ {
+ case SHT_IA_64_UNWIND:
+ /* See comments in gas/config/tc-ia64.c:dot_endp on why we
+ have to do this. */
+ sname = bfd_get_section_name (abfd, s);
+ len = sizeof (ELF_STRING_ia64_unwind) - 1;
+ if (sname && strncmp (sname, ELF_STRING_ia64_unwind, len) == 0)
+ {
+ sname += len;
+
+ if (sname[0] == '\0')
+ /* .IA_64.unwind -> .text */
+ text_sect = bfd_get_section_by_name (abfd, ".text");
+ else
+ /* .IA_64.unwindFOO -> FOO */
+ text_sect = bfd_get_section_by_name (abfd, sname);
+ }
+ else if (sname
+ && (len = sizeof (ELF_STRING_ia64_unwind_once) - 1,
+ strncmp (sname, ELF_STRING_ia64_unwind_once, len)) == 0)
+ {
+ /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.t.FOO */
+ size_t len2 = sizeof (".gnu.linkonce.t.") - 1;
+ char *once_name = alloca (len2 + strlen (sname) - len + 1);
+
+ memcpy (once_name, ".gnu.linkonce.t.", len2);
+ strcpy (once_name + len2, sname + len);
+ text_sect = bfd_get_section_by_name (abfd, once_name);
+ }
+ else
+ /* last resort: fall back on .text */
+ text_sect = bfd_get_section_by_name (abfd, ".text");
+
+ if (text_sect)
+ {
+ /* The IA-64 processor-specific ABI requires setting
+ sh_link to the unwind section, whereas HP-UX requires
+ sh_info to do so. For maximum compatibility, we'll
+ set both for now... */
+ hdr->sh_link = elf_section_data (text_sect)->this_idx;
+ hdr->sh_info = elf_section_data (text_sect)->this_idx;
+ }
+ break;
+ }
+ }
+}
+
/* Hook called by the linker routine which adds symbols from an object
file. We use it to put .comm items in .sbss, and not .bss. */
bfd *abfd;
struct bfd_link_info *info;
const Elf_Internal_Sym *sym;
- const char **namep;
- flagword *flagsp;
+ const char **namep ATTRIBUTE_UNUSED;
+ flagword *flagsp ATTRIBUTE_UNUSED;
asection **secp;
bfd_vma *valp;
{
if (sym->st_shndx == SHN_COMMON
&& !info->relocateable
- && sym->st_size <= bfd_get_gp_size (abfd))
+ && sym->st_size <= (unsigned) bfd_get_gp_size (abfd))
{
/* Common symbols less than or equal to -G nn bytes are
automatically put into .sbss. */
return true;
}
+static boolean
+elfNN_ia64_aix_vec (const bfd_target *vec)
+{
+ extern const bfd_target bfd_elfNN_ia64_aix_little_vec;
+ extern const bfd_target bfd_elfNN_ia64_aix_big_vec;
+
+ return (/**/vec == & bfd_elfNN_ia64_aix_little_vec
+ || vec == & bfd_elfNN_ia64_aix_big_vec);
+}
+
+/* Hook called by the linker routine which adds symbols from an object
+ file. We use it to handle OS-specific symbols. */
+
+static boolean
+elfNN_ia64_aix_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ const Elf_Internal_Sym *sym;
+ const char **namep;
+ flagword *flagsp;
+ asection **secp;
+ bfd_vma *valp;
+{
+ if (strcmp (*namep, "__GLOB_DATA_PTR") == 0)
+ {
+ /* Define __GLOB_DATA_PTR when it is encountered. This is expected to
+ be a linker-defined symbol by the Aix C runtime startup code. IBM sez
+ no one else should use it b/c it is undocumented. */
+ struct elf_link_hash_entry *h;
+
+ h = (struct elf_link_hash_entry *) bfd_link_hash_lookup (info->hash, *namep, false, false, false);
+ if (h == NULL)
+ {
+ struct elf_backend_data *bed;
+ struct elfNN_ia64_link_hash_table *ia64_info;
+
+ bed = get_elf_backend_data (abfd);
+ ia64_info = elfNN_ia64_hash_table (info);
+
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, abfd, *namep, BSF_GLOBAL,
+ bfd_get_section_by_name (abfd, ".bss"),
+ bed->got_symbol_offset, (const char *) NULL, false,
+ bed->collect, (struct bfd_link_hash_entry **) &h)))
+ return false;
+
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->type = STT_OBJECT;
+
+ if (! _bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
+ return true;
+ }
+ else if (sym->st_shndx == SHN_LOOS)
+ {
+ int i;
+
+ /* SHN_AIX_SYSCALL: Treat this as any other symbol. The special symbol
+ is only relevant when compiling code for extended system calls.
+ Replace the "special" section with .text, if possible.
+ Note that these symbols are always assumed to be in .text. */
+ for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++)
+ {
+ asection * sec = bfd_section_from_elf_index (abfd, i);
+
+ if (sec && strcmp (sec->name, ".text") == 0)
+ {
+ *secp = sec;
+ break;
+ }
+ }
+
+ if (*secp == NULL)
+ *secp = bfd_abs_section_ptr;
+
+ *valp = sym->st_size;
+
+ return true;
+ }
+ else
+ {
+ return elfNN_ia64_add_symbol_hook (abfd, info, sym,
+ namep, flagsp, secp, valp);
+ }
+}
+
+boolean
+elfNN_ia64_aix_link_add_symbols (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ /* Make sure dynamic sections are always created. */
+ if (! elf_hash_table (info)->dynamic_sections_created
+ && abfd->xvec == info->hash->creator)
+ {
+ if (! bfd_elfNN_link_create_dynamic_sections (abfd, info))
+ return false;
+ }
+
+ /* Now do the standard call. */
+ return bfd_elfNN_bfd_link_add_symbols (abfd, info);
+}
+
/* Return the number of additional phdrs we will need. */
static int
if (s && (s->flags & SEC_LOAD))
++ret;
- /* See if we need a PT_IA_64_UNWIND segment. */
- s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_unwind);
- if (s && (s->flags & SEC_LOAD))
- ++ret;
+ /* Count how many PT_IA_64_UNWIND segments we need. */
+ for (s = abfd->sections; s; s = s->next)
+ if (is_unwind_section_name(s->name) && (s->flags & SEC_LOAD))
+ ++ret;
return ret;
}
bfd *abfd;
{
struct elf_segment_map *m, **pm;
+ Elf_Internal_Shdr *hdr;
asection *s;
/* If we need a PT_IA_64_ARCHEXT segment, it must come before
}
}
- /* Install the PT_IA_64_UNWIND segment, if needed. */
- s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_unwind);
- if (s && (s->flags & SEC_LOAD))
+ /* Install PT_IA_64_UNWIND segments, if needed. */
+ for (s = abfd->sections; s; s = s->next)
{
- for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
- if (m->p_type == PT_IA_64_UNWIND)
- break;
- if (m == NULL)
+ hdr = &elf_section_data (s)->this_hdr;
+ if (hdr->sh_type != SHT_IA_64_UNWIND)
+ continue;
+
+ if (s && (s->flags & SEC_LOAD))
{
- m = (struct elf_segment_map *) bfd_zalloc (abfd, sizeof *m);
+ for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+ if (m->p_type == PT_IA_64_UNWIND && m->sections[0] == s)
+ break;
+
if (m == NULL)
- return false;
+ {
+ m = (struct elf_segment_map *) bfd_zalloc (abfd, sizeof *m);
+ if (m == NULL)
+ return false;
- m->p_type = PT_IA_64_UNWIND;
- m->count = 1;
- m->sections[0] = s;
- m->next = NULL;
+ m->p_type = PT_IA_64_UNWIND;
+ m->count = 1;
+ m->sections[0] = s;
+ m->next = NULL;
- /* We want to put it last. */
- pm = &elf_tdata (abfd)->segment_map;
- while (*pm != NULL)
- pm = &(*pm)->next;
- *pm = m;
+ /* We want to put it last. */
+ pm = &elf_tdata (abfd)->segment_map;
+ while (*pm != NULL)
+ pm = &(*pm)->next;
+ *pm = m;
+ }
}
}
return true;
}
-
/* According to the Tahoe assembler spec, all labels starting with a
'.' are local. */
static boolean
elfNN_ia64_is_local_label_name (abfd, name)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
const char *name;
{
return name[0] == '.';
if (h->dynindx == -1)
return false;
+ switch (ELF_ST_VISIBILITY (h->other))
+ {
+ case STV_INTERNAL:
+ case STV_HIDDEN:
+ return false;
+ }
if (h->root.type == bfd_link_hash_undefweak
|| h->root.type == bfd_link_hash_defweak)
static boolean
elfNN_ia64_local_hash_table_init (ht, abfd, new)
struct elfNN_ia64_local_hash_table *ht;
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
new_hash_entry_func new;
{
- memset (ht, 0, sizeof(*ht));
+ memset (ht, 0, sizeof (*ht));
return bfd_hash_table_init (&ht->root, new);
}
/* Initialize our local data. All zeros, and definitely easier
than setting a handful of bit fields. */
- memset (ret, 0, sizeof(*ret));
+ memset (ret, 0, sizeof (*ret));
/* Call the allocation method of the superclass. */
ret = ((struct elfNN_ia64_local_hash_entry *)
/* Initialize our local data. All zeros, and definitely easier
than setting a handful of bit fields. */
- memset (ret, 0, sizeof(*ret));
+ memset (ret, 0, sizeof (*ret));
/* Call the allocation method of the superclass. */
ret = ((struct elfNN_ia64_link_hash_entry *)
dir = (struct elfNN_ia64_link_hash_entry *)xdir;
ind = (struct elfNN_ia64_link_hash_entry *)xind;
- /* Copy down any references that we may have already seen to the
+ /* Copy down any references that we may have already seen to the
symbol which just became indirect. */
dir->root.elf_link_hash_flags |=
h = (struct elfNN_ia64_link_hash_entry *)xh;
h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
- h->root.dynindx = -1;
+ if ((h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+ h->root.dynindx = -1;
for (dyn_i = h->info; dyn_i; dyn_i = dyn_i->next)
dyn_i->want_plt2 = 0;
struct bfd_link_info *info;
{
struct elfNN_ia64_link_hash_table *ia64_info;
- struct elf_link_hash_entry *h;
asection *s;
if (! _bfd_elf_create_dynamic_sections (abfd, info))
struct elfNN_ia64_dyn_sym_info **pp;
struct elfNN_ia64_dyn_sym_info *dyn_i;
bfd_vma addend = rel ? rel->r_addend : 0;
-
+
if (h)
pp = &((struct elfNN_ia64_link_hash_entry *)h)->info;
else
/* Construct a string for use in the elfNN_ia64_local_hash_table.
The name describes what was once anonymous memory. */
- len = sizeof(void*)*2 + 1 + sizeof(bfd_vma)*4 + 1 + 1;
+ len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1;
len += 10; /* %p slop */
addr_name = alloca (len);
- sprintf (addr_name, "%p:%lx", abfd, ELFNN_R_SYM (rel->r_info));
+ sprintf (addr_name, "%p:%lx", (void *) abfd, ELFNN_R_SYM (rel->r_info));
/* Collect the canonical entry data for this address. */
loc_h = elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
BFD_ASSERT (loc_h);
pp = &loc_h->info;
- }
+ }
for (dyn_i = *pp; dyn_i && dyn_i->addend != addend; dyn_i = *pp)
pp = &dyn_i->next;
struct bfd_link_info *info;
struct elfNN_ia64_link_hash_table *ia64_info;
{
- asection *got, *srel;
+ asection *got;
bfd *dynobj;
got = ia64_info->got_sec;
static asection *
get_fptr (abfd, info, ia64_info)
bfd *abfd;
- struct bfd_link_info *info;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
struct elfNN_ia64_link_hash_table *ia64_info;
{
asection *fptr;
static asection *
get_pltoff (abfd, info, ia64_info)
bfd *abfd;
- struct bfd_link_info *info;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
struct elfNN_ia64_link_hash_table *ia64_info;
{
asection *pltoff;
struct elfNN_ia64_dyn_sym_info *dyn_i;
int need_entry;
boolean maybe_dynamic;
- int dynrel_type;
+ int dynrel_type = R_IA64_NONE;
if (r_symndx >= symtab_hdr->sh_info)
{
maybe_dynamic = false;
if (h && ((info->shared && ! info->symbolic)
|| ! (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
- || h->root.type == bfd_link_hash_defweak))
+ || h->root.type == bfd_link_hash_defweak
+ || elfNN_ia64_aix_vec (abfd->xvec)))
maybe_dynamic = true;
need_entry = 0;
case R_IA64_FPTR32LSB:
case R_IA64_FPTR64MSB:
case R_IA64_FPTR64LSB:
- if (info->shared || h)
+ if (info->shared || h || elfNN_ia64_aix_vec (abfd->xvec))
need_entry = NEED_FPTR | NEED_DYNREL;
else
need_entry = NEED_FPTR;
case R_IA64_DIR64MSB:
case R_IA64_DIR64LSB:
/* Shared objects will always need at least a REL relocation. */
- if (info->shared || maybe_dynamic)
+ if (info->shared || maybe_dynamic
+ || (elfNN_ia64_aix_vec (abfd->xvec)
+ && (!h || strcmp (h->root.root.string,
+ "__GLOB_DATA_PTR") != 0)))
need_entry = NEED_DYNREL;
dynrel_type = R_IA64_DIR64LSB;
break;
+ case R_IA64_IPLTMSB:
+ case R_IA64_IPLTLSB:
+ /* Shared objects will always need at least a REL relocation. */
+ if (info->shared || maybe_dynamic)
+ need_entry = NEED_DYNREL;
+ dynrel_type = R_IA64_IPLTLSB;
+ break;
+
case R_IA64_PCREL22:
case R_IA64_PCREL64I:
case R_IA64_PCREL32MSB:
/* FPTRs for shared libraries are allocated by the dynamic
linker. Make sure this local symbol will appear in the
dynamic symbol table. */
- if (!h && info->shared)
+ if (!h && (info->shared
+ /* AIX also needs one */
+ || elfNN_ia64_aix_vec (abfd->xvec)))
{
if (! (_bfd_elfNN_link_record_local_dynamic_symbol
(info, abfd, r_symndx)))
if (dyn_i->want_got
&& ! dyn_i->want_fptr
- && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info))
+ && (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
+ || (elfNN_ia64_aix_vec (x->info->hash->creator)
+ && (!dyn_i->h || strcmp (dyn_i->h->root.root.string,
+ "__GLOB_DATA_PTR") != 0))))
{
dyn_i->got_offset = x->ofs;
x->ofs += 8;
if (dyn_i->want_got
&& dyn_i->want_fptr
- && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info))
+ && (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
+ || elfNN_ia64_aix_vec (x->info->hash->creator)))
{
dyn_i->got_offset = x->ofs;
x->ofs += 8;
struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data;
if (dyn_i->want_got
- && ! elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info))
+ && ! (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
+ || elfNN_ia64_aix_vec (x->info->hash->creator)))
{
dyn_i->got_offset = x->ofs;
x->ofs += 8;
if (dyn_i->want_fptr)
{
struct elf_link_hash_entry *h = dyn_i->h;
-
+
if (h)
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;
- if (x->info->shared)
+ if (x->info->shared
+ /* AIX needs an FPTR in this case. */
+ || (elfNN_ia64_aix_vec (x->info->hash->creator)
+ && (!h
+ || h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)))
{
if (h && h->dynindx == -1)
{
boolean dynamic_symbol, shared;
ia64_info = elfNN_ia64_hash_table (x->info);
- dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info);
+ dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)
+ || (elfNN_ia64_aix_vec (x->info->hash->creator)
+ /* Don't allocate an entry for __GLOB_DATA_PTR */
+ && (!dyn_i->h || strcmp (dyn_i->h->root.root.string,
+ "__GLOB_DATA_PTR") != 0));
shared = x->info->shared;
/* Take care of the normal data relocations. */
for (rent = dyn_i->reloc_entries; rent; rent = rent->next)
{
+ int count = rent->count;
+
switch (rent->type)
{
case R_IA64_FPTR64LSB:
if (!dynamic_symbol && !shared)
continue;
break;
+ case R_IA64_IPLTLSB:
+ if (!dynamic_symbol && !shared)
+ continue;
+ /* Use two REL relocations for IPLT relocations
+ against local symbols. */
+ if (!dynamic_symbol)
+ count *= 2;
+ break;
+ default:
+ abort ();
}
- rent->srel->_raw_size += sizeof (ElfNN_External_Rela) * rent->count;
+ rent->srel->_raw_size += sizeof (ElfNN_External_Rela) * count;
}
/* Take care of the GOT and PLT relocations. */
static boolean
elfNN_ia64_adjust_dynamic_symbol (info, h)
- struct bfd_link_info *info;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
struct elf_link_hash_entry *h;
{
/* ??? Undefined symbols with PLT entries should be re-defined
{
sec = bfd_get_section_by_name (dynobj, ".interp");
BFD_ASSERT (sec != NULL);
- sec->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
- sec->_raw_size = strlen (ELF_DYNAMIC_INTERPRETER) + 1;
- }
-
- /* DT_INIT and DT_FINI get function descriptors not raw code addresses.
- Force their symbols to have pltoff entries so we can use those. */
- if (ia64_info->root.dynamic_sections_created)
- {
- struct elf_link_hash_entry *h;
- struct elfNN_ia64_dyn_sym_info *dyn_i;
-
- if (info->init_function
- && (h = elf_link_hash_lookup (elf_hash_table (info),
- info->init_function, false,
- false, false))
- && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR)) != 0)
- {
- dyn_i = get_dyn_sym_info (ia64_info, h, output_bfd, NULL, true);
- dyn_i->want_pltoff = 1;
- }
-
- if (info->fini_function
- && (h = elf_link_hash_lookup (elf_hash_table (info),
- info->fini_function, false,
- false, false))
- && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR)) != 0)
- {
- dyn_i = get_dyn_sym_info (ia64_info, h, output_bfd, NULL, true);
- dyn_i->want_pltoff = 1;
- }
+ sec->contents = (bfd_byte *) DYNAMIC_INTERPRETER (output_bfd);
+ sec->_raw_size = strlen (DYNAMIC_INTERPRETER (output_bfd)) + 1;
}
/* Allocate the GOT entries. */
if (! bfd_elfNN_add_dynamic_entry (info, DT_RELA, 0)
|| ! bfd_elfNN_add_dynamic_entry (info, DT_RELASZ, 0)
|| ! bfd_elfNN_add_dynamic_entry (info, DT_RELAENT,
- sizeof(ElfNN_External_Rela)))
+ sizeof (ElfNN_External_Rela)))
return false;
if (reltext)
case R_IA64_LDXMOV:
return bfd_reloc_ok;
- /* Instruction relocations. */
+ /* Instruction relocations. */
case R_IA64_IMM14: opnd = IA64_OPND_IMM14; break;
break;
/* Unsupported / Dynamic relocations. */
-
- case R_IA64_REL32MSB:
- case R_IA64_REL32LSB:
- case R_IA64_REL64MSB:
- case R_IA64_REL64LSB:
-
- case R_IA64_IPLTMSB:
- case R_IA64_IPLTLSB:
- case R_IA64_EPLTMSB:
- case R_IA64_EPLTLSB:
- case R_IA64_COPY:
-
- case R_IA64_SEGBASE:
-
- case R_IA64_TPREL22:
- case R_IA64_TPREL64MSB:
- case R_IA64_TPREL64LSB:
- case R_IA64_LTOFF_TP22:
-
default:
return bfd_reloc_notsupported;
}
case 0: shift = 5; break;
case 1: shift = 14; hit_addr += 3; break;
case 2: shift = 23; hit_addr += 6; break;
- case 3: return bfd_reloc_notsupported; /* shouldn't happen... */
+ case 3: return bfd_reloc_notsupported; /* shouldn't happen... */
}
dword = bfd_get_64 (abfd, hit_addr);
insn = (dword >> shift) & 0x1ffffffffffLL;
bfd_elfNN_swap_reloca_out (abfd, &outrel,
((ElfNN_External_Rela *) srel->contents
+ srel->reloc_count++));
- BFD_ASSERT (sizeof(ElfNN_External_Rela) * srel->reloc_count
+ BFD_ASSERT (sizeof (ElfNN_External_Rela) * srel->reloc_count
<= srel->_cooked_size);
}
/* Install a dynamic relocation if needed. */
if (info->shared
|| elfNN_ia64_dynamic_symbol_p (dyn_i->h, info)
+ || elfNN_ia64_aix_vec (abfd->xvec)
|| (dynindx != -1 && dyn_r_type == R_IA64_FPTR64LSB))
{
if (dynindx == -1)
if ((! dyn_i->want_plt || is_plt)
&& !dyn_i->pltoff_done)
{
+ bfd_vma gp = _bfd_get_gp_value (abfd);
+
/* Fill in the function descriptor. */
bfd_put_64 (abfd, value, pltoff_sec->contents + dyn_i->pltoff_offset);
- bfd_put_64 (abfd, _bfd_get_gp_value (abfd),
- pltoff_sec->contents + dyn_i->pltoff_offset + 8);
+ bfd_put_64 (abfd, gp, pltoff_sec->contents + dyn_i->pltoff_offset + 8);
/* Install dynamic relocations if needed. */
if (!is_plt && info->shared)
elfNN_ia64_install_dyn_reloc (abfd, NULL, pltoff_sec,
ia64_info->rel_pltoff_sec,
dyn_i->pltoff_offset,
- dyn_r_type, 0, 0);
+ dyn_r_type, 0, value);
elfNN_ia64_install_dyn_reloc (abfd, NULL, pltoff_sec,
ia64_info->rel_pltoff_sec,
dyn_i->pltoff_offset + 8,
- dyn_r_type, 0, 0);
+ dyn_r_type, 0, gp);
}
dyn_i->pltoff_done = 1;
(*_bfd_error_handler)
(_("%s: short data segment overflowed (0x%lx >= 0x400000)"),
bfd_get_filename (abfd),
- (unsigned long)(max_short_vma - min_short_vma));
+ (unsigned long) (max_short_vma - min_short_vma));
return false;
}
else if ((gp_val > min_short_vma
}
_bfd_set_gp_value (abfd, gp_val);
- }
- /* Tricky bits. DT_INIT and DT_FINI use a pltoff entry, which is
- normally initialized in finish_dynamic_sections. Except that
- we need all non-plt pltoff entries to be initialized before
- finish_dynamic_symbols. This because the array of relocations
- used for plt entries (aka DT_JMPREL) begins after all the
- non-plt pltoff relocations. If the order gets confused, we
- munge either the array or the array base. */
- if (ia64_info->root.dynamic_sections_created)
- {
- struct elf_link_hash_entry *h;
- struct elfNN_ia64_dyn_sym_info *dyn_i;
- bfd_vma addr;
-
- if (info->init_function
- && (h = elf_link_hash_lookup (elf_hash_table (info),
- info->init_function, false,
- false, false))
- && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR)) != 0)
- {
- dyn_i = get_dyn_sym_info (ia64_info, h, NULL, NULL, false);
- addr = (h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset
- + h->root.u.def.value);
- (void) set_pltoff_entry (abfd, info, dyn_i, addr, false);
- }
-
- if (info->fini_function
- && (h = elf_link_hash_lookup (elf_hash_table (info),
- info->fini_function, false,
- false, false))
- && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR)) != 0)
- {
- dyn_i = get_dyn_sym_info (ia64_info, h, NULL, NULL, false);
- addr = (h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset
- + h->root.u.def.value);
- (void) set_pltoff_entry (abfd, info, dyn_i, addr, false);
- }
+ if (gp)
+ {
+ gp->root.type = bfd_link_hash_defined;
+ gp->root.u.def.value = gp_val;
+ gp->root.u.def.section = bfd_abs_section_ptr;
+ }
}
/* If we're producing a final executable, we need to sort the contents
case R_IA64_DIR64MSB:
case R_IA64_DIR64LSB:
/* Install a dynamic relocation for this reloc. */
- if ((dynamic_symbol_p || info->shared)
+ if ((dynamic_symbol_p || info->shared
+ || (elfNN_ia64_aix_vec (info->hash->creator)
+ /* Don't emit relocs for __GLOB_DATA_PTR on AIX. */
+ && (!h || strcmp (h->root.root.string,
+ "__GLOB_DATA_PTR") != 0)))
&& (input_section->flags & SEC_ALLOC) != 0)
{
unsigned int dyn_r_type;
long dynindx;
+ bfd_vma addend;
BFD_ASSERT (srel != NULL);
matching RELATIVE relocation. */
dyn_r_type = r_type;
if (dynamic_symbol_p)
- dynindx = h->dynindx;
+ {
+ dynindx = h->dynindx;
+ addend = rel->r_addend;
+ value = 0;
+ }
else
{
switch (r_type)
continue;
}
dynindx = 0;
+ addend = value;
}
+ if (elfNN_ia64_aix_vec (info->hash->creator))
+ rel->r_addend = value;
elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section,
srel, rel->r_offset, dyn_r_type,
- dynindx, rel->r_addend);
+ dynindx, addend);
}
/* FALLTHRU */
case R_IA64_PCREL64MSB:
case R_IA64_PCREL64LSB:
/* Install a dynamic relocation for this reloc. */
- if (dynamic_symbol_p)
+ if (dynamic_symbol_p
+ || elfNN_ia64_aix_vec (info->hash->creator))
{
BFD_ASSERT (srel != NULL);
r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
break;
- case R_IA64_SEGBASE:
-
- case R_IA64_REL32MSB:
- case R_IA64_REL32LSB:
- case R_IA64_REL64MSB:
- case R_IA64_REL64LSB:
-
case R_IA64_IPLTMSB:
case R_IA64_IPLTLSB:
- case R_IA64_EPLTMSB:
- case R_IA64_EPLTLSB:
- case R_IA64_COPY:
+ /* Install a dynamic relocation for this reloc. */
+ if ((dynamic_symbol_p || info->shared)
+ && (input_section->flags & SEC_ALLOC) != 0)
+ {
+ BFD_ASSERT (srel != NULL);
+
+ /* If we don't need dynamic symbol lookup, install two
+ RELATIVE relocations. */
+ if (! dynamic_symbol_p)
+ {
+ unsigned int dyn_r_type;
+
+ if (r_type == R_IA64_IPLTMSB)
+ dyn_r_type = R_IA64_REL64MSB;
+ else
+ dyn_r_type = R_IA64_REL64LSB;
+
+ elfNN_ia64_install_dyn_reloc (output_bfd, info,
+ input_section,
+ srel, rel->r_offset,
+ dyn_r_type, 0, value);
+ elfNN_ia64_install_dyn_reloc (output_bfd, info,
+ input_section,
+ srel, rel->r_offset + 8,
+ dyn_r_type, 0, gp_val);
+ }
+ else
+ elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section,
+ srel, rel->r_offset, r_type,
+ h->dynindx, rel->r_addend);
+ }
+
+ if (r_type == R_IA64_IPLTMSB)
+ r_type = R_IA64_DIR64MSB;
+ else
+ r_type = R_IA64_DIR64LSB;
+ elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type);
+ r = elfNN_ia64_install_value (output_bfd, hit_addr + 8, gp_val,
+ r_type);
+ break;
- case R_IA64_TPREL22:
- case R_IA64_TPREL64MSB:
- case R_IA64_TPREL64LSB:
- case R_IA64_LTOFF_TP22:
default:
r = bfd_reloc_notsupported;
break;
case DT_RELASZ:
/* Do not have RELASZ include JMPREL. This makes things
- easier on ld.so. This is not what the rest of BFD set up. */
+ easier on ld.so. This is not what the rest of BFD set up. */
dyn.d_un.d_val -= (ia64_info->minplt_entries
* sizeof (ElfNN_External_Rela));
break;
-
- case DT_INIT:
- case DT_FINI:
- {
- struct elf_link_hash_entry *h;
- struct elfNN_ia64_dyn_sym_info *dyn_i;
- const char *which;
-
- if (dyn.d_tag == DT_INIT)
- which = info->init_function;
- else
- which = info->fini_function;
-
- h = elf_link_hash_lookup (elf_hash_table (info), which,
- false, false, false);
- dyn_i = get_dyn_sym_info (ia64_info, h, NULL, NULL, false);
- dyn.d_un.d_ptr = set_pltoff_entry (abfd, info, dyn_i,
- dyn.d_un.d_ptr, 0);
- }
}
bfd_elfNN_swap_dyn_out (abfd, &dyn, dyncon);
\f
/* ELF file flag handling: */
-/* Function to keep IA-64 specific file flags. */
+/* Function to keep IA-64 specific file flags. */
static boolean
elfNN_ia64_set_private_flags (abfd, flags)
bfd *abfd;
(flags & EF_IA_64_NOFUNCDESC_CONS_GP) ? "NOFUNCDESC_CONS_GP, " : "",
(flags & EF_IA_64_ABSOLUTE) ? "ABSOLUTE, " : "",
(flags & EF_IA_64_ABI64) ? "ABI64" : "ABI32");
-
+
_bfd_elf_print_private_bfd_data (abfd, ptr);
return true;
}
elfNN_ia64_section_flags
#define elf_backend_fake_sections \
elfNN_ia64_fake_sections
+#define elf_backend_final_write_processing \
+ elfNN_ia64_final_write_processing
#define elf_backend_add_symbol_hook \
elfNN_ia64_add_symbol_hook
#define elf_backend_additional_program_headers \
#define elf_backend_hide_symbol elfNN_ia64_hash_hide_symbol
#include "elfNN-target.h"
+
+/* AIX-specific vectors. */
+
+#undef TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM bfd_elfNN_ia64_aix_little_vec
+#undef TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME "elfNN-ia64-aix-little"
+#undef TARGET_BIG_SYM
+#define TARGET_BIG_SYM bfd_elfNN_ia64_aix_big_vec
+#undef TARGET_BIG_NAME
+#define TARGET_BIG_NAME "elfNN-ia64-aix-big"
+
+#undef elf_backend_add_symbol_hook
+#define elf_backend_add_symbol_hook elfNN_ia64_aix_add_symbol_hook
+
+#undef bfd_elfNN_bfd_link_add_symbols
+#define bfd_elfNN_bfd_link_add_symbols elfNN_ia64_aix_link_add_symbols
+
+#define elfNN_bed elfNN_ia64_aix_bed
+
+#include "elfNN-target.h"