]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add support for PURECODE
authorThomas Preud'homme <thomas.preudhomme@arm.com>
Fri, 23 Sep 2016 13:17:55 +0000 (14:17 +0100)
committerThomas Preud'homme <thomas.preudhomme@arm.com>
Fri, 23 Sep 2016 13:17:55 +0000 (14:17 +0100)
2016-09-23  Andre Vieria  <andre.simoesdiasvieira@arm.com>

bfd/
* bfd-in2.h (SEC_ELF_PURECODE): New.
* 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.
(elf32_arm_post_process_headers): Set p_flag.
(elf32_arm_fake_sections): Handle SEC_ELF_PURECODE.
(elf32_arm_section_flags): New.
(elf_backend_section_flags): Define to elf32_arm_section_flags.
(elf32_arm_lookup_section_flags): New.
(elf_backend_lookup_section_flags_hook): Define to
elf32_arm_lookup_section_flags.
* section.c (SEC_ELF_PURECODE): NEW.

binutils/
* objdump.c (dump_section_header): Handle SEC_ELF_PURECODE.
* readelf.c (get_elf_section_flags): Handle PURECODE.
(process_section_headers): Add purecode to help message.

include/elf/
* arm.h (SHF_ARM_PURECODE): New.

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

14 files changed:
bfd/ChangeLog.arm
bfd/bfd-in2.h
bfd/elf32-arm.c
bfd/section.c
binutils/ChangeLog.arm
binutils/objdump.c
binutils/readelf.c
include/elf/ChangeLog.arm
include/elf/arm.h
ld/testsuite/ChangeLog.arm
ld/testsuite/ld-arm/arm-elf.exp
ld/testsuite/ld-arm/arm_purecode.ld [new file with mode: 0644]
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 b2c63d0da37fabca9bd7579923d775250e0762b1..bdf0fb9e2860b50b46b1a58937693d8adb02cd50 100644 (file)
@@ -1,3 +1,22 @@
+2016-09-23  Andre Vieria  <andre.simoesdiasvieira@arm.com>
+
+       * bfd-in2.h (SEC_ELF_PURECODE): New.
+       * 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.
+       (elf32_arm_post_process_headers): Set p_flag.
+       (elf32_arm_fake_sections): Handle SEC_ELF_PURECODE.
+       (elf32_arm_section_flags): New.
+       (elf_backend_section_flags): Define to elf32_arm_section_flags.
+       (elf32_arm_lookup_section_flags): New.
+       (elf_backend_lookup_section_flags_hook): Define to
+       elf32_arm_lookup_section_flags.
+       * section.c (SEC_ELF_PURECODE): NEW.
+
 2016-09-22  Andre Vieira  <andre.simoesdiasvieira@arm.com>
 
        Backport from mainline
index fe7e11931f5ba1ca179cd800f94d5fddd7f47724..70f279a8a001879942ea394d0ee249bbd217fc83 100644 (file)
@@ -1436,6 +1436,9 @@ typedef struct bfd_section
      when memory read flag isn't set. */
 #define SEC_COFF_NOREAD 0x40000000
 
+  /* Indicate that section has the purecode flag set.  */
+#define SEC_ELF_PURECODE 0x80000000
+
   /*  End of section flags.  */
 
   /* Some internal packed boolean fields.  */
index 4c8c9f60b47447d64e1064394eee98e48821606e..42cd1981cd5d7d5752408e3c28edbcbb09cf11a0 100644 (file)
@@ -2304,6 +2304,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)}
@@ -2353,6 +2355,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[] =
@@ -2586,6 +2597,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
@@ -3775,6 +3787,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:
@@ -3815,6 +3828,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;
@@ -3827,6 +3842,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
@@ -3914,6 +3934,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
@@ -3936,16 +3965,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
@@ -3990,6 +4042,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.  */
@@ -4454,6 +4514,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:
@@ -4537,6 +4598,7 @@ arm_new_stubs_start_offset_ptr (struct elf32_arm_link_hash_table *htab,
     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:
@@ -16397,6 +16459,7 @@ elf32_arm_post_process_headers (bfd * abfd, struct bfd_link_info * link_info ATT
 {
   Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form.  */
   struct elf32_arm_link_hash_table *globals;
+  struct elf_segment_map *m;
 
   i_ehdrp = elf_elfheader (abfd);
 
@@ -16422,6 +16485,26 @@ elf32_arm_post_process_headers (bfd * abfd, struct bfd_link_info * link_info ATT
       else
        i_ehdrp->e_flags |= EF_ARM_ABI_FLOAT_SOFT;
     }
+
+  /* Scan segment to set p_flags attribute if it contains only sections with
+     SHF_ARM_PURECODE flag.  */
+  for (m = elf_seg_map (abfd); m != NULL; m = m->next)
+    {
+      unsigned int j;
+
+      if (m->count == 0)
+       continue;
+      for (j = 0; j < m->count; j++)
+       {
+         if (!(elf_section_flags (m->sections[j]) & SHF_ARM_PURECODE))
+           break;
+       }
+      if (j == m->count)
+       {
+         m->p_flags = PF_X;
+         m->p_flags_valid = 1;
+       }
+    }
 }
 
 static enum elf_reloc_type_class
@@ -16475,6 +16558,10 @@ elf32_arm_fake_sections (bfd * abfd, Elf_Internal_Shdr * hdr, asection * sec)
       hdr->sh_type = SHT_ARM_EXIDX;
       hdr->sh_flags |= SHF_LINK_ORDER;
     }
+
+  if (sec->flags & SEC_ELF_PURECODE)
+    hdr->sh_flags |= SHF_ARM_PURECODE;
+
   return TRUE;
 }
 
