On Wed, Nov 11, 2026 at 2:01 PM Harmen Stoppels <[email protected]> wrote:
>
> Copies from constant data, such as a memcpy from a string literal, are
> expanded into stores of vector constants when store_by_pieces allows it.
> This splits the string into pieces of vector width, the last one often
> overlapping with the previous one, so the string literal may no longer
> appear in the resulting binary.
>
> This complicates scanning binaries for embedded absolute paths, which is
> common practice in package managers.
>
> The new option allows package managers to opt out of this optimization,
> so they can reliably scan binaries for embedded absolute paths.

At least your testcase is fragile as it relies on assembler scanning.
"Unfixed" the object file still contains the strings:

> strings t.o
/opt/memcpy/0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdef89abcdefghijklmnopqrstuvwxyz/foo/opt/array/0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefg9abcdefghijklmnopqrstuvwxyz/bar

albeit in .data section.

I think the approach of scanning binaries is just fragile and if you
can resort to a compile-time workaround (add your new flag) you
could as well invent other compile-time means to diagnose
absolute paths (matching some pattern).

So no, this doesn't look like something we'd want.

Richard.

> gcc/ChangeLog:
>
>         * common.opt (fstore-constants-by-pieces): New option.
>         * doc/invoke.texi (-fno-store-constants-by-pieces): Document.
>         * expr.cc (can_store_by_pieces): Return false for copies from
>         constant data with -fno-store-constants-by-pieces.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/i386/store-constants-by-pieces-1.c: New test.
>
> Signed-off-by: Harmen Stoppels <[email protected]>
> ---
>
> Hello,
>
> In the Spack package manager we scan binaries for embedded absolute
> paths, which only works if literal C-strings are preserved in the
> binary. That is not the case when targeting x86_64, where a default
> optimization breaks the string literals up into constants that fit in
> vector registers. As I understand it, there is no guarantee that those
> constants are stored contiguously (which could have the happy
> side-effect of getting the literal back in the binary), but even if they
> did, the very last chunk is special in that it overlaps with the
> previous chunk when the literal's size is not a multiple of the vector
> width.
>
> As far as I can see, -mmove-max=128 is related, but that only lowers the
> limit to 255 bytes, and also negatively affects ordinary memory copies,
> so it does not really help.
>
> Therefore, I'm proposing a compiler option that allows us to disable
> this optimization, with the hope that we can reliably scan for
> non-relocatable absolute paths that accidentally get embedded in
> binaries.
>
> I have not checked, but presumably we are not the only package manager
> that has such audits after a build.
>
> Best,
>
> Harmen Stoppels
>
>  gcc/common.opt                                 |  4 ++++
>  gcc/doc/invoke.texi                            | 13 ++++++++++++-
>  gcc/expr.cc                                    |  3 +++
>  .../i386/store-constants-by-pieces-1.c         | 18 ++++++++++++++++++
>  4 files changed, 37 insertions(+), 1 deletion(-)
>  create mode 100644 
> gcc/testsuite/gcc.target/i386/store-constants-by-pieces-1.c
>
> diff --git a/gcc/common.opt b/gcc/common.opt
> index c40606570e9..14fd9453589 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1956,6 +1956,10 @@ fstrict-volatile-bitfields
>  Common Var(flag_strict_volatile_bitfields) Init(-1) Optimization
>  Force bitfield accesses to match their type width.
>
> +fstore-constants-by-pieces
> +Common Var(flag_store_constants_by_pieces) Init(1) Optimization
> +Expand copies from constant data into stores of immediates.
> +
>  fstore-merging
>  Common Var(flag_store_merging) Optimization
>  Merge adjacent stores.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index ef9cb025c22..11927e2dd16 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -681,7 +681,8 @@ Objective-C and Objective-C++ Dialects}.
>  -fsingle-precision-constant  -fsplit-ivs-in-unroller  -fsplit-loops
>  -fspeculatively-call-stored-functions
>  -fsplit-wide-types  -fsplit-wide-types-early  -fssa-backprop  -fssa-phiopt
> --fstdarg-opt  -fstore-merging  -fstrict-aliasing -fipa-strict-aliasing
> +-fstdarg-opt  -fstore-constants-by-pieces  -fstore-merging
> +-fstrict-aliasing -fipa-strict-aliasing
>  -fthread-jumps  -ftracer  -ftree-bit-ccp
>  -ftree-builtin-call-dce  -ftree-ccp  -ftree-ch  -ftree-coalesce-vars
>  -ftree-copy-prop  -ftree-cselim  -ftree-dce  -ftree-dominator-opts
> @@ -15420,6 +15421,16 @@ merges contiguous stores of immediate values 
> narrower than a word into fewer
>  wider stores to reduce the number of instructions.  This is enabled by 
> default
>  at @option{-O2} and higher as well as @option{-Os}.
>
> +@opindex fstore-constants-by-pieces
> +@opindex fno-store-constants-by-pieces
> +@item -fno-store-constants-by-pieces
> +Do not expand copies from constant data, such as a @code{memcpy} from a
> +string literal or the initialization of a character array, into stores of
> +immediate values.  The data is copied from the constant in memory instead,
> +so that it stays intact in the object file.  This is useful when binaries
> +are scanned for embedded strings, such as absolute paths.  The default is
> +@option{-fstore-constants-by-pieces}.
> +
>  @opindex ftree-ter
>  @opindex fno-tree-ter
>  @item -ftree-ter
> diff --git a/gcc/expr.cc b/gcc/expr.cc
> index c654387ab01..bd8119af61d 100644
> --- a/gcc/expr.cc
> +++ b/gcc/expr.cc
> @@ -1772,6 +1772,9 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
>    if (len == 0)
>      return true;
>
> +  if (!memsetp && !flag_store_constants_by_pieces)
> +    return false;
> +
>    if (!targetm.use_by_pieces_infrastructure_p (len, align,
>                                                memsetp
>                                                  ? SET_BY_PIECES
> diff --git a/gcc/testsuite/gcc.target/i386/store-constants-by-pieces-1.c 
> b/gcc/testsuite/gcc.target/i386/store-constants-by-pieces-1.c
> new file mode 100644
> index 00000000000..5feff67cb29
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/store-constants-by-pieces-1.c
> @@ -0,0 +1,18 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mavx2 -fno-store-constants-by-pieces" } */
> +
> +void
> +foo (char *d)
> +{
> +  __builtin_memcpy (d, 
> "/opt/memcpy/0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz/foo",
>  88);
> +}
> +
> +void
> +bar (void (*f) (char *))
> +{
> +  char b[] = 
> "/opt/array/0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz/bar";
> +  f (b);
> +}
> +
> +/* { dg-final { scan-assembler 
> "/opt/memcpy/0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz/foo"
>  } } */
> +/* { dg-final { scan-assembler 
> "/opt/array/0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz/bar"
>  } } */
> --
> 2.53.0
>
>

Reply via email to