/* IA-64 support for 64-bit ELF
- Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ 2009 Free Software Foundation, Inc.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of BFD, the Binary File Descriptor library.
/* The main hash table. */
struct elf_link_hash_table root;
- asection *got_sec; /* the linkage table section (or NULL) */
- asection *rel_got_sec; /* dynamic relocation section for same */
asection *fptr_sec; /* function descriptor table (or NULL) */
asection *rel_fptr_sec; /* dynamic relocation section for same */
- asection *plt_sec; /* the primary plt section (or NULL) */
asection *pltoff_sec; /* private descriptors for plt (or NULL) */
asection *rel_pltoff_sec; /* dynamic relocation section for same */
one pass. */
*again = FALSE;
+ if (link_info->relocatable)
+ (*link_info->callbacks->einfo)
+ (_("%P%F: --relax and -r may not be used together\n"));
+
/* Don't even try to relax for non-ELF outputs. */
if (!is_elf_hash_table (link_info->hash))
return FALSE;
if (r_type != R_IA64_PCREL21B)
continue;
- tsec = ia64_info->plt_sec;
+ tsec = ia64_info->root.splt;
toff = dyn_i->plt2_offset;
BFD_ASSERT (irel->r_addend == 0);
}
+ sec->output_offset
+ roff) & (bfd_vma) -4;
+ /* The .plt section is aligned at 32byte and the .text section
+ is aligned at 64byte. The .text section is right after the
+ .plt section. After the first relaxation pass, linker may
+ increase the gap between the .plt and .text sections up
+ to 32byte. We assume linker will always insert 32byte
+ between the .plt and .text sections after the the first
+ relaxation pass. */
+ if (tsec == ia64_info->root.splt)
+ offset = -0x1000000 + 32;
+ else
+ offset = -0x1000000;
+
/* If the branch is in range, no need to do anything. */
- if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000
+ if ((bfd_signed_vma) (symaddr - reladdr) >= offset
&& (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0)
{
/* If the 60-bit branch is in 21-bit range, optimize it. */
size_t size;
- if (tsec == ia64_info->plt_sec)
+ if (tsec == ia64_info->root.splt)
size = sizeof (plt_full_entry);
else
size = oor_branch_size;
goto error_return;
sec->size = amt;
- if (tsec == ia64_info->plt_sec)
+ if (tsec == ia64_info->root.splt)
{
memcpy (contents + trampoff, plt_full_entry, size);
elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data);
elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data);
elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data);
- ia64_info->got_sec->size = data.ofs;
+ ia64_info->root.sgot->size = data.ofs;
if (ia64_info->root.dynamic_sections_created
- && ia64_info->rel_got_sec != NULL)
+ && ia64_info->root.srelgot != NULL)
{
/* Resize .rela.got. */
- ia64_info->rel_got_sec->size = 0;
+ ia64_info->root.srelgot->size = 0;
if (link_info->shared
&& ia64_info->self_dtpmod_offset != (bfd_vma) -1)
- ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela);
+ ia64_info->root.srelgot->size += sizeof (ElfNN_External_Rela);
data.only_got = TRUE;
elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_dynrel_entries,
&data);
struct elfNN_ia64_local_hash_entry *entry
= (struct elfNN_ia64_local_hash_entry *) ptr;
- return (((entry->id & 0xff) << 24) | ((entry->id & 0xff00) << 8))
- ^ entry->r_sym ^ (entry->id >> 16);
+ return ELF_LOCAL_SYMBOL_HASH (entry->id, entry->r_sym);
}
/* Compare local hash entries. */
ia64_info = elfNN_ia64_hash_table (info);
- ia64_info->plt_sec = bfd_get_section_by_name (abfd, ".plt");
- ia64_info->got_sec = bfd_get_section_by_name (abfd, ".got");
-
{
- flagword flags = bfd_get_section_flags (abfd, ia64_info->got_sec);
- bfd_set_section_flags (abfd, ia64_info->got_sec, SEC_SMALL_DATA | flags);
+ flagword flags = bfd_get_section_flags (abfd, ia64_info->root.sgot);
+ bfd_set_section_flags (abfd, ia64_info->root.sgot,
+ SEC_SMALL_DATA | flags);
/* The .got section is always aligned at 8 bytes. */
- bfd_set_section_alignment (abfd, ia64_info->got_sec, 3);
+ bfd_set_section_alignment (abfd, ia64_info->root.sgot, 3);
}
if (!get_pltoff (abfd, info, ia64_info))
return FALSE;
ia64_info->rel_pltoff_sec = s;
- s = bfd_make_section_with_flags (abfd, ".rela.got",
- (SEC_ALLOC | SEC_LOAD
- | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY
- | SEC_LINKER_CREATED
- | SEC_READONLY));
- if (s == NULL
- || !bfd_set_section_alignment (abfd, s, LOG_SECTION_ALIGN))
- return FALSE;
- ia64_info->rel_got_sec = s;
-
return TRUE;
}
{
struct elfNN_ia64_local_hash_entry e, *ret;
asection *sec = abfd->sections;
- hashval_t h = (((sec->id & 0xff) << 24) | ((sec->id & 0xff00) << 8))
- ^ ELFNN_R_SYM (rel->r_info) ^ (sec->id >> 16);
+ hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id,
+ ELFNN_R_SYM (rel->r_info));
void **slot;
e.id = sec->id;
asection *got;
bfd *dynobj;
- got = ia64_info->got_sec;
+ got = ia64_info->root.sgot;
if (!got)
{
flagword flags;
if (!_bfd_elf_create_got_section (dynobj, info))
return 0;
- got = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (got);
- ia64_info->got_sec = got;
+ got = ia64_info->root.sgot;
/* The .got section is always aligned at 8 bytes. */
if (!bfd_set_section_alignment (abfd, got, 3))
|| !x->info->pie
|| dyn_i->h == NULL
|| dyn_i->h->root.type != bfd_link_hash_undefweak)
- ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela);
+ ia64_info->root.srelgot->size += sizeof (ElfNN_External_Rela);
}
if ((dynamic_symbol || shared) && dyn_i->want_tprel)
- ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela);
+ ia64_info->root.srelgot->size += sizeof (ElfNN_External_Rela);
if (dynamic_symbol && dyn_i->want_dtpmod)
- ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela);
+ ia64_info->root.srelgot->size += sizeof (ElfNN_External_Rela);
if (dynamic_symbol && dyn_i->want_dtprel)
- ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela);
+ ia64_info->root.srelgot->size += sizeof (ElfNN_External_Rela);
if (x->only_got)
return TRUE;
/* Allocate the GOT entries. */
- if (ia64_info->got_sec)
+ if (ia64_info->root.sgot)
{
data.ofs = 0;
elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data);
elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data);
elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data);
- ia64_info->got_sec->size = data.ofs;
+ ia64_info->root.sgot->size = data.ofs;
}
/* Allocate the FPTR entries. */
BFD_ASSERT (ia64_info->root.dynamic_sections_created);
- ia64_info->plt_sec->size = data.ofs;
+ ia64_info->root.splt->size = data.ofs;
/* If we've got a .plt, we need some extra memory for the dynamic
linker. We stuff these in .got.plt. */
required. */
if (info->shared && ia64_info->self_dtpmod_offset != (bfd_vma) -1)
- ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela);
+ ia64_info->root.srelgot->size += sizeof (ElfNN_External_Rela);
data.only_got = FALSE;
elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_dynrel_entries, &data);
}
strip = (sec->size == 0);
- if (sec == ia64_info->got_sec)
+ if (sec == ia64_info->root.sgot)
strip = FALSE;
- else if (sec == ia64_info->rel_got_sec)
+ else if (sec == ia64_info->root.srelgot)
{
if (strip)
- ia64_info->rel_got_sec = NULL;
+ ia64_info->root.srelgot = NULL;
else
/* We use the reloc_count field as a counter if we need to
copy relocs into the output file. */
copy relocs into the output file. */
sec->reloc_count = 0;
}
- else if (sec == ia64_info->plt_sec)
+ else if (sec == ia64_info->root.splt)
{
if (strip)
- ia64_info->plt_sec = NULL;
+ ia64_info->root.splt = NULL;
}
else if (sec == ia64_info->pltoff_sec)
{
bfd_vma got_offset;
ia64_info = elfNN_ia64_hash_table (info);
- got_sec = ia64_info->got_sec;
+ got_sec = ia64_info->root.sgot;
switch (dyn_r_type)
{
}
elfNN_ia64_install_dyn_reloc (abfd, NULL, got_sec,
- ia64_info->rel_got_sec,
+ ia64_info->root.srelgot,
got_offset, dyn_r_type,
dynindx, addend);
}
{
/* Pick a sensible value. */
- asection *got_sec = ia64_info->got_sec;
+ asection *got_sec = ia64_info->root.sgot;
/* Start with just the address of the .got. */
if (got_sec)
/* Should have caught this earlier. */
BFD_ASSERT (rel->r_addend == 0);
- value = (ia64_info->plt_sec->output_section->vma
- + ia64_info->plt_sec->output_offset
+ value = (ia64_info->root.splt->output_section->vma
+ + ia64_info->root.splt->output_offset
+ dyn_i->plt2_offset);
}
else
/* Initialize the minimal PLT entry. */
index = (dyn_i->plt_offset - PLT_HEADER_SIZE) / PLT_MIN_ENTRY_SIZE;
- plt_sec = ia64_info->plt_sec;
+ plt_sec = ia64_info->root.splt;
loc = plt_sec->contents + dyn_i->plt_offset;
memcpy (loc, plt_min_entry, PLT_MIN_ENTRY_SIZE);
}
/* Initialize the PLT0 entry. */
- if (ia64_info->plt_sec)
+ if (ia64_info->root.splt)
{
- bfd_byte *loc = ia64_info->plt_sec->contents;
+ bfd_byte *loc = ia64_info->root.splt->contents;
bfd_vma pltres;
memcpy (loc, plt_header, PLT_HEADER_SIZE);
}
}
+static bfd_boolean
+elfNN_vms_section_from_shdr (bfd *abfd,
+ Elf_Internal_Shdr *hdr,
+ const char *name,
+ int shindex)
+{
+ asection *newsect;
+
+ switch (hdr->sh_type)
+ {
+ case SHT_IA_64_VMS_TRACE:
+ case SHT_IA_64_VMS_DEBUG:
+ case SHT_IA_64_VMS_DEBUG_STR:
+ break;
+
+ default:
+ return elfNN_ia64_section_from_shdr (abfd, hdr, name, shindex);
+ }
+
+ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+ return FALSE;
+ newsect = hdr->bfd_section;
+
+ return TRUE;
+}
+
+static bfd_boolean
+elfNN_vms_object_p (bfd *abfd)
+{
+ Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
+ Elf_Internal_Phdr *i_phdr = elf_tdata (abfd)->phdr;
+ unsigned int i;
+ unsigned int num_text = 0;
+ unsigned int num_data = 0;
+ unsigned int num_rodata = 0;
+ char name[16];
+
+ if (!elfNN_ia64_object_p (abfd))
+ return FALSE;
+
+ for (i = 0; i < i_ehdrp->e_phnum; i++, i_phdr++)
+ {
+ /* Is there a section for this segment? */
+ bfd_vma base_vma = i_phdr->p_vaddr;
+ bfd_vma limit_vma = base_vma + i_phdr->p_filesz;
+
+ if (i_phdr->p_type != PT_LOAD)
+ continue;
+
+ again:
+ while (base_vma < limit_vma)
+ {
+ bfd_vma next_vma = limit_vma;
+ asection *nsec;
+ asection *sec;
+ flagword flags;
+ char *nname = NULL;
+
+ /* Find a section covering base_vma. */
+ for (sec = abfd->sections; sec != NULL; sec = sec->next)
+ {
+ if ((sec->flags & (SEC_ALLOC | SEC_LOAD)) == 0)
+ continue;
+ if (sec->vma <= base_vma && sec->vma + sec->size > base_vma)
+ {
+ base_vma = sec->vma + sec->size;
+ goto again;
+ }
+ if (sec->vma < next_vma && sec->vma + sec->size >= base_vma)
+ next_vma = sec->vma;
+ }
+
+ /* No section covering [base_vma; next_vma). Create a fake one. */
+ flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS;
+ if (i_phdr->p_flags & PF_X)
+ {
+ flags |= SEC_CODE;
+ if (num_text++ == 0)
+ nname = ".text";
+ else
+ sprintf (name, ".text$%u", num_text);
+ }
+ else if ((i_phdr->p_flags & (PF_R | PF_W)) == PF_R)
+ {
+ flags |= SEC_READONLY;
+ sprintf (name, ".rodata$%u", num_rodata++);
+ }
+ else
+ {
+ flags |= SEC_DATA;
+ sprintf (name, ".data$%u", num_data++);
+ }
+
+ /* Allocate name. */
+ if (nname == NULL)
+ {
+ size_t name_len = strlen (name) + 1;
+ nname = bfd_alloc (abfd, name_len);
+ if (nname == NULL)
+ return FALSE;
+ memcpy (nname, name, name_len);
+ }
+
+ /* Create and fill new section. */
+ nsec = bfd_make_section_anyway_with_flags (abfd, nname, flags);
+ if (nsec == NULL)
+ return FALSE;
+ nsec->vma = base_vma;
+ nsec->size = next_vma - base_vma;
+ nsec->filepos = i_phdr->p_offset + (base_vma - i_phdr->p_vaddr);
+
+ base_vma = next_vma;
+ }
+ }
+ return TRUE;
+}
+
+static void
+elfNN_vms_post_process_headers (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+ Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
+
+ i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_OPENVMS;
+ i_ehdrp->e_ident[EI_ABIVERSION] = 2;
+}
+
+static bfd_boolean
+elfNN_vms_section_processing (bfd *abfd ATTRIBUTE_UNUSED,
+ Elf_Internal_Shdr *hdr)
+{
+ if (hdr->bfd_section != NULL)
+ {
+ const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
+
+ if (strcmp (name, ".text") == 0)
+ hdr->sh_flags |= SHF_IA_64_VMS_SHARED;
+ else if ((strcmp (name, ".debug") == 0)
+ || (strcmp (name, ".debug_abbrev") == 0)
+ || (strcmp (name, ".debug_aranges") == 0)
+ || (strcmp (name, ".debug_frame") == 0)
+ || (strcmp (name, ".debug_info") == 0)
+ || (strcmp (name, ".debug_loc") == 0)
+ || (strcmp (name, ".debug_macinfo") == 0)
+ || (strcmp (name, ".debug_pubnames") == 0)
+ || (strcmp (name, ".debug_pubtypes") == 0))
+ hdr->sh_type = SHT_IA_64_VMS_DEBUG;
+ else if ((strcmp (name, ".debug_line") == 0)
+ || (strcmp (name, ".debug_ranges") == 0))
+ hdr->sh_type = SHT_IA_64_VMS_TRACE;
+ else if (strcmp (name, ".debug_str") == 0)
+ hdr->sh_type = SHT_IA_64_VMS_DEBUG_STR;
+ else if (strcmp (name, ".vms_display_name_info") == 0)
+ {
+ int idx, symcount;
+ asymbol **syms;
+ struct elf_obj_tdata *t = elf_tdata (abfd);
+ int buf[2];
+ int demangler_sym_idx = -1;
+
+ symcount = bfd_get_symcount (abfd);
+ syms = bfd_get_outsymbols (abfd);
+ for (idx = 0; idx < symcount; idx++)
+ {
+ asymbol *sym;
+ sym = syms[idx];
+ if ((sym->flags & (BSF_DEBUGGING | BSF_DYNAMIC))
+ && strchr (sym->name, '@')
+ && (strcmp (sym->section->name, BFD_ABS_SECTION_NAME) == 0))
+ {
+ demangler_sym_idx = sym->udata.i;
+ break;
+ }
+ }
+
+ hdr->sh_type = SHT_IA_64_VMS_DISPLAY_NAME_INFO;
+ hdr->sh_entsize = 4;
+ hdr->sh_addralign = 0;
+ hdr->sh_link = t->symtab_section;
+
+ /* Find symtab index of demangler routine and stuff it in
+ the second long word of section data. */
+
+ if (demangler_sym_idx > -1)
+ {
+ bfd_seek (abfd, hdr->sh_offset, SEEK_SET);
+ bfd_bread (buf, hdr->sh_size, abfd);
+ buf [1] = demangler_sym_idx;
+ bfd_seek (abfd, hdr->sh_offset, SEEK_SET);
+ bfd_bwrite (buf, hdr->sh_size, abfd);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/* The final processing done just before writing out a VMS IA-64 ELF
+ object file. */
+
+static void
+elfNN_vms_final_write_processing (bfd *abfd,
+ bfd_boolean linker ATTRIBUTE_UNUSED)
+{
+ Elf_Internal_Shdr *hdr;
+ asection *s;
+ int unwind_info_sect_idx = 0;
+
+ for (s = abfd->sections; s; s = s->next)
+ {
+ hdr = &elf_section_data (s)->this_hdr;
+
+ if (strcmp (bfd_get_section_name (abfd, hdr->bfd_section),
+ ".IA_64.unwind_info") == 0)
+ unwind_info_sect_idx = elf_section_data (s)->this_idx;
+
+ switch (hdr->sh_type)
+ {
+ case SHT_IA_64_UNWIND:
+ /* VMS requires sh_info to point to the unwind info section. */
+ hdr->sh_info = unwind_info_sect_idx;
+ break;
+ }
+ }
+
+ if (! elf_flags_init (abfd))
+ {
+ unsigned long flags = 0;
+
+ if (abfd->xvec->byteorder == BFD_ENDIAN_BIG)
+ flags |= EF_IA_64_BE;
+ if (bfd_get_mach (abfd) == bfd_mach_ia64_elf64)
+ flags |= EF_IA_64_ABI64;
+
+ elf_elfheader(abfd)->e_flags = flags;
+ elf_flags_init (abfd) = TRUE;
+ }
+}
+
+static bfd_boolean
+elfNN_vms_close_and_cleanup (bfd *abfd)
+{
+ if (bfd_get_format (abfd) == bfd_object)
+ {
+ long isize, irsize;
+
+ if (elf_shstrtab (abfd) != NULL)
+ _bfd_elf_strtab_free (elf_shstrtab (abfd));
+
+ /* Pad to 8 byte boundary for IPF/VMS. */
+ isize = bfd_get_size (abfd);
+ if ((irsize = isize/8*8) < isize)
+ {
+ int ishort = (irsize + 8) - isize;
+ bfd_seek (abfd, isize, SEEK_SET);
+ bfd_bwrite (bfd_zmalloc (ishort), ishort, abfd);
+ }
+ }
+
+ return _bfd_generic_close_and_cleanup (abfd);
+}
\f
#define TARGET_LITTLE_SYM bfd_elfNN_ia64_little_vec
#define TARGET_LITTLE_NAME "elfNN-ia64-little"
#include "elfNN-target.h"
+/* VMS-specific vectors. */
+
+#undef TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM bfd_elfNN_ia64_vms_vec
+#undef TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME "elfNN-ia64-vms"
+#undef TARGET_BIG_SYM
+#undef TARGET_BIG_NAME
+
+/* These are VMS specific functions. */
+
+#undef elf_backend_object_p
+#define elf_backend_object_p elfNN_vms_object_p
+
+#undef elf_backend_section_from_shdr
+#define elf_backend_section_from_shdr elfNN_vms_section_from_shdr
+
+#undef elf_backend_post_process_headers
+#define elf_backend_post_process_headers elfNN_vms_post_process_headers
+
+#undef elf_backend_section_processing
+#define elf_backend_section_processing elfNN_vms_section_processing
+
+#undef elf_backend_final_write_processing
+#define elf_backend_final_write_processing elfNN_vms_final_write_processing
+
+#undef bfd_elfNN_close_and_cleanup
+#define bfd_elfNN_close_and_cleanup elfNN_vms_close_and_cleanup
+
+#undef elf_backend_section_from_bfd_section
+
+#undef elf_backend_symbol_processing
+
#undef elf_backend_want_p_paddr_set_to_zero
+
+#undef ELF_MAXPAGESIZE
+#define ELF_MAXPAGESIZE 0x10000 /* 64KB */
+
+#undef elfNN_bed
+#define elfNN_bed elfNN_ia64_vms_bed
+
+#include "elfNN-target.h"