[ARM] Purecode compatible long branch veneer for M-profile targets with MOVW.
authorAndre Vieria <andre.simoesdiasvieira@arm.com>
Tue, 5 Jul 2016 10:39:06 +0000 (11:39 +0100)
committerRichard Earnshaw <Richard.Earnshaw@arm.com>
Tue, 5 Jul 2016 10:39:06 +0000 (11:39 +0100)
2016-07-05  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.

2016-07-05  Andre Vieria  <andre.simoesdiasvieira@arm.com>

* testsuite/ld-arm/farcall-thumb2-purecode.d: New test result.
* testsuite/ld-arm/farcall-thumb2-purecode.s: New test.
* testsuite/ld-arm/arm-elf.exp: Run it.

bfd/ChangeLog
bfd/elf32-arm.c
ld/ChangeLog
ld/testsuite/ld-arm/arm-elf.exp
ld/testsuite/ld-arm/farcall-thumb2-purecode.d [new file with mode: 0644]
ld/testsuite/ld-arm/farcall-thumb2-purecode.s [new file with mode: 0644]

index cff9b323773c32f730504b645174507e69082dd5..40311715a78e1d8df61d238d6d1821c54cfdb1d0 100644 (file)
@@ -1,3 +1,13 @@
+2016-07-05  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.
+
 2016-07-05  Andre Vieria  <andre.simoesdiasvieira@arm.com>
 
        * bfd-in2.h (SEC_ELF_NOREAD): Rename to ...
index 93314710c79e320dad8d195ee9067d404f2a09b6..834d61506526054c653a8fd70b36b453ac676293 100644 (file)
@@ -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
@@ -3808,6 +3820,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:
@@ -3847,6 +3860,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;
@@ -3859,6 +3874,11 @@ arm_type_of_stub (struct bfd_link_info *info,
   thumb2 = using_thumb2 (globals);
   thumb2_bl = using_thumb2_bl (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
@@ -3945,6 +3965,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
@@ -3967,16 +3996,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
@@ -4021,6 +4073,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.  */
@@ -4446,6 +4506,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:
index cc598af62063ec803c92a64cc4906078fce489fe..6ee54fc3c8653b00345bf06458ea7ed56977bf12 100644 (file)
@@ -1,3 +1,9 @@
+2016-07-05  Andre Vieria  <andre.simoesdiasvieira@arm.com>
+
+       * testsuite/ld-arm/farcall-thumb2-purecode.d: New test result.
+       * testsuite/ld-arm/farcall-thumb2-purecode.s: New test.
+       * testsuite/ld-arm/arm-elf.exp: Run it.
+
 2016-07-05  Andre Vieria  <andre.simoesdiasvieira@arm.com>
 
        * testsuite/ld-arm/arm_noread.ld: Renamed to ...
index 597bdcf4ccbc9db7e78df20b34ecc7a6f4ea6410..d0c9a2f240d4f28ebc61d0310f4a1840f2327b67 100644 (file)
@@ -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 (file)
index 0000000..2a62fe4
--- /dev/null
@@ -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 (file)
index 0000000..a16731a
--- /dev/null
@@ -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