public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 2/2] xcoff: implement linker relaxation
@ 2022-03-17 15:01 CHIGOT, CLEMENT
  2022-04-13 16:32 ` Nick Clifton
  0 siblings, 1 reply; 8+ messages in thread
From: CHIGOT, CLEMENT @ 2022-03-17 15:01 UTC (permalink / raw)
  To: binutils; +Cc: Kavana N Bhat, Ayappan P2, pro

[-- Attachment #1: Type: text/plain, Size: 3706 bytes --]

This patch enables a first part of the linker relaxation in
order to fix unreachable branches in large binaries.
It has been tested by compiling gcc. However, the exact
maximum branch offset (1<<25) could not be tested as other
problems are appearing. However, the generation of stubs
when considering that the maximum offset is (1<<24) is
working fine and able to fully compile gcc. This is simply
generating more stubs than actually needed.

Note that as I'll stop working for AIX at this end of this
month. Thus, I hope we'll have the time to merge it before.
Moreover, Kavana and Ayappan will retrieve my work and 
knowledge on Binutils for AIX. Thus, they will be able to submit
patches if anything goes wrong after the merge. I'm also adding
my personal mail in order to answer questions but I won't have
access to AIX anymore. 


bfd/ChangeLog:

	* coff-rs6000.c (xcoff_reloc_type_noop): Add info argument.
	(xcoff_reloc_type_fail): Likewise.
	(xcoff_reloc_type_pos): Likewise.
	(xcoff_reloc_type_neg): Likewise.
	(xcoff_reloc_type_rel): Likewise.
	(xcoff_reloc_type_toc): Likewise.
	(xcoff_reloc_type_ba): Likewise.
	(xcoff_reloc_type_crel): Likewise.
	(xcoff_reloc_type_tls): Likewise.
	(xcoff_reloc_type_br): Add stub handler.
	(xcoff_ppc_relocate_section): Add info to
	xcoff_calculate_relocation.
	(xcoff_stub_indirect_call_code): New constant.
	(xcoff_stub_shared_call_code): Likewise.
	(bfd_xcoff_backend_data): Add stub code fields.
	(bfd_pmac_xcoff_backend_data): Likewise.
	* coff64-rs6000.c (xcoff64_reloc_type_br): Add stub handler.
	(xcoff64_ppc_relocate_section): Add info to
	xcoff64_calculate_relocation.
	(xcoff64_stub_indirect_call_code): New constant.
	(xcoff64_stub_shared_call_code): Likewise.
	(bfd_xcoff_backend_data): Add stub code fields.
	(bfd_xcoff_aix5_backend_data): Likewise.
	* libxcoff.h (struct xcoff_backend_data_rec): Add stub fields.
	(bfd_xcoff_stub_indirect_call_code): New define.
	(bfd_xcoff_stub_indirect_call_size): New define.
	(bfd_xcoff_stub_shared_call_code): New define.
	(bfd_xcoff_stub_shared_call_size): New define.
	(xcoff_reloc_function): Add info argument.
	(enum xcoff_stub_type): New enum.
	(struct xcoff_stub_hash_entry): New structure.
	* xcofflink.c (struct xcoff_link_hash_table): Add stub hash
	table and params fields.
	(xcoff_stub_hash_entry): New define.
	(xcoff_stub_hash_lookup): New define.
	(stub_hash_newfunc): New function.
	(_bfd_xcoff_bfd_link_hash_table_free): Free the new stub hash
	table.
	(_bfd_xcoff_bfd_link_hash_table_create): Create the new stub
	hash table.
	(xcoff_link_add_symbols): Save rawsize for XTY_SD.
	(bfd_xcoff_link_init): New function.
	(xcoff_stub_csect_name): New function.
	(xcoff_stub_get_csect_in_range): New function.
	(xcoff_stub_name): New function.
	(bfd_xcoff_get_stub_entry): New function.
	(bfd_xcoff_type_of_stub): New function.
	(xcoff_add_stub): New function.
	(xcoff_build_one_stub): New function.
	(bfd_xcoff_size_stubs): New function.
	(bfd_xcoff_build_stubs): New function.
	(xcoff_stub_create_relocations): New function.
	(xcoff_link_input_bfd): Adapt relocations to stub.
	(xcoff_write_global_symbol): Adapt to new TOC entries generated
	for stubs.
	(_bfd_xcoff_bfd_final_link): Handle stub file.
	* xcofflink.h (struct bfd_xcoff_link_params): New structure.

ld/ChangeLog:

	* emultempl/aix.em (params): New variable.
	(stub_file): New variable.
	(xcoff_add_stub_section): New function.
	(xcoff_layout_sections_again): New function
	(hook_in_stub): New function.
	(_after_allocation): Add stub creation.
	(_create_output_section_statements): Allocate stub file and
	pass params to backend.




[-- Attachment #2: 0002-xcoff-implement-linker-relaxation.patch --]
[-- Type: application/octet-stream, Size: 56995 bytes --]

From 77bcbf685ab4e6d08f72f586f52552d8b0570311 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= <clement.chigot@atos.net>
Date: Thu, 17 Mar 2022 10:24:55 +0100
Subject: [PATCH 2/2] xcoff: implement linker relaxation

This patch enables a first part of the linker relaxation in
order to fix unreachable branches in large binaries.
It has been tested by compiling gcc. However, the exact
maximum branch offset (1<<25) could not be tested as other
problems are appearing. However, the generation of stubs
when considering that the maximum offset is (1<<24) is
working fine and able to fully compile gcc. This is simply
generating more stubs than actually needed.

bfd/ChangeLog:

	* coff-rs6000.c (xcoff_reloc_type_noop): Add info argument.
	(xcoff_reloc_type_fail): Likewise.
	(xcoff_reloc_type_pos): Likewise.
	(xcoff_reloc_type_neg): Likewise.
	(xcoff_reloc_type_rel): Likewise.
	(xcoff_reloc_type_toc): Likewise.
	(xcoff_reloc_type_ba): Likewise.
	(xcoff_reloc_type_crel): Likewise.
	(xcoff_reloc_type_tls): Likewise.
	(xcoff_reloc_type_br): Add stub handler.
	(xcoff_ppc_relocate_section): Add info to
	xcoff_calculate_relocation.
	(xcoff_stub_indirect_call_code): New constant.
	(xcoff_stub_shared_call_code): Likewise.
	(bfd_xcoff_backend_data): Add stub code fields.
	(bfd_pmac_xcoff_backend_data): Likewise.
	* coff64-rs6000.c (xcoff64_reloc_type_br): Add stub handler.
	(xcoff64_ppc_relocate_section): Add info to
	xcoff64_calculate_relocation.
	(xcoff64_stub_indirect_call_code): New constant.
	(xcoff64_stub_shared_call_code): Likewise.
	(bfd_xcoff_backend_data): Add stub code fields.
	(bfd_xcoff_aix5_backend_data): Likewise.
	* libxcoff.h (struct xcoff_backend_data_rec): Add stub fields.
	(bfd_xcoff_stub_indirect_call_code): New define.
	(bfd_xcoff_stub_indirect_call_size): New define.
	(bfd_xcoff_stub_shared_call_code): New define.
	(bfd_xcoff_stub_shared_call_size): New define.
	(xcoff_reloc_function): Add info argument.
	(enum xcoff_stub_type): New enum.
	(struct xcoff_stub_hash_entry): New structure.
	* xcofflink.c (struct xcoff_link_hash_table): Add stub hash
	table and params fields.
	(xcoff_stub_hash_entry): New define.
	(xcoff_stub_hash_lookup): New define.
	(stub_hash_newfunc): New function.
	(_bfd_xcoff_bfd_link_hash_table_free): Free the new stub hash
	table.
	(_bfd_xcoff_bfd_link_hash_table_create): Create the new stub
	hash table.
	(xcoff_link_add_symbols): Save rawsize for XTY_SD.
	(bfd_xcoff_link_init): New function.
	(xcoff_stub_csect_name): New function.
	(xcoff_stub_get_csect_in_range): New function.
	(xcoff_stub_name): New function.
	(bfd_xcoff_get_stub_entry): New function.
	(bfd_xcoff_type_of_stub): New function.
	(xcoff_add_stub): New function.
	(xcoff_build_one_stub): New function.
	(bfd_xcoff_size_stubs): New function.
	(bfd_xcoff_build_stubs): New function.
	(xcoff_stub_create_relocations): New function.
	(xcoff_link_input_bfd): Adapt relocations to stub.
	(xcoff_write_global_symbol): Adapt to new TOC entries generated
	for stubs.
	(_bfd_xcoff_bfd_final_link): Handle stub file.
	* xcofflink.h (struct bfd_xcoff_link_params): New structure.

ld/ChangeLog:

	* emultempl/aix.em (params): New variable.
	(stub_file): New variable.
	(xcoff_add_stub_section): New function.
	(xcoff_layout_sections_again): New function
	(hook_in_stub): New function.
	(_after_allocation): Add stub creation.
	(_create_output_section_statements): Allocate stub file and
	pass params to backend.
---
 bfd/coff-rs6000.c   |  99 ++++-
 bfd/coff64-rs6000.c |  66 +++-
 bfd/libxcoff.h      |  63 ++-
 bfd/xcofflink.c     | 940 +++++++++++++++++++++++++++++++++++++++++++-
 bfd/xcofflink.h     |  17 +
 ld/emultempl/aix.em | 190 ++++++++-
 6 files changed, 1342 insertions(+), 33 deletions(-)

diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index 8656dfdb4c4..8819187ab42 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -2937,7 +2937,8 @@ xcoff_reloc_type_noop (bfd *input_bfd ATTRIBUTE_UNUSED,
 		       bfd_vma val ATTRIBUTE_UNUSED,
 		       bfd_vma addend ATTRIBUTE_UNUSED,
 		       bfd_vma *relocation ATTRIBUTE_UNUSED,
-		       bfd_byte *contents ATTRIBUTE_UNUSED)
+		       bfd_byte *contents ATTRIBUTE_UNUSED,
+		       struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   return true;
 }
@@ -2952,7 +2953,8 @@ xcoff_reloc_type_fail (bfd *input_bfd,
 		       bfd_vma val ATTRIBUTE_UNUSED,
 		       bfd_vma addend ATTRIBUTE_UNUSED,
 		       bfd_vma *relocation ATTRIBUTE_UNUSED,
-		       bfd_byte *contents ATTRIBUTE_UNUSED)
+		       bfd_byte *contents ATTRIBUTE_UNUSED,
+		       struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   _bfd_error_handler
     /* xgettext: c-format */
@@ -2972,7 +2974,8 @@ xcoff_reloc_type_pos (bfd *input_bfd ATTRIBUTE_UNUSED,
 		      bfd_vma val,
 		      bfd_vma addend,
 		      bfd_vma *relocation,
-		      bfd_byte *contents ATTRIBUTE_UNUSED)
+		      bfd_byte *contents ATTRIBUTE_UNUSED,
+		      struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   *relocation = val + addend;
   return true;
@@ -2988,7 +2991,8 @@ xcoff_reloc_type_neg (bfd *input_bfd ATTRIBUTE_UNUSED,
 		      bfd_vma val,
 		      bfd_vma addend,
 		      bfd_vma *relocation,
-		      bfd_byte *contents ATTRIBUTE_UNUSED)
+		      bfd_byte *contents ATTRIBUTE_UNUSED,
+		      struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   *relocation = - val - addend;
   return true;
@@ -3004,7 +3008,8 @@ xcoff_reloc_type_rel (bfd *input_bfd ATTRIBUTE_UNUSED,
 		      bfd_vma val,
 		      bfd_vma addend,
 		      bfd_vma *relocation,
-		      bfd_byte *contents ATTRIBUTE_UNUSED)
+		      bfd_byte *contents ATTRIBUTE_UNUSED,
+		      struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   howto->pc_relative = true;
 
@@ -3027,7 +3032,8 @@ xcoff_reloc_type_toc (bfd *input_bfd,
 		      bfd_vma val,
 		      bfd_vma addend ATTRIBUTE_UNUSED,
 		      bfd_vma *relocation,
-		      bfd_byte *contents ATTRIBUTE_UNUSED)
+		      bfd_byte *contents ATTRIBUTE_UNUSED,
+		      struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   struct xcoff_link_hash_entry *h;
 
@@ -3076,7 +3082,8 @@ xcoff_reloc_type_ba (bfd *input_bfd ATTRIBUTE_UNUSED,
 		     bfd_vma val,
 		     bfd_vma addend,
 		     bfd_vma *relocation,
-		     bfd_byte *contents ATTRIBUTE_UNUSED)
+		     bfd_byte *contents ATTRIBUTE_UNUSED,
+		     struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   howto->src_mask &= ~3;
   howto->dst_mask = howto->src_mask;
@@ -3096,10 +3103,13 @@ xcoff_reloc_type_br (bfd *input_bfd,
 		     bfd_vma val,
 		     bfd_vma addend,
 		     bfd_vma *relocation,
-		     bfd_byte *contents)
+		     bfd_byte *contents,
+		     struct bfd_link_info *info)
 {
   struct xcoff_link_hash_entry *h;
   bfd_vma section_offset;
+  struct xcoff_stub_hash_entry *stub_entry = NULL;
+  enum xcoff_stub_type stub_type;
 
   if (0 > rel->r_symndx)
     return false;
@@ -3153,6 +3163,27 @@ xcoff_reloc_type_br (bfd *input_bfd,
       howto->complain_on_overflow = complain_overflow_dont;
     }
 
+  /* Check if a stub is needed.  */
+  stub_type = bfd_xcoff_type_of_stub (input_section, rel, val, h);
+  if (stub_type != xcoff_stub_none)
+    {
+      asection *stub_csect;
+
+      stub_entry = bfd_xcoff_get_stub_entry (input_section, h, info);
+      if (stub_entry == NULL)
+	{
+	  _bfd_error_handler (_("Unable to find the stub entry targeting %s"),
+			      h->root.root.string);
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
+
+      stub_csect = stub_entry->hcsect->root.u.def.section;
+      val = (stub_entry->stub_offset
+	     + stub_csect->output_section->vma
+	     + stub_csect->output_offset);
+    }
+
   /* The original PC-relative relocation is biased by -r_vaddr, so adding
      the value below will give the absolute target address.  */
   *relocation = val + addend + rel->r_vaddr;
@@ -3202,7 +3233,8 @@ xcoff_reloc_type_crel (bfd *input_bfd ATTRIBUTE_UNUSED,
 		       bfd_vma val ATTRIBUTE_UNUSED,
 		       bfd_vma addend,
 		       bfd_vma *relocation,
-		       bfd_byte *contents ATTRIBUTE_UNUSED)
+		       bfd_byte *contents ATTRIBUTE_UNUSED,
+		       struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   howto->pc_relative = true;
   howto->src_mask &= ~3;
@@ -3227,7 +3259,8 @@ xcoff_reloc_type_tls (bfd *input_bfd ATTRIBUTE_UNUSED,
 		      bfd_vma val,
 		      bfd_vma addend,
 		      bfd_vma *relocation,
-		      bfd_byte *contents ATTRIBUTE_UNUSED)
+		      bfd_byte *contents ATTRIBUTE_UNUSED,
+		      struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   struct xcoff_link_hash_entry *h;
 
@@ -3763,7 +3796,7 @@ xcoff_ppc_relocate_section (bfd *output_bfd,
       if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
 	  || !((*xcoff_calculate_relocation[rel->r_type])
 	       (input_bfd, input_section, output_bfd, rel, sym, &howto, val,
-		addend, &relocation, contents)))
+		addend, &relocation, contents, info)))
 	return false;
 
       /* address */
@@ -4281,6 +4314,34 @@ HOWTO (0,			/* type */
        0xffffffff,		/* dst_mask */
        false);			/* pcrel_offset */
 
+/* Indirect call stub
+   The first word of the code must be modified by filling in
+   the correct TOC offset.  */
+
+static const unsigned long xcoff_stub_indirect_call_code[4] =
+  {
+    0x81820000,	/* lwz r12,0(r2) */
+    0x800c0000,	/* lwz r0,0(r12) */
+    0x7c0903a6,	/* mtctr r0 */
+    0x4e800420,	/* bctr */
+  };
+
+/*  Shared call stub
+    The first word of the code must be modified by filling in
+    the correct TOC offset.
+    This is exactly as the glink code but without the traceback,
+    as it won't be an independent function.  */
+
+static const unsigned long xcoff_stub_shared_call_code[6] =
+  {
+    0x81820000,	/* lwz r12,0(r2) */
+    0x90410014,	/* stw r2,20(r1) */
+    0x800c0000,	/* lwz r0,0(r12) */
+    0x804c0004,	/* lwz r2,4(r12) */
+    0x7c0903a6,	/* mtctr r0 */
+    0x4e800420,	/* bctr */
+  };
+
 /*  glink
 
    The first word of global linkage code must be modified by filling in
@@ -4497,6 +4558,14 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data =
     /* rtinit */
     64,				/* _xcoff_rtinit_size */
     xcoff_generate_rtinit,
+
+    /* Stub indirect call.  */
+    &xcoff_stub_indirect_call_code[0],
+    16,				/* _xcoff_stub_indirect_call_size */
+
+    /* Stub shared call.  */
+    &xcoff_stub_shared_call_code[0],
+    24,				/* _xcoff_stub_shared_call_size */
   };
 
 /* The transfer vector that leads the outside world to all of the above.  */
@@ -4679,6 +4748,14 @@ static const struct xcoff_backend_data_rec bfd_pmac_xcoff_backend_data =
     /* rtinit */
     0,				/* _xcoff_rtinit_size */
     xcoff_generate_rtinit,
+
+    /* Stub indirect call.  */
+    &xcoff_stub_indirect_call_code[0],
+    16,				/* _xcoff_stub_indirect_call_size */
+
+    /* Stub shared call.  */
+    &xcoff_stub_shared_call_code[0],
+    24,				/* _xcoff_stub_shared_call_size */
   };
 
 /* The transfer vector that leads the outside world to all of the above.  */
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index 95abbb9e957..2f8077ae6a2 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -778,10 +778,13 @@ xcoff64_reloc_type_br (bfd *input_bfd,
 		       bfd_vma val,
 		       bfd_vma addend,
 		       bfd_vma *relocation,
-		       bfd_byte *contents)
+		       bfd_byte *contents,
+		       struct bfd_link_info *info)
 {
   struct xcoff_link_hash_entry *h;
   bfd_vma section_offset;
+  struct xcoff_stub_hash_entry *stub_entry = NULL;
+  enum xcoff_stub_type stub_type;
 
   if (0 > rel->r_symndx)
     return false;
@@ -833,6 +836,27 @@ xcoff64_reloc_type_br (bfd *input_bfd,
       howto->complain_on_overflow = complain_overflow_dont;
     }
 
+  /* Check if a stub is needed.  */
+  stub_type = bfd_xcoff_type_of_stub (input_section, rel, val, h);
+  if (stub_type != xcoff_stub_none)
+    {
+      asection *stub_csect;
+
+      stub_entry = bfd_xcoff_get_stub_entry (input_section, h, info);
+      if (stub_entry == NULL)
+	{
+	  _bfd_error_handler (_("Unable to find the stub entry targeting %s"),
+			      h->root.root.string);
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
+
+      stub_csect = stub_entry->hcsect->root.u.def.section;
+      val = (stub_entry->stub_offset
+	     + stub_csect->output_section->vma
+	     + stub_csect->output_offset);
+    }
+
   /* The original PC-relative relocation is biased by -r_vaddr, so adding
      the value below will give the absolute target address.  */
   *relocation = val + addend + rel->r_vaddr;
@@ -1645,7 +1669,7 @@ xcoff64_ppc_relocate_section (bfd *output_bfd,
       if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
 	  || !((*xcoff64_calculate_relocation[rel->r_type])
 	      (input_bfd, input_section, output_bfd, rel, sym, &howto, val,
-	       addend, &relocation, contents)))
+	       addend, &relocation, contents, info)))
 	return false;
 
       /* address */
@@ -2386,12 +2410,32 @@ HOWTO (0,			/* type */
        MINUS_ONE,		/* dst_mask */
        false);			/* pcrel_offset */
 
+/* Indirect call stub */
+static const unsigned long xcoff64_stub_indirect_call_code[4] =
+  {
+    0xe9820000,	/* ld r12,0(r2) */
+    0xe80c0000,	/* ld r0,0(r12) */
+    0x7c0903a6,	/* mtctr r0 */
+    0x4e800420,	/* bctr */
+  };
+
+/* Shared call stub */
+static const unsigned long xcoff64_stub_shared_call_code[6] =
+  {
+    0xe9820000,	/* ld r12,0(r2) */
+    0xf8410028,	/* std r2,40(r1) */
+    0xe80c0000,	/* ld r0,0(r12) */
+    0xe84c0008,	/* ld r2,8(r12) */
+    0x7c0903a6,	/* mtctr r0 */
+    0x4e800420,	/* bctr */
+  };
+
 static const unsigned long xcoff64_glink_code[10] =
 {
   0xe9820000,	/* ld r12,0(r2) */
   0xf8410028,	/* std r2,40(r1) */
   0xe80c0000,	/* ld r0,0(r12) */
-  0xe84c0008,	/* ld r0,8(r12) */
+  0xe84c0008,	/* ld r2,8(r12) */
   0x7c0903a6,	/* mtctr r0 */
   0x4e800420,	/* bctr */
   0x00000000,	/* start of traceback table */
@@ -2495,6 +2539,14 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data =
     /* rtinit.  */
     88,				/* _xcoff_rtinit_size */
     xcoff64_generate_rtinit,
+
+    /* Stub indirect call.  */
+    &xcoff64_stub_indirect_call_code[0],
+    16,				/* _xcoff_stub_indirect_call_size */
+
+    /* Stub shared call.  */
+    &xcoff64_stub_shared_call_code[0],
+    24,				/* _xcoff_stub_shared_call_size */
   };
 
 /* The transfer vector that leads the outside world to all of the above.  */
@@ -2759,6 +2811,14 @@ static const struct xcoff_backend_data_rec bfd_xcoff_aix5_backend_data =
     /* rtinit.  */
     88,				/* _xcoff_rtinit_size */
     xcoff64_generate_rtinit,
+
+    /* Stub indirect call.  */
+    &xcoff64_stub_indirect_call_code[0],
+    16,				/* _xcoff_stub_indirect_call_size */
+
+    /* Stub shared call.  */
+    &xcoff64_stub_shared_call_code[0],
+    24,				/* _xcoff_stub_shared_call_size */
   };
 
 /* The transfer vector that leads the outside world to all of the above.  */
diff --git a/bfd/libxcoff.h b/bfd/libxcoff.h
index 2a71ee5851a..c6ad6dc2c4a 100644
--- a/bfd/libxcoff.h
+++ b/bfd/libxcoff.h
@@ -99,6 +99,15 @@ struct xcoff_backend_data_rec
   unsigned int _xcoff_rtinit_size;
   bool (*_xcoff_generate_rtinit)
     (bfd *, const char *, const char *, bool);
+
+  /* Stubs code generation.
+     The code part is an array which might need to be modified by
+     some relocations.
+     The size is in bytes.  */
+  const unsigned long *_xcoff_stub_indirect_call_code;
+  unsigned long _xcoff_stub_indirect_call_size;
+  const unsigned long *_xcoff_stub_shared_call_code;
+  unsigned long _xcoff_stub_shared_call_size;
 };
 
 /* Look up an entry in an XCOFF link hash table.  */
@@ -185,6 +194,11 @@ struct xcoff_backend_data_rec
 #define bfd_xcoff_glink_code(a, b)   ((xcoff_backend (a)->_xcoff_glink_code[(b)]))
 #define bfd_xcoff_glink_code_size(a) ((xcoff_backend (a)->_xcoff_glink_size))
 
+#define bfd_xcoff_stub_indirect_call_code(a, b)   ((xcoff_backend (a)->_xcoff_stub_indirect_call_code[(b)]))
+#define bfd_xcoff_stub_indirect_call_size(a) ((xcoff_backend (a)->_xcoff_stub_indirect_call_size))
+#define bfd_xcoff_stub_shared_call_code(a, b)   ((xcoff_backend (a)->_xcoff_stub_shared_call_code[(b)]))
+#define bfd_xcoff_stub_shared_call_size(a) ((xcoff_backend (a)->_xcoff_stub_shared_call_size))
+
 /* Check for the magic number U803XTOCMAGIC or U64_TOCMAGIC for 64 bit
    targets.  */
 #define bfd_xcoff_is_xcoff64(a) \
@@ -211,11 +225,12 @@ struct xcoff_backend_data_rec
 #define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1)
 
 typedef bool xcoff_reloc_function (bfd *, asection *, bfd *,
-					  struct internal_reloc *,
-					  struct internal_syment *,
-					  struct reloc_howto_struct *,
-					  bfd_vma, bfd_vma,
-					  bfd_vma *, bfd_byte *);
+				   struct internal_reloc *,
+				   struct internal_syment *,
+				   struct reloc_howto_struct *,
+				   bfd_vma, bfd_vma,
+				   bfd_vma *, bfd_byte *,
+				   struct bfd_link_info *);
 
 typedef bool xcoff_complain_function (bfd *, bfd_vma, bfd_vma,
 					     struct reloc_howto_struct *);
@@ -261,4 +276,42 @@ struct xcoff_dwsect_name {
 extern const struct xcoff_dwsect_name
   xcoff_dwsect_names[XCOFF_DWSECT_NBR_NAMES];
 
+/* Structure and functions needed by backend in order to handle
+   stubs created in xcofflink.c.  */
+
+enum xcoff_stub_type
+  {
+    xcoff_stub_none,
+    xcoff_stub_indirect_call,
+    xcoff_stub_shared_call
+  };
+
+struct xcoff_stub_hash_entry
+{
+  /* Base hash table entry structure.  */
+  struct bfd_hash_entry root;
+
+  enum xcoff_stub_type stub_type;
+
+  /* The hash table entry of the stub's csect.  */
+  struct xcoff_link_hash_entry *hcsect;
+
+  /* Offset in the stub's csect.  */
+  bfd_vma stub_offset;
+
+  /* The target's section.  */
+  asection *target_section;
+
+  /* The target's hash table entry.  */
+  struct xcoff_link_hash_entry *htarget;
+};
+
+
+extern enum xcoff_stub_type bfd_xcoff_type_of_stub
+  (asection *, const struct internal_reloc *, bfd_vma,
+   struct xcoff_link_hash_entry *);
+
+extern struct xcoff_stub_hash_entry *bfd_xcoff_get_stub_entry
+  (asection *, struct xcoff_link_hash_entry *, struct bfd_link_info *);
+
 #endif /* LIBXCOFF_H */
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index 6d4abdd1eda..6dbcd299b88 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -93,6 +93,12 @@ struct xcoff_link_hash_table
 {
   struct bfd_link_hash_table root;
 
+  /* The stub hash table.  */
+  struct bfd_hash_table stub_hash_table;
+
+  /* Info passed by the linker.  */
+  struct bfd_xcoff_link_params *params;
+
   /* The .debug string hash table.  We need to compute this while
      reading the input files, so that we know how large the .debug
      section will be before we assign section positions.  */
@@ -193,6 +199,13 @@ struct xcoff_final_link_info
   bfd_byte *external_relocs;
 };
 
+#define xcoff_stub_hash_entry(ent)		\
+  ((struct xcoff_stub_hash_entry *)(ent))
+
+#define xcoff_stub_hash_lookup(table, string, create, copy)	\
+  ((struct xcoff_stub_hash_entry *)				\
+   bfd_hash_lookup ((table), (string), (create), (copy)))
+
 static bool xcoff_mark (struct bfd_link_info *, asection *);
 
 \f
@@ -529,6 +542,41 @@ xcoff_get_archive_info (struct bfd_link_info *info, bfd *archive)
   return entryp;
 }
 \f
+
+/* Initialize an entry in the stub hash table.  */
+static struct bfd_hash_entry *
+stub_hash_newfunc (struct bfd_hash_entry *entry,
+		   struct bfd_hash_table *table,
+		   const char *string)
+{
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table,
+				 sizeof (struct xcoff_stub_hash_entry));
+      if (entry == NULL)
+	return entry;
+    }
+
+  /* Call the allocation method of the superclass.  */
+  entry = bfd_hash_newfunc (entry, table, string);
+  if (entry != NULL)
+    {
+      struct xcoff_stub_hash_entry *hsh;
+
+      /* Initialize the local fields.  */
+      hsh = (struct xcoff_stub_hash_entry *) entry;
+      hsh->stub_type = xcoff_stub_none;
+      hsh->hcsect = NULL;
+      hsh->stub_offset = 0;
+      hsh->target_section = NULL;
+      hsh->htarget = NULL;
+    }
+
+  return entry;
+}
+
 /* Routine to create an entry in an XCOFF link hash table.  */
 
 static struct bfd_hash_entry *
@@ -577,6 +625,8 @@ _bfd_xcoff_bfd_link_hash_table_free (bfd *obfd)
     htab_delete (ret->archive_info);
   if (ret->debug_strtab)
     _bfd_stringtab_free (ret->debug_strtab);
+
+  bfd_hash_table_free (&ret->stub_hash_table);
   _bfd_generic_link_hash_table_free (obfd);
 }
 
@@ -599,6 +649,14 @@ _bfd_xcoff_bfd_link_hash_table_create (bfd *abfd)
       return NULL;
     }
 
+  /* Init the stub hash table too.  */
+  if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc,
+			    sizeof (struct xcoff_stub_hash_entry)))
+    {
+      _bfd_xcoff_bfd_link_hash_table_free (abfd);
+      return NULL;
+    }
+
   isxcoff64 = bfd_coff_debug_string_prefix_length (abfd) == 4;
 
   ret->debug_strtab = _bfd_xcoff_stringtab_init (isxcoff64);
@@ -1738,6 +1796,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
 			      + sym.n_value
 			      - enclosing->vma);
 	    csect->size = aux.x_csect.x_scnlen.l;
+	    csect->rawsize = aux.x_csect.x_scnlen.l;
 	    csect->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS;
 	    csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp);
 
@@ -3159,6 +3218,17 @@ xcoff_sweep (struct bfd_link_info *info)
     }
 }
 
+/* Initialize the back-end with linker infos.  */
+
+bool
+bfd_xcoff_link_init (struct bfd_link_info *info,
+		     struct bfd_xcoff_link_params *params)
+{
+  xcoff_hash_table (info)->params = params;
+
+  return true;
+}
+
 /* Record the number of elements in a set.  This is used to output the
    correct csect length.  */
 
@@ -4218,6 +4288,750 @@ bfd_xcoff_link_generate_rtinit (bfd *abfd,
   return true;
 }
 \f
+
+/* Linker stubs.
+   The stubs will be gathered in stub csects named "@FIX'number'".
+   A new csect will be created by xcoff_stub_get_csect_in_range,
+   everytime a relocation cannot reach its target and its section
+   is too far from the others stub csects.
+   The stubs will simply be code generated inside these stub
+   csects.  In order to simplify the symbol table, only the symbols
+   for the stub csects are written.
+
+   As the code is dependent of the architecture, it's defined
+   in the backend.
+
+   xcoff_stub_indirect_call:
+   Used when a 24 bit branch cannot reach its destination and that
+   this destination isn't a global linkage symbol.
+
+   xcoff_stub_shared_call:
+   As above but when it's a global linkage symbol.
+   The main difference being that it doesn't branch to the global
+   linkage symbol which will then call the shared library.  It
+   directly call it saving the TOC.
+
+   TODO: -bbigtoc option should be able to be implemented using
+   this stubs.  */
+
+/* Get the name of a csect which will contain stubs.
+   It has the same pattern as AIX linker: @FIX"number".  */
+static char * xcoff_stub_csect_name (unsigned int n)
+{
+  char buf[6];
+  size_t len;
+  char *csect_name;
+
+  /* For now, allow "only" 1000000 stub csects.  */
+  if (n >= 1000000)
+    {
+      BFD_FAIL();
+      return NULL;
+    }
+
+  sprintf (buf, "%d", n);
+  len = 4 + strlen (buf) + 1;
+
+  csect_name = bfd_malloc (len);
+  if (csect_name == NULL)
+    return NULL;
+  sprintf (csect_name, "@FIX%d", n);
+
+  return csect_name;
+}
+
+/* Return a stub section which can be reach with a single branch
+   from SECTION.  CREATE means that creating a csect is allowed.  */
+static struct xcoff_link_hash_entry *
+xcoff_stub_get_csect_in_range (asection *section,
+			       struct bfd_link_info *info,
+			       bool create)
+{
+  struct xcoff_link_hash_table *htab = xcoff_hash_table (info);
+  struct xcoff_link_hash_entry *csect_entry;
+  struct bfd_link_hash_entry *bh = NULL;
+  asection *csect;
+  unsigned int it;
+  char *csect_name;
+
+  /* Search for a csect in range.  */
+  for (csect = htab->params->stub_bfd->sections, it = 0;
+       csect != NULL;
+       csect = csect->next, it++)
+    {
+      /* A csect is in range if everything instructions in SECTION
+         can branch to every stubs in the stub csect.  This can
+	 be simplify by saying that the first entry of each sections
+	 (ie the vma of this section) can reach the last entry of the
+	 stub csect (ie the vma of the csect + its size).
+         However, as the stub csect might be growing its size isn't
+         fixed.  Thus, the last entry of SECTION might not be able
+         to reach the first entry of the stub csect anymore.
+         If this case happens, the following condition will be
+         false during the next pass of bfd_xcoff_size_stubs and
+         another csect will be used.
+         This means we might create more stubs than needed.  */
+      bfd_vma csect_vma, section_vma;
+      bfd_vma csect_last_vma, section_last_vma;
+
+      csect_vma = (csect->output_section->vma
+			+ csect->output_offset);
+      csect_last_vma = (csect->output_section->vma
+			+ csect->output_offset
+			+ csect->size);
+      section_vma = (section->output_section->vma
+		     + section->output_offset);
+      section_last_vma = (section->output_section->vma
+		     + section->output_offset
+		     + section->size);
+
+      if (csect_last_vma - section_vma + (1 << 25) < 2 * (1 << 25)
+	  && section_last_vma - csect_vma + (1 << 25) < 2 * (1 << 25))
+	break;
+    }
+
+  if (!create && csect == NULL)
+    return NULL;
+
+  csect_name = xcoff_stub_csect_name (it);
+  if (!csect_name)
+    return NULL;
+
+  /* A stub csect already exists, get its entry.  */
+  if (csect != NULL)
+    {
+      csect_entry = xcoff_link_hash_lookup (htab, csect_name, false, false, true);
+      free(csect_name);
+      return csect_entry;
+    }
+
+  /* Create the csect and its symbol.  */
+  csect = (*htab->params->add_stub_section) (".pr", section);
+  if (!csect)
+    {
+      free(csect_name);
+      return NULL;
+    }
+
+  csect->alignment_power = 2;
+  csect->gc_mark = 1;
+  csect->reloc_count = 0;
+
+  /* We need to associate a VMA to this new csect.  Otherwise,
+     our "in range" algorithm won't find it for the next stub.
+     And as we will be adding this stub section just after the
+     SECTION, we know its address.  */
+  csect->output_offset = BFD_ALIGN (section->output_offset + section->size,
+				    4);
+
+  if (!_bfd_generic_link_add_one_symbol (info, htab->params->stub_bfd,
+					 csect_name, BSF_GLOBAL, csect, 0,
+					 NULL, true, true, &bh))
+    {
+      free(csect_name);
+      return NULL;
+    }
+
+  csect_entry = (struct xcoff_link_hash_entry *)bh;
+  csect_entry->smclas = XMC_PR;
+  csect_entry->flags = XCOFF_MARK | XCOFF_DEF_REGULAR;
+
+  free(csect_name);
+  return csect_entry;
+}
+
+
+/* Build a name for an entry in the stub hash table.  */
+static char *
+xcoff_stub_name (const struct xcoff_link_hash_entry *h,
+		 const struct xcoff_link_hash_entry *hcsect)
+{
+  char *stub_name;
+  size_t len;
+
+  if (h)
+    {
+      /* The name of a stub is based on its stub csect and the
+	 symbol it wants to reach.  It looks like: ".@FIX0.tramp.f".
+	 When the stub targets a function, the last dot of ".tramp."
+	 is removed to avoid having two dot.  */
+      len = (1 + 6
+	     + strlen (hcsect->root.root.string)
+	     + strlen (h->root.root.string)
+	     + 1);
+      if (h->root.root.string[0] != '.')
+	len++;
+
+      stub_name = bfd_malloc (len);
+      if (stub_name == NULL)
+	return stub_name;
+
+      if (h->root.root.string[0] == '.')
+	sprintf (stub_name, ".%s.tramp%s",
+		 hcsect->root.root.string,
+		 h->root.root.string);
+      else
+	sprintf (stub_name, ".%s.tramp.%s",
+		 hcsect->root.root.string,
+		 h->root.root.string);
+    }
+  else
+    {
+      BFD_FAIL();
+      return NULL;
+    }
+
+  return stub_name;
+}
+
+/* Look up an entry in the stub hash.  */
+struct xcoff_stub_hash_entry *
+bfd_xcoff_get_stub_entry (asection *section,
+			  struct xcoff_link_hash_entry *h,
+			  struct bfd_link_info *info)
+{
+  struct xcoff_link_hash_table *htab = xcoff_hash_table (info);
+  struct xcoff_link_hash_entry *hcsect;
+  struct xcoff_stub_hash_entry *hstub;
+  char *stub_name;
+
+  hcsect = xcoff_stub_get_csect_in_range (section, info, false);
+  if (!hcsect)
+    return NULL;
+
+  stub_name = xcoff_stub_name (h, hcsect);
+  if (stub_name == NULL)
+    return NULL;
+
+  hstub = xcoff_stub_hash_lookup (&htab->stub_hash_table,
+				  stub_name, false, false);
+
+  free (stub_name);
+  return hstub;
+}
+
+/* Check if the symbol targeted by IREL is reachable.
+   Return the type of stub needed otherwise.  */
+enum xcoff_stub_type
+bfd_xcoff_type_of_stub (asection *sec,
+			const struct internal_reloc *irel,
+			bfd_vma destination,
+			struct xcoff_link_hash_entry *h)
+{
+  bfd_vma location, offset, max_offset;
+
+  switch (irel->r_type)
+    {
+    default:
+      return xcoff_stub_none;
+
+    case R_BR:
+    case R_RBR:
+      location = (sec->output_section->vma
+		  + sec->output_offset
+		  + irel->r_vaddr
+		  - sec->vma);
+
+      max_offset = 1 << 25 ;
+
+      offset = destination - location;
+
+      if (offset + max_offset < 2 * max_offset)
+	return xcoff_stub_none;
+
+      /* A stub is needed.  Now, check that we can make one.  */
+      if (h != NULL
+	  && h->descriptor != NULL)
+	{
+	  /* Not sure how to handle this case. For now, skip it. */
+	  if (bfd_is_abs_section (h->root.u.def.section))
+	    return xcoff_stub_none;
+
+	  if (h->smclas == XMC_GL)
+	    return xcoff_stub_shared_call;
+	  else
+	    return xcoff_stub_indirect_call;
+	}
+      break;
+    }
+
+  return xcoff_stub_none;
+}
+
+/* Add a new stub entry to the stub hash.  Not all fields of the new
+   stub entry are initialised.  */
+static struct xcoff_stub_hash_entry *
+xcoff_add_stub (const char *stub_name,
+		struct xcoff_link_hash_entry *hstub_csect,
+		struct xcoff_link_hash_entry *htarget,
+		struct bfd_link_info *info,
+		enum xcoff_stub_type stub_type)
+{
+  struct xcoff_link_hash_table *htab = xcoff_hash_table (info);
+  struct xcoff_stub_hash_entry *hstub;
+  bfd_vma stub_offset;
+  asection *stub_csect;
+
+  stub_csect = hstub_csect->root.u.def.section;
+  stub_offset = stub_csect->size;
+
+  /* Update the relocation counter and the size of
+     the containing csect.  The size is needed for
+     the algorithm in xcoff_stub_get_csect_in_range.  */
+  switch (stub_type)
+    {
+    default:
+      BFD_FAIL ();
+      return NULL;
+
+    case xcoff_stub_indirect_call:
+      stub_csect->reloc_count++;
+      stub_csect->size += bfd_xcoff_stub_indirect_call_size (info->output_bfd);
+	break;
+
+    case xcoff_stub_shared_call:
+      stub_csect->reloc_count++;
+      stub_csect->size += bfd_xcoff_stub_shared_call_size (info->output_bfd);
+      break;
+    }
+
+  /* Create the stub entry.  */
+  hstub = xcoff_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+				       true, true);
+  if (hstub == NULL)
+    return NULL;
+
+  hstub->htarget = htarget;
+  hstub->stub_offset = stub_offset;
+
+  /* For indirect call or shared call, the relocations are against
+     the target descriptor.  Its toc entry will be used.  */
+  if (stub_type == xcoff_stub_indirect_call
+      || stub_type == xcoff_stub_shared_call)
+    {
+      struct xcoff_link_hash_entry *hds = htarget->descriptor;
+      asection *hds_section = hds->root.u.def.section;
+
+      hstub->htarget = hds;
+
+      /* If the symbol haven't been marked, its section might have
+	 its size and its relocation count been deleted by xcoff_sweep.
+	 Restore it.  */
+      if ((hds->flags & XCOFF_MARK) == 0)
+	{
+	  if (hds_section->size == 0
+	      && hds_section->reloc_count == 0
+	      && hds_section->rawsize != 0)
+	    {
+	      hds_section->size = hds_section->rawsize;
+	      /* Always two relocations for a XMC_DS symbol.  */
+	      hds_section->reloc_count = 2;
+	    }
+
+	  /* Mark the section and the symbol.  */
+	  if (!xcoff_mark (info, hds_section))
+	    return NULL;
+	}
+
+      /* Add a TOC entry for the descriptor if non exists.  */
+      if (hds->toc_section == NULL)
+	{
+	  int byte_size;
+
+	  if (bfd_xcoff_is_xcoff64 (info->output_bfd))
+	    byte_size = 8;
+	  else if (bfd_xcoff_is_xcoff32 (info->output_bfd))
+	    byte_size = 4;
+	  else
+	    return NULL;
+
+	  /* Allocate room in the fallback TOC section.  */
+	  hds->toc_section = xcoff_hash_table (info)->toc_section;
+	  hds->u.toc_offset = hds->toc_section->size;
+	  hds->toc_section->size += byte_size;
+	  if (!xcoff_mark (info, hds->toc_section))
+	    return NULL;
+
+	  /* Update relocation counters for a static and dynamic
+	     R_TOC relocation.  */
+	  ++hds->toc_section->reloc_count;
+	  ++htab->ldinfo.ldrel_count;
+
+	  /* Set the index to -2 to force this symbol to
+	     get written out.  */
+	  hds->indx = -2;
+	  hds->flags |= XCOFF_SET_TOC;
+	}
+    }
+
+  return hstub;
+}
+
+static bool
+xcoff_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
+{
+  struct xcoff_stub_hash_entry *hstub
+    = (struct xcoff_stub_hash_entry *) gen_entry;
+
+  bfd *stub_bfd;
+  bfd *output_bfd;
+  struct bfd_link_info *info;
+  bfd_byte *loc;
+  bfd_byte *p;
+  unsigned int i;
+
+  info = (struct bfd_link_info *) in_arg;
+  stub_bfd = xcoff_hash_table (info)->params->stub_bfd;
+  output_bfd = info->output_bfd;
+
+  /* Fail if the target section could not be assigned to an output
+     section.  The user should fix his linker script.  */
+  if (hstub->target_section != NULL
+      && hstub->target_section->output_section == NULL
+      && info->non_contiguous_regions)
+    info->callbacks->einfo (_("%F%P: Could not assign '%pA' to an output section. "
+			      "Retry without --enable-non-contiguous-regions.\n"),
+			    hstub->target_section);
+
+  loc = (hstub->hcsect->root.u.def.section->contents
+	 + hstub->stub_offset);
+  p = loc;
+
+  switch (hstub->stub_type)
+    {
+    case xcoff_stub_indirect_call:
+      BFD_ASSERT (hstub->htarget->toc_section != NULL);
+      /* The first instruction in the stub code needs to be
+	 cooked to hold the correct offset in the toc.  It will
+         be filled by xcoff_stub_create_relocations.  */
+      for (i = 0; i < bfd_xcoff_stub_indirect_call_size(output_bfd) / 4; i++)
+	bfd_put_32 (stub_bfd,
+		    (bfd_vma) bfd_xcoff_stub_indirect_call_code(output_bfd, i),
+		    &p[4 * i]);
+      break;
+
+    case xcoff_stub_shared_call:
+      BFD_ASSERT (hstub->htarget->toc_section != NULL);
+      /* The first instruction in the glink code needs to be
+	 cooked to hold the correct offset in the toc.  It will
+         be filled by xcoff_stub_create_relocations.  */
+      for (i = 0; i < bfd_xcoff_stub_shared_call_size(output_bfd) / 4; i++)
+	bfd_put_32 (stub_bfd,
+		    (bfd_vma) bfd_xcoff_stub_shared_call_code(output_bfd, i),
+		    &p[4 * i]);
+
+      break;
+
+    default:
+      BFD_FAIL ();
+      return false;
+    }
+  return true;
+}
+
+/* Check relocations and adds stubs if needed.  */
+
+bool
+bfd_xcoff_size_stubs (struct bfd_link_info *info)
+{
+  struct xcoff_link_hash_table *htab = xcoff_hash_table (info);
+  struct xcoff_loader_info *ldinfo = &(htab->ldinfo);
+
+  while (1)
+    {
+      bfd *input_bfd;
+      bool stub_changed = false;
+
+      for (input_bfd = info->input_bfds;
+	   input_bfd != NULL;
+	   input_bfd = input_bfd->link.next)
+	{
+	  asection *section;
+	  bfd_size_type symcount;
+	  bfd_size_type symesz;
+	  bfd_byte *esyms;
+
+	  if (bfd_get_flavour (input_bfd) != bfd_target_xcoff_flavour)
+	    continue;
+
+	  symcount = obj_raw_syment_count (input_bfd);
+	  if (!symcount)
+	    continue;
+	  symesz = bfd_coff_symesz (input_bfd);
+	  esyms = (bfd_byte *) obj_coff_external_syms (input_bfd);
+
+	  /* Walk over each section attached to the input bfd.  */
+	  for (section = input_bfd->sections;
+	       section != NULL;
+	       section = section->next)
+	    {
+	      struct internal_reloc *internal_relocs;
+	      struct internal_reloc *irel, *irelend;
+
+	      /* If there aren't any relocs, then there's nothing more
+		 to do.  */
+	      if ((section->flags & SEC_RELOC) == 0
+		  || section->reloc_count == 0)
+		continue;
+
+	      /* If this section is a link-once section that will be
+		 discarded, then don't create any stubs.  */
+	      if (section->output_section == NULL
+		  || section->output_section->owner != info->output_bfd)
+		continue;
+
+	      /* This section have been garbage-collected.  */
+	      if (section->gc_mark == 0)
+		continue;
+
+	      /* Read in the relocs.  */
+	      internal_relocs = (xcoff_read_internal_relocs
+				 (input_bfd, section, true, NULL,
+				  false, NULL));
+	      if (internal_relocs == NULL)
+		goto error_ret;
+
+	      irel = internal_relocs;
+	      irelend = irel + section->reloc_count;
+	      for (; irel < irelend; irel++)
+		{
+		  enum xcoff_stub_type stub_type;
+		  struct xcoff_link_hash_entry *hsym = NULL;
+		  struct xcoff_link_hash_entry *hstub_csect = NULL;
+		  struct xcoff_stub_hash_entry *hstub = NULL;
+		  asection *sym_sec;
+		  bfd_vma sym_value;
+		  bfd_vma destination;
+		  char *stub_name;
+
+		  if (irel->r_symndx == -1)
+		    continue;
+
+		  switch (irel->r_type)
+		    {
+		    default:
+		      continue;
+
+		    case R_BR:
+		    case R_RBR:
+		      break;
+		    }
+
+		  /* Retrieve targeted symbol address */
+		  hsym = obj_xcoff_sym_hashes (input_bfd)[irel->r_symndx];
+		  if (hsym == NULL)
+		    {
+		      struct internal_syment sym;
+		      if ((long unsigned int)irel->r_symndx > symcount)
+			{
+			  BFD_FAIL();
+			  goto error_ret;
+			}
+
+		      bfd_coff_swap_sym_in (input_bfd,
+					    (void *) esyms + irel->r_symndx * symesz,
+					    (void *) &sym);
+
+		      sym_sec = xcoff_data (input_bfd)->csects[irel->r_symndx];
+		      sym_value = sym.n_value - sym_sec->vma;
+
+		      destination = (sym_value
+				     + sym_sec->output_section->vma
+				     + sym_sec->output_offset);
+		    }
+		  else if (hsym->root.type == bfd_link_hash_defined
+			   || hsym->root.type == bfd_link_hash_defweak)
+		    {
+		      sym_sec = hsym->root.u.def.section;
+		      sym_value = hsym->root.u.def.value;
+		      destination = (sym_value
+				     + sym_sec->output_section->vma
+				     + sym_sec->output_offset);
+		    }
+		  else
+		    {
+		      bfd_set_error (bfd_error_bad_value);
+		      goto error_ret;
+		    }
+
+		  /* I'm not sure how to handle this case. Skip it for now.  */
+		  if (bfd_is_abs_section (sym_sec))
+		    continue;
+
+		  stub_type = bfd_xcoff_type_of_stub (section, irel, destination, hsym);
+
+		  if (stub_type == xcoff_stub_none)
+		    continue;
+
+		  /* Get a stub csect in ranch.  */
+		  hstub_csect = xcoff_stub_get_csect_in_range (section, info, true);
+		  if (!hstub_csect)
+		    {
+		      /* xgettext:c-format */
+		      _bfd_error_handler (_("%pB: Unable to find a stub csect in range"
+					    "of relocation at %#" PRIx64 " targeting"
+					    "'%s'"),
+					  section->owner, irel->r_vaddr,
+					  hsym->root.root.string);
+		      goto error_ret;
+		    }
+
+		  /* Get the name of this stub.  */
+		  stub_name = xcoff_stub_name (hsym, hstub_csect);
+		  if (!stub_name)
+		    goto error_ret;
+
+		  hstub = xcoff_stub_hash_lookup (&(xcoff_hash_table (info)->stub_hash_table),
+						       stub_name, false, false);
+
+		  /* A stub entry inside the in range csect already exists.  */
+		  if (hstub != NULL)
+		    {
+		      free (stub_name);
+		      continue;
+		    }
+
+		  stub_changed = true;
+
+		  hstub = xcoff_add_stub (stub_name, hstub_csect, hsym, info, stub_type);
+		  if (hstub == NULL)
+		    {
+		      free (stub_name);
+		      /* xgettext:c-format */
+		      _bfd_error_handler (_("%pB: Cannot create stub entry '%s'"),
+					  section->owner, stub_name);
+		      goto error_ret;
+		    }
+
+		  hstub->stub_type = stub_type;
+		  hstub->hcsect = hstub_csect;
+		  hstub->target_section = sym_sec;
+		  free (stub_name);
+		}
+	    }
+	}
+
+      if (!stub_changed)
+	break;
+
+      /* Update the size of the loader.  */
+      if (xcoff_hash_table (info)->loader_section
+	  && !xcoff_size_loader_section (ldinfo))
+	goto error_ret;
+
+      /* Ask the linker to do its stuff.  */
+      (*htab->params->layout_sections_again) ();
+
+    }
+  return true;
+
+ error_ret:
+  bfd_set_error (bfd_error_bad_value);
+  return false;
+}
+
+bool
+bfd_xcoff_build_stubs (struct bfd_link_info *info)
+{
+  struct xcoff_link_hash_table *htab = xcoff_hash_table (info);
+  asection *stub_sec;
+
+  for (stub_sec = htab->params->stub_bfd->sections;
+       stub_sec != NULL;
+       stub_sec = stub_sec->next)
+    {
+      bfd_size_type size;
+
+      /* Allocate memory to hold the linker stubs.  */
+      size = stub_sec->size;
+      stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, size);
+      if (stub_sec->contents == NULL && size != 0)
+	return false;
+
+    }
+
+  /* Build the stubs as directed by the stub hash table.  */
+  bfd_hash_traverse (&htab->stub_hash_table, xcoff_build_one_stub, info);
+  return true;
+}
+
+/* Create and apply relocations made by a stub entry.  */
+static bool
+xcoff_stub_create_relocations (struct bfd_hash_entry *bh, void * inf)
+{
+  struct xcoff_stub_hash_entry *hstub
+    = (struct xcoff_stub_hash_entry *) bh;
+  struct xcoff_final_link_info *flinfo
+    = (struct xcoff_final_link_info *) inf;
+
+  bfd *output_bfd;
+  struct internal_reloc *irel;
+  struct xcoff_link_hash_entry **rel_hash;
+  struct xcoff_link_hash_entry *htarget;
+  asection *sec, *osec;
+  bfd_vma off;
+  bfd_byte *p;
+
+  htarget = hstub->htarget;
+  sec = hstub->hcsect->root.u.def.section;
+  osec = sec->output_section;
+
+  irel = (flinfo->section_info[osec->target_index].relocs
+	  + osec->reloc_count);
+  rel_hash = (flinfo->section_info[osec->target_index].rel_hashes
+	      + osec->output_section->reloc_count);
+  *rel_hash = NULL;
+  output_bfd = flinfo->output_bfd;
+
+  irel->r_symndx = htarget->indx;
+  irel->r_vaddr = (osec->vma
+		   + sec->output_offset
+		   + hstub->hcsect->root.u.def.value
+		   + hstub->stub_offset);
+
+  p = (sec->contents
+       + hstub->stub_offset);
+
+  switch (hstub->stub_type)
+    {
+    default:
+      BFD_FAIL ();
+      return false;
+
+      /* The first instruction of this stub code need
+         a R_TOC relocation.  */
+    case xcoff_stub_indirect_call:
+    case xcoff_stub_shared_call:
+      irel->r_size = 0xf;
+      irel->r_type = R_TOC;
+
+      /* Retrieve the toc offset of the target which is
+	 a function descriptor.  */
+      BFD_ASSERT (htarget->toc_section != NULL);
+      if ((htarget->flags & XCOFF_SET_TOC) != 0)
+	off = hstub->htarget->u.toc_offset;
+      else
+	off = (htarget->toc_section->output_section->vma
+	       + htarget->toc_section->output_offset
+	       - xcoff_data (flinfo->output_bfd)->toc);
+      if ((off & 0xffff) != off)
+	{
+	  _bfd_error_handler
+	    (_("TOC overflow during stub generation; try -mminimal-toc "
+	       "when compiling"));
+	  bfd_set_error (bfd_error_file_too_big);
+	  return false;
+	}
+
+      bfd_put_16 (output_bfd, off & 0xffff, p+2);
+      break;
+    }
+
+  ++osec->reloc_count;
+  return true;
+}
+
+
 /* Return the section that defines H.  Return null if no section does.  */
 
 static asection *
@@ -5049,8 +5863,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *flinfo,
 
 	      /* Adjust the reloc address and symbol index.  */
 
-	      irel->r_vaddr += offset;
-
 	      r_symndx = irel->r_symndx;
 
 	      if (r_symndx == -1)
@@ -5058,8 +5870,48 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *flinfo,
 	      else
 		h = obj_xcoff_sym_hashes (input_bfd)[r_symndx];
 
+	      /* In case of a R_BR or R_RBR, change the target if
+		 a stub is being called.  */
+	      if (h != NULL
+		  && (irel->r_type == R_BR
+		      || irel->r_type == R_RBR))
+		{
+		  asection *sym_sec;
+		  bfd_vma dest;
+		  struct xcoff_stub_hash_entry *hstub = NULL;
+		  enum xcoff_stub_type stub_type;
+
+		  if (h->root.type == bfd_link_hash_defined
+		      || h->root.type == bfd_link_hash_defweak)
+		    {
+		      sym_sec = h->root.u.def.section;
+		      dest = (h->root.u.def.value
+			      + sym_sec->output_section->vma
+			      + sym_sec->output_offset);
+		    }
+		  else
+		    {
+		      BFD_FAIL ();
+		      goto err_out;
+		    }
+
+		  stub_type = bfd_xcoff_type_of_stub (o, irel, dest, h);
+		  if (stub_type != xcoff_stub_none)
+		    {
+		      hstub = bfd_xcoff_get_stub_entry (o, h, flinfo->info);
+		      if (hstub == NULL)
+			goto err_out;
+
+		      h = hstub->hcsect;
+		    }
+
+		}
+
+	      irel->r_vaddr += offset;
+
 	      if (r_symndx != -1 && flinfo->info->strip != strip_all)
 		{
+
 		  if (h != NULL
 		      && h->smclas != XMC_TD
 		      && (irel->r_type == R_TOC
@@ -5574,8 +6426,6 @@ xcoff_write_global_symbol (struct bfd_hash_entry *bh, void * inf)
 	  irel->r_symndx = obj_raw_syment_count (output_bfd);
 	}
 
-      BFD_ASSERT (h->ldindx >= 0);
-
       /* Initialize the aux union here instead of closer to when it is
 	 written out below because the length of the csect depends on
 	 whether the output is 32 or 64 bit.  */
@@ -5607,9 +6457,43 @@ xcoff_write_global_symbol (struct bfd_hash_entry *bh, void * inf)
       flinfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
       ++osec->reloc_count;
 
-      if (!xcoff_create_ldrel (output_bfd, flinfo, osec,
-			       output_bfd, irel, NULL, h))
-	return false;
+      /* There are two kind of linker-created TOC entry.
+	 The ones importing their symbols from outside, made for the
+	 global linkage.  These symbols have XCOFF_LDREL set and only
+	 requires a loader relocation on their imported symbol.
+	 On the other hand, symbols without XCOFF_LDREL are TOC entries
+	 of internal symbols (like function descriptors made for stubs).
+	 These symbols needs a loader relocation over .data and this
+	 relocation must be applied.  */
+
+      if ((h->flags & XCOFF_LDREL) != 0
+	  && h->ldindx >= 0)
+	{
+	  if (!xcoff_create_ldrel (output_bfd, flinfo, osec,
+				   output_bfd, irel, NULL, h))
+	    return false;
+	}
+      else
+	{
+	  bfd_byte *p;
+	  bfd_vma val;
+
+	  p = tocsec->contents + h->u.toc_offset;
+	  val = (h->root.u.def.value
+		 + h->root.u.def.section->output_section->vma
+		 + h->root.u.def.section->output_offset);
+
+	  if (bfd_xcoff_is_xcoff64 (output_bfd))
+	    bfd_put_64 (output_bfd, val, p);
+	  else if (bfd_xcoff_is_xcoff32 (output_bfd))
+	    bfd_put_32 (output_bfd, val, p);
+	  else
+	    return false;
+
+	  if (!xcoff_create_ldrel (output_bfd, flinfo, osec,
+				   output_bfd, irel, h->root.u.def.section, h))
+	    return false;
+	}
 
       /* We need to emit a symbol to define a csect which holds
 	 the reloc.  */
@@ -5836,7 +6720,12 @@ xcoff_write_global_symbol (struct bfd_hash_entry *bh, void * inf)
       isym.n_sclass = C_HIDEXT;
       aux.x_csect.x_smtyp = XTY_SD;
 
-      if ((h->flags & XCOFF_HAS_SIZE) != 0)
+      /* For stub symbols, the section already has its correct size.  */
+      if (h->root.u.def.section->owner == xcoff_hash_table (flinfo->info)->params->stub_bfd)
+	{
+	  aux.x_csect.x_scnlen.l = h->root.u.def.section->size;
+	}
+      else if ((h->flags & XCOFF_HAS_SIZE) != 0)
 	{
 	  for (l = xcoff_hash_table (flinfo->info)->size_list;
 	       l != NULL;
@@ -6403,8 +7292,20 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
 	      sub = p->u.indirect.section->owner;
 	      if (! sub->output_has_begun)
 		{
-		  if (! xcoff_link_input_bfd (&flinfo, sub))
-		    goto error_return;
+		  if (sub == xcoff_hash_table (info)->params->stub_bfd)
+		    {
+		      continue;
+		    }
+		  else
+		    {
+		      if (! xcoff_link_input_bfd (&flinfo, sub))
+			{
+			  _bfd_error_handler
+			    (_("Unable to link input file: %s"), sub->filename);
+			  bfd_set_error (bfd_error_sorry);
+			  goto error_return;
+			}
+		    }
 		  sub->output_has_begun = true;
 		}
 	    }
@@ -6451,6 +7352,12 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
      input files.  */
   bfd_hash_traverse (&info->hash->table, xcoff_write_global_symbol, &flinfo);
 
+  /* Write out the relocations created by stub entries. The symbols
+     will have been already written by xcoff_write_global_symbol.  */
+  bfd_hash_traverse (&xcoff_hash_table(info)->stub_hash_table,
+		     xcoff_stub_create_relocations,
+		     &flinfo);
+
   free (flinfo.outsyms);
   flinfo.outsyms = NULL;
 
@@ -6551,6 +7458,19 @@ _bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
       flinfo.section_info = NULL;
     }
 
+  /* Write out the stub sections.  */
+  for (o = xcoff_hash_table (info)->params->stub_bfd->sections;
+       o != NULL; o = o->next)
+    {
+      if ((o->flags & SEC_HAS_CONTENTS) == 0
+	  || o->size == 0)
+	continue;
+
+      if (!bfd_set_section_contents (abfd, o->output_section, o->contents,
+				     (file_ptr) o->output_offset, o->size))
+	goto error_return;
+    }
+
   /* Write out the loader section contents.  */
   o = xcoff_hash_table (info)->loader_section;
   if (o != NULL
diff --git a/bfd/xcofflink.h b/bfd/xcofflink.h
index 92feeb58958..d647ba0a5df 100644
--- a/bfd/xcofflink.h
+++ b/bfd/xcofflink.h
@@ -18,6 +18,17 @@
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
    MA 02110-1301, USA.  */
 
+/* Used to pass info between ld and bfd.  */
+struct bfd_xcoff_link_params
+{
+  /* Linker stub bfd.  */
+  bfd *stub_bfd;
+
+  /* Linker call-backs.  */
+  asection * (*add_stub_section) (const char *, asection *);
+  void (*layout_sections_again) (void);
+};
+
 extern bool bfd_xcoff_split_import_path
   (bfd *, const char *, const char **, const char **);
 extern bool bfd_xcoff_set_archive_import_path
@@ -41,3 +52,9 @@ extern bool bfd_xcoff_build_dynamic_sections
   (bfd *, struct bfd_link_info *);
 extern bool bfd_xcoff_link_generate_rtinit
   (bfd *, const char *, const char *, bool);
+extern bool bfd_xcoff_link_init
+  (struct bfd_link_info *, struct bfd_xcoff_link_params *);
+extern bool bfd_xcoff_size_stubs
+  (struct bfd_link_info *info);
+extern bool bfd_xcoff_build_stubs
+  (struct bfd_link_info *info);
diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em
index 3878d58bb32..355e2a4ffff 100644
--- a/ld/emultempl/aix.em
+++ b/ld/emultempl/aix.em
@@ -63,6 +63,15 @@ static void gld${EMULATION_NAME}_free (void *);
 static void gld${EMULATION_NAME}_find_relocs (lang_statement_union_type *);
 static void gld${EMULATION_NAME}_find_exp_assignment (etree_type *);
 
+static asection *xcoff_add_stub_section (const char *, asection *);
+static void xcoff_layout_sections_again (void);
+
+static struct bfd_xcoff_link_params params = {
+  NULL,
+  &xcoff_add_stub_section,
+  &xcoff_layout_sections_again
+};
+
 
 /* The file alignment required for each section.  */
 static unsigned long file_align;
@@ -138,6 +147,9 @@ static int rtld;
 /* Explicit command line library path, -blibpath */
 static char *command_line_blibpath = NULL;
 
+/* Fake input file for stubs.  */
+static lang_input_statement_type *stub_file;
+
 /* This routine is called before anything else is done.  */
 
 static void
@@ -154,6 +166,7 @@ gld${EMULATION_NAME}_before_parse (void)
 
   link_info.init_function = NULL;
   link_info.fini_function = NULL;
+
 }
 
 /* Handle AIX specific options.  */
@@ -1009,12 +1022,157 @@ gld${EMULATION_NAME}_before_allocation (void)
   before_allocation_default ();
 }
 
+struct hook_stub_info
+{
+  lang_statement_list_type add;
+  asection *input_section;
+};
+
+/* Traverse the linker tree to find the spot where the stub goes.  */
+
+static bool
+hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp)
+{
+  lang_statement_union_type *l;
+  bool ret;
+
+  for (; (l = *lp) != NULL; lp = &l->header.next)
+    {
+      switch (l->header.type)
+	{
+	case lang_constructors_statement_enum:
+	  ret = hook_in_stub (info, &constructor_list.head);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_output_section_statement_enum:
+	  ret = hook_in_stub (info,
+			      &l->output_section_statement.children.head);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_wild_statement_enum:
+	  ret = hook_in_stub (info, &l->wild_statement.children.head);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_group_statement_enum:
+	  ret = hook_in_stub (info, &l->group_statement.children.head);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_input_section_enum:
+	  if (l->input_section.section == info->input_section)
+	    {
+	      /* We've found our section.  Insert the stub immediately
+		 after its associated input section.  */
+	      *(info->add.tail) = l->header.next;
+	      l->header.next = info->add.head;
+	      return true;
+	    }
+	  break;
+
+	case lang_data_statement_enum:
+	case lang_reloc_statement_enum:
+	case lang_object_symbols_statement_enum:
+	case lang_output_statement_enum:
+	case lang_target_statement_enum:
+	case lang_input_statement_enum:
+	case lang_assignment_statement_enum:
+	case lang_padding_statement_enum:
+	case lang_address_statement_enum:
+	case lang_fill_statement_enum:
+	  break;
+
+	default:
+	  FAIL ();
+	  break;
+	}
+    }
+  return false;
+}
+
+/* Call-back for bfd_xcoff_link_relocations.
+   Create a new stub section, and arrange for it to be linked
+   immediately before INPUT_SECTION.  */
+
+static asection *
+xcoff_add_stub_section (const char *stub_sec_name, asection *input_section)
+{
+  asection *stub_sec;
+  flagword flags;
+  asection *output_section;
+  lang_output_section_statement_type *os;
+  struct hook_stub_info info;
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
+	   | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_KEEP);
+  stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
+						 stub_sec_name, flags);
+  if (stub_sec == NULL)
+    goto err_ret;
+
+  output_section = input_section->output_section;
+  os = lang_output_section_get (output_section);
+
+  info.input_section = input_section;
+  lang_list_init (&info.add);
+  lang_add_section (&info.add, stub_sec, NULL, NULL, os);
+
+  if (info.add.head == NULL)
+    goto err_ret;
+
+  if (hook_in_stub (&info, &os->children.head))
+    return stub_sec;
+
+ err_ret:
+  einfo (_("%X%P: can not make stub section: %E\n"));
+  return NULL;
+}
+
+/* Another call-back for bfd_xcoff_link_relocations.  */
+
+static void
+xcoff_layout_sections_again (void)
+{
+  /* If we have changed sizes of the stub sections, then we need
+     to recalculate all the section offsets.  This may mean we need to
+     add even more stubs.  */
+   lang_relax_sections (true);
+}
+
+/* Call the back-end to verify relocations.  */
+
 static void
 gld${EMULATION_NAME}_after_allocation (void)
 {
+
+  /* If generating a relocatable output file, then we don't have any
+     stubs.  */
+  if (stub_file != NULL && !bfd_link_relocatable (&link_info))
+    {
+      /* Call into the BFD backend to do the real work.  */
+      if (!bfd_xcoff_size_stubs (&link_info))
+	einfo (_("%X%P: can not size stub sections: %E\n"));
+    }
+
   /* Now that everything is in place, finalize the dynamic sections.  */
   if (!bfd_xcoff_build_dynamic_sections (link_info.output_bfd, &link_info))
     einfo (_("%F%P: failed to layout dynamic sections: %E\n"));
+
+  if (!bfd_link_relocatable (&link_info))
+    {
+      /* Now build the linker stubs.  */
+      if (stub_file != NULL && stub_file->the_bfd->sections != NULL)
+	{
+	  if (! bfd_xcoff_build_stubs (&link_info))
+	    einfo (_("%X%P: can not build stubs: %E\n"));
+	}
+    }
 }
 
 static char *
@@ -1503,11 +1661,35 @@ fragment <<EOF
 static void
 gld${EMULATION_NAME}_create_output_section_statements (void)
 {
+  if ((bfd_get_flavour (link_info.output_bfd) != bfd_target_xcoff_flavour))
+    return;
+
+  /* Stub file */
+  stub_file = lang_add_input_file ("linker stubs",
+				   lang_input_file_is_fake_enum,
+				   NULL);
+  stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd);
+  if (stub_file->the_bfd == NULL
+      || !bfd_set_arch_mach (stub_file->the_bfd,
+			     bfd_get_arch (link_info.output_bfd),
+			     bfd_get_mach (link_info.output_bfd)))
+    {
+      einfo (_("%F%P: can not create stub BFD: %E\n"));
+      return;
+    }
+
+  stub_file->the_bfd->flags |= BFD_LINKER_CREATED;
+  ldlang_add_file (stub_file);
+  params.stub_bfd = stub_file->the_bfd;
+
+  /* Pass linker params to the back-end. */
+  if (!bfd_xcoff_link_init (&link_info, &params))
+    einfo (_("%F%P: can not init BFD: %E\n"));
+
   /* __rtinit */
-  if ((bfd_get_flavour (link_info.output_bfd) == bfd_target_xcoff_flavour)
-      && (link_info.init_function != NULL
-	  || link_info.fini_function != NULL
-	  || rtld))
+  if (link_info.init_function != NULL
+      || link_info.fini_function != NULL
+      || rtld)
     {
       initfini_file = lang_add_input_file ("initfini",
 					   lang_input_file_is_file_enum,
-- 
2.33.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] xcoff: implement linker relaxation
  2022-03-17 15:01 [PATCH 2/2] xcoff: implement linker relaxation CHIGOT, CLEMENT
@ 2022-04-13 16:32 ` Nick Clifton
  2022-04-20  9:52   ` pro
  0 siblings, 1 reply; 8+ messages in thread
From: Nick Clifton @ 2022-04-13 16:32 UTC (permalink / raw)
  To: CHIGOT, CLEMENT, binutils; +Cc: pro, Kavana N Bhat, Ayappan P2

Hi Clement,

   This patch generates a compile time error (using gcc 11.2.1):

bfd/xcofflink.c: In function 'xcoff_stub_get_csect_in_range':
bfd/xcofflink.c:4332:20: error: 'sprintf' may write a terminating nul past the end of the destination [-Werror=format-overflow=]
  4332 |   sprintf (buf, "%d", n);
       |                    ^
bfd/xcofflink.c:4332:3: note: 'sprintf' output between 2 and 7 bytes into a destination of size 6
  4332 |   sprintf (buf, "%d", n);
       |   ^~~~~~~~~~~~~~~~~~~~~~

   I suggest increasing the size of "buf" to at least 8.  In addition
   if you are feeling paranoid, you could use snprintf instead of
   sprintf.

   Other than that though the patch looks good to me, so approved,
   once that above problem has been fixed.

Cheers
   Nick


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] xcoff: implement linker  relaxation
  2022-04-13 16:32 ` Nick Clifton
