This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

powerpc64-linux finishing touches


This just about closes my TODO list on powerpc64-linux binutils
support.  Yay!

a) Makes the srec linker functional on powerpc64-linux.  Seven new
   howto->special_function functions added, and the one existing
   howto function revamped.  Tweakery to ppc64_elf_set_toc so we
   can find TOCstart for non-ELF linker.  Check added in
   ppc64_elf_func_desc_adjust so we don't crash when we don't have
   our normal hash table.
b) Fixes bugs in reloc descriptions.  Fixes brtaken/brntaken reloc code.
c) Optimizes creation of the blr for undefweak symbols (which also
   allows ld-srec tests to pass).
d) Moves some code to ppc64elf.em

bfd/ChangeLog
	* elf64-ppc.c (ppc64_elf_addr16_ha_reloc): Delete.
	(ppc64_elf_ha_reloc): New function.
	(ppc64_elf_brtaken_reloc): New function.
	(ppc64_elf_sectoff_reloc): New function.
	(ppc64_elf_sectoff_ha_reloc): New function.
	(ppc64_elf_toc_reloc): New function.
	(ppc64_elf_toc_ha_reloc): New function.
	(ppc64_elf_toc64_reloc): New function.
	(ppc64_elf_unhandled_reloc): New function.
	(ppc64_elf_howto_raw): Use the above.
	<R_PPC64_RELATIVE>: Mark pc_relative, pcrel_offset.
	<R_PPC64_SECTOFF>: Not pc_relative or pcrel_offset.  Fix dst_mask.
	<R_PPC64_SECTOFF_DS>: Likewise.
	(IS_ABSOLUTE_RELOC): Update.
	(struct ppc_link_hash_table): Add have_undefweak.
	(ppc64_elf_link_hash_table_create): Init.
	(func_desc_adjust): Set have_undefweak.
	(ppc64_elf_func_desc_adjust): Call func_desc_adjust earlier.  Only
	add the .sfpr blr when have_undefweak.
	(ppc64_elf_setup_section_lists): Check hash table flavour.
	(ppc64_elf_next_input_section): Move output_section->owner test to
	ppc64elf.em.
	(ppc64_elf_set_toc): Rename to ppc64_elf_toc, remove info param
	and relocatable test.  Return TOCstart and don't set elf_gp.
	(ppc64_elf_relocate_section): Correct BRTAKEN/BRNTAKEN branch
	offset calculation.  Add assert on weak sym branch tweaks.
	* elf64-ppc.h (ppc64_elf_set_toc): Delete.
	(ppc64_elf_toc): Declare.
	(ppc64_elf_next_input_section): Update.

ld/ChangeLog
	* emultempl/ppc64elf.em (gld${EMULATION_NAME}_after_allocation):
	Adjust for ppc64_elf_set_toc change.  #include libbfd.h.
	(build_section_lists): Do output_section tests here.

Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.34
diff -c -p -r1.34 elf64-ppc.c
*** bfd/elf64-ppc.c	1 May 2002 02:34:20 -0000	1.34
--- bfd/elf64-ppc.c	2 May 2002 08:57:18 -0000
*************** static reloc_howto_type *ppc64_elf_reloc
*** 39,45 ****
    PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
  static void ppc64_elf_info_to_howto
    PARAMS ((bfd *abfd, arelent *cache_ptr, Elf64_Internal_Rela *dst));
! static bfd_reloc_status_type ppc64_elf_addr16_ha_reloc
    PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
  static boolean ppc64_elf_set_private_flags
    PARAMS ((bfd *, flagword));
--- 39,59 ----
    PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
  static void ppc64_elf_info_to_howto
    PARAMS ((bfd *abfd, arelent *cache_ptr, Elf64_Internal_Rela *dst));
! static bfd_reloc_status_type ppc64_elf_ha_reloc
!   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
! static bfd_reloc_status_type ppc64_elf_brtaken_reloc
!   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
! static bfd_reloc_status_type ppc64_elf_sectoff_reloc
!   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
! static bfd_reloc_status_type ppc64_elf_sectoff_ha_reloc
!   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
! static bfd_reloc_status_type ppc64_elf_toc_reloc
!   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
! static bfd_reloc_status_type ppc64_elf_toc_ha_reloc
!   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
! static bfd_reloc_status_type ppc64_elf_toc64_reloc
!   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
! static bfd_reloc_status_type ppc64_elf_unhandled_reloc
    PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
  static boolean ppc64_elf_set_private_flags
    PARAMS ((bfd *, flagword));
