This is the mail archive of the binutils@sourceware.org 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]

[2/2 PATCH][ARM] Purecode compatible long branch veneer for M-profile targets with movw


Hello,

This patch introduces a long branch veneer for M-profile targets with
the movw instruction that is compatible with the processor-specific ELF
section attribute SHF_ARM_PURECODE. This attribute restricts sections to
only contain code, and no data. For this reason a new type of veneer
must be used that does not rely on literal pools and instead, we use the
R_ARM_THM_MOVT_ABS and R_ARM_THM_MOVW_ABS_NC relocations to load the
address into a register. These relocation types are documented in the
ELF for the ARM Architecture found on http://infocenter.arm.com.

As mentioned earlier, we only support M-Profile targets with the mowv
instruction. For any other targets the linker will issue a warning for
every veneer that is to be created inside a section with the
SHF_ARM_PURECODE. We could add an option to turn this warning into an
error if that proves to be useful. Other perhaps useful functionality
that could be added later is to not use purecode veneers in sections
with the SHF_ARM_PURECODE if these sections were deliberately put into
segments with other impure sections, thus stripping such a section of
its SHF_ARM_PURECODE attribute.

Is this OK?

Best Regards,
Andre

bfd/ChangeLog
2016-06-30  Andre Vieria  <andre.simoesdiasvieira@arm.com>

        * elf32-arm.c (THUMB32_MOVT): New veneer macro.
          (THUMB32_MOVW): Likewise.
          (elf32_arm_stub_long_branch_thumb2_only_pure): New.
          (DEF_STUBS): Define long_branch_thumb2_only_pure.
          (arm_stub_is_thumb): Add new veneer stub.
          (arm_type_of_stub): Use new veneer.
          (arm_stub_required_alignment): Add new veneer.
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index d7cff9bd85e0b9693b3ce9134184938a24b6b941..006970141137bc952e424ae647aa863c3f557f43 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2360,6 +2360,8 @@ enum stub_insn_type
    is inserted in arm_build_one_stub().  */
 #define THUMB16_BCOND_INSN(X)	{(X), THUMB16_TYPE, R_ARM_NONE, 1}
 #define THUMB32_INSN(X)		{(X), THUMB32_TYPE, R_ARM_NONE, 0}
+#define THUMB32_MOVT(X)		{(X), THUMB32_TYPE, R_ARM_THM_MOVT_ABS, 0}
+#define THUMB32_MOVW(X)		{(X), THUMB32_TYPE, R_ARM_THM_MOVW_ABS_NC, 0}
 #define THUMB32_B_INSN(X, Z)	{(X), THUMB32_TYPE, R_ARM_THM_JUMP24, (Z)}
 #define ARM_INSN(X)		{(X), ARM_TYPE, R_ARM_NONE, 0}
 #define ARM_REL_INSN(X, Z)	{(X), ARM_TYPE, R_ARM_JUMP24, (Z)}
@@ -2409,6 +2411,15 @@ static const insn_sequence elf32_arm_stub_long_branch_thumb2_only[] =
   DATA_WORD (0, R_ARM_ABS32, 0),     /* dcd  R_ARM_ABS32(x) */
 };
 
+/* Thumb -> Thumb long branch stub. Used for PureCode sections on Thumb2
+   M-profile architectures.  */
+static const insn_sequence elf32_arm_stub_long_branch_thumb2_only_pure[] =
+{
+  THUMB32_MOVW (0xf2400c00),	     /* mov.w ip, R_ARM_MOVW_ABS_NC */
+  THUMB32_MOVT (0xf2c00c00),	     /* movt  ip, R_ARM_MOVT_ABS << 16 */
+  THUMB16_INSN (0x4760),             /* bx   ip */
+};
+
 /* V4T Thumb -> Thumb long branch stub. Using the stack is not
    allowed.  */
 static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb[] =
@@ -2634,6 +2645,7 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
   DEF_STUB(a8_veneer_bl) \
   DEF_STUB(a8_veneer_blx) \
   DEF_STUB(long_branch_thumb2_only) \
