/* PowerPC-specific support for 32-bit ELF
- Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *));
static bfd_reloc_status_type ppc_elf_addr16_ha_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static boolean ppc_elf_object_p PARAMS ((bfd *));
static boolean ppc_elf_set_private_flags PARAMS ((bfd *, flagword));
-static boolean ppc_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *));
static boolean ppc_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
static int ppc_elf_additional_program_headers PARAMS ((bfd *));
static boolean ppc_elf_modify_segment_map PARAMS ((bfd *));
+static asection *ppc_elf_create_got
+ PARAMS ((bfd *, struct bfd_link_info *));
static boolean ppc_elf_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean ppc_elf_section_from_shdr PARAMS ((bfd *,
Elf32_Internal_Shdr *,
- char *));
+ const char *));
static boolean ppc_elf_fake_sections
PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
0xffff, /* dst_mask */
false), /* pcrel_offset */
- /* 32-bit section relative relocation. */
+ /* 16-bit section relative relocation. */
HOWTO (R_PPC_SECTOFF, /* type */
0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- true, /* pc_relative */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_SECTOFF", /* name */
false, /* partial_inplace */
0, /* src_mask */
- 0, /* dst_mask */
- true), /* pcrel_offset */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
/* 16-bit lower half section relative relocation. */
HOWTO (R_PPC_SECTOFF_LO, /* type */
case BFD_RELOC_HI16_PLTOFF: ppc_reloc = R_PPC_PLT16_HI; break;
case BFD_RELOC_HI16_S_PLTOFF: ppc_reloc = R_PPC_PLT16_HA; break;
case BFD_RELOC_GPREL16: ppc_reloc = R_PPC_SDAREL16; break;
- case BFD_RELOC_32_BASEREL: ppc_reloc = R_PPC_SECTOFF; break;
+ case BFD_RELOC_16_BASEREL: ppc_reloc = R_PPC_SECTOFF; break;
case BFD_RELOC_LO16_BASEREL: ppc_reloc = R_PPC_SECTOFF_LO; break;
case BFD_RELOC_HI16_BASEREL: ppc_reloc = R_PPC_SECTOFF_HI; break;
case BFD_RELOC_HI16_S_BASEREL: ppc_reloc = R_PPC_SECTOFF_HA; break;
return bfd_reloc_continue;
}
+/* Fix bad default arch selected for a 32 bit input bfd when the
+ default is 64 bit. */
+
+static boolean
+ppc_elf_object_p (abfd)
+ bfd *abfd;
+{
+ if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64)
+ {
+ Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
+
+ if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32)
+ {
+ /* Relies on arch after 64 bit default being 32 bit default. */
+ abfd->arch_info = abfd->arch_info->next;
+ BFD_ASSERT (abfd->arch_info->bits_per_word == 32);
+ }
+ }
+ return true;
+}
+
/* Function to set whether a module needs the -mrelocatable bit set. */
static boolean
return true;
}
-/* Copy backend specific data from one object module to another */
-static boolean
-ppc_elf_copy_private_bfd_data (ibfd, obfd)
- bfd *ibfd;
- bfd *obfd;
-{
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
- || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
- return true;
-
- BFD_ASSERT (!elf_flags_init (obfd)
- || elf_elfheader (obfd)->e_flags == elf_elfheader (ibfd)->e_flags);
-
- elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
- elf_flags_init (obfd) = true;
- return true;
-}
-
/* Merge backend specific data from an object file to the output
object file when linking */
static boolean
boolean error;
/* Check if we have the same endianess */
- if (_bfd_generic_verify_endian_match (ibfd, obfd) == false)
+ if (! _bfd_generic_verify_endian_match (ibfd, obfd))
return false;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
ppc_elf_section_from_shdr (abfd, hdr, name)
bfd *abfd;
Elf32_Internal_Shdr *hdr;
- char *name;
+ const char *name;
{
asection *newsect;
flagword flags;
return true;
}
\f
+/* The powerpc .got has a blrl instruction in it. Mark it executable. */
+
+static asection *
+ppc_elf_create_got (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ register asection *s;
+ flagword flags;
+
+ if (!_bfd_elf_create_got_section (abfd, info))
+ return NULL;
+
+ s = bfd_get_section_by_name (abfd, ".got");
+ if (s == NULL)
+ abort ();
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
+ if (!bfd_set_section_flags (abfd, s, flags))
+ return NULL;
+ return s;
+}
+
/* We have to create .dynsbss and .rela.sbss here so that they get mapped
to output sections (just like _bfd_elf_create_dynamic_sections has
to create .dynbss and .rela.bss). */
register asection *s;
flagword flags;
+ if (!ppc_elf_create_got (abfd, info))
+ return false;
+
if (!_bfd_elf_create_dynamic_sections (abfd, info))
return false;
|| ! bfd_set_section_alignment (abfd, s, 2))
return false;
}
- return true;
+
+ s = bfd_get_section_by_name (abfd, ".plt");
+ if (s == NULL)
+ abort ();
+
+ flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED;
+ return bfd_set_section_flags (abfd, s, flags);
}
/* Adjust a symbol defined by a dynamic object and referenced by a
return true;
}
+ else
+ 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 (dynobj == NULL)
elf_hash_table (info)->dynobj = dynobj = abfd;
- if (! _bfd_elf_create_got_section (dynobj, info))
+ sgot = ppc_elf_create_got (dynobj, info);
+ if (sgot == NULL)
return false;
- sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
}
}
{
if (dynobj == NULL)
elf_hash_table (info)->dynobj = dynobj = abfd;
- if (! _bfd_elf_create_got_section (dynobj, info))
+ sgot = ppc_elf_create_got (dynobj, info);
+ if (sgot == NULL)
return false;
- sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
}
if (srelgot == NULL
if (h != NULL)
{
- if (h->got.refcount == -1)
+ if (h->got.refcount == 0)
{
/* Make sure this symbol is output as a dynamic symbol. */
if (h->dynindx == -1)
sgot->_raw_size += 4;
/* Allocate relocation space. */
srelgot->_raw_size += sizeof (Elf32_External_Rela);
-
- h->got.refcount = 1;
}
- else
- h->got.refcount++;
+ h->got.refcount++;
}
else
{
size = symtab_hdr->sh_info;
size *= sizeof (bfd_signed_vma);
local_got_refcounts
- = (bfd_signed_vma *) bfd_alloc (abfd, size);
+ = (bfd_signed_vma *) bfd_zalloc (abfd, size);
if (local_got_refcounts == NULL)
return false;
elf_local_got_refcounts (abfd) = local_got_refcounts;
- memset (local_got_refcounts, -1, (size_t) size);
}
- if (local_got_refcounts[r_symndx] == -1)
+ if (local_got_refcounts[r_symndx] == 0)
{
sgot->_raw_size += 4;
dynamic linker can adjust this GOT entry. */
if (info->shared)
srelgot->_raw_size += sizeof (Elf32_External_Rela);
-
- local_got_refcounts[r_symndx] = 1;
}
- else
- local_got_refcounts[r_symndx]++;
+ local_got_refcounts[r_symndx]++;
}
break;
if (! bfd_elf32_link_record_dynamic_symbol (info, h))
return false;
}
- if (h->plt.refcount == -1)
- {
- h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
- h->plt.refcount = 1;
- }
- else
- h->plt.refcount++;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ h->plt.refcount++;
break;
/* The following relocations don't need to propagate the
}
else
{
- if (!(elf_bad_symtab (abfd)
- && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
- && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
- && sym->st_shndx != SHN_COMMON))
- {
- return bfd_section_from_elf_index (abfd, sym->st_shndx);
- }
+ return bfd_section_from_elf_index (abfd, sym->st_shndx);
}
return NULL;
{
if (sym->st_shndx == SHN_COMMON
&& !info->relocateable
- && sym->st_size <= elf_gp_size (abfd))
+ && sym->st_size <= elf_gp_size (abfd)
+ && info->hash->creator->flavour == bfd_target_elf_flavour)
{
/* Common symbols less than or equal to -G nn bytes are automatically
put into .sdata. */
(info->relocateable) ? " (relocatable)" : "");
#endif
+ if (info->relocateable)
+ return true;
+
if (!ppc_elf_howto_table[R_PPC_ADDR32])
/* Initialize howto table if needed. */
ppc_elf_howto_init ();
howto = ppc_elf_howto_table[(int) r_type];
r_symndx = ELF32_R_SYM (rel->r_info);
- if (info->relocateable)
- {
- /* This is a relocateable 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 ((unsigned) ELF_ST_TYPE (sym->st_info) == STT_SECTION)
- {
- sec = local_sections[r_symndx];
- addend = rel->r_addend += sec->output_offset + sym->st_value;
- }
- }
-
-#ifdef DEBUG
- fprintf (stderr, "\ttype = %s (%d), symbol index = %ld, offset = %ld, addend = %ld\n",
- howto->name,
- (int) r_type,
- r_symndx,
- (long) offset,
- (long) addend);
-#endif
- continue;
- }
-
- /* This is a final link. */
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
sym_name = "<local symbol>";
- relocation = (sec->output_section->vma
- + sec->output_offset
- + sym->st_value);
+ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+ addend = rel->r_addend;
/* Relocs to local symbols are always resolved. */
will_become_local = 1;
}
ret = false;
continue;
+ case (int) R_PPC_NONE:
+ continue;
+
/* Relocations that need no special processing. */
case (int) R_PPC_LOCAL24PC:
/* It makes no sense to point a local relocation
/* Relocations that always need to be propagated if this is a shared
object. */
- case (int) R_PPC_NONE:
case (int) R_PPC_ADDR32:
case (int) R_PPC_ADDR24:
case (int) R_PPC_ADDR16:
case (int) R_PPC_ADDR14:
case (int) R_PPC_UADDR32:
case (int) R_PPC_UADDR16:
- if (info->shared)
+ if (info->shared && r_symndx != 0)
{
Elf_Internal_Rela outrel;
- boolean skip;
+ int skip;
#ifdef DEBUG
fprintf (stderr, "ppc_elf_relocate_section need to create relocation for %s\n",
BFD_ASSERT (sreloc != NULL);
}
- 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, &elf_hash_table (info)->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;
- }
+ skip = 0;
+ outrel.r_offset =
+ _bfd_elf_section_offset (output_bfd, info, input_section,
+ rel->r_offset);
+ if (outrel.r_offset == (bfd_vma) -1
+ || outrel.r_offset == (bfd_vma) -2)
+ skip = (int) outrel.r_offset;
outrel.r_offset += (input_section->output_section->vma
+ input_section->output_offset);
/* This reloc will be computed at runtime, so there's no
need to do anything now, unless this is a RELATIVE
reloc in an unallocated section. */
- if (skip
+ if (skip != -1
|| (input_section->flags & SEC_ALLOC) != 0
|| ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE)
continue;
#define elf_backend_plt_not_loaded 1
#define elf_backend_got_symbol_offset 4
#define elf_backend_can_gc_sections 1
+#define elf_backend_can_refcount 1
#define elf_backend_got_header_size 12
#define elf_backend_plt_header_size PLT_INITIAL_ENTRY_SIZE
+#define elf_backend_rela_normal 1
-#define bfd_elf32_bfd_copy_private_bfd_data ppc_elf_copy_private_bfd_data
#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data
#define bfd_elf32_bfd_relax_section ppc_elf_relax_section
#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup
#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags
#define bfd_elf32_bfd_final_link _bfd_elf32_gc_common_final_link
+#define elf_backend_object_p ppc_elf_object_p
#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook
#define elf_backend_gc_sweep_hook ppc_elf_gc_sweep_hook
#define elf_backend_section_from_shdr ppc_elf_section_from_shdr