*************** static reloc_howto_type ppc64_elf_howto_
*** 225,231 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_addr16_ha_reloc, /* special_function */
  	 "R_PPC64_ADDR16_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 239,245 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_ha_reloc,	/* special_function */
  	 "R_PPC64_ADDR16_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 258,264 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_ADDR14_BRTAKEN",/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 272,278 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 ppc64_elf_brtaken_reloc, /* special_function */
  	 "R_PPC64_ADDR14_BRTAKEN",/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 275,281 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_ADDR14_BRNTAKEN",/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 289,295 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 ppc64_elf_brtaken_reloc, /* special_function */
  	 "R_PPC64_ADDR14_BRNTAKEN",/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 322,328 ****
  	 true,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_REL14_BRTAKEN", /* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 336,342 ----
  	 true,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 ppc64_elf_brtaken_reloc, /* special_function */
  	 "R_PPC64_REL14_BRTAKEN", /* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 339,345 ****
  	 true,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_REL14_BRNTAKEN",/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 353,359 ----
  	 true,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 ppc64_elf_brtaken_reloc, /* special_function */
  	 "R_PPC64_REL14_BRNTAKEN",/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 355,361 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_GOT16",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 369,375 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_GOT16",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 371,377 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_GOT16_LO",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 385,391 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_GOT16_LO",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 387,393 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont,/* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_GOT16_HI",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 401,407 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont,/* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_GOT16_HI",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 403,409 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont,/* complain_on_overflow */
! 	 ppc64_elf_addr16_ha_reloc, /* special_function */
  	 "R_PPC64_GOT16_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 417,423 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont,/* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_GOT16_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 422,428 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	 /* special_function */
  	 "R_PPC64_COPY",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 436,442 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc,  /* special_function */
  	 "R_PPC64_COPY",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 438,444 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	 /* special_function */
  	 "R_PPC64_GLOB_DAT",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 452,458 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc,  /* special_function */
  	 "R_PPC64_GLOB_DAT",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 454,460 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_JMP_SLOT",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 468,474 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_JMP_SLOT",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 468,474 ****
  	 0,			/* rightshift */
  	 4,			/* size (0=byte, 1=short, 2=long, 4=64 bits) */
  	 64,			/* bitsize */
! 	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
  	 bfd_elf_generic_reloc,	/* special_function */
--- 482,488 ----
  	 0,			/* rightshift */
  	 4,			/* size (0=byte, 1=short, 2=long, 4=64 bits) */
  	 64,			/* bitsize */
! 	 true,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
  	 bfd_elf_generic_reloc,	/* special_function */
*************** static reloc_howto_type ppc64_elf_howto_
*** 476,482 ****
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
  	 0xffffffffffffffff,	/* dst_mask */
! 	 false),		/* pcrel_offset */
  
    /* Like R_PPC64_ADDR32, but may be unaligned.  */
    HOWTO (R_PPC64_UADDR32,	/* type */
--- 490,496 ----
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
  	 0xffffffffffffffff,	/* dst_mask */
! 	 true),			/* pcrel_offset */
  
    /* Like R_PPC64_ADDR32, but may be unaligned.  */
    HOWTO (R_PPC64_UADDR32,	/* type */
*************** static reloc_howto_type ppc64_elf_howto_
*** 532,538 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLT32",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 546,552 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLT32",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 564,570 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLT16_LO",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 578,584 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLT16_LO",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 580,586 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLT16_HI",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 594,600 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLT16_HI",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 596,602 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_addr16_ha_reloc, /* special_function */
  	 "R_PPC64_PLT16_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 610,616 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLT16_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 604,624 ****
  	 false),		/* pcrel_offset */
  
    /* 32-bit section relative relocation.  */
