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]

RFA: gas-arm: maintain literal pools on a per section/per-subsection basis


Hi Guys,

  Attached below is a patch that changes GAS for ARM so that it
  maintains a separate literal pool for each section and each
  subsection (if they are needed).  This means that code like this:

	.text 0
	ldr r0, =message

	.text 1
	.ltorg       @ dump sub-section 1 literals
     message:
	.asciz "Message"

	.text 0
	.ltorg       @ dump sub-section 0 literals
     table:
	.space 4096

  will assemble correctly instead of reporting:

    Error: invalid literal constant: pool needs to be closer

  The problem is that with the current code the literal pool
  containing the address of 'message' is dumped at the start of
  sub-section 1 of the .text section because of the first .ltorg
  directive, instead of in the middle of sub-section 0 of .text
  section, because of the second .ltorg directive.  Since sub-section
  1 is only emitted after the end of sub-section 0, and sub-section 0
  has a great big '.space 4096' directive in it, the literal pool
  is dumped too far away.

  What might be controversial about this patch however, and the reason
  why I am asking for comments first, is that it also changes the
  default behavior of the assembler so that the literal pool is no
  longer automatically dumped upon section change, but instead only
  when a .ltorg directive is encountered, or at the end of input.
  This makes more sense, since it allows the programmer complete
  control over where the literal pools will be placed.

  The old behavior - dumping literal pools on section change - can be
  restored via a (new) command line switch -mimplicit-litpool-dump.
  The reason for the old behavior was because of an attempt to be
  compatible with ARM's assembler.  The ARM assembler however, can
  have only one occurrence of a section with a given name per source
  file.  Hence it only needs to maintain one literal pool and it knows
  that it is safe to dump it as soon as a section change occurs. GAS,
  on the other hand, allows multiple occurrences of a section within
  a given source file and simply concatenates the contents from each
  occurrence.  Thus each section needs its own, independently
  maintained literal pool.

  So - any comments on, or objections to this patch ?

Cheers
        Nick

2002-07-26  Nick Clifton  <nickc@redhat.com>

	* config/tc-arm.c (struct literal_pool): Add fields to allow
	multiple literal pools to be maintained.
        (dump_lit_pool_on_section_change): New variable.
	(find_literal_pool): New function.
	(find_or_make_literal_pool): New function.
	(add_to_literal_pool): Use find_or_make_literal_pool.
        (arm_s_text): Test dump_lit_pool_on_section_change.
        (arm_s_data): Test dump_lit_pool_on_section_change.
        (arm_s_section): Test dump_lit_pool_on_section_change.
	(s_ltorg): Use find_literal_pool.
	(arm_cleanup): Dump all literal pools.
        (arm_opts[]): Add -mimplicit-litpool-dump and
	-mno-implicit-litpool-dump.
        * doc/c-arm.texi: Document -mimplicit-litpool-dump and
	-mno-implicit-litpool-dump.
        * doc/as.texinfo: Mention -mimplicit-litpool-dump and
	-mno-implicit-litpool-dump.

Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.c,v
retrieving revision 1.124
diff -c -3 -p -w -r1.124 tc-arm.c
*** gas/config/tc-arm.c	8 Jun 2002 07:37:15 -0000	1.124
--- gas/config/tc-arm.c	26 Jul 2002 15:20:48 -0000
*************** const pseudo_typeS md_pseudo_table[] =
*** 2095,2101 ****
  #ifdef OBJ_ELF
    { "word",        s_arm_elf_cons, 4 },
    { "long",        s_arm_elf_cons, 4 },
!   { "file",        dwarf2_directive_file, 0 },
    { "loc",         dwarf2_directive_loc,  0 },
  #else
    { "word",        cons, 4},
--- 2095,2101 ----
  #ifdef OBJ_ELF
    { "word",        s_arm_elf_cons, 4 },
    { "long",        s_arm_elf_cons, 4 },
