This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [Patch, ARM] Support NOREAD section attribute across Bintuils for ARM target
- From: Richard Earnshaw <rearnsha at arm dot com>
- To: Terry Guo <terry dot guo at arm dot com>
- Cc: "binutils at sourceware dot org" <binutils at sourceware dot org>, "nickc at redhat dot com" <nickc at redhat dot com>
- Date: Thu, 08 May 2014 13:44:55 +0100
- Subject: Re: [Patch, ARM] Support NOREAD section attribute across Bintuils for ARM target
- Authentication-results: sourceware.org; auth=none
- References: <000001cf5aaf$bac0d510$30427f30$ at arm dot com>
On 18/04/14 03:41, Terry Guo wrote:
> Hi there,
>
> In order to protect proprietary code from reverse-engineering, some ARM
> baremetal boards have a special flash area where code is executable but not
> readable. Normally this area is very small and can only accommodate certain
> code sections (sections with NOREAD attribute in this case). The attached
> patch implements a new letter 'y' to represent this new SHF_NOREAD section
> attribute and enables user to define/allocate such code sections to
> executable-only flash area in linker script. We talked to community with an
> intention to make it to be a common and standard ELF section attribute, but
> got rejected. So now it is implemented as a process-specific attribute for
> ARM target.
>
> This new attribute is a supplementary attribute to normal code section. It
> won't break current way to handle code section. It will be safely ignored
> for targets that don't have executable-only feature i.e. code section with
> this new attribute will be treated as a normal code section.
>
> Tested with all regression tests in Binutils, no new regressions. Is it OK
> to trunk?
>
This isn't documented in AAELF.
R.
> BR,
> Terry
>
> include/ChangeLog:
> 2014-04-18 Terry Guo <terry.guo@arm.com>
>
> * elf/arm.h (SHF_NOREAD): New flag to represent NOREAD attribute.
>
> bfd/ChangeLog:
> 2014-04-18 Terry Guo <terry.guo@arm.com>
>
> * elf32-arm.c (elf32_arm_elf_lookup_section_flags): New function to
> help linker
> recognize flag SHF_NOREAD.
> (elf_backend_lookup_section_flags_hook): Implement this hook for ARM
> target.
>
> gas/ChangeLog:
> 2014-04-18 Terry Guo <terry.guo@arm.com>
>
> * config/obj-elf.c (obj_elf_change_section): Accept ARM executable-only
> text section.
> * config/tc-arm.h (md_elf_section_letter): Implement this hook for ARM
> target.
> (arm_elf_section_letter): Declare it.
> * config/tc-arm.c (arm_elf_section_letter): Handle ARM section
> attribute letter 'y'.
> * doc/c-arm.texi (ARM section attribute 'y'): Document it.
>
> gas/testsuite/ChangeLog:
> 2014-04-18 Terry Guo <terry.guo@arm.com>
>
> * gas/arm/section-execute-only.s: New test case.
> * gas/arm/section-execute-only.d: Expected output.
>
> binutils/ChangeLog:
> 2014-04-18 Terry Guo <terry.guo@arm.com>
>
> * readelf.c (get_elf_section_flags): Display ARM specific NOREAD
> section attribute.
>
> ld/testsuite/ChangeLog:
> 2014-04-18 Terry Guo <terry.guo@arm.com>
>
> * ld-arm/section-execute-only.s: New test.
> * ld-arm/execute-only-section.ld: Linker script with executable-only
> memory.
> * ld-arm/section-execute-only.d: Expected output for target with
> executable-only memory.
> * ld-arm/no-execute-only-section.ld: Linker script without
> executable-only memory.
> * ld-arm/no-section-execute-only.d: Expected output for target without
> executable-only memory.
> * ld-arm/arm-elf.exp: Add tests for executable-only attribute.
>
>
> binutils-exo-v4.txt
>
>
> diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
> index 16467a4..aea5b9c 100644
> --- a/bfd/elf32-arm.c
> +++ b/bfd/elf32-arm.c
> @@ -15877,6 +15877,16 @@ elf32_arm_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
> return TRUE;
> }
>
> +static flagword
> +elf32_arm_elf_lookup_section_flags (char *flag_name)
> +{
> +
> + if (!strcmp (flag_name, "SHF_NOREAD"))
> + return SHF_NOREAD;
> +
> + return 0;
> +}
> +
> /* We use this to override swap_symbol_in and swap_symbol_out. */
> const struct elf_size_info elf32_arm_size_info =
> {
> @@ -16142,6 +16152,7 @@ elf32_arm_get_synthetic_symtab (bfd *abfd,
> #define elf_backend_output_arch_local_syms elf32_arm_output_arch_local_syms
> #define elf_backend_begin_write_processing elf32_arm_begin_write_processing
> #define elf_backend_add_symbol_hook elf32_arm_add_symbol_hook
> +#define elf_backend_lookup_section_flags_hook elf32_arm_elf_lookup_section_flags
>
> #define elf_backend_can_refcount 1
> #define elf_backend_can_gc_sections 1
> diff --git a/binutils/readelf.c b/binutils/readelf.c
> index c757a63..846990c 100644
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -4752,7 +4752,9 @@ get_elf_section_flags (bfd_vma sh_flags)
> /* Generic. */
> /* 18 */ { STRING_COMMA_LEN ("EXCLUDE") },
> /* SPARC specific. */
> - /* 19 */ { STRING_COMMA_LEN ("ORDERED") }
> + /* 19 */ { STRING_COMMA_LEN ("ORDERED") },
> + /* ARM specific. */
> + /* 20 */ { STRING_COMMA_LEN ("NOREAD") }
> };
>
> if (do_section_details)
> @@ -4821,6 +4823,10 @@ get_elf_section_flags (bfd_vma sh_flags)
> if (flag == SHF_ORDERED)
> sindex = 19;
> break;
> + case EM_ARM:
> + if (flag == SHF_NOREAD)
> + sindex = 20;
> + break;
> default:
> break;
> }
> @@ -4869,6 +4875,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_NOREAD)
> + *p = 'y';
> else if (flag & SHF_MASKOS)
> {
> *p = 'o';
> diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
> index 52c6b64..46929c5 100644
> --- a/gas/config/obj-elf.c
> +++ b/gas/config/obj-elf.c
> @@ -64,6 +64,10 @@
> #include "elf/nios2.h"
> #endif
>
> +#ifdef TC_ARM
> +#include "elf/arm.h"
> +#endif
> +
> static void obj_elf_line (int);
> static void obj_elf_size (int);
> static void obj_elf_type (int);
> @@ -672,6 +676,11 @@ obj_elf_change_section (const char *name,
> /* RX init/fini arrays can and should have the "awx" attributes set. */
> ;
> #endif
> +#ifdef TC_ARM
> + else if (attr == (SHF_EXECINSTR | SHF_NOREAD | SHF_ALLOC))
> + /* ARM can have code section with SHF_NOREAD attribute. */
> + ;
> +#endif
> else
> {
> if (group_name == NULL)
> diff --git a/gas/config/tc-arm.h b/gas/config/tc-arm.h
> index f88fa29..11bb1ac 100644
> --- a/gas/config/tc-arm.h
> +++ b/gas/config/tc-arm.h
> @@ -276,6 +276,7 @@ struct current_it
> # define md_elf_section_type(str, len) arm_elf_section_type (str, len)
> # define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_"
> # define TC_SEGMENT_INFO_TYPE struct arm_segment_info_type
> +# define md_elf_section_letter arm_elf_section_letter
>
> /* This is not really an alignment operation, but it's something we
> need to do at the same time: whenever we are figuring out the
> @@ -369,6 +370,7 @@ void tc_pe_dwarf2_emit_offset (symbolS *, unsigned int);
> #define CONVERT_SYMBOLIC_ATTRIBUTE(name) arm_convert_symbolic_attribute (name)
> extern int arm_convert_symbolic_attribute (const char *);
> extern int arm_apply_sym_value (struct fix *);
> +extern bfd_vma arm_elf_section_letter (int, char **);
> #endif
>
> #define tc_comment_chars arm_comment_chars
> diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
> index 69299c7..7c44961 100644
> --- a/gas/config/tc-arm.c
> +++ b/gas/config/tc-arm.c
> @@ -25373,4 +25373,17 @@ arm_apply_sym_value (struct fix * fixP)
> }
> return 0;
> }
> +
> +/* Map 'y' to SHF_NOREAD. */
> +
> +bfd_vma
> +arm_elf_section_letter (int letter, char **ptr_msg)
> +{
> + if (letter == 'y')
> + return SHF_NOREAD;
> +
> + *ptr_msg = _("bad .section directive: want a,e,w,x,y,M,S,G,T in string");
> +
> + return -1;
> +}
> #endif /* OBJ_ELF */
> diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi
> index 7bcce94..fdee70d 100644
> --- a/gas/doc/c-arm.texi
> +++ b/gas/doc/c-arm.texi
> @@ -23,6 +23,7 @@
> * ARM Opcodes:: Opcodes
> * ARM Mapping Symbols:: Mapping Symbols
> * ARM Unwinding Tutorial:: Unwinding
> +* ARM Section Attribute:: Section Attribute
> @end menu
>
> @node ARM Options
> @@ -1185,3 +1186,13 @@ code that calls functions which may throw exceptions. If you need to
> know more about the object-file format used to represent unwind
> information, you may consult the @cite{Exception Handling ABI for the
> ARM Architecture} available from @uref{http://infocenter.arm.com}.
> +
> +@node ARM Section Attribute
> +@section Section Attribute
> +
> +@cindex ARM section attribute
> +@table @code
> +@item y
> +text section with NOREAD attribute for target that supports this feature,
> +otherwise such section will be treated as normal text section.
> +@end table
> diff --git a/gas/testsuite/gas/arm/section-execute-only.d b/gas/testsuite/gas/arm/section-execute-only.d
> new file mode 100644
> index 0000000..fd6fe90
> --- /dev/null
> +++ b/gas/testsuite/gas/arm/section-execute-only.d
> @@ -0,0 +1,27 @@
> +# name: test executable-only section attribute
> +# as:
> +# readelf: -t
> +# This test is only valid on EABI based ports.
> +# target: *-*-*eabi* *-*-nacl*
> +There are 10 section headers, starting at offset 0xc4:
> +
> +Section Headers:
> + \[Nr\] Name
> + Type Addr Off Size ES Lk Inf Al
> + Flags
> + \[ 0\]
> + NULL 00000000 000000 000000 00 0 0 0
> + \[00000000\]:
> + \[ 1\] .text
> + PROGBITS 00000000 000034 000000 00 0 0 2
> + \[00000006\]: ALLOC, EXEC
> + \[ 2\] .data
> + PROGBITS 00000000 000034 000000 00 0 0 1
> + \[00000003\]: WRITE, ALLOC
> + \[ 3\] .bss
> + NOBITS 00000000 000034 000000 00 0 0 1
> + \[00000003\]: WRITE, ALLOC
> + \[ 4\] .text.foo
> + PROGBITS 00000000 000034 000010 00 0 0 4
> + \[20000006\]: ALLOC, EXEC, NOREAD
> +#pass
> diff --git a/gas/testsuite/gas/arm/section-execute-only.s b/gas/testsuite/gas/arm/section-execute-only.s
> new file mode 100644
> index 0000000..9d5ffc6
> --- /dev/null
> +++ b/gas/testsuite/gas/arm/section-execute-only.s
> @@ -0,0 +1,30 @@
> + .syntax unified
> + .cpu cortex-m3
> + .fpu softvfp
> + .eabi_attribute 20, 1
> + .eabi_attribute 21, 1
> + .eabi_attribute 23, 3
> + .eabi_attribute 24, 1
> + .eabi_attribute 25, 1
> + .eabi_attribute 26, 1
> + .eabi_attribute 30, 2
> + .eabi_attribute 34, 1
> + .eabi_attribute 18, 4
> + .thumb
> + .section .text.foo,"axy",%progbits
> + .align 2
> + .global foo
> + .thumb
> + .thumb_func
> + .type foo, %function
> +foo:
> + @ args = 0, pretend = 0, frame = 0
> + @ frame_needed = 0, uses_anonymous_args = 0
> + @ link register save eliminated.
> + movs r0, #1
> + movs r1, #1
> + movw r2, #257
> + movs r3, #1
> + b madd
> + .size foo, .-foo
> +
> diff --git a/include/elf/arm.h b/include/elf/arm.h
> index 34afdfd..c6cd873 100644
> --- a/include/elf/arm.h
> +++ b/include/elf/arm.h
> @@ -84,6 +84,7 @@
> /* ARM-specific values for sh_flags. */
> #define SHF_ENTRYSECT 0x10000000 /* Section contains an entry point. */
> #define SHF_COMDEF 0x80000000 /* Section may be multiply defined in the input to a link step. */
> +#define SHF_NOREAD 0x20000000 /* Section isn't readable. */
>
> /* ARM-specific program header flags. */
> #define PF_ARM_SB 0x10000000 /* Segment contains the location addressed by the static base. */
> diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
> index c255587..d95f47f 100644
> --- a/ld/testsuite/ld-arm/arm-elf.exp
> +++ b/ld/testsuite/ld-arm/arm-elf.exp
> @@ -671,6 +671,13 @@ set armeabitests_nonacl {
> {{objdump -d thumb-b-lks-sym.d}}
> "thumb-b-lks-sym"}
>
> + {"link executable-only text section for targets supporting this feature" "-T execute-only-section.ld" "" "" {section-execute-only.s}
> + {{readelf -S section-execute-only.d}}
> + "has-execute-only-memory"}
> + {"link executable-only text section for normal targets" "-T no-execute-only-section.ld" "" "" {section-execute-only.s}
> + {{readelf -S no-section-execute-only.d}}
> + "no-execute-only-memory"}
> +
> {"erratum 760522 fix (default for v6z)" "--section-start=.foo=0x2001014" ""
> "-march=armv6z" {fix-arm1176.s}
> {{objdump -d fix-arm1176-on.d}}
> diff --git a/ld/testsuite/ld-arm/execute-only-section.ld b/ld/testsuite/ld-arm/execute-only-section.ld
> new file mode 100644
> index 0000000..b2897b0
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/execute-only-section.ld
> @@ -0,0 +1,22 @@
> +/* Linker script to configure memory regions. */
> +MEMORY
> +{
> + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K
> + FLASH_XO (rx) : ORIGIN = 0x00000000+256K, LENGTH = 256K
> + RAM (rwx) : ORIGIN = 0x100000C8, LENGTH = (32K - 0xC8)
> +}
> +
> +ENTRY(main)
> +
> +SECTIONS
> +{
> + .text :
> + {
> + INPUT_SECTION_FLAGS (!SHF_NOREAD) *(.text*)
> + } > FLASH
> +
> + .text.xo :
> + {
> + INPUT_SECTION_FLAGS (SHF_NOREAD) *(.text*)
> + } > FLASH_XO
> +}
> diff --git a/ld/testsuite/ld-arm/no-execute-only-section.ld b/ld/testsuite/ld-arm/no-execute-only-section.ld
> new file mode 100644
> index 0000000..5746138
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/no-execute-only-section.ld
> @@ -0,0 +1,16 @@
> +/* Linker script to configure memory regions. */
> +MEMORY
> +{
> + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K
> + RAM (rwx) : ORIGIN = 0x100000C8, LENGTH = (32K - 0xC8)
> +}
> +
> +ENTRY(main)
> +
> +SECTIONS
> +{
> + .text :
> + {
> + *(.text*)
> + } > FLASH
> +}
> diff --git a/ld/testsuite/ld-arm/no-section-execute-only.d b/ld/testsuite/ld-arm/no-section-execute-only.d
> new file mode 100644
> index 0000000..30e73a0
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/no-section-execute-only.d
> @@ -0,0 +1,11 @@
> +There are 6 section headers, starting at offset 0x807c:
> +
> +Section Headers:
> + \[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
> + \[ 0\] NULL 00000000 000000 000000 00 0 0 0
> + \[ 1\] .text PROGBITS 00000000 008000 000018 00 AX 0 0 4
> + \[ 2\] .ARM.attributes ARM_ATTRIBUTES 00000000 008018 000033 00 0 0 1
> + \[ 3\] .shstrtab STRTAB 00000000 00804b 000031 00 0 0 1
> + \[ 4\] .symtab SYMTAB 00000000 00816c 0000a0 10 5 7 4
> + \[ 5\] .strtab STRTAB 00000000 00820c 00002f 00 0 0 1
> +#pass
> diff --git a/ld/testsuite/ld-arm/section-execute-only.d b/ld/testsuite/ld-arm/section-execute-only.d
> new file mode 100644
> index 0000000..12b0ed5
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/section-execute-only.d
> @@ -0,0 +1,12 @@
> +There are 7 section headers, starting at offset 0x1007c:
> +
> +Section Headers:
> + \[Nr\] Name Type Addr Off Size ES Flg Lk Inf Al
> + \[ 0\] NULL 00000000 000000 000000 00 0 0 0
> + \[ 1\] .text PROGBITS 00000000 008000 00000c 00 AX 0 0 4
> + \[ 2\] .text.xo PROGBITS 00040000 010000 00000c 00 AXy 0 0 4
> + \[ 3\] .ARM.attributes ARM_ATTRIBUTES 00000000 01000c 000033 00 0 0 1
> + \[ 4\] .shstrtab STRTAB 00000000 01003f 00003a 00 0 0 1
> + \[ 5\] .symtab SYMTAB 00000000 010194 0000b0 10 6 8 4
> + \[ 6\] .strtab STRTAB 00000000 010244 00002f 00 0 0 1
> +#pass
> diff --git a/ld/testsuite/ld-arm/section-execute-only.s b/ld/testsuite/ld-arm/section-execute-only.s
> new file mode 100644
> index 0000000..d3838f0
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/section-execute-only.s
> @@ -0,0 +1,58 @@
> + .syntax unified
> + .cpu cortex-m3
> + .fpu softvfp
> + .eabi_attribute 20, 1
> + .eabi_attribute 21, 1
> + .eabi_attribute 23, 3
> + .eabi_attribute 24, 1
> + .eabi_attribute 25, 1
> + .eabi_attribute 26, 1
> + .eabi_attribute 30, 2
> + .eabi_attribute 34, 1
> + .eabi_attribute 18, 4
> + .thumb
> + .section .text.foo,"axy",%progbits
> + .align 2
> + .global foo
> + .thumb
> + .thumb_func
> + .type foo, %function
> +foo:
> + @ args = 0, pretend = 0, frame = 0
> + @ frame_needed = 0, uses_anonymous_args = 0
> + @ link register save eliminated.
> + movs r0, #1
> + movs r1, #1
> + movw r2, #257
> + movs r3, #1
> + bx lr
> + .size foo, .-foo
> +
> + .section .text.bar,"ax",%progbits
> + .align 2
> + .global bar
> + .thumb
> + .thumb_func
> + .type bar, %function
> +bar:
> + @ args = 0, pretend = 0, frame = 0
> + @ frame_needed = 0, uses_anonymous_args = 0
> + @ link register save eliminated.
> + movs r0, #1
> + movs r1, #1
> + bx lr
> +
> + .section .text.startup,"ax",%progbits
> + .align 2
> + .global main
> + .thumb
> + .thumb_func
> + .type main, %function
> +main:
> + @ args = 0, pretend = 0, frame = 0
> + @ frame_needed = 0, uses_anonymous_args = 0
> + @ link register save eliminated.
> + movs r0, #0
> + bx lr
> + .size main, .-main
> +
>