-   /* FIXME: Verify R_PPC64_SECTOFF.  Seems strange with size=2 and
-      dst_mask=0.  */
    HOWTO (R_PPC64_SECTOFF,	/* type */
  	 0,			/* rightshift */
  	 2,			/* size (0 = byte, 1 = short, 2 = long) */
  	 32,			/* bitsize */
! 	 true,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_SECTOFF",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
! 	 0,			/* dst_mask */
! 	 true),			/* pcrel_offset */
  
    /* 16-bit lower half section relative relocation.  */
    HOWTO (R_PPC64_SECTOFF_LO,	/* type */
--- 618,636 ----
  	 false),		/* pcrel_offset */
  
    /* 32-bit section relative relocation.  */
    HOWTO (R_PPC64_SECTOFF,	/* type */
  	 0,			/* rightshift */
  	 2,			/* size (0 = byte, 1 = short, 2 = long) */
  	 32,			/* bitsize */
! 	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 ppc64_elf_sectoff_reloc, /* special_function */
  	 "R_PPC64_SECTOFF",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
! 	 0xffffffff,		/* dst_mask */
! 	 false),		/* pcrel_offset */
  
    /* 16-bit lower half section relative relocation.  */
    HOWTO (R_PPC64_SECTOFF_LO,	/* type */
*************** static reloc_howto_type ppc64_elf_howto_
*** 628,634 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_SECTOFF_LO",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 640,646 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_sectoff_reloc, /* special_function */
  	 "R_PPC64_SECTOFF_LO",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 643,649 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_SECTOFF_HI",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 655,661 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_sectoff_reloc, /* special_function */
  	 "R_PPC64_SECTOFF_HI",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 658,664 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_addr16_ha_reloc, /* special_function */
  	 "R_PPC64_SECTOFF_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 670,676 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_sectoff_ha_reloc, /* special_function */
  	 "R_PPC64_SECTOFF_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 666,673 ****
  	 false),		/* pcrel_offset */
  
    /* Like R_PPC64_REL24 without touching the two least significant
!      bits.  */
!   /* FIXME: Verify R_PPC64_ADDR30.  */
    HOWTO (R_PPC64_ADDR30,	/* type */
  	 2,			/* rightshift */
  	 2,			/* size (0 = byte, 1 = short, 2 = long) */
--- 678,684 ----
  	 false),		/* pcrel_offset */
  
    /* Like R_PPC64_REL24 without touching the two least significant
!      bits.  Should have been named R_PPC64_REL30!  */
    HOWTO (R_PPC64_ADDR30,	/* type */
  	 2,			/* rightshift */
  	 2,			/* size (0 = byte, 1 = short, 2 = long) */
*************** static reloc_howto_type ppc64_elf_howto_
*** 723,729 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_addr16_ha_reloc, /* special_function */
  	 "R_PPC64_ADDR16_HIGHERA", /* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 734,740 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_ha_reloc,	/* special_function */
  	 "R_PPC64_ADDR16_HIGHERA", /* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 754,760 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_addr16_ha_reloc, /* special_function */
  	 "R_PPC64_ADDR16_HIGHESTA", /* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 765,771 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_ha_reloc,	/* special_function */
  	 "R_PPC64_ADDR16_HIGHESTA", /* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 799,805 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLT64",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 810,816 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLT64",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 816,822 ****
  	 true,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLTREL64",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 827,833 ----
  	 true,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLTREL64",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 833,839 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_TOC16",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 844,850 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 ppc64_elf_toc_reloc,	/* special_function */
  	 "R_PPC64_TOC16",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 850,856 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_TOC16_LO",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 861,867 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_toc_reloc,	/* special_function */
  	 "R_PPC64_TOC16_LO",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 867,873 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_TOC16_HI",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 878,884 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_toc_reloc,	/* special_function */
  	 "R_PPC64_TOC16_HI",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 886,892 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_addr16_ha_reloc, /* special_function */
  	 "R_PPC64_TOC16_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 897,903 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_toc_ha_reloc, /* special_function */
  	 "R_PPC64_TOC16_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 903,909 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_TOC",		/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 914,920 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 ppc64_elf_toc64_reloc,	/* special_function */
  	 "R_PPC64_TOC",		/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 926,932 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLTGOT16",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 937,943 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLTGOT16",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 942,948 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLTGOT16_LO",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 953,959 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLTGOT16_LO",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 958,964 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLTGOT16_HI",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 969,975 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLTGOT16_HI",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 976,982 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont,/* complain_on_overflow */
! 	 ppc64_elf_addr16_ha_reloc, /* special_function */
  	 "R_PPC64_PLTGOT16_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 987,993 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont,/* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLTGOT16_HA",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 1021,1027 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_GOT16_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 1032,1038 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_GOT16_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 1036,1042 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_GOT16_LO_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 1047,1053 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_GOT16_LO_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 1051,1057 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLT16_LO_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 1062,1068 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLT16_LO_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 1059,1079 ****
  	 false),		/* pcrel_offset */
  
    /* Like R_PPC64_SECTOFF, but for instructions with a DS field.  */
