changeset 83:ebe258a85813

toolchain: binutils patch to emit the "short" form of Thumb->ARM call veneers
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Mon, 19 Aug 2013 05:16:34 +0000
parents dd13211c9f10
children ccc5161848c7
files toolchain/binutils-patches/elf32-arm.patch toolchain/build+install.sh
diffstat 2 files changed, 64 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolchain/binutils-patches/elf32-arm.patch	Mon Aug 19 05:16:34 2013 +0000
@@ -0,0 +1,62 @@
+# The present patch to the ARM ELF linking code in binutils (made against
+# binutils-2.21.1a) is a hack that affects the generation of Thumb->ARM
+# call veneers.  The binutils linker can make these veneers in two forms:
+#
+#	"Short"			"Long"
+#	(16-bit) bx pc		(16-bit) bx pc
+#	(16-bit) nop		(16-bit) nop
+#	(32-bit) b dest		(32-bit) ldr pc, [pc, #-4]
+#				(32-bit) .long target
+#
+# For code that's going to run on the Calypso ARM7 processor, the
+# "short" form is the one we want: because of the way the address space
+# is laid out, the range of an ARM branch instruction will always be
+# sufficient for us, whereas the long version is more costly in terms
+# of the number of cycles required, especially when executing from
+# external memory.
+#
+# Unfortunately, the code which decides between these two forms
+# (located in the arm_type_of_stub() function in bfd/elf32-arm.c)
+# is broken.  The original code (which you can see below in the
+# "before" part of the patch hunk) exhibits two problems:
+#
+# 1. The distance that matters here is not from the original
+#    call point to the destination, but from the stub to
+#    the destination - and in this function we don't know
+#    where the stub will end up.
+#
+# 2. Because it's an ARM branch, the limits should be
+#    ARM_MAX_[BF]WD_BRANCH_OFFSET, not the THM_ ones.
+#
+# The 2nd problem would be trivial to fix, but the 1st one
+# much less so: this function doesn't know where the stub
+# will end up, and considering that for the present purpose
+# of the FreeCalypso project always emitting the "short"
+# version would be perfect, there is no justification for
+# expending the time and effort to restructure the linker
+# to do the proper relaxation for the case at hand.
+#
+# Therefore, the patch we apply is a hack: we simply force the
+# use of the "short" form unconditionally.
+
+*** elf32-arm.c	Wed May 11 07:29:12 2011
+--- elf32-arm-patched.c	Mon Aug 19 03:24:38 2013
+***************
+*** 3203,3211 ****
+  		   : arm_stub_long_branch_v4t_thumb_arm);
+  
+  	      /* Handle v4t short branches.  */
+! 	      if ((stub_type == arm_stub_long_branch_v4t_thumb_arm)
+! 		  && (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET)
+! 		  && (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET))
+  		stub_type = arm_stub_short_branch_v4t_thumb_arm;
+  	    }
+  	}
+--- 3203,3209 ----
+  		   : arm_stub_long_branch_v4t_thumb_arm);
+  
+  	      /* Handle v4t short branches.  */
+! 	      if (stub_type == arm_stub_long_branch_v4t_thumb_arm)
+  		stub_type = arm_stub_short_branch_v4t_thumb_arm;
+  	    }
+  	}
--- a/toolchain/build+install.sh	Sat Aug 17 19:29:48 2013 +0000
+++ b/toolchain/build+install.sh	Mon Aug 19 05:16:34 2013 +0000
@@ -33,6 +33,8 @@
 
 # binutils come first
 tar xjf $1/binutils-2.21.1a.tar.bz2
+# apply patches
+patch binutils-2.21.1/bfd/elf32-arm.c < binutils-patches/elf32-arm.patch
 mkdir -p binutils-build
 cd binutils-build
 ../binutils-2.21.1/configure --prefix=$2 ${target_args} --disable-nls