!   { "file",        (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
    { "loc",         dwarf2_directive_loc,  0 },
  #else
    { "word",        cons, 4},
*************** static int arm_parse_fpu PARAMS ((char *
*** 2125,2197 ****
  symbolS *  last_label_seen;
  static int label_is_thumb_function_name = false;
  
! /* Literal stuff.  */
  
  #define MAX_LITERAL_POOL_SIZE 1024
  
! typedef struct literalS
  {
!   struct expressionS exp;
!   struct arm_it *    inst;
! } literalT;
  
! literalT literals[MAX_LITERAL_POOL_SIZE];
  
! /* Next free entry in the pool.  */
! int next_literal_pool_place = 0;
  
! /* Next literal pool number.  */
! int lit_pool_num = 1;
  
! symbolS * current_poolP = NULL;
  
  static int
  add_to_lit_pool ()
  {
!   int lit_count = 0;
  
!   if (current_poolP == NULL)
!     current_poolP = symbol_create (FAKE_LABEL_NAME, undefined_section,
! 				   (valueT) 0, &zero_address_frag);
  
!   /* Check if this literal value is already in the pool:  */
!   while (lit_count < next_literal_pool_place)
      {
!       if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op
! 	  && inst.reloc.exp.X_op == O_constant
! 	  && (literals[lit_count].exp.X_add_number
  	      == inst.reloc.exp.X_add_number)
! 	  && literals[lit_count].exp.X_unsigned == inst.reloc.exp.X_unsigned)
  	break;
  
!       if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op
! 	  && inst.reloc.exp.X_op == O_symbol
! 	  && (literals[lit_count].exp.X_add_number
  	      == inst.reloc.exp.X_add_number)
! 	  && (literals[lit_count].exp.X_add_symbol
  	      == inst.reloc.exp.X_add_symbol)
! 	  && (literals[lit_count].exp.X_op_symbol
  	      == inst.reloc.exp.X_op_symbol))
  	break;
- 
-       lit_count++;
      }
  
!   if (lit_count == next_literal_pool_place) /* New entry.  */
      {
!       if (next_literal_pool_place >= MAX_LITERAL_POOL_SIZE)
  	{
! 	  inst.error = _("literal pool overflow");
  	  return FAIL;
  	}
  
!       literals[next_literal_pool_place].exp = inst.reloc.exp;
!       lit_count = next_literal_pool_place++;
      }
  
    inst.reloc.exp.X_op = O_symbol;
!   inst.reloc.exp.X_add_number = (lit_count) * 4 - 8;
!   inst.reloc.exp.X_add_symbol = current_poolP;
  
    return SUCCESS;
  }
--- 2125,2274 ----
  symbolS *  last_label_seen;
  static int label_is_thumb_function_name = false;
  
! /* Literal Pool stuff.  */
  
  #define MAX_LITERAL_POOL_SIZE 1024
  
! /* Literal pool structure.  Held on a per-section
!    and per-sub-section basis.  */
! typedef struct literal_pool
  {
!   expressionS    literals [MAX_LITERAL_POOL_SIZE];
!   unsigned int   next_free_entry;
!   unsigned int   id;
!   symbolS *      symbol;
!   segT           section;
!   subsegT        sub_section;
!   struct literal_pool * next;  
! } literal_pool;
  
! /* Pointer to a linked list of literal pools.  */
! literal_pool * list_of_pools = NULL;
  
! /* True if the current literal pool should automatically be dumped
!    when a section change occurs.  This is the default behaviour for
!    older versions of arm-gas but newer versions only enable this
!    via command line switch -mimplicit-litpool-dump.  The new
!    scheme allows the assembly programmer complete control over
!    where the literal pools are place in the output.
  
!    The reason for the old behavior (dumping the pool on section
!    change) was because of an attempt to be compatible with ARM's
!    own assembler.  The ARM assembler however, can have only one
!    occurence of a section with a given name per source file.  Hence
!    it only needs to maintain one literal pool and it knows that it
!    is safe to dump it as soon as a section change occurs. GAS, on
!    the other hand, allows multiple ocurrences of a section within
!    a given source file and simply concatenates the contents from
!    each ocurrence.  Thus the placement of the literal pool needs
!    to be under the control of the programmer, or happen automatically
!    only at the end of the source file.  */
! static int dump_lit_pool_on_section_change;
     
! static literal_pool * find_literal_pool PARAMS ((void));
! static literal_pool * find_or_make_literal_pool PARAMS ((void));
  
+ static literal_pool *
+ find_literal_pool ()
+ {
+   literal_pool * pool;
+ 
+   for (pool = list_of_pools; pool != NULL; pool = pool->next)
+     {
+       if (pool->section == now_seg
+ 	  && pool->sub_section == now_subseg)
+ 	break;
+     }
+ 
+   return pool;
+ }
+ 
+ static literal_pool *
+ find_or_make_literal_pool ()
+ {
+   /* Next literal pool ID number.  */
+   static unsigned int latest_pool_num = 1;
+   literal_pool *      pool;
+ 
+   pool = find_literal_pool ();
+ 
+   if (pool == NULL)
+     {
+       /* Create a new pool.  */
+       pool = (literal_pool *) xmalloc (sizeof (* pool));
+       if (! pool)
+ 	return NULL;
+ 
+       pool->next_free_entry = 0;
+       pool->section         = now_seg;
+       pool->sub_section     = now_subseg;
+       pool->next            = list_of_pools;
+       pool->symbol          = NULL;
+ 
+       /* Add it to the list.  */
+       list_of_pools = pool;
+     }
+ 
+   /* New pools, and emptied pools, will have a NULL symbol.  */
+   if (pool->symbol == NULL)
+     {
+       pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
+ 				    (valueT) 0, &zero_address_frag);
+       pool->id = latest_pool_num ++;
+     }
+ 
+   /* Done.  */
+   return pool;
+ }
+ 
+ /* Add the literal in the global 'inst'
+    structure to the relevent literal pool.  */
  static int
  add_to_lit_pool ()
  {
!   literal_pool * pool;  
!   unsigned int entry;
  
!   pool = find_or_make_literal_pool ();
  
!   /* Check if this literal value is already in the pool.  */
!   for (entry = 0; entry < pool->next_free_entry; entry ++)
      {
!       if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
! 	  && (inst.reloc.exp.X_op == O_constant)
! 	  && (pool->literals[entry].X_add_number
  	      == inst.reloc.exp.X_add_number)
! 	  && (pool->literals[entry].X_unsigned
! 	      == inst.reloc.exp.X_unsigned))
  	break;
  
!       if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
!           && (inst.reloc.exp.X_op == O_symbol)
!           && (pool->literals[entry].X_add_number
  	      == inst.reloc.exp.X_add_number)
!           && (pool->literals[entry].X_add_symbol
  	      == inst.reloc.exp.X_add_symbol)
!           && (pool->literals[entry].X_op_symbol
  	      == inst.reloc.exp.X_op_symbol))
          break;
      }
  