-   /* FIXME: Verify R_PPC64_SECTOFF.  Seems strange with size=2 and
-      dst_mask=0.  */
    HOWTO (R_PPC64_SECTOFF_DS,	/* type */
  	 0,			/* rightshift */
  	 2,			/* size (0 = byte, 1 = short, 2 = long) */
  	 32,			/* bitsize */
! 	 true,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_SECTOFF_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
! 	 0,			/* dst_mask */
! 	 true),			/* pcrel_offset */
  
    /* Like R_PPC64_SECTOFF_LO, but for instructions with a DS field.  */
    HOWTO (R_PPC64_SECTOFF_LO_DS, /* type */
--- 1070,1088 ----
  	 false),		/* pcrel_offset */
  
    /* Like R_PPC64_SECTOFF, but for instructions with a DS field.  */
    HOWTO (R_PPC64_SECTOFF_DS,	/* type */
  	 0,			/* rightshift */
  	 2,			/* size (0 = byte, 1 = short, 2 = long) */
  	 32,			/* bitsize */
! 	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_bitfield, /* complain_on_overflow */
! 	 ppc64_elf_sectoff_reloc, /* special_function */
  	 "R_PPC64_SECTOFF_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
! 	 0xfffffffc,		/* dst_mask */
! 	 false),		/* pcrel_offset */
  
    /* Like R_PPC64_SECTOFF_LO, but for instructions with a DS field.  */
    HOWTO (R_PPC64_SECTOFF_LO_DS, /* type */
*************** static reloc_howto_type ppc64_elf_howto_
*** 1083,1089 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_SECTOFF_LO_DS",/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 1092,1098 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_sectoff_reloc, /* special_function */
  	 "R_PPC64_SECTOFF_LO_DS",/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 1098,1104 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_TOC16_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 1107,1113 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 ppc64_elf_toc_reloc,	/* special_function */
  	 "R_PPC64_TOC16_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 1113,1119 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_TOC16_LO_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 1122,1128 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_toc_reloc,	/* special_function */
  	 "R_PPC64_TOC16_LO_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 1129,1135 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLTGOT16_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 1138,1144 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_signed, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLTGOT16_DS",	/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** static reloc_howto_type ppc64_elf_howto_
*** 1145,1151 ****
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 bfd_elf_generic_reloc,	/* special_function */
  	 "R_PPC64_PLTGOT16_LO_DS",/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
--- 1154,1160 ----
  	 false,			/* pc_relative */
  	 0,			/* bitpos */
  	 complain_overflow_dont, /* complain_on_overflow */
! 	 ppc64_elf_unhandled_reloc, /* special_function */
  	 "R_PPC64_PLTGOT16_LO_DS",/* name */
  	 false,			/* partial_inplace */
  	 0,			/* src_mask */
*************** ppc64_elf_info_to_howto (abfd, cache_ptr
*** 1369,1409 ****
  /* Handle the R_PPC_ADDR16_HA and similar relocs.  */
  
  static bfd_reloc_status_type
! ppc64_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section,
! 			   output_bfd, error_message)
!      bfd *abfd ATTRIBUTE_UNUSED;
       arelent *reloc_entry;
       asymbol *symbol;
!      PTR data ATTRIBUTE_UNUSED;
       asection *input_section;
       bfd *output_bfd;
!      char **error_message ATTRIBUTE_UNUSED;
  {
!   bfd_vma relocation;
  
    if (output_bfd != NULL)
      {
!       reloc_entry->address += input_section->output_offset;
!       return bfd_reloc_ok;
      }
  
!   if (reloc_entry->address > input_section->_cooked_size)
!     return bfd_reloc_outofrange;
  
!   if (bfd_is_com_section (symbol->section))
!     relocation = 0;
!   else
!     relocation = symbol->value;
  
!   relocation += symbol->section->output_section->vma;
!   relocation += symbol->section->output_offset;
!   relocation += reloc_entry->addend;
  
!   reloc_entry->addend += (relocation & 0x8000) << 1;
  
    return bfd_reloc_continue;
  }
  
  /* Function to set whether a module needs the -mrelocatable bit set.  */
  
  static boolean
--- 1378,1642 ----
  /* Handle the R_PPC_ADDR16_HA and similar relocs.  */
  
  static bfd_reloc_status_type
! ppc64_elf_ha_reloc (abfd, reloc_entry, symbol, data,
! 		    input_section, output_bfd, error_message)
!      bfd *abfd;
!      arelent *reloc_entry;
!      asymbol *symbol;
!      PTR data;
!      asection *input_section;
!      bfd *output_bfd;
!      char **error_message;
! {
!   /* If this is a relocatable link (output_bfd test tells us), just
!      call the generic function.  Any adjustment will be done at final
!      link time.  */
!   if (output_bfd != NULL)
!     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,	
! 				  input_section, output_bfd, error_message);
! 
!   /* Adjust the addend for sign extension of the low 16 bits.
!      We won't actually be using the low 16 bits, so trashing them
!      doesn't matter.  */
!   reloc_entry->addend += 0x8000;
!   return bfd_reloc_continue;
! }
! 
! static bfd_reloc_status_type
! ppc64_elf_brtaken_reloc (abfd, reloc_entry, symbol, data,
! 			 input_section, output_bfd, error_message)
!      bfd *abfd;
       arelent *reloc_entry;
       asymbol *symbol;
!      PTR data;
       asection *input_section;
       bfd *output_bfd;
!      char **error_message;
  {
!   long insn;
!   enum elf_ppc_reloc_type r_type;
!   bfd_size_type octets;
!   /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
!   boolean is_power4 = false;
  
+   /* If this is a relocatable link (output_bfd test tells us), just
+      call the generic function.  Any adjustment will be done at final
+      link time.  */
    if (output_bfd != NULL)
+     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,	
+ 				  input_section, output_bfd, error_message);
+ 
+   octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+   insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+   insn &= ~(0x01 << 21);
+   r_type = (enum elf_ppc_reloc_type) reloc_entry->howto->type;
+   if (r_type == R_PPC64_ADDR14_BRTAKEN
+       || r_type == R_PPC64_REL14_BRTAKEN)
+     insn |= 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */
+ 
+   if (is_power4)
+     {
+       /* Set 'a' bit.  This is 0b00010 in BO field for branch
+ 	 on CR(BI) insns (BO == 001at or 011at), and 0b01000
+ 	 for branch on CTR insns (BO == 1a00t or 1a01t).  */
+       if ((insn & (0x14 << 21)) == (0x04 << 21))
+ 	insn |= 0x02 << 21;
+       else if ((insn & (0x14 << 21)) == (0x10 << 21))
+ 	insn |= 0x08 << 21;
+       else
+ 	return bfd_reloc_continue;
+     }
+   else
      {
!       bfd_vma target = 0;
!       bfd_vma from;
! 
!       if (!bfd_is_com_section (symbol->section))
! 	target = symbol->value;
!       target += symbol->section->output_section->vma;
!       target += symbol->section->output_offset;
!       target += reloc_entry->addend;
! 
!       from = (reloc_entry->address
! 	      + input_section->output_offset
! 	      + input_section->output_section->vma);
! 
!       /* Invert 'y' bit if not the default.  */
!       if ((bfd_signed_vma) (target - from) < 0)
! 	insn ^= 0x01 << 21;
      }
+   bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + octets);
+   return bfd_reloc_continue;
+ }
  
