-fstack-protect has -fstack-protect to reorder the stack variables enabled by default in some versions of Linux for almost 10 years, especially Ubuntu, Redhat, gentoo. Also by default since gcc 4.8.3 ("4.9 and later versions include -fstack-protector-strong.")
Ubuntu page about gcc defaults: https://wiki.ubuntu.com/ToolChain/CompilerFlags
Ubuntu-defined default compiler flags in the -fstack-protector used to provide additional security features for Ubuntu .... The default -fstack-protector ... First included in Ubuntu 6.10.
Ubuntu stack protection page https://wiki.ubuntu.com/GccSsp
gcc 4.1 now ships with SSP, which is a good technology to reduce the operational reliability of multiple buffer overflows .... SSP provides technology to stop using this class of vulnerabilities by (1) reordering stack variables ... RedHat and gentoo use SSP by default in over the years
This reordering requires several O(n^2) moves for all local function variables that slow down compilation for long functions, for example, "Why does compiling more than 100,000 lines of std :: vector :: push_back take a lot of time?" - fooobar.com/questions/274377 / ...
Deferred distribution is forced when -fstack-protect enabled (sometimes it needs to change the order of all the stack variables) ... cfgexpand.c
969 976 977 static bool 978 defer_stack_allocation (tree var, bool toplevel) 980
So gcc will reorder all the variables in the stack, and the lines will be at the top of the frame. Try -fno-stack-protector disable.
As usual, the gcc author does not document how -fstack-protect works in the public documentation https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html :
-fstack-protector Extract additional code to check for buffer overflows, such as packet-based attacks. This is done by adding a security variable to functions with vulnerable objects. This includes functions that call alloca and functions with buffers larger than 8 bytes. Guards are initialized when a function is entered, and then checked when the function exits. If the security check fails, an error message is displayed and the program exits the system.
-fstack-protector-all Like -fstack-protector , except that all functions are protected.
-fstack-protector-strong Like -fstack-protector , but it includes additional security features — those that have local array definitions or that have links to local frame addresses.
-fstack-protector-explicit Like -fstack-protector , but protects only those functions that have the stack_protect attribute.
And the only documentation on arrays in front of the locales that I see is the real, best documentation: the source code
https://gcc.gnu.org/viewcvs/gcc/branches/gcc-4_6-branch/gcc/cfgexpand.c?revision=175029&view=markup#l1526 - expand_used_vars()
1533 if (has_protected_decls) 1534 { 1535 1536 expand_stack_vars (stack_protect_decl_phase_1); 1537 1538 1539 if (flag_stack_protect == 2) 1540 expand_stack_vars (stack_protect_decl_phase_2); 1541 } 1542 1543 expand_stack_vars (NULL);
phase 1 and phase 2 are separated by the symbol stack_protect_decl_phase() https://gcc.gnu.org/viewcvs/gcc/branches/gcc-4_6-branch/gcc/cfgexpand.c?revision=175029&view=markup#l1235
1235 /* Return nonzero if DECL should be segregated into the "vulnerable" upper 1236 part of the local stack frame. Remember if we ever return nonzero for 1237 any variable in this function. The return value is the phase number in 1238 which the variable should be allocated. */ 1239 1240 static int 1241 stack_protect_decl_phase (tree decl) ... 1243 unsigned int bits = stack_protect_classify_type (TREE_TYPE (decl)); ... 1249 if (flag_stack_protect == 2) 1250 { 1251 if ((bits & (SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_LARGE_CHAR_ARRAY)) 1252 && !(bits & SPCT_HAS_AGGREGATE)) 1253 ret = 1; 1254 else if (bits & SPCT_HAS_ARRAY) 1255 ret = 2; 1256 }
stack_protect_classify_type will return HAS_ARRAY bits with HAS_*_CHAR_ARRAY only for char arrays (both char, unsigned char and signed char )