@ 2022-04-20  9:52   ` pro
  2022-04-20 14:13     ` Nick Clifton
  0 siblings, 1 reply; 8+ messages in thread
From: pro @ 2022-04-20  9:52 UTC (permalink / raw)
  To: Nick Clifton; +Cc: CHIGOT, CLEMENT, binutils, Kavana N Bhat, Ayappan P2


Hi Nick,

As I said to the previous patch, I can't do it right now. Thus, if you find a bit of time I woudl be grateful if you can make these changes yourself and apply the patch for me. 
Otherwise, maybe Kavana can make the change and push the new patch. 

Thansk and sorry for that. 
Clément

On Wednesday, April 13, 2022 18:32 CEST, Nick Clifton <nickc@redhat.com> wrote:
 Hi Clement,

This patch generates a compile time error (using gcc 11.2.1):

bfd/xcofflink.c: In function 'xcoff_stub_get_csect_in_range':
bfd/xcofflink.c:4332:20: error: 'sprintf' may write a terminating nul past the end of the destination [-Werror=format-overflow=]
4332 | sprintf (buf, "%d", n);
| ^
bfd/xcofflink.c:4332:3: note: 'sprintf' output between 2 and 7 bytes into a destination of size 6
4332 | sprintf (buf, "%d", n);
| ^~~~~~~~~~~~~~~~~~~~~~

