https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95052
Bug ID: 95052 Summary: Excess padding of partially initialized strings/char arrays Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: krzysztof.a.nowicki+gcc at gmail dot com Target Milestone: --- Created attachment 48506 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=48506&action=edit generated assembly (GCC 11.0 trunk, -Os -g0) When compiling the following code with -Os: extern void func(char *buf, unsigned size); int main(int argc, char *argv[]) { char str[1*1024*1024] = "fooiuhluhpiuhliuhliyfyukyfklyugkiuhpoipoipoipoipoipoipoipoipoipoipoipoipoimipoipiuhoulouihnliuhl"; char arr[1*1024*1024] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 6, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; func(str, sizeof(str)); func(arr, sizeof(arr)); } GCC generates initializers for both local variables (str and arr) in the .rodata section and at run-time initializes the explicit part of the variable with the provided contents, and zero-inits the remainder. Unfortunately the initializer stored in the .rodata section is padded up to the target array size: .LC0: .string "fooiuhluhpiuhliuhliyfyukyfklyugkiuhpoipoipoipoipoipoipoipoipoipoipoipoipoimipoipiuhoulouihnliuhl" .zero 1048479 .LC1: .string "\001\026\003\004\005?\007\b'" .string "\001\002\003\004\005>\033\b1" .string "\001\006\002\003\004\005\006\007\b\t" .string "\003\001\002\003\004\005\006\007\b\t" .string "\001\002\003\004\005\006\007\b\t" .string "\001\002\003\004\005\006\007\b\t" .string "\002\002\003\004\005>\033\b1" .string "\001\006\002\003\004\005\006\007\b\t" .string "\003\001\002\003\004\005\006\007\b\t" .string "\001\002\003\004\005\006\007\b\t" .string "\001\002\003\004\005" .zero 1048466 This causes the resulting binary to become unnecessarily large, even though the zero padding is completely redundant (the run-time initializer code does not copy these bytes to the target variable, but zero-initializes them. I suspect that this is caused by GCC not being able to distinguish between: - initialization of a global (or static local) variable, - initialization of a local variable In the former case the contents of the variable live in the read/write data section and are initialized by the compiler. In such case padding is necessary as any further changes to the variable will be done in-place. In the latter case the contents of the variable live on the stack and are initialized from a read-only copy in the read-only data section. In such case only the non-zero explicitly initialized part needs to be stored - any padding can be skipped as it will not be used. This mis-optimization occurs depending on compiler flags, architecture and size of the array as well as the initialized part, as GCC may choose (and usually does) to initialize the variable by using store assembly instructions with immediate values, as this method is usually faster at the cost of increased code size.