This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

[PATCH] ARM: Handle Thumb call-indirect in an EABI-compliant manner


This patch is really for EABI compliance, but it also fixes PR 7525.

The EABI requires that a strictly conforming object should not rely on
compiler helper functions that are not part of the standard list
(strictly speaking it just requires that any functions it does use must
be freely redistributable with the object, but we really don't want to
be doing that unless it's really necessary, and in this case it isn't).

The Thumb instruction set in v4t does not have a call-indirect
instruction (v5t does, blx <reg>), and what is more, an ARM-style
sequence, like

	mov	lr, pc
	bx	reg

does not work because the Thumb bit is stripped from the return address
by the mov.  The previous solution to this was to call a stub library
function (a trampoline) using a normal bl instruction.  That trampoline
could then safely do the bx <reg> since the bl instruction will have
already established the return value in lr.

However, given that there is no such function in the portable library,
we need another way.  The solution adopted here is to embed the
trampolines into object files that need them; we can then use local
branches to the targets and avoid any problems with reachability as well
as with names.

To avoid excessive code bloat we try to optimize the number of
trampolines we emit; for code that is emitted in text_section() we can
just emit one trampoline per file per register used for indirect
calling.  For code that is emitted into a named section we have to be
more careful to ensure that the stub remains reachable, in this case we
emit one stub per function.

Tested on arm-elf with no regressions in the compiler.  There are two
regressions triggered in GDB, but these appear to be the debugger
failing to detect the new trampoline sequence.

R.

2005-01-14  Richard Earnshaw  <rearnsha@arm.com>

	PR target/7525
	* arm.h (struct machine_function): Add call_via field.
	(thumb_call_via_label): Declare.
	* arm.c (thumb_call_via_label): New variable.
	(thumb_call_reg_needed): New variable.
	(arm_output_function_epilogue): For Thumb code, output any per-function
	call-indirect trampolines.
	(thumb_call_via_reg): New function.
	(arm_file_end): New function.
	(TARGET_ASM_FILE_END): Call arm_file_end.
	(aof_file_end): Likewise.
	* arm-protos.h (thumb_call_via_reg): Declare.
	* arm.md (call_reg_thumb, call_value_reg_thumb): Call 
	thumb_call_via_reg in normal case.


