From: Thomas Preud'homme Date: Fri, 23 Sep 2016 13:17:55 +0000 (+0100) Subject: Add support for PURECODE X-Git-Tag: users/ARM/embedded-binutils-2_26-branch-2016q3~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5a9c321e5c946de39a1b7728e28b70190f615dc4;p=thirdparty%2Fbinutils-gdb.git Add support for PURECODE 2016-09-23 Andre Vieria 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. --- diff --git a/bfd/ChangeLog.arm b/bfd/ChangeLog.arm index b2c63d0da37..bdf0fb9e286 100644 --- a/bfd/ChangeLog.arm +++ b/bfd/ChangeLog.arm @@ -1,3 +1,22 @@ +2016-09-23 Andre Vieria + + * 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 Backport from mainline diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index fe7e11931f5..70f279a8a00 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -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. */ diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 4c8c9f60b47..42cd1981cd5 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -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. */ diff --git a/bfd/section.c b/bfd/section.c index 247d98ad141..fdb13e6710d 100644 --- a/bfd/section.c +++ b/bfd/section.c @@ -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. *} diff --git a/binutils/ChangeLog.arm b/binutils/ChangeLog.arm index 15fc9f8051a..cd0e336fba9 100644 --- a/binutils/ChangeLog.arm +++ b/binutils/ChangeLog.arm @@ -1,3 +1,9 @@ +2016-09-23 Andre Vieria + + * 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 * readelf.c (display_arm_attribute): Add output for Tag_DSP_extension. diff --git a/binutils/objdump.c b/binutils/objdump.c index c85b0234f18..85f78a1f3c6 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -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"); diff --git a/binutils/readelf.c b/binutils/readelf.c index 182b31aaa1f..13a95008b75 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -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\ diff --git a/include/elf/ChangeLog.arm b/include/elf/ChangeLog.arm index 87268d284b7..e17cecf0aa7 100644 --- a/include/elf/ChangeLog.arm +++ b/include/elf/ChangeLog.arm @@ -1,3 +1,7 @@ +2016-09-23 Andre Vieria + + * arm.h (SHF_ARM_PURECODE): New. + 2016-05-20 Thomas Preud'homme * arm.h (enum arm_st_branch_type): Add ST_BRANCH_ENUM_SIZE enumerator. diff --git a/include/elf/arm.h b/include/elf/arm.h index e5127056334..ac7e3e87fce 100644 --- a/include/elf/arm.h +++ b/include/elf/arm.h @@ -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. */ diff --git a/ld/testsuite/ChangeLog.arm b/ld/testsuite/ChangeLog.arm index aeb1b7d690b..60e6379d7fc 100644 --- a/ld/testsuite/ChangeLog.arm +++ b/ld/testsuite/ChangeLog.arm @@ -1,3 +1,10 @@ +2016-09-23 Andre Vieria + + * 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 Backport from mainline diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp index b8ece342acb..e6ed8594867 100644 --- a/ld/testsuite/ld-arm/arm-elf.exp +++ b/ld/testsuite/ld-arm/arm-elf.exp @@ -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 index 00000000000..195aca1be93 --- /dev/null +++ b/ld/testsuite/ld-arm/arm_purecode.ld @@ -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 index 00000000000..2a62fe4cdd4 --- /dev/null +++ b/ld/testsuite/ld-arm/farcall-thumb2-purecode.d @@ -0,0 +1,22 @@ +.*: file format .* + +Disassembly of section .text: + +00001000 : + 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 00000000000..a16731acf3e --- /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