I suggest increasing the size of "buf" to at least 8. In addition
if you are feeling paranoid, you could use snprintf instead of
sprintf.

Other than that though the patch looks good to me, so approved,
once that above problem has been fixed.

Cheers
Nick
 


 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] xcoff: implement linker relaxation
  2022-04-20  9:52   ` pro
@ 2022-04-20 14:13     ` Nick Clifton
  2022-04-20 14:27       ` Luis Machado
  2022-04-20 14:32       ` Alan Modra
  0 siblings, 2 replies; 8+ messages in thread
From: Nick Clifton @ 2022-04-20 14:13 UTC (permalink / raw)
  To: pro; +Cc: CHIGOT, CLEMENT, binutils, Kavana N Bhat, Ayappan P2

Hi Clément,

> As I said to the previous patch, I can't do it right now. Thus, if you find a bit of time I woudl be grateful if you can make these changes yourself and apply the patch for me.

Patch applied.

Cheers
   Nick



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] xcoff: implement linker relaxation
  2022-04-20 14:13     ` Nick Clifton
@ 2022-04-20 14:27       ` Luis Machado
  2022-04-20 14:32       ` Alan Modra
  1 sibling, 0 replies; 8+ messages in thread
From: Luis Machado @ 2022-04-20 14:27 UTC (permalink / raw)
  To: Nick Clifton, pro; +Cc: Ayappan P2, Kavana N Bhat, CHIGOT, CLEMENT, binutils

Hi Nick,
On 4/20/22 15:13, Nick Clifton via Binutils wrote:
> Hi Clément,
> 
>> As I said to the previous patch, I can't do it right now. Thus, if you 
>> find a bit of time I woudl be grateful if you can make these changes 
>> yourself and apply the patch for me.
> 
> Patch applied.
> 
> Cheers
>    Nick
> 
> 

Did this include a fix to the format-overflow compilation error? I'm 
still seeing it.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] xcoff: implement linker relaxation
  2022-04-20 14:13     ` Nick Clifton
  2022-04-20 14:27       ` Luis Machado
@ 2022-04-20 14:32       ` Alan Modra
  2022-04-20 14:36         ` Luis Machado
  2022-04-21 14:47         ` pro
  1 sibling, 2 replies; 8+ messages in thread