! static bfd_reloc_status_type
! ppc64_elf_sectoff_reloc (abfd, reloc_entry, symbol, data,
! 			 input_section, output_bfd, error_message)
!      bfd *abfd;
!      arelent *reloc_entry;
!      asymbol *symbol;
!      PTR data;
!      asection *input_section;
!      bfd *output_bfd;
!      char **error_message;
! {
!   /* If this is a relocatable link (output_bfd test tells us), just
!      call the generic function.  Any adjustment will be done at final
!      link time.  */
!   if (output_bfd != NULL)
!     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,	
! 				  input_section, output_bfd, error_message);
  
!   /* Subtract the symbol section base address.  */
!   reloc_entry->addend -= symbol->section->output_section->vma;
!   return bfd_reloc_continue;
! }
  
! static bfd_reloc_status_type
! ppc64_elf_sectoff_ha_reloc (abfd, reloc_entry, symbol, data,
! 			    input_section, output_bfd, error_message)
!      bfd *abfd;
!      arelent *reloc_entry;
!      asymbol *symbol;
!      PTR data;
!      asection *input_section;
!      bfd *output_bfd;
!      char **error_message;
! {
!   /* If this is a relocatable link (output_bfd test tells us), just
!      call the generic function.  Any adjustment will be done at final
!      link time.  */
!   if (output_bfd != NULL)
!     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,	
! 				  input_section, output_bfd, error_message);
! 
!   /* Subtract the symbol section base address.  */
!   reloc_entry->addend -= symbol->section->output_section->vma;
! 
!   /* Adjust the addend for sign extension of the low 16 bits.  */
!   reloc_entry->addend += 0x8000;
!   return bfd_reloc_continue;
! }
! 
! static bfd_reloc_status_type
! ppc64_elf_toc_reloc (abfd, reloc_entry, symbol, data,
! 		     input_section, output_bfd, error_message)
!      bfd *abfd;
!      arelent *reloc_entry;
!      asymbol *symbol;
!      PTR data;
!      asection *input_section;
!      bfd *output_bfd;
!      char **error_message;
! {
!   bfd_vma TOCstart;
! 
!   /* If this is a relocatable link (output_bfd test tells us), just
!      call the generic function.  Any adjustment will be done at final
!      link time.  */
!   if (output_bfd != NULL)
!     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,	
! 				  input_section, output_bfd, error_message);
! 
!   TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
!   if (TOCstart == 0)
!     TOCstart = ppc64_elf_toc (input_section->output_section->owner);
! 
!   /* Subtract the TOC base address.  */
!   reloc_entry->addend -= TOCstart + TOC_BASE_OFF;
!   return bfd_reloc_continue;
! }
! 
! static bfd_reloc_status_type
! ppc64_elf_toc_ha_reloc (abfd, reloc_entry, symbol, data,
! 			input_section, output_bfd, error_message)
!      bfd *abfd;
!      arelent *reloc_entry;
!      asymbol *symbol;
!      PTR data;
!      asection *input_section;
!      bfd *output_bfd;
!      char **error_message;
! {
!   bfd_vma TOCstart;
! 
!   /* If this is a relocatable link (output_bfd test tells us), just
!      call the generic function.  Any adjustment will be done at final
!      link time.  */
!   if (output_bfd != NULL)
!     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,	
! 				  input_section, output_bfd, error_message);
! 
!   TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
!   if (TOCstart == 0)
!     TOCstart = ppc64_elf_toc (input_section->output_section->owner);
  
!   /* Subtract the TOC base address.  */
!   reloc_entry->addend -= TOCstart + TOC_BASE_OFF;
  
+   /* Adjust the addend for sign extension of the low 16 bits.  */
+   reloc_entry->addend += 0x8000;
    return bfd_reloc_continue;
  }
  
+ static bfd_reloc_status_type
+ ppc64_elf_toc64_reloc (abfd, reloc_entry, symbol, data,
+ 		       input_section, output_bfd, error_message)
+      bfd *abfd;
+      arelent *reloc_entry;
+      asymbol *symbol;
+      PTR data;
+      asection *input_section;
+      bfd *output_bfd;
+      char **error_message;
+ {
+   bfd_vma TOCstart;
+   bfd_size_type octets;
+ 
+   /* If this is a relocatable link (output_bfd test tells us), just
+      call the generic function.  Any adjustment will be done at final
+      link time.  */
+   if (output_bfd != NULL)
+     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,	
+ 				  input_section, output_bfd, error_message);
+ 
+   TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
+   if (TOCstart == 0)
+     TOCstart = ppc64_elf_toc (input_section->output_section->owner);
+ 
+   octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+   bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets);
+   return bfd_reloc_ok;
+ }
+ 
+ static bfd_reloc_status_type
+ ppc64_elf_unhandled_reloc (abfd, reloc_entry, symbol, data,
+ 			   input_section, output_bfd, error_message)
+      bfd *abfd;
+      arelent *reloc_entry;
+      asymbol *symbol;
+      PTR data;
+      asection *input_section;
+      bfd *output_bfd;
+      char **error_message;
+ {
+   /* If this is a relocatable link (output_bfd test tells us), just
+      call the generic function.  Any adjustment will be done at final
+      link time.  */
+   if (output_bfd != NULL)
+     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,	
+ 				  input_section, output_bfd, error_message);
+ 
+   if (error_message != NULL)
+     {
+       static char buf[60];
+       sprintf (buf, "generic linker can't handle %s",
+ 	       reloc_entry->howto->name);
+       *error_message = buf;
+     }
+   return bfd_reloc_dangerous;
+ }
+ 
  /* Function to set whether a module needs the -mrelocatable bit set.  */
  
  static boolean
