Pourquoi le compilateur alloue-t-il plus que nécessaire dans la stack?

J’ai un programme en C simple. Disons, par exemple, que j’ai un entier et un tableau de caractères de longueur 20. J’ai besoin de 24 octets au total.

int main() { char buffer[20]; int x = 0; buffer[0] = 'a'; buffer[19] = 'a'; } 

La stack doit être alignée sur une limite de 16 octets, donc je suppose qu’un compilateur réserve 32 octets. Mais lorsque je comstack un tel programme avec gcc x86-64 et que je lis l’assembly de sortie, le compilateur réserve 64 octets.

 ..\gcc -S -o main.s main.c 

Donne moi:

  .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_endprolog 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" 

Pourquoi donc? Lorsque je programme l’assemblage, je ne réserve toujours que le minimum de mémoire dont j’ai besoin sans aucun problème. Est-ce une limitation du compilateur qui a du mal à évaluer la mémoire nécessaire ou y a-t-il une raison à cela?

Voici 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-ssortingng --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/prerequirejsites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw520/prerequirejsites/x86_64-w64-mingw32-static --with-mpc=/c/mingw520/prerequirejsites/x86_64-w64-mingw32-static --with-isl=/c/mingw520/prerequirejsites/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/prerequirejsites/x86_64-zlib-static/include -I/c/mingw520/prerequirejsites/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/prerequirejsites/x86_64-zlib-static/include -I/c/mingw520/prerequirejsites/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/prerequirejsites/x86_64-zlib-static/lib -L/c/mingw520/prerequirejsites/x86_64-w64-mingw32-static/lib ' Thread model: posix gcc version 5.2.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 

Les compilateurs peuvent en effet réserver de la mémoire supplémentaire pour eux-mêmes.

Gcc a un drapeau, -mpreferred-stack-boundary , pour définir l’alignement à maintenir. Selon la documentation , la valeur par défaut est 4, ce qui devrait produire un alignement de 16 octets, nécessaire pour les instructions SSE.

Comme VermillionAzure l’a noté dans un commentaire , vous devez indiquer votre version de gcc et vos options de compilation (utilisez gcc -v pour les afficher).

Parce que vous n’avez pas activé l’optimisation.

Sans optimisation, le compilateur ne cherche pas à minimiser l’espace ou le temps dont il a besoin pour tout ce qui se trouve dans le code généré – il génère simplement du code de la manière la plus simple possible.

Ajoutez -O2 (ou même simplement -O1 ) ou -Os si vous voulez que le compilateur produise un code correct.

J’ai besoin de 24 octets au total.

Le compilateur a besoin d’espace pour une adresse de retour et un pointeur de base. Comme vous êtes en mode 64 bits, vous disposez de 16 octets supplémentaires. Total 40. Arrondissez cela à une limite de 32 octets et vous obtenez 64.