@@ -18803,6 +18890,23 @@ elf32_arm_get_synthetic_symtab (bfd *abfd,
   return n;
 }
 
+static bfd_boolean
+elf32_arm_section_flags (flagword *flags, const Elf_Internal_Shdr * hdr)
+{
+  if (hdr->sh_flags & SHF_ARM_PURECODE)
+    *flags |= SEC_ELF_PURECODE;
+  return TRUE;
+}
+
+static flagword
+elf32_arm_lookup_section_flags (char *flag_name)
+{
+  if (!strcmp (flag_name, "SHF_ARM_PURECODE"))
+    return SHF_ARM_PURECODE;
+
+  return SEC_NO_FLAGS;
+}
+
 #define ELF_ARCH                       bfd_arch_arm
 #define ELF_TARGET_ID                  ARM_ELF_DATA
 #define ELF_MACHINE_CODE               EM_ARM
@@ -18882,6 +18986,11 @@ elf32_arm_get_synthetic_symtab (bfd *abfd,
 #define elf_backend_obj_attrs_order            elf32_arm_obj_attrs_order
 #define elf_backend_obj_attrs_handle_unknown   elf32_arm_obj_attrs_handle_unknown
 
+#undef elf_backend_section_flags
+#define elf_backend_section_flags              elf32_arm_section_flags
+#undef elf_backend_lookup_section_flags_hook
+#define elf_backend_lookup_section_flags_hook   elf32_arm_lookup_section_flags
+
 #include "elf32-target.h"
 
 /* Native Client targets.  */
index 247d98ad1417b2b8cf41974d4edffc968c3fa7fe..fdb13e6710d6bc8d4583c4f0ff7317c5d31fec33 100644 (file)
@@ -361,6 +361,9 @@ CODE_FRAGMENT
 .     when memory read flag isn't set. *}
 .#define SEC_COFF_NOREAD 0x40000000
 .
+.  {* Indicate that section has the purecode flag set.  *}
+.#define SEC_ELF_PURECODE 0x80000000
+.
 .  {*  End of section flags.  *}
 .
 .  {* Some internal packed boolean fields.  *}
index 15fc9f8051a50e1ff61b73aa94ad61df7eda3f27..cd0e336fba97a8fcc19af0e3ae7dfe000ba7554d 100644 (file)
@@ -1,3 +1,9 @@
+2016-09-23  Andre Vieria  <andre.simoesdiasvieira@arm.com>
+
+       * objdump.c (dump_section_header): Handle SEC_ELF_PURECODE.
+       * readelf.c (get_elf_section_flags): Handle PURECODE.
+       (process_section_headers): Add purecode to help message.
+
 2016-03-29  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        * readelf.c (display_arm_attribute): Add output for Tag_DSP_extension.
index c85b0234f181262163587a74bf1633bfecf37934..85f78a1f3c6d98f06b4bc96e030437abd175099a 100644 (file)
@@ -489,6 +489,8 @@ dump_section_header (bfd *abfd, asection *section,
   PF (SEC_SMALL_DATA, "SMALL_DATA");
   if (bfd_get_flavour (abfd) == bfd_target_coff_flavour)
     PF (SEC_COFF_SHARED, "SHARED");
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+    PF (SEC_ELF_PURECODE, "PURECODE");
   PF (SEC_THREAD_LOCAL, "THREAD_LOCAL");
   PF (SEC_GROUP, "GROUP");
 
index 182b31aaa1f74efc06304209bda3efee5cec2e91..13a95008b75fb52bf627fdc743e27e7a22a3240d 100644 (file)
@@ -5271,7 +5271,9 @@ get_elf_section_flags (bfd_vma sh_flags)
       /* 18 */ { STRING_COMMA_LEN ("EXCLUDE") },
       /* SPARC specific.  */
       /* 19 */ { STRING_COMMA_LEN ("ORDERED") },
-      /* 20 */ { STRING_COMMA_LEN ("COMPRESSED") }
+      /* 20 */ { STRING_COMMA_LEN ("COMPRESSED") },
+      /* ARM specific.  */
+      /* 22 */ { STRING_COMMA_LEN ("ARM_PURECODE") },
     };
 
   if (do_section_details)
@@ -5341,6 +5343,15 @@ get_elf_section_flags (bfd_vma sh_flags)
                  if (flag == SHF_ORDERED)
                    sindex = 19;
                  break;
+
+               case EM_ARM:
+                 switch (flag)
+                   {
+                   case SHF_ARM_PURECODE: sindex = 22; break;
+                   default: break;
+                   }
+                 break;
+
                default:
                  break;
                }
