asection *rel_pltoff_sec; /* dynamic relocation section for same */
bfd_size_type minplt_entries; /* number of minplt entries */
+ unsigned reltext : 1; /* are there relocs against readonly sections? */
struct elfNN_ia64_local_hash_table loc_hash_table;
};
PARAMS ((const char *));
static boolean elfNN_ia64_section_from_shdr
PARAMS ((bfd *, ElfNN_Internal_Shdr *, char *));
+static boolean elfNN_ia64_section_flags
+ PARAMS ((flagword *, ElfNN_Internal_Shdr *));
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, 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_modify_segment_map
+ PARAMS ((bfd *));
static boolean elfNN_ia64_is_local_label_name
PARAMS ((bfd *abfd, const char *name));
static boolean elfNN_ia64_dynamic_symbol_p
static struct bfd_hash_entry *elfNN_ia64_new_elf_hash_entry
PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table,
const char *string));
+static void elfNN_ia64_hash_copy_indirect
+ PARAMS ((struct elf_link_hash_entry *, struct elf_link_hash_entry *));
+static void elfNN_ia64_hash_hide_symbol
+ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
static struct bfd_link_hash_table *elfNN_ia64_hash_table_create
PARAMS ((bfd *abfd));
static struct elfNN_ia64_local_hash_entry *elfNN_ia64_local_hash_lookup
PARAMS ((struct elfNN_ia64_local_hash_table *table, const char *string,
boolean create, boolean copy));
+static boolean elfNN_ia64_global_dyn_sym_thunk
+ PARAMS ((struct bfd_hash_entry *, PTR));
+static boolean elfNN_ia64_local_dyn_sym_thunk
+ PARAMS ((struct bfd_hash_entry *, PTR));
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),
PARAMS ((bfd *abfd, struct bfd_link_info *info,
struct elfNN_ia64_dyn_sym_info *dyn_i,
bfd_vma value, boolean));
+static int elfNN_ia64_unwind_entry_compare
+ PARAMS ((const PTR, const PTR));
static boolean elfNN_ia64_final_link
PARAMS ((bfd *abfd, struct bfd_link_info *info));
static boolean elfNN_ia64_relocate_section
PARAMS ((bfd *ibfd, bfd *obfd));
static boolean elfNN_ia64_print_private_bfd_data
PARAMS ((bfd *abfd, PTR ptr));
+static enum elf_reloc_type_class elfNN_ia64_reloc_type_class
+ PARAMS ((int));
\f
/* ia64-specific relocation */
IA64_HOWTO (R_IA64_LTOFF_FPTR22, "LTOFF_FPTR22", 0, false, true),
IA64_HOWTO (R_IA64_LTOFF_FPTR64I, "LTOFF_FPTR64I", 0, false, true),
+ IA64_HOWTO (R_IA64_LTOFF_FPTR32MSB, "LTOFF_FPTR32MSB", 2, false, true),
+ IA64_HOWTO (R_IA64_LTOFF_FPTR32LSB, "LTOFF_FPTR32LSB", 2, false, true),
IA64_HOWTO (R_IA64_LTOFF_FPTR64MSB, "LTOFF_FPTR64MSB", 4, false, true),
IA64_HOWTO (R_IA64_LTOFF_FPTR64LSB, "LTOFF_FPTR64LSB", 4, false, true),
case BFD_RELOC_IA64_LTOFF_FPTR22: rtype = R_IA64_LTOFF_FPTR22; break;
case BFD_RELOC_IA64_LTOFF_FPTR64I: rtype = R_IA64_LTOFF_FPTR64I; break;
+ case BFD_RELOC_IA64_LTOFF_FPTR32MSB: rtype = R_IA64_LTOFF_FPTR32MSB; break;
+ case BFD_RELOC_IA64_LTOFF_FPTR32LSB: rtype = R_IA64_LTOFF_FPTR32LSB; break;
case BFD_RELOC_IA64_LTOFF_FPTR64MSB: rtype = R_IA64_LTOFF_FPTR64MSB; break;
case BFD_RELOC_IA64_LTOFF_FPTR64LSB: rtype = R_IA64_LTOFF_FPTR64LSB; break;
};
#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. */
is_unwind_section_name (name)
const char *name;
{
- size_t len1, len2;
+ size_t len1, len2, len3;
len1 = sizeof (ELF_STRING_ia64_unwind) - 1;
len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1;
- return (strncmp (name, ELF_STRING_ia64_unwind, len1) == 0
- && strncmp (name, ELF_STRING_ia64_unwind_info, len2) != 0);
+ 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
/* .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 (sym->st_shndx == SHN_COMMON
&& !info->relocateable
- && sym->st_size <= (unsigned) bfd_get_gp_size (abfd))
+ && sym->st_size <= elf_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
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 elfNN_ia64_link_hash_table *ret;
- ret = bfd_alloc (abfd, sizeof (*ret));
+ ret = bfd_zalloc (abfd, sizeof (*ret));
if (!ret)
return 0;
if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
len += 10; /* %p slop */
addr_name = alloca (len);
- sprintf (addr_name, "%p:%lx", (void *) abfd, ELFNN_R_SYM (rel->r_info));
+ sprintf (addr_name, "%p:%lx",
+ (void *) abfd, (unsigned long) 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,
return NULL;
}
+ if (sec->flags & SEC_READONLY)
+ ia64_info->reltext = 1;
+
return srel;
}
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_LTOFF_FPTR22:
case R_IA64_LTOFF_FPTR64I:
+ case R_IA64_LTOFF_FPTR32MSB:
+ case R_IA64_LTOFF_FPTR32LSB:
case R_IA64_LTOFF_FPTR64MSB:
case R_IA64_LTOFF_FPTR64LSB:
need_entry = NEED_FPTR | NEED_GOT | NEED_LTOFF_FPTR;
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;
/* 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;
|| 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. */
struct elfNN_ia64_link_hash_table *ia64_info;
asection *sec;
bfd *dynobj;
- boolean reltext = false;
boolean relplt = false;
dynobj = elf_hash_table(info)->dynobj;
{
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;
+ sec->contents = (bfd_byte *) DYNAMIC_INTERPRETER (output_bfd);
+ sec->_raw_size = strlen (DYNAMIC_INTERPRETER (output_bfd)) + 1;
}
/* Allocate the GOT entries. */
{
if (!strip)
{
- const char *outname;
- asection *target;
-
- /* If this relocation section applies to a read only
- section, then we probably need a DT_TEXTREL entry. */
- outname = bfd_get_section_name (output_bfd,
- sec->output_section);
- if (outname[4] == 'a')
- outname += 5;
- else
- outname += 4;
-
- target = bfd_get_section_by_name (output_bfd, outname);
- if (target != NULL
- && (target->flags & SEC_READONLY) != 0
- && (target->flags & SEC_ALLOC) != 0)
- reltext = true;
-
/* We use the reloc_count field as a counter if we need to
copy relocs into the output file. */
sec->reloc_count = 0;
sizeof (ElfNN_External_Rela)))
return false;
- if (reltext)
+ if (ia64_info->reltext)
{
if (! bfd_elfNN_add_dynamic_entry (info, DT_TEXTREL, 0))
return false;
case R_IA64_GPREL32MSB:
case R_IA64_FPTR32MSB:
case R_IA64_PCREL32MSB:
+ case R_IA64_LTOFF_FPTR32MSB:
case R_IA64_SEGREL32MSB:
case R_IA64_SECREL32MSB:
case R_IA64_LTV32MSB:
case R_IA64_GPREL32LSB:
case R_IA64_FPTR32LSB:
case R_IA64_PCREL32LSB:
+ case R_IA64_LTOFF_FPTR32LSB:
case R_IA64_SEGREL32LSB:
case R_IA64_SECREL32LSB:
case R_IA64_LTV32LSB:
/* 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)
static int
elfNN_ia64_unwind_entry_compare (a, b)
- PTR a;
- PTR b;
+ const PTR a;
+ const PTR b;
{
bfd_vma av, bv;
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;
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, addend);
case R_IA64_LTOFF_FPTR22:
case R_IA64_LTOFF_FPTR64I:
+ case R_IA64_LTOFF_FPTR32MSB:
+ case R_IA64_LTOFF_FPTR32LSB:
case R_IA64_LTOFF_FPTR64MSB:
case R_IA64_LTOFF_FPTR64LSB:
{
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);
_bfd_elf_print_private_bfd_data (abfd, ptr);
return true;
}
+
+static enum elf_reloc_type_class
+elfNN_ia64_reloc_type_class (type)
+ int type;
+{
+ switch (type)
+ {
+ case R_IA64_REL32MSB:
+ case R_IA64_REL32LSB:
+ case R_IA64_REL64MSB:
+ case R_IA64_REL64LSB:
+ return reloc_class_relative;
+ case R_IA64_IPLTMSB:
+ case R_IA64_IPLTLSB:
+ return reloc_class_plt;
+ case R_IA64_COPY:
+ return reloc_class_copy;
+ default:
+ return reloc_class_normal;
+ }
+}
\f
#define TARGET_LITTLE_SYM bfd_elfNN_ia64_little_vec
#define TARGET_LITTLE_NAME "elfNN-ia64-little"
#define elf_backend_want_dynbss 0
#define elf_backend_copy_indirect_symbol elfNN_ia64_hash_copy_indirect
#define elf_backend_hide_symbol elfNN_ia64_hash_hide_symbol
+#define elf_backend_reloc_type_class elfNN_ia64_reloc_type_class
+
+#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"