!   /* Do we need to create a new entry?  */
!   if (entry == pool->next_free_entry)
      {
!       if (entry >= MAX_LITERAL_POOL_SIZE)
  	{
! 	  inst.error = _("Literal Pool Overflow");
  	  return FAIL;
  	}
  
!       pool->literals[entry] = inst.reloc.exp;
!       pool->next_free_entry += 1;
      }
  
    inst.reloc.exp.X_op         = O_symbol;
!   inst.reloc.exp.X_add_number = (entry) * 4 - 8;
!   inst.reloc.exp.X_add_symbol = pool->symbol;
  
    return SUCCESS;
  }
*************** static void
*** 2353,2362 ****
  s_ltorg (ignored)
       int ignored ATTRIBUTE_UNUSED;
  {
!   int lit_count = 0;
    char sym_name[20];
  
!   if (current_poolP == NULL)
      return;
  
    /* Align pool as you have word accesses.
--- 2430,2443 ----
  s_ltorg (ignored)
       int ignored ATTRIBUTE_UNUSED;
  {
!   unsigned int entry;
!   literal_pool * pool;
    char sym_name[20];
  
!   pool = find_literal_pool ();
!   if (pool == NULL
!       || pool->symbol == NULL
!       || pool->next_free_entry == 0)
      return;
  
    /* Align pool as you have word accesses.
*************** s_ltorg (ignored)
*** 2366,2389 ****
  
    record_alignment (now_seg, 2);
  
!   sprintf (sym_name, "$$lit_\002%x", lit_pool_num++);
  
!   symbol_locate (current_poolP, sym_name, now_seg,
  		 (valueT) frag_now_fix (), frag_now);
!   symbol_table_insert (current_poolP);
  
!   ARM_SET_THUMB (current_poolP, thumb_mode);
  
  #if defined OBJ_COFF || defined OBJ_ELF
!   ARM_SET_INTERWORK (current_poolP, support_interwork);
  #endif
  
!   while (lit_count < next_literal_pool_place)
      /* First output the expression in the instruction to the pool.  */
!     emit_expr (&(literals[lit_count++].exp), 4); /* .word  */
  
!   next_literal_pool_place = 0;
!   current_poolP = NULL;
  }
  
  /* Same as s_align_ptwo but align 0 => align 2.  */