*************** struct ppc_dyn_relocs
*** 1642,1653 ****
     selects between relative and absolute types.  */
  
  #define IS_ABSOLUTE_RELOC(RTYPE)		\
!   ((RTYPE) != R_PPC64_REL14			\
!    && (RTYPE) != R_PPC64_REL14_BRNTAKEN		\
!    && (RTYPE) != R_PPC64_REL14_BRTAKEN		\
!    && (RTYPE) != R_PPC64_REL24			\
!    && (RTYPE) != R_PPC64_REL32			\
!    && (RTYPE) != R_PPC64_REL64)
  
  /* Section name for stubs is the associated section name plus this
     string.  */
--- 1875,1883 ----
     selects between relative and absolute types.  */
  
  #define IS_ABSOLUTE_RELOC(RTYPE)		\
!   ((RTYPE) != R_PPC64_REL32			\
!    && (RTYPE) != R_PPC64_REL64			\
!    && (RTYPE) != R_PPC64_ADDR30)
  
  /* Section name for stubs is the associated section name plus this
     string.  */
*************** struct ppc_link_hash_table
*** 1795,1800 ****
--- 2025,2033 ----
       select suitable defaults for the stub group size.  */
    unsigned int has_14bit_branch;
  
+   /* Set if we detect a reference undefined weak symbol.  */
+   unsigned int have_undefweak;
+ 
    /* Incremented every time we size stubs.  */
    unsigned int stub_iteration;
  
*************** ppc64_elf_link_hash_table_create (abfd)
*** 2036,2041 ****
--- 2269,2275 ----
    htab->srelbrlt = NULL;
    htab->stub_error = 0;
    htab->has_14bit_branch = 0;
+   htab->have_undefweak = 0;
    htab->stub_iteration = 0;
    htab->sym_sec.abfd = NULL;
  
*************** func_desc_adjust (h, inf)
*** 2931,2936 ****
--- 3165,3174 ----
    if (!((struct ppc_link_hash_entry *) h)->is_func)
      return true;
  
+   if (h->root.type == bfd_link_hash_undefweak
+       && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
+     htab->have_undefweak = true;
+ 
    if (h->plt.refcount > 0
        && h->root.root.string[0] == '.'
        && h->root.root.string[1] != '\0')
*************** ppc64_elf_func_desc_adjust (obfd, info)
*** 3080,3090 ****
  	}
      }
  
    htab->sfpr->_raw_size = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
  			   + (MAX_SAVE_FPR + 2 - lowest_restf) * 4);
  
    if (htab->sfpr->_raw_size == 0)
!     htab->sfpr->_raw_size = 4;
  
    p = (bfd_byte *) bfd_alloc (htab->elf.dynobj, htab->sfpr->_raw_size);
    if (p == NULL)
--- 3318,3338 ----
  	}
      }
  
+   elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
+ 
    htab->sfpr->_raw_size = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
  			   + (MAX_SAVE_FPR + 2 - lowest_restf) * 4);
  
    if (htab->sfpr->_raw_size == 0)
!     {
!       if (!htab->have_undefweak)
! 	{
! 	  _bfd_strip_section_from_output (info, htab->sfpr);
! 	  return true;
! 	}
! 
!       htab->sfpr->_raw_size = 4;
!     }
  
    p = (bfd_byte *) bfd_alloc (htab->elf.dynobj, htab->sfpr->_raw_size);
    if (p == NULL)
*************** ppc64_elf_func_desc_adjust (obfd, info)
*** 3117,3123 ****
        bfd_put_32 (htab->elf.dynobj, BLR, p);
      }
  
-   elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
    return true;
  }
  