Index: arm-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm-protos.h,v
retrieving revision 1.79
diff -p -r1.79 arm-protos.h
*** arm-protos.h	20 Nov 2004 11:21:51 -0000	1.79
--- arm-protos.h	14 Jan 2005 12:46:35 -0000
*************** extern int thumb_shiftable_const (unsign
*** 150,155 ****
--- 150,156 ----
  extern void thumb_final_prescan_insn (rtx);
  extern const char *thumb_load_double_from_address (rtx *);
  extern const char *thumb_output_move_mem_multiple (int, rtx *);
+ extern const char *thumb_call_via_reg (rtx);
  extern void thumb_expand_movmemqi (rtx *);
  extern rtx *thumb_legitimize_pic_address (rtx, enum machine_mode, rtx);
  extern int thumb_go_if_legitimate_address (enum machine_mode, rtx);
Index: arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.426
diff -p -r1.426 arm.c
*** arm.c	5 Jan 2005 18:53:08 -0000	1.426
--- arm.c	14 Jan 2005 12:46:36 -0000
*************** static int arm_arg_partial_bytes (CUMULA
*** 153,158 ****
--- 153,161 ----
  #ifndef ARM_PE
  static void arm_encode_section_info (tree, rtx, int);
  #endif
+ 
+ static void arm_file_end (void);
+ 
  #ifdef AOF_ASSEMBLER
  static void aof_globalize_label (FILE *, const char *);
  static void aof_dump_imports (FILE *);
*************** static unsigned HOST_WIDE_INT arm_shift_
*** 188,193 ****
--- 191,199 ----
  #undef  TARGET_ATTRIBUTE_TABLE
  #define TARGET_ATTRIBUTE_TABLE arm_attribute_table
  
+ #undef TARGET_ASM_FILE_END
+ #define TARGET_ASM_FILE_END arm_file_end
+ 
  #ifdef AOF_ASSEMBLER
  #undef  TARGET_ASM_BYTE_OP
  #define TARGET_ASM_BYTE_OP "\tDCB\t"
*************** const char * target_abi_name = NULL;
*** 366,371 ****
--- 372,381 ----
  const char * structure_size_string = NULL;
  int    arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
  
+ /* Used for Thumb call_via trampolines.  */
+ rtx thumb_call_via_label[13];
+ static int thumb_call_reg_needed;
+ 
  /* Bit values used to identify processor capabilities.  */
  #define FL_CO_PROC    (1 << 0)        /* Has external co-processor bus */
  #define FL_ARCH3M     (1 << 1)        /* Extended multiply */
*************** arm_output_function_epilogue (FILE *file
*** 9600,9605 ****
--- 9610,9632 ----
  
    if (TARGET_THUMB)
      {
+       int regno;
+ 
+       /* Emit any call-via-reg trampolines that are needed for v4t support
+ 	 of call_reg and call_value_reg type insns.  */
+       for (regno = 0; regno < SP_REGNUM; regno++)
+ 	{
+ 	  rtx label = cfun->machine->call_via[regno];
+ 
+ 	  if (label != NULL)
+ 	    {
+ 	      function_section (current_function_decl);
+ 	      targetm.asm_out.internal_label (asm_out_file, "L",
+ 					      CODE_LABEL_NUMBER (label));
+ 	      asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
+ 	    }
+ 	}
+ 
        /* ??? Probably not safe to set this here, since it assumes that a
  	 function will be emitted as assembly immediately after we generate
  	 RTL for it.  This does not happen for inline functions.  */
*************** thumb_output_move_mem_multiple (int n, r
*** 13652,13657 ****
--- 13679,13715 ----
    return "";
  }
  
+ /* Output a call-via instruction for thumb state.  */
+ const char *
+ thumb_call_via_reg (rtx reg)
+ {
+   int regno = REGNO (reg);
+   rtx *labelp;
+ 
+   gcc_assert (regno < SP_REGNUM);
+ 
+   /* If we are in the normal text section we can use a single instance
+      per compilation unit.  If we are doing function sections, then we need
+      an entry per section, since we can't rely on reachability.  */
+   if (in_text_section ())
+     {
+       thumb_call_reg_needed = 1;
+ 
+       if (thumb_call_via_label[regno] == NULL)
+ 	thumb_call_via_label[regno] = gen_label_rtx ();
+       labelp = thumb_call_via_label + regno;
+     }
+   else
+     {
+       if (cfun->machine->call_via[regno] == NULL)
+ 	cfun->machine->call_via[regno] = gen_label_rtx ();
+       labelp = cfun->machine->call_via + regno;
+     }
+ 
+   output_asm_insn ("bl\t%a0", labelp);
+   return "";
+ }
+ 
  /* Routines for generating rtl.  */
  void
  thumb_expand_movmemqi (rtx *operands)
*************** arm_asm_output_labelref (FILE *stream, c
*** 13762,13767 ****
--- 13820,13850 ----
      asm_fprintf (stream, "%U%s", name);
  }
  
+ static void
+ arm_file_end (void)
+ {
+   int regno;
+ 
+   if (! thumb_call_reg_needed)
+     return;
+ 
+   text_section ();
+   asm_fprintf (asm_out_file, "\t.code 16\n");
+   ASM_OUTPUT_ALIGN (asm_out_file, 1);
+ 
+   for (regno = 0; regno < SP_REGNUM; regno++)
+     {
+       rtx label = thumb_call_via_label[regno];
+ 
+       if (label != 0)
+ 	{
+ 	  targetm.asm_out.internal_label (asm_out_file, "L",
+ 					  CODE_LABEL_NUMBER (label));
+ 	  asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
+ 	}
+     }
+ }
+ 
  rtx aof_pic_label;
  
  #ifdef AOF_ASSEMBLER
*************** aof_file_end (void)
*** 13958,13963 ****
--- 14041,14047 ----
  {
    if (flag_pic)
      aof_dump_pic_table (asm_out_file);
+   arm_file_end ();
    aof_dump_imports (asm_out_file);
    fputs ("\tEND\n", asm_out_file);
  }
Index: arm.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.264
diff -p -r1.264 arm.h
*** arm.h	5 Jan 2005 11:56:24 -0000	1.264
--- arm.h	14 Jan 2005 12:46:37 -0000
*************** typedef struct machine_function GTY(())
*** 1703,1711 ****
--- 1703,1718 ----
    /* Records if sibcalls are blocked because an argument
       register is needed to preserve stack alignment.  */
    int sibcall_blocked;
+   /* Labels for per-function Thumb call-via stubs.  One per potential calling
+      register.  We can never call via SP, LR or PC.  */
+   rtx call_via[13];
  }
  machine_function;
  
+ /* As in the machine_function, a global set of call-via labels, for code 
+    that is in text_section().  */
+ extern GTY(()) rtx thumb_call_via_label[13];
+ 
  /* A C type for declaring a variable that is used as the first argument of
     `FUNCTION_ARG' and other related values.  For some target machines, the
     type `int' suffices and can hold the number of bytes of argument so far.  */
Index: arm.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.188
diff -p -r1.188 arm.md
*** arm.md	15 Dec 2004 14:03:58 -0000	1.188
--- arm.md	14 Jan 2005 12:46:38 -0000
***************
*** 7436,7442 ****
    "*
    {
      if (!TARGET_CALLER_INTERWORKING)
!       return \"bl\\t%__call_via_%0\";
      else if (operands[1] == const0_rtx)
        return \"bl\\t%__interwork_call_via_%0\";
      else if (frame_pointer_needed)
--- 7436,7442 ----
    "*
    {
      if (!TARGET_CALLER_INTERWORKING)
!       return thumb_call_via_reg (operands[0]);
      else if (operands[1] == const0_rtx)
        return \"bl\\t%__interwork_call_via_%0\";
      else if (frame_pointer_needed)
***************
*** 7530,7536 ****
    "*
    {
      if (!TARGET_CALLER_INTERWORKING)
!       return \"bl\\t%__call_via_%1\";
      else if (operands[2] == const0_rtx)
        return \"bl\\t%__interwork_call_via_%1\";
      else if (frame_pointer_needed)
--- 7530,7536 ----
    "*
    {
      if (!TARGET_CALLER_INTERWORKING)
!       return thumb_call_via_reg (operands[1]);
      else if (operands[2] == const0_rtx)
        return \"bl\\t%__interwork_call_via_%1\";
      else if (frame_pointer_needed)

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