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 > >