--- 3365,3370 ----
*************** ppc64_elf_setup_section_lists (output_bf
*** 4036,4042 ****
    bfd_size_type amt;
    struct ppc_link_hash_table *htab = ppc_hash_table (info);
  
!   if (htab->sbrlt == NULL)
      return 0;
  
    /* Count the number of input BFDs and find the top input section id.  */
--- 4283,4290 ----
    bfd_size_type amt;
    struct ppc_link_hash_table *htab = ppc_hash_table (info);
  
!   if (htab->elf.root.creator->flavour != bfd_target_elf_flavour
!       || htab->sbrlt == NULL)
      return 0;
  
    /* Count the number of input BFDs and find the top input section id.  */
*************** ppc64_elf_setup_section_lists (output_bf
*** 4102,4117 ****
     we may insert linker stubs.  */
  
  void
! ppc64_elf_next_input_section (output_bfd, info, isec)
!      bfd *output_bfd;
       struct bfd_link_info *info;
       asection *isec;
  {
    struct ppc_link_hash_table *htab = ppc_hash_table (info);
  
!   if (isec->output_section != NULL
!       && isec->output_section->owner == output_bfd
!       && isec->output_section->index <= htab->top_index)
      {
        asection **list = htab->input_list + isec->output_section->index;
        if (*list != bfd_abs_section_ptr)
--- 4350,4362 ----
     we may insert linker stubs.  */
  
  void
! ppc64_elf_next_input_section (info, isec)
       struct bfd_link_info *info;
       asection *isec;
  {
    struct ppc_link_hash_table *htab = ppc_hash_table (info);
  
!   if (isec->output_section->index <= htab->top_index)
      {
        asection **list = htab->input_list + isec->output_section->index;
        if (*list != bfd_abs_section_ptr)
*************** ppc64_elf_size_stubs (output_bfd, stub_b
*** 4600,4665 ****
  }
  
  /* Called after we have determined section placement.  If sections
!    move, we'll be called again.  Provide a value for TOCstart, and
!    store in the output bfd elf_gp.  */
  
! boolean
! ppc64_elf_set_toc (obfd, info)
       bfd *obfd;
-      struct bfd_link_info *info;
  {
!   if (!info->relocateable)
!     {
!       asection *s;
!       bfd_vma TOCstart;
  
!       /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
! 	 order.  The TOC starts where the first of these sections starts.  */
!       s = bfd_get_section_by_name (obfd, ".got");
!       if (s == NULL)
! 	s = bfd_get_section_by_name (obfd, ".toc");
        if (s == NULL)
! 	s = bfd_get_section_by_name (obfd, ".tocbss");
        if (s == NULL)
! 	s = bfd_get_section_by_name (obfd, ".plt");
        if (s == NULL)
! 	{
! 	  /* This may happen for
! 	     o  references to TOC base (SYM@toc / TOC[tc0]) without a
! 	     .toc directive
! 	     o  bad linker script
! 	     o --gc-sections and empty TOC sections
! 
! 	     FIXME: Warn user?  */
! 
! 	  /* Look for a likely section.  We probably won't even be
! 	     using TOCstart.  */
! 	  for (s = obfd->sections; s != NULL; s = s->next)
! 	    if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY))
! 		== (SEC_ALLOC | SEC_SMALL_DATA))
! 	      break;
! 	  if (s == NULL)
! 	    for (s = obfd->sections; s != NULL; s = s->next)
! 	      if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA))
! 		  == (SEC_ALLOC | SEC_SMALL_DATA))
! 		break;
! 	  if (s == NULL)
! 	    for (s = obfd->sections; s != NULL; s = s->next)
! 	      if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
! 		break;
! 	  if (s == NULL)
! 	    for (s = obfd->sections; s != NULL; s = s->next)
! 	      if ((s->flags & SEC_ALLOC) == SEC_ALLOC)
! 		break;
! 	}
  
!       TOCstart = 0;
!       if (s != NULL)
! 	TOCstart = s->output_section->vma + s->output_offset;
  
!       elf_gp (obfd) = TOCstart;
!     }
!   return true;
  }
  
  /* Build all the stubs associated with the current output file.
--- 4845,4904 ----
  }
  
  /* Called after we have determined section placement.  If sections
!    move, we'll be called again.  Provide a value for TOCstart.  */
  
! bfd_vma
! ppc64_elf_toc (obfd)
       bfd *obfd;
  {
!   asection *s;
!   bfd_vma TOCstart;
  
!   /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
!      order.  The TOC starts where the first of these sections starts.  */
!   s = bfd_get_section_by_name (obfd, ".got");
!   if (s == NULL)
!     s = bfd_get_section_by_name (obfd, ".toc");
!   if (s == NULL)
!     s = bfd_get_section_by_name (obfd, ".tocbss");
!   if (s == NULL)
!     s = bfd_get_section_by_name (obfd, ".plt");
!   if (s == NULL)
!     {
!       /* This may happen for
! 	 o  references to TOC base (SYM@toc / TOC[tc0]) without a
! 	 .toc directive
! 	 o  bad linker script
! 	 o --gc-sections and empty TOC sections
! 
! 	 FIXME: Warn user?  */
! 
!       /* Look for a likely section.  We probably won't even be
! 	 using TOCstart.  */
!       for (s = obfd->sections; s != NULL; s = s->next)
! 	if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY))
! 	    == (SEC_ALLOC | SEC_SMALL_DATA))
! 	  break;
        if (s == NULL)
! 	for (s = obfd->sections; s != NULL; s = s->next)
! 	  if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA))
! 	      == (SEC_ALLOC | SEC_SMALL_DATA))
! 	    break;
        if (s == NULL)
! 	for (s = obfd->sections; s != NULL; s = s->next)
! 	  if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
! 	    break;
        if (s == NULL)
! 	for (s = obfd->sections; s != NULL; s = s->next)
! 	  if ((s->flags & SEC_ALLOC) == SEC_ALLOC)
! 	    break;
!     }
  
!   TOCstart = 0;
!   if (s != NULL)
!     TOCstart = s->output_section->vma + s->output_offset;
  
!   return TOCstart;
  }
  
  /* Build all the stubs associated with the current output file.
*************** ppc64_elf_relocate_section (output_bfd, 
*** 4963,4970 ****
  	    }
  	  else
  	    {
  	      /* Invert 'y' bit if not the default.  */
! 	      if ((bfd_signed_vma) (relocation - offset) < 0)
  		insn ^= 0x01 << 21;
  	    }
  