@@ -5393,6 +5404,9 @@ get_elf_section_flags (bfd_vma sh_flags)
                   || elf_header.e_machine == EM_K1OM)
                  && flag == SHF_X86_64_LARGE)
                *p = 'l';
+             else if (elf_header.e_machine == EM_ARM
+                      && flag == SHF_ARM_PURECODE)
+                 *p = 'y';
              else if (flag & SHF_MASKOS)
                {
                  *p = 'o';
@@ -5969,6 +5983,11 @@ process_section_headers (FILE * file)
        printf (_("Key to Flags:\n\
   W (write), A (alloc), X (execute), M (merge), S (strings), l (large)\n\
   I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)\n\
+  O (extra OS processing required) o (OS specific), p (processor specific)\n"));
+      else if (elf_header.e_machine == EM_ARM)
+       printf (_("Key to Flags:\n\
+  W (write), A (alloc), X (execute), M (merge), S (strings), y (purecode)\n\
+  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)\n\
   O (extra OS processing required) o (OS specific), p (processor specific)\n"));
       else
        printf (_("Key to Flags:\n\
index 87268d284b7f04061229707df9fed9d06b01a7b5..e17cecf0aa79324012625282a499cb356c65162c 100644 (file)
@@ -1,3 +1,7 @@
+2016-09-23  Andre Vieria  <andre.simoesdiasvieira@arm.com>
+
+       * arm.h (SHF_ARM_PURECODE): New.
+
 2016-05-20  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        * arm.h (enum arm_st_branch_type): Add ST_BRANCH_ENUM_SIZE enumerator.
index e5127056334d64ce38ec21ecdf0b2d047548a991..ac7e3e87fced3d65a62f1b17626d5fe60105cd63 100644 (file)
@@ -82,6 +82,7 @@
 
 /* ARM-specific values for sh_flags.  */
 #define SHF_ENTRYSECT      0x10000000   /* Section contains an entry point.  */
+#define SHF_ARM_PURECODE   0x20000000   /* Section contains only code and no data.  */
 #define SHF_COMDEF         0x80000000   /* Section may be multiply defined in the input to a link step.  */
 
 /* ARM-specific program header flags.  */
index aeb1b7d690b191652a3925a7cc862a57273309a3..60e6379d7fcff21c057c6896e242e25105288775 100644 (file)
@@ -1,3 +1,10 @@
+2016-09-23  Andre Vieria  <andre.simoesdiasvieira@arm.com>
+
+       * ld-arm/arm_purecode.ld: New.
+       * ld-arm/farcall-thumb2-purecode.d: New test result.
+       * ld-arm/farcall-thumb2-purecode.s: New test.
+       * ld-arm/arm-elf.exp: Run it.
+
 2016-06-20  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        Backport from mainline
index b8ece342acb38210c7af6097625bb1e872168907..e6ed8594867ee6e3d16db540baf9c8da438cc89c 100644 (file)
@@ -477,6 +477,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/arm_purecode.ld b/ld/testsuite/ld-arm/arm_purecode.ld
new file mode 100644 (file)
index 0000000..195aca1
--- /dev/null
@@ -0,0 +1,32 @@
+/* Script for ld testsuite.  */
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+MEMORY
+{
+ read_memory   (rx)   : ORIGIN = 0x00008000, LENGTH = 4M
+ purecode_memory (!rx)  : ORIGIN = 0x00800000, LENGTH = 4M
+}
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = 0x8000); . = 0x8000;
+  .text.purecode      :
+    {
+        INPUT_SECTION_FLAGS (SHF_ARM_PURECODE) *(.text*)
+    } > purecode_memory
+  .text           :
+  {
+    *(.before)
+    *(.text)
+    *(.after)
+    *(.ARM.extab*)
+    *(.glue_7)
+    *(.v4_bx)
+  } > read_memory
+  .ARM.exidx : { *(.ARM.exidx*) }
+  . = 0x9000;
+  .got            : { *(.got) *(.got.plt)}
+  . = 0x12340000;
+  .far : { *(.far) }
+  .ARM.attribues 0 : { *(.ARM.atttributes) }
+}
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