--- 2447,2471 ----
  
    record_alignment (now_seg, 2);
  
!   sprintf (sym_name, "$$lit_\002%x", pool->id);
  
!   symbol_locate (pool->symbol, sym_name, now_seg,
  		 (valueT) frag_now_fix (), frag_now);
!   symbol_table_insert (pool->symbol);
  
!   ARM_SET_THUMB (pool->symbol, thumb_mode);
  
  #if defined OBJ_COFF || defined OBJ_ELF
!   ARM_SET_INTERWORK (pool->symbol, support_interwork);
  #endif
  
!   for (entry = 0; entry < pool->next_free_entry; entry ++)
      /* First output the expression in the instruction to the pool.  */
!     emit_expr (&(pool->literals[entry]), 4); /* .word  */
  
!   /* Mark the pool as empty.  */
!   pool->next_free_entry = 0;
!   pool->symbol = NULL;
  }
  
  /* Same as s_align_ptwo but align 0 => align 2.  */
*************** static void
*** 2556,2562 ****
  arm_s_text (ignore)
       int ignore;
  {
!   if (now_seg != text_section)
      s_ltorg (0);
  
  #ifdef OBJ_ELF
--- 2638,2645 ----
  arm_s_text (ignore)
       int ignore;
  {
!   if (now_seg != text_section
!       && dump_lit_pool_on_section_change)
      s_ltorg (0);
  
  #ifdef OBJ_ELF
*************** static void
*** 2570,2575 ****
--- 2653,2660 ----
  arm_s_data (ignore)
       int ignore;
  {
+   if (dump_lit_pool_on_section_change)
+     {
        if (flag_readonly_data_in_text)
  	{
  	  if (now_seg != text_section)
*************** arm_s_data (ignore)
*** 2577,2582 ****
--- 2662,2668 ----
  	}
        else if (now_seg != data_section)
  	s_ltorg (0);
+     }
  
  #ifdef OBJ_ELF
    obj_elf_data (ignore);
*************** static void
*** 2589,2594 ****
--- 2675,2681 ----
  arm_s_section (ignore)
       int ignore;
  {
+   if (dump_lit_pool_on_section_change)
      s_ltorg (0);
  
  #ifdef OBJ_ELF
*************** tc_gen_reloc (section, fixp)
*** 10254,10263 ****
  
      case BFD_RELOC_ARM_LITERAL:
      case BFD_RELOC_ARM_HWLITERAL:
!       /* If this is called then the a literal has been referenced across
! 	 a section boundary - possibly due to an implicit dump.  */
        as_bad_where (fixp->fx_file, fixp->fx_line,
  		    _("literal referenced across section boundary (Implicit dump?)"));
        return NULL;
  
  #ifdef OBJ_ELF
--- 10341,10356 ----
  
      case BFD_RELOC_ARM_LITERAL:
      case BFD_RELOC_ARM_HWLITERAL:
!       /* If this is called then the a literal has
! 	 been referenced across a section boundary.  */
!       if (dump_lit_pool_on_section_change)
! 	/* This might have ahppened because the literal was
! 	   dumped into a pool when a section change occured.  */
  	as_bad_where (fixp->fx_file, fixp->fx_line,
  		      _("literal referenced across section boundary (Implicit dump?)"));
+       else
+         as_bad_where (fixp->fx_file, fixp->fx_line,
+ 		      _("Literal referenced across section boundary"));	
        return NULL;
  
  #ifdef OBJ_ELF
*************** md_assemble (str)
*** 10504,10511 ****
  	      -k			 Generate PIC code
  	      -mthumb			 Start in Thumb mode
  	      -mthumb-interwork		 Code supports ARM/Thumb interworking
  
!       For now we will also provide support for
  
  	      -mapcs-32			 32-bit Program counter
  	      -mapcs-26			 26-bit Program counter
--- 10597,10605 ----
  	      -k			 Generate PIC code
  	      -mthumb			 Start in Thumb mode
  	      -mthumb-interwork		 Code supports ARM/Thumb interworking
+ 	      -mimplicit-litpool-dump    Dump literal pool on section change
  
!       For now we will also provide support for:
  
  	      -mapcs-32			 32-bit Program counter
  	      -mapcs-26			 26-bit Program counter
*************** struct arm_option_table arm_opts[] =
*** 10598,10603 ****
--- 10692,10704 ----
    {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 1,
     NULL},
  
+   {"mimplicit-litpool-dump",
+    N_("Automatically dump the literal pool on section change"),
+    & dump_lit_pool_on_section_change, 1, NULL},
+   {"mno-implicit-litpool-dump",
+    N_("Automatically dump the literal pool on section change"),
+    & dump_lit_pool_on_section_change, 0, NULL},
+   
    /* These are recognized by the assembler, but have no affect on code.  */
    {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL},
    {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL},
*************** cons_fix_new_arm (frag, where, size, exp
*** 11210,11221 ****
  void
  arm_cleanup ()
  {
!   if (current_poolP == NULL)
!     return;
  
!   /* Put it at the end of text section.  */
!   subseg_set (text_section, 0);
    s_ltorg (0);
  }
  
  void
--- 11311,11324 ----
  void
  arm_cleanup ()
  {
!   literal_pool * pool;
  
!   for (pool = list_of_pools; pool; pool = pool->next)
!     {
!       /* Put it at the end of the relevent section.  */
!       subseg_set (pool->section, pool->sub_section);
        s_ltorg (0);
+     }
  }
  
  void
Index: gas/doc/c-arm.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-arm.texi,v
retrieving revision 1.15
diff -c -3 -p -w -r1.15 c-arm.texi
*** gas/doc/c-arm.texi	21 Jan 2002 00:20:58 -0000	1.15
--- gas/doc/c-arm.texi	26 Jul 2002 15:20:48 -0000
*************** conventions, based on a beta release rel
*** 228,233 ****
--- 228,248 ----
  specifications, rather than the default conventions which are based on
  the final release of the ARM-ELF specifications.
  
+ @cindex @code{-mimplicit-litpool-dump} command line option, ARM
+ @item -mimplicit-pool-dump
+ This indicates that the current literal pool should be dumped
+ whenever a section change occurs.  This was the default behavior of
+ earlier versions of the assembler.
+ 
+ @cindex @code{-mno-implicit-litpool-dump} command line option, ARM
+ @item -mno-implicit-pool-dump
+ This restores the default behavior of the assembler.  Literal pools
+ will be accumulated on a per section and per sub-section basis and
+ only dumped when a @code{.ltorg} directive is encountered in the
+ relevant section/sub-section.  If there are any non-empty literal
+ pools at the of assembly they will be dumped at the end of their
+ relevant sections/sub-sections.
+ 
  @end table
  
  
Index: gas/doc/as.texinfo
===================================================================
RCS file: /cvs/src/src/gas/doc/as.texinfo,v
retrieving revision 1.69
diff -c -3 -p -w -r1.69 as.texinfo
*** gas/doc/as.texinfo	22 Jul 2002 19:04:28 -0000	1.69
--- gas/doc/as.texinfo	26 Jul 2002 15:20:50 -0000
*************** gcc(1), ld(1), and the Info entries for 
*** 296,301 ****
--- 296,302 ----
     [@b{-mapcs-32}|@b{-mapcs-26}|@b{-mapcs-float}|
      @b{-mapcs-reentrant}]
     [@b{-mthumb-interwork}] [@b{-moabi}] [@b{-k}]
+    [@b{-mimplicit-litpool-dump}|@b{-mno-implicit-litpool-dump}]
  @end ifset
  @ifset CRIS
  
*************** Specify that the code has been generated
*** 621,626 ****
--- 622,629 ----
  ARM code in mind.
  @item -k
  Specify that PIC code has been generated.
+ @item -mimplicit-litpool-dump
+ Cause the literal pool to be dumped every time a section change occurs.
  @end table
  @end ifset
  


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