--- 5202,5213 ----
  	    }
  	  else
  	    {
+ 	      from = (offset
+ 		      + input_section->output_offset
+ 		      + input_section->output_section->vma);
+ 
  	      /* Invert 'y' bit if not the default.  */
! 	      if ((bfd_signed_vma) (relocation + addend - from) < 0)
  		insn ^= 0x01 << 21;
  	    }
  
*************** ppc64_elf_relocate_section (output_bfd, 
*** 5025,5039 ****
  		 blr.  We can thus call a weak function without first
  		 checking whether the function is defined.  We have a
  		 blr at the end of .sfpr.  */
  	      relocation = (htab->sfpr->_raw_size - 4
  			    + htab->sfpr->output_offset
  			    + htab->sfpr->output_section->vma);
  	      from = (offset
  		      + input_section->output_offset
  		      + input_section->output_section->vma);
  	      /* But let's not be silly about it.  If the blr isn't in
  		 reach, just go to the next instruction.  */
! 	      if (relocation - from + (1 << 25) >= (1 << 26))
  		relocation = from + 4;
  	    }
  	  break;
--- 5268,5285 ----
  		 blr.  We can thus call a weak function without first
  		 checking whether the function is defined.  We have a
  		 blr at the end of .sfpr.  */
+ 	      BFD_ASSERT (htab->sfpr->_raw_size != 0);
  	      relocation = (htab->sfpr->_raw_size - 4
  			    + htab->sfpr->output_offset
  			    + htab->sfpr->output_section->vma);
  	      from = (offset
  		      + input_section->output_offset
  		      + input_section->output_section->vma);
+ 
  	      /* But let's not be silly about it.  If the blr isn't in
  		 reach, just go to the next instruction.  */
! 	      if (relocation - from + (1 << 25) >= (1 << 26)
! 		  || htab->sfpr->_raw_size == 0)
  		relocation = from + 4;
  	    }
  	  break;
Index: bfd/elf64-ppc.h
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.h,v
retrieving revision 1.2
diff -c -p -r1.2 elf64-ppc.h
*** bfd/elf64-ppc.h	1 May 2002 02:34:20 -0000	1.2
--- bfd/elf64-ppc.h	2 May 2002 08:57:18 -0000
*************** You should have received a copy of the G
*** 17,28 ****
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  
! boolean ppc64_elf_set_toc
!   PARAMS ((bfd *, struct bfd_link_info *));
  int ppc64_elf_setup_section_lists
    PARAMS ((bfd *, struct bfd_link_info *));
  void ppc64_elf_next_input_section
!   PARAMS ((bfd *, struct bfd_link_info *, asection *));
  boolean ppc64_elf_size_stubs
    PARAMS ((bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma,
  	   asection *(*) (const char *, asection *), void (*) (void)));
--- 17,28 ----
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  
! bfd_vma ppc64_elf_toc
!   PARAMS ((bfd *));
  int ppc64_elf_setup_section_lists
    PARAMS ((bfd *, struct bfd_link_info *));
  void ppc64_elf_next_input_section
!   PARAMS ((struct bfd_link_info *, asection *));
  boolean ppc64_elf_size_stubs
    PARAMS ((bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma,
  	   asection *(*) (const char *, asection *), void (*) (void)));
Index: ld/emultempl/ppc64elf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/ppc64elf.em,v
retrieving revision 1.5
diff -c -p -r1.5 ppc64elf.em
*** ld/emultempl/ppc64elf.em	1 May 2002 02:34:54 -0000	1.5
--- ld/emultempl/ppc64elf.em	2 May 2002 08:57:18 -0000
***************
*** 24,29 ****
--- 24,30 ----
  cat >>e${EMULATION_NAME}.c <<EOF
  
  #include "ldctor.h"
+ #include "libbfd.h"
  #include "elf64-ppc.h"
  
  /* Fake input file for stubs.  */
*************** ppc_layout_sections_again ()
*** 222,229 ****
  static void
  gld${EMULATION_NAME}_after_allocation ()
  {
!   if (!ppc64_elf_set_toc (output_bfd, &link_info))
!     einfo ("%X%P: can not set TOC base: %E\n");
  }
  
  
--- 223,230 ----
  static void
  gld${EMULATION_NAME}_after_allocation ()
  {
!   if (!link_info.relocateable)
!     _bfd_set_gp_value (output_bfd, ppc64_elf_toc (output_bfd));
  }
  
  
*************** build_section_lists (statement)
*** 232,240 ****
       lang_statement_union_type *statement;
  {
    if (statement->header.type == lang_input_section_enum
!       && !statement->input_section.ifile->just_syms_flag)
      {
!       ppc64_elf_next_input_section (output_bfd, &link_info,
  				    statement->input_section.section);
      }
  }
--- 233,243 ----
       lang_statement_union_type *statement;
  {
    if (statement->header.type == lang_input_section_enum
!       && !statement->input_section.ifile->just_syms_flag
!       && statement->input_section.section->output_section != NULL
!       && statement->input_section.section->output_section->owner == output_bfd)
      {
!       ppc64_elf_next_input_section (&link_info,
  				    statement->input_section.section);
      }
  }

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]