¿Por qué el compilador asigna más de lo necesario en la pila?
memory compiler-construction (3)
Tengo un programa simple de C. Digamos, por ejemplo, que tengo una matriz int y char de longitud 20. Necesito 24 bytes en total.
int main()
{
char buffer[20];
int x = 0;
buffer[0] = ''a'';
buffer[19] = ''a'';
}
La pila debe estar alineada con un límite de 16 bytes, por lo que supongo que un compilador reservará 32 bytes. Pero cuando compilo dicho programa con gcc x86-64 y leo el ensamblaje de salida, el compilador reserva 64 bytes.
../gcc -S -o main.s main.c
Me da
.file "main.c"
.def __main; .scl 2; .type 32; .endef
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp # RBP is pushed, so no need to reserve more for it
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $64, %rsp # Reserving the 64 bytes
.seh_stackalloc 64
.seh_endprologue
call __main
movl $0, -4(%rbp) # Using the first 4 bytes to store the int
movb $97, -32(%rbp) # Using from RBP-32
movb $97, -13(%rbp) # to RBP-13 to store the char array
movl $0, %eax
addq $64, %rsp # Restoring the stack with the last 32 bytes unused
popq %rbp
ret
.seh_endproc
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 5.2.0"
¿Porqué es eso? Cuando programo el ensamblaje, siempre reservo solo la memoria mínima que necesito sin ningún problema. ¿Es eso una limitación del compilador que tiene problemas para evaluar la memoria necesaria o hay alguna razón para ello?
Aquí está gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=D:/Mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/5.2.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-5.2.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw520/x86_64-520-posix-seh-rt_v4-rev0/mingw64 --with-gxx-include-dir=/mingw64/x86_64-w64-mingw32/include/c++ --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,objc,obj-c++,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-isl-version-check --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw520/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw520/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw520/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw520/prerequisites/x86_64-w64-mingw32-static --with-pkgversion=''x86_64-posix-seh-rev0, Built by MinGW-W64 project'' --with-bugurl=http://sourceforge.net/projects/mingw-w64 CFLAGS=''-O2 -pipe -I/c/mingw520/x86_64-520-posix-seh-rt_v4-rev0/mingw64/opt/include -I/c/mingw520/prerequisites/x86_64-zlib-static/include -I/c/mingw520/prerequisites/x86_64-w64-mingw32-static/include'' CXXFLAGS=''-O2 -pipe -I/c/mingw520/x86_64-520-posix-seh-rt_v4-rev0/mingw64/opt/include -I/c/mingw520/prerequisites/x86_64-zlib-static/include -I/c/mingw520/prerequisites/x86_64-w64-mingw32-static/include'' CPPFLAGS= LDFLAGS=''-pipe -L/c/mingw520/x86_64-520-posix-seh-rt_v4-rev0/mingw64/opt/lib -L/c/mingw520/prerequisites/x86_64-zlib-static/lib -L/c/mingw520/prerequisites/x86_64-w64-mingw32-static/lib ''
Thread model: posix
gcc version 5.2.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)
Necesito 24 bytes en total.
El compilador necesita espacio para una dirección de retorno y un puntero base. Como está en modo de 64 bits, eso es otros 16 bytes. Total 40. Redondea eso hasta un límite de 32 bytes y obtienes 64.
De hecho, los compiladores pueden reservar memoria adicional para ellos.
Gcc tiene una bandera,
-mpreferred-stack-boundary
, para establecer la alineación que mantendrá.
De acuerdo con
la documentación
, el valor predeterminado es 4, que debería producir una alineación de 16 bytes, necesaria para las instrucciones SSE.
Como
VermillionAzure señaló en un comentario
, debe proporcionar su versión de gcc y las opciones de tiempo de compilación (use
gcc -v
para mostrarlas).
Porque no has habilitado la optimización.
Sin la optimización, el compilador no intenta minimizar la cantidad de espacio o tiempo que necesita para nada en el código generado, solo genera código de la manera más directa posible.
Agregue
-O2
(o incluso solo
-O1
) u
-Os
si desea que el compilador produzca un código decente.