From: Alan Modra @ 2022-04-20 14:32 UTC (permalink / raw)
  To: Nick Clifton; +Cc: pro, Ayappan P2, Kavana N Bhat, CHIGOT, CLEMENT, binutils

On Wed, Apr 20, 2022 at 03:13:25PM +0100, Nick Clifton via Binutils wrote:
> Hi Clément,
> 
> > As I said to the previous patch, I can't do it right now. Thus, if you find a bit of time I woudl be grateful if you can make these changes yourself and apply the patch for me.
> 
> Patch applied.

And a few fixes.

	* xcofflink.c (xcoff_stub_csect_name): Increase buffer size.
	(xcoff_stub_get_csect_in_range, xcoff_build_one_stub): Whitespace.
	(bfd_xcoff_size_stubs): Cast PRIx64 arg to required type.
	Don't use freed stub_name.

diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index 6dbcd299b88..83469775208 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -4316,9 +4316,10 @@ bfd_xcoff_link_generate_rtinit (bfd *abfd,
 
 /* Get the name of a csect which will contain stubs.
    It has the same pattern as AIX linker: @FIX"number".  */
-static char * xcoff_stub_csect_name (unsigned int n)
+static char *
+xcoff_stub_csect_name (unsigned int n)
 {
-  char buf[6];
+  char buf[8];
   size_t len;
   char *csect_name;
 
@@ -4360,30 +4361,30 @@ xcoff_stub_get_csect_in_range (asection *section,
        csect = csect->next, it++)
     {
       /* A csect is in range if everything instructions in SECTION
-         can branch to every stubs in the stub csect.  This can
+	 can branch to every stubs in the stub csect.  This can
 	 be simplify by saying that the first entry of each sections
 	 (ie the vma of this section) can reach the last entry of the
 	 stub csect (ie the vma of the csect + its size).
-         However, as the stub csect might be growing its size isn't
-         fixed.  Thus, the last entry of SECTION might not be able
-         to reach the first entry of the stub csect anymore.
-         If this case happens, the following condition will be
-         false during the next pass of bfd_xcoff_size_stubs and
-         another csect will be used.
-         This means we might create more stubs than needed.  */
+	 However, as the stub csect might be growing its size isn't
+	 fixed.  Thus, the last entry of SECTION might not be able
+	 to reach the first entry of the stub csect anymore.
+	 If this case happens, the following condition will be
+	 false during the next pass of bfd_xcoff_size_stubs and
+	 another csect will be used.
+	 This means we might create more stubs than needed.  */
       bfd_vma csect_vma, section_vma;
       bfd_vma csect_last_vma, section_last_vma;
 
       csect_vma = (csect->output_section->vma
-			+ csect->output_offset);
+		   + csect->output_offset);
       csect_last_vma = (csect->output_section->vma
 			+ csect->output_offset
 			+ csect->size);
       section_vma = (section->output_section->vma
 		     + section->output_offset);
       section_last_vma = (section->output_section->vma
-		     + section->output_offset
-		     + section->size);
+			  + section->output_offset
+			  + section->size);
 
       if (csect_last_vma - section_vma + (1 << 25) < 2 * (1 << 25)
 	  && section_last_vma - csect_vma + (1 << 25) < 2 * (1 << 25))
@@ -4703,7 +4704,7 @@ xcoff_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       BFD_ASSERT (hstub->htarget->toc_section != NULL);
       /* The first instruction in the stub code needs to be
 	 cooked to hold the correct offset in the toc.  It will
-         be filled by xcoff_stub_create_relocations.  */
+	 be filled by xcoff_stub_create_relocations.  */
       for (i = 0; i < bfd_xcoff_stub_indirect_call_size(output_bfd) / 4; i++)
 	bfd_put_32 (stub_bfd,
 		    (bfd_vma) bfd_xcoff_stub_indirect_call_code(output_bfd, i),
@@ -4714,7 +4715,7 @@ xcoff_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       BFD_ASSERT (hstub->htarget->toc_section != NULL);
       /* The first instruction in the glink code needs to be
 	 cooked to hold the correct offset in the toc.  It will
-         be filled by xcoff_stub_create_relocations.  */
+	 be filled by xcoff_stub_create_relocations.  */
       for (i = 0; i < bfd_xcoff_stub_shared_call_size(output_bfd) / 4; i++)
 	bfd_put_32 (stub_bfd,
 		    (bfd_vma) bfd_xcoff_stub_shared_call_code(output_bfd, i),
@@ -4871,7 +4872,7 @@ bfd_xcoff_size_stubs (struct bfd_link_info *info)
 		      _bfd_error_handler (_("%pB: Unable to find a stub csect in range"
 					    "of relocation at %#" PRIx64 " targeting"
 					    "'%s'"),
-					  section->owner, irel->r_vaddr,
+					  section->owner, (uint64_t) irel->r_vaddr,
 					  hsym->root.root.string);
 		      goto error_ret;
 		    }
@@ -4896,10 +4897,10 @@ bfd_xcoff_size_stubs (struct bfd_link_info *info)
 		  hstub = xcoff_add_stub (stub_name, hstub_csect, hsym, info, stub_type);
 		  if (hstub == NULL)
 		    {
-		      free (stub_name);
 		      /* xgettext:c-format */
 		      _bfd_error_handler (_("%pB: Cannot create stub entry '%s'"),
 					  section->owner, stub_name);
+		      free (stub_name);
 		      goto error_ret;
 		    }
 
@@ -4999,7 +5000,7 @@ xcoff_stub_create_relocations (struct bfd_hash_entry *bh, void * inf)
       return false;
 
       /* The first instruction of this stub code need
-         a R_TOC relocation.  */
+	 a R_TOC relocation.  */
     case xcoff_stub_indirect_call:
     case xcoff_stub_shared_call:
       irel->r_size = 0xf;


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] xcoff: implement linker relaxation
  2022-04-20 14:32       ` Alan Modra
@ 2022-04-20 14:36         ` Luis Machado
  2022-04-21 14:47         ` pro
  1 sibling, 0 replies; 8+ messages in thread
From: Luis Machado @ 2022-04-20 14:36 UTC (permalink / raw)
  To: Alan Modra, Nick Clifton
  Cc: pro, binutils, Kavana N Bhat, Ayappan P2, CHIGOT, CLEMENT

On 4/20/22 15:32, Alan Modra via Binutils wrote:
> On Wed, Apr 20, 2022 at 03:13:25PM +0100, Nick Clifton via Binutils wrote:
>> Hi Cl�ment,
>>
>>> As I said to the previous patch, I can't do it right now. Thus, if you find a bit of time I woudl be grateful if you can make these changes yourself and apply the patch for me.
>>
>> Patch applied.
> 
> And a few fixes.
> 
> 	* xcofflink.c (xcoff_stub_csect_name): Increase buffer size.
> 	(xcoff_stub_get_csect_in_range, xcoff_build_one_stub): Whitespace.
> 	(bfd_xcoff_size_stubs): Cast PRIx64 arg to required type.
> 	Don't use freed stub_name.
> 
> diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
> index 6dbcd299b88..83469775208 100644
> --- a/bfd/xcofflink.c
> +++ b/bfd/xcofflink.c
> @@ -4316,9 +4316,10 @@ bfd_xcoff_link_generate_rtinit (bfd *abfd,
>   
>   /* Get the name of a csect which will contain stubs.
>      It has the same pattern as AIX linker: @FIX"number".  */
> -static char * xcoff_stub_csect_name (unsigned int n)
> +static char *
> +xcoff_stub_csect_name (unsigned int n)
>   {
> -  char buf[6];
> +  char buf[8];
>     size_t len;
>     char *csect_name;
>   
> @@ -4360,30 +4361,30 @@ xcoff_stub_get_csect_in_range (asection *section,
>          csect = csect->next, it++)
>       {
>         /* A csect is in range if everything instructions in SECTION
> -         can branch to every stubs in the stub csect.  This can
> +	 can branch to every stubs in the stub csect.  This can
>   	 be simplify by saying that the first entry of each sections
>   	 (ie the vma of this section) can reach the last entry of the
>   	 stub csect (ie the vma of the csect + its size).
> -         However, as the stub csect might be growing its size isn't
> -         fixed.  Thus, the last entry of SECTION might not be able
> -         to reach the first entry of the stub csect anymore.
> -         If this case happens, the following condition will be
> -         false during the next pass of bfd_xcoff_size_stubs and
> -         another csect will be used.
> -         This means we might create more stubs than needed.  */
> +	 However, as the stub csect might be growing its size isn't
> +	 fixed.  Thus, the last entry of SECTION might not be able
> +	 to reach the first entry of the stub csect anymore.
> +	 If this case happens, the following condition will be
> +	 false during the next pass of bfd_xcoff_size_stubs and
> +	 another csect will be used.
> +	 This means we might create more stubs than needed.  */
>         bfd_vma csect_vma, section_vma;
>         bfd_vma csect_last_vma, section_last_vma;
>   
>         csect_vma = (csect->output_section->vma
> -			+ csect->output_offset);
> +		   + csect->output_offset);
>         csect_last_vma = (csect->output_section->vma
>   			+ csect->output_offset
>   			+ csect->size);
>         section_vma = (section->output_section->vma
>   		     + section->output_offset);
>         section_last_vma = (section->output_section->vma
> -		     + section->output_offset
> -		     + section->size);
> +			  + section->output_offset
> +			  + section->size);
>   
>         if (csect_last_vma - section_vma + (1 << 25) < 2 * (1 << 25)
>   	  && section_last_vma - csect_vma + (1 << 25) < 2 * (1 << 25))
> @@ -4703,7 +4704,7 @@ xcoff_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
>         BFD_ASSERT (hstub->htarget->toc_section != NULL);
>         /* The first instruction in the stub code needs to be
>   	 cooked to hold the correct offset in the toc.  It will
> -         be filled by xcoff_stub_create_relocations.  */
> +	 be filled by xcoff_stub_create_relocations.  */
>         for (i = 0; i < bfd_xcoff_stub_indirect_call_size(output_bfd) / 4; i++)
>   	bfd_put_32 (stub_bfd,
>   		    (bfd_vma) bfd_xcoff_stub_indirect_call_code(output_bfd, i),
> @@ -4714,7 +4715,7 @@ xcoff_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
>         BFD_ASSERT (hstub->htarget->toc_section != NULL);
>         /* The first instruction in the glink code needs to be
>   	 cooked to hold the correct offset in the toc.  It will
> -         be filled by xcoff_stub_create_relocations.  */
> +	 be filled by xcoff_stub_create_relocations.  */
>         for (i = 0; i < bfd_xcoff_stub_shared_call_size(output_bfd) / 4; i++)
>   	bfd_put_32 (stub_bfd,
>   		    (bfd_vma) bfd_xcoff_stub_shared_call_code(output_bfd, i),
> @@ -4871,7 +4872,7 @@ bfd_xcoff_size_stubs (struct bfd_link_info *info)
>   		      _bfd_error_handler (_("%pB: Unable to find a stub csect in range"
>   					    "of relocation at %#" PRIx64 " targeting"
>   					    "'%s'"),
> -					  section->owner, irel->r_vaddr,
> +					  section->owner, (uint64_t) irel->r_vaddr,
>   					  hsym->root.root.string);
>   		      goto error_ret;
>   		    }
> @@ -4896,10 +4897,10 @@ bfd_xcoff_size_stubs (struct bfd_link_info *info)
>   		  hstub = xcoff_add_stub (stub_name, hstub_csect, hsym, info, stub_type);
>   		  if (hstub == NULL)
>   		    {
> -		      free (stub_name);
>   		      /* xgettext:c-format */
>   		      _bfd_error_handler (_("%pB: Cannot create stub entry '%s'"),
>   					  section->owner, stub_name);
> +		      free (stub_name);
>   		      goto error_ret;
>   		    }
>   
> @@ -4999,7 +5000,7 @@ xcoff_stub_create_relocations (struct bfd_hash_entry *bh, void * inf)
>         return false;
>   
>         /* The first instruction of this stub code need
> -         a R_TOC relocation.  */
> +	 a R_TOC relocation.  */
>       case xcoff_stub_indirect_call:
>       case xcoff_stub_shared_call:
>         irel->r_size = 0xf;
> 
> 

Thanks Alan.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] xcoff: implement linker  relaxation
  2022-04-20 14:32       ` Alan Modra
  2022-04-20 14:36         ` Luis Machado
@ 2022-04-21 14:47         ` pro
  1 sibling, 0 replies; 8+ messages in thread
From: pro @ 2022-04-21 14:47 UTC (permalink / raw)
  To: Alan Modra; +Cc: Nick Clifton, Ayappan P2, Kavana N Bhat, binutils


> > Hi Clément,
> >
> > > As I said to the previous patch, I can't do it right now. Thus, if you find a bit of time I woudl be grateful if you can make these changes yourself and apply the patch for me.
> >
> > Patch applied
> 
> And a few fixes.

Thanks a lot for the help guys ! 

Clément

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-04-21 14:47 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-17 15:01 [PATCH 2/2] xcoff: implement linker relaxation CHIGOT, CLEMENT
2022-04-13 16:32 ` Nick Clifton
2022-04-20  9:52   ` pro
2022-04-20 14:13     ` Nick Clifton
2022-04-20 14:27       ` Luis Machado
2022-04-20 14:32       ` Alan Modra
2022-04-20 14:36         ` Luis Machado
2022-04-21 14:47         ` pro

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).