[PATCH, arm] ASM_OUTPUT_MI_THUNK on Thumb

Adam Nemet anemet@Lnxw.COM
Mon Oct 21 22:23:00 GMT 2002


Hi,

Linking the C++ testcase below fails with relocation truncated for
Thumb.  This is due to the fact that on Thumb, the branch to immediate
instrunction ranges +/-2Kb from the current instruction
(R_ARM_THM_PC11) and that is not too hard to exceed.  If the size of
the function is larger than 2Kb and since the thunk is emitted after
the function, the branch to immediate instrunction will not work.

Another related bug fix in ASM_OUTPUT_MI_THUNK is that it appended
`(PLT)' to the function symbol in the Thumb case as well where that
led to an assembly error.

In this patch I split the relevant part of ASM_OUTPUT_MI_THUNK into
ARM_ASM_OUTPUT_MI_THUNK_JUMP and THUMB_ASM_OUTPUT_MI_THUNK_JUMP and
use an indirect jump in the Thumb case.

I also considered switching to ARM and branching in ARM mode for the
Thumb version as well but that resulted in a bigger thunk (20 bytes)
so I rejected that idea.

The patch was reg-tested on arm-elf with both -marm and -mthumb.

I am not sure if it is worthwile to add the testcase to the testsuite.

Please apply if OK.

Adam

struct A {
  int i;
  virtual int Foo (void *p) {}
  virtual int Baz (void *p) {}
};

struct B1: virtual A {
  virtual int Foo (void *p) {}
};

struct B2: virtual A {
  virtual int Foo (void *p) {}
};

void f (int a, int b, int c, int d) {}
#define F1 f (1, 2, 3, 4)
#define F2 F1;F1;F1;F1;F1;F1;F1;F1
#define F3 F2;F2;F2;F2;F2;F2;F2;F2

struct C : B1, B2 {
  virtual int Foo (void *p) { F3; F3; F3; }
};


int main()
{
  C c;
  return 0;
}

2002-10-21  Adam Nemet  <anemet@lnxw.com>

	* config/arm/arm.h (ASM_OUTPUT_MI_THUNK_JUMP): New macro.
	(ASM_OUTPUT_MI_THUNK): Use it.
	(ARM_ASM_OUTPUT_MI_THUNK_JUMP): New macro.
	(THUMB_ASM_OUTPUT_MI_THUNK_JUMP): New macro.

Index: arm.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.164
diff -c -p -r1.164 arm.h
*** arm.h	30 Sep 2002 11:18:38 -0000	1.164
--- arm.h	22 Oct 2002 04:09:10 -0000
*************** extern int making_const_table;
*** 2695,2732 ****
    else						\
      THUMB_PRINT_OPERAND_ADDRESS (STREAM, X)
       
! /* Output code to add DELTA to the first argument, and then jump to FUNCTION.
!    Used for C++ multiple inheritance.  */
! #define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION)		\
!   do										\
!     {										\
!       int mi_delta = (DELTA);							\
!       const char *const mi_op = mi_delta < 0 ? "sub" : "add";			\
!       int shift = 0;								\
!       int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION)))	\
! 		        ? 1 : 0);						\
!       if (mi_delta < 0)								\
!         mi_delta = - mi_delta;							\
!       while (mi_delta != 0)							\
!         {									\
!           if ((mi_delta & (3 << shift)) == 0)					\
! 	    shift += 2;								\
!           else									\
! 	    {									\
! 	      asm_fprintf (FILE, "\t%s\t%r, %r, #%d\n",				\
! 		           mi_op, this_regno, this_regno,			\
! 		           mi_delta & (0xff << shift));				\
! 	      mi_delta &= ~(0xff << shift);					\
! 	      shift += 8;							\
! 	    }									\
!         }									\
!       fputs ("\tb\t", FILE);							\
!       assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0));		\
!       if (NEED_PLT_RELOC)							\
!         fputs ("(PLT)", FILE);							\
!       fputc ('\n', FILE);							\
!     }										\
    while (0)
  
  /* A C expression whose value is RTL representing the value of the return
     address for the frame COUNT steps up from the current frame.  */
--- 2695,2765 ----
    else						\
      THUMB_PRINT_OPERAND_ADDRESS (STREAM, X)
       
! /* Most of ASM_OUTPUT_MI_THUNK can be shared between ARM and Thumb.
!    The only difference is implemented by ASM_OUTPUT_MI_THUNK_JUMP
!    below.  */
! 
! #define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION)	\
!   do									\
!     {									\
!       int mi_delta = (DELTA);						\
!       const char *const mi_op = mi_delta < 0 ? "sub" : "add";		\
!       int shift = 0;							\
!       int this_regno =							\
! 	(aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) ? 1 : 0);	\
!       if (mi_delta < 0)							\
!         mi_delta = - mi_delta;						\
!       while (mi_delta != 0)						\
!         {								\
!           if ((mi_delta & (3 << shift)) == 0)				\
! 	    shift += 2;							\
!           else								\
! 	    {								\
! 	      asm_fprintf (FILE, "\t%s\t%r, %r, #%d\n",			\
! 		           mi_op, this_regno, this_regno,		\
! 		           mi_delta & (0xff << shift));			\
! 	      mi_delta &= ~(0xff << shift);				\
! 	      shift += 8;						\
! 	    }								\
!         }								\
!       ASM_OUTPUT_MI_THUNK_JUMP (FILE, FUNCTION);			\
!     }									\
    while (0)
+ 
+ #define ASM_OUTPUT_MI_THUNK_JUMP(FILE, FUNCTION)	\
+   if (TARGET_ARM)					\
+     ARM_ASM_OUTPUT_MI_THUNK_JUMP (FILE, FUNCTION);	\
+   else							\
+     THUMB_ASM_OUTPUT_MI_THUNK_JUMP (FILE, FUNCTION);
+ 
+ #define ARM_ASM_OUTPUT_MI_THUNK_JUMP(FILE, FUNCTION)			\
+   do									\
+     {									\
+       fputs ("\tb\t", FILE);						\
+       assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0));	\
+       if (NEED_PLT_RELOC)						\
+         fputs ("(PLT)", FILE);						\
+       fputc ('\n', FILE);						\
+     }									\
+   while (0)
+ 
+ /* Since on Thumb, branch to an immediate is limited to a 2Kb relative
+    range we have to use an indirect jump via IP.  */
+  
+ #define THUMB_ASM_OUTPUT_MI_THUNK_JUMP(FILE, FUNCTION)			\
+   do									\
+     {									\
+       asm_fprintf (FILE, "\tpush\t{%r}\n", 2);				\
+       asm_fprintf (FILE, "\tldr\t%r, [%r, #4]\n", 2, PC_REGNUM);	\
+       asm_fprintf (FILE, "\tmov\t%r, %r\n", IP_REGNUM, 2);		\
+       asm_fprintf (FILE, "\tpop\t{%r}\n", 2);				\
+       asm_fprintf (FILE, "\tbx\t%r\n", IP_REGNUM);			\
+       fputs ("\t.word\t", FILE);					\
+       assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0));	\
+       fputc ('\n', FILE);						\
+     }									\
+   while (0) 
+ 
  
  /* A C expression whose value is RTL representing the value of the return
     address for the frame COUNT steps up from the current frame.  */



More information about the Gcc-patches mailing list