+  DEF_STUB(long_branch_thumb2_only_pure)
 
 #define DEF_STUB(x) arm_stub_##x,
 enum elf32_arm_stub_type
@@ -3790,6 +3802,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
     {
     case arm_stub_long_branch_thumb_only:
     case arm_stub_long_branch_thumb2_only:
+    case arm_stub_long_branch_thumb2_only_pure:
     case arm_stub_long_branch_v4t_thumb_arm:
     case arm_stub_short_branch_v4t_thumb_arm:
     case arm_stub_long_branch_v4t_thumb_arm_pic:
@@ -3830,6 +3843,8 @@ arm_type_of_stub (struct bfd_link_info *info,
   enum arm_st_branch_type branch_type = *actual_branch_type;
   union gotplt_union *root_plt;
   struct arm_plt_info *arm_plt;
+  int arch;
+  int thumb2_movw;
 
   if (branch_type == ST_BRANCH_LONG)
     return stub_type;
@@ -3842,6 +3857,11 @@ arm_type_of_stub (struct bfd_link_info *info,
 
   thumb2 = using_thumb2 (globals);
 
+  arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch);
+
+  /* True for architectures that implement the thumb2 movw instruction.  */
+  thumb2_movw = thumb2 || (arch  == TAG_CPU_ARCH_V8M_BASE);
+
   /* Determine where the call point is.  */
   location = (input_sec->output_offset
 	      + input_sec->output_section->vma
@@ -3928,6 +3948,15 @@ arm_type_of_stub (struct bfd_link_info *info,
 	      /* Thumb to thumb.  */
 	      if (!thumb_only)
 		{
+		  if (input_sec->flags & SEC_ELF_PURECODE)
+		    (*_bfd_error_handler) (_("%B(%s): warning: long branch "
+					     " veneers used in section with "
+					     "SHF_ARM_PURECODE section "
+					     "attribute is only supported"
+					     " for M-profile targets that "
+					     "implement the movw "
+					     "instruction."));
+
 		  stub_type = (bfd_link_pic (info) | globals->pic_veneer)
 		    /* PIC stubs.  */
 		    ? ((globals->use_blx
@@ -3950,16 +3979,39 @@ arm_type_of_stub (struct bfd_link_info *info,
 		}
 	      else
 		{
-		  stub_type = (bfd_link_pic (info) | globals->pic_veneer)
-		    /* PIC stub.  */
-		    ? arm_stub_long_branch_thumb_only_pic
-		    /* non-PIC stub.  */
-		    : (thumb2 ? arm_stub_long_branch_thumb2_only
-			      : arm_stub_long_branch_thumb_only);
+		  if (thumb2_movw && (input_sec->flags & SEC_ELF_PURECODE))
+		      stub_type = arm_stub_long_branch_thumb2_only_pure;
+		  else
+		    {
+		      if (input_sec->flags & SEC_ELF_PURECODE)
+			(*_bfd_error_handler) (_("%B(%s): warning: long branch "
+						 " veneers used in section with "
+						 "SHF_ARM_PURECODE section "
+						 "attribute is only supported"
+						 " for M-profile targets that "
+						 "implement the movw "
+						 "instruction."));
+
+		      stub_type = (bfd_link_pic (info) | globals->pic_veneer)
+			/* PIC stub.  */
+			? arm_stub_long_branch_thumb_only_pic
+			/* non-PIC stub.  */
+			: (thumb2 ? arm_stub_long_branch_thumb2_only
+				  : arm_stub_long_branch_thumb_only);
+		    }
 		}
 	    }
 	  else
 	    {
+	      if (input_sec->flags & SEC_ELF_PURECODE)
+		(*_bfd_error_handler) (_("%B(%s): warning: long branch "
+					 " veneers used in section with "
+					 "SHF_ARM_PURECODE section "
+					 "attribute is only supported"
+					 " for M-profile targets that "
+					 "implement the movw "
+					 "instruction."));
+
 	      /* Thumb to arm.  */
 	      if (sym_sec != NULL
 		  && sym_sec->owner != NULL
@@ -4004,6 +4056,14 @@ arm_type_of_stub (struct bfd_link_info *info,
 	   || r_type == R_ARM_PLT32
 	   || r_type == R_ARM_TLS_CALL)
     {
+      if (input_sec->flags & SEC_ELF_PURECODE)
+	(*_bfd_error_handler) (_("%B(%s): warning: long branch "
+				 " veneers used in section with "
+				 "SHF_ARM_PURECODE section "
+				 "attribute is only supported"
+				 " for M-profile targets that "
+				 "implement the movw "
+				 "instruction."));
       if (branch_type == ST_BRANCH_TO_THUMB)
 	{
 	  /* Arm to thumb.  */
@@ -4429,6 +4489,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_v4t_arm_thumb:
     case arm_stub_long_branch_thumb_only:
     case arm_stub_long_branch_thumb2_only:
+    case arm_stub_long_branch_thumb2_only_pure:
     case arm_stub_long_branch_v4t_thumb_thumb:
     case arm_stub_long_branch_v4t_thumb_arm:
     case arm_stub_short_branch_v4t_thumb_arm:
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index a5d4c8757cbe96367ecc4defe75397b4d9645c51..c544c2b48367015a9be14fe2b34863cf47d537e7 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -505,6 +505,9 @@ set armeabitests_nonacl {
      {farcall-thumb-thumb-m-no-profile-a.s farcall-thumb-thumb-m-no-profile-b.s}
      {{objdump -d farcall-thumb-thumb-m-no-profile.d}}
      "farcall-thumb-thumb-m-no-profile"}
+    {"Thumb2 purecode farcall" "-Ttext 0x1000 --section-start .foo=0x2001020" "" "" {farcall-thumb2-purecode.s}
+     {{objdump -d farcall-thumb2-purecode.d}}
+     "farcall-thumb2-purecode"}
 
     {"Thumb-ARM farcall" "-Ttext 0x1c01010 --section-start .foo=0x2001014" "" "-W" {farcall-thumb-arm.s}
      {{objdump -d farcall-thumb-arm.d}}
diff --git a/ld/testsuite/ld-arm/farcall-thumb2-purecode.d b/ld/testsuite/ld-arm/farcall-thumb2-purecode.d
new file mode 100644
index 0000000000000000000000000000000000000000..2a62fe4cdd4c9ae04d2e2c9b1124742aa973d3fe
--- /dev/null
+++ b/ld/testsuite/ld-arm/farcall-thumb2-purecode.d
@@ -0,0 +1,22 @@
+.*:     file format .*
+
+Disassembly of section .text:
+
+00001000 <bar>:
+    1000:	4770      	bx	lr
+
+Disassembly of section .foo:
+
+02001020 <_start>:
+ 2001020:	f000 f802 	bl	2001028 <__bar_veneer>
+ 2001024:	0000      	movs	r0, r0
+	\.\.\.
+
+02001028 <__bar_veneer>:
+ 2001028:	f241 0c01 	movw	ip, #4097	; 0x1001
+ 200102c:	f2c0 0c00 	movt	ip, #0
+ 2001030:	4760      	bx	ip
+ 2001032:	0000      	movs	r0, r0
+ 2001034:	0000      	movs	r0, r0
+	\.\.\.
+
diff --git a/ld/testsuite/ld-arm/farcall-thumb2-purecode.s b/ld/testsuite/ld-arm/farcall-thumb2-purecode.s
new file mode 100644
index 0000000000000000000000000000000000000000..a16731acf3e3b4fa871419702d531eb5df5c2808
--- /dev/null
+++ b/ld/testsuite/ld-arm/farcall-thumb2-purecode.s
@@ -0,0 +1,19 @@
+@ Test to ensure that a purecode Thumb2 call exceeding 4Mb generates a stub.
+
+	.global _start
+	.syntax unified
+	.arch armv7-m
+	.thumb
+	.thumb_func
+
+@ We will place the section .text at 0x1000.
+
+	.text
+bar:
+	bx lr
+
+@ We will place the section .foo at 0x02001014.
+
+	.section .foo, "0x20000006"
+_start:
+	bl bar

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