int3 Posted October 7, 2013 at 04:36 PM Report #527911 Posted October 7, 2013 at 04:36 PM Boa tarde programadores! Alguém me pode explicar mais ou menos o que é o "stack align"? Vejamos neste exemplo: (isto foi feito sobre linux com a versao gdb: "GNU gdb (GDB) 7.5.91.20130417-cvs-ubuntu" e o gcc:"gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1)" C: #include <stdio.h> main() { int a,b,c; a=0xbeef; b=0xdead; c=0xfaceb00c; a=a+b; printf("%d-%d",a,c); } Agora, vamos ver no debugger gdb: 0x0804841c <+0>: push %ebp 0x0804841d <+1>: mov %esp,%ebp 0x0804841f <+3>: and $0xfffffff0,%esp 0x08048422 <+6>: sub $0x20,%esp 0x08048425 <+9>: movl $0xbeef,0x14(%esp) 0x0804842d <+17>: movl $0xdead,0x18(%esp) 0x08048435 <+25>: movl $0xfaceb00c,0x1c(%esp) 0x0804843d <+33>: mov 0x18(%esp),%eax 0x08048441 <+37>: add %eax,0x14(%esp) 0x08048445 <+41>: mov 0x1c(%esp),%eax 0x08048449 <+45>: mov %eax,0x8(%esp) 0x0804844d <+49>: mov 0x14(%esp),%eax 0x08048451 <+53>: mov %eax,0x4(%esp) 0x08048455 <+57>: movl $0x8048500,(%esp) 0x0804845c <+64>: call 0x80482f0 <printf@plt> 0x08048461 <+69>: leave 0x08048462 <+70>: ret Dizem que a instrução " and $0xfffffff0,%esp " é para fazer o data alignment para ser mais rápido ou lá como é. Intel usa isto na tecnologia desde o pentium 3 acho eu, chama-se SIMD. Mas ainda não entendi realmente o que se passa na stack. então no offset +6 do main está a fazer já o sub 0x20 do esp para reservar espaço para as variàveis porque é que é preciso fazer o stack alignment? Ainda não entendi onde isto mete sobre performance ao assunto :/ Estou disposto a ouvir qualquer um 😄
pwseo Posted October 7, 2013 at 04:55 PM Report #527914 Posted October 7, 2013 at 04:55 PM Com a instrução and estás a alinhar a stack em limites de 16 bytes (que é obrigatório para usares instruções SIMD, caso contrário o teu programa irá segfaultar) -- isto permite que os dados sejam acedidos em endereços que são múltiplos de 16, e é isso que aumenta a performance (e impede os crashes caso uses SIMD). Tendo em conta que a stack já foi previamente alinhada, basta reservar espaço para as variáveis locais em múltiplos de 16 bytes: tu tens 3 inteiros (presumivelmente, cada um ocupa 8 bytes), o que implica reservar 8×3 = 24 bytes de espaço na stack. Ora, 24 não é um múltiplo de 16, por isso arredonda-se para cima, para 32 (que é 0x20 em hexadecimal). Penso que é isto; assembly também não é o meu forte. 1 Report
int3 Posted October 7, 2013 at 05:27 PM Author Report #527918 Posted October 7, 2013 at 05:27 PM (edited) Pois o interessante agora que percebi melhor é que o compilador mete sempre a reservar 0x20 de espaço em relação ao main. Neste exemplo: short a=0xbeef; printf("%d",a); fica: 0x0804841c <+0>: push %ebp 0x0804841d <+1>: mov %esp,%ebp 0x0804841f <+3>: and $0xfffffff0,%esp 0x08048422 <+6>: sub $0x20,%esp 0x08048425 <+9>: movw $0xbeef,0x1e(%esp) 0x0804842c <+16>: movswl 0x1e(%esp),%eax 0x08048431 <+21>: mov %eax,0x4(%esp) 0x08048435 <+25>: movl $0x80484e0,(%esp) 0x0804843c <+32>: call 0x80482f0 <printf@plt> 0x08048441 <+37>: leave 0x08048442 <+38>: ret nesse até usei um short que é de 16bits. supostamente devia de reservar ao certo nao? EDIT: Esquece xD o short é de 16bits logo é tem 2 bytes. significa que se reservar 20h=32d ou seja se dividir fica 32/16=2, 2bytes 🙂 no "0x08048425 <+9>: movw $0xbeef,0x1e(%esp)" vê-se que está a colocar a 30bytes. mas assim sobra 2bytes de espaço na frame. é por isto que faz o alinhamento? Edited October 7, 2013 at 05:33 PM by int3
pwseo Posted October 7, 2013 at 06:21 PM Report #527927 Posted October 7, 2013 at 06:21 PM (edited) Se tem 2 bytes, só precisarias de reservar 16 bytes. De facto não sei por que motivo o GCC reserva sempre pelo menos 32 bytes mesmo que 16 sejam suficientes. Se esquecermos esse pormenor, sabemos que é garantido que aumenta a stack em blocos de 16 bytes consoante as variáveis locais que declarares (isto, obviamente, depende da configuração do compilador, mas por defeito este alinha tudo a 16 bytes). De qualquer modo, o código que mostras deixa 30 bytes livres entre a tua variável e %esp (e não apenas 2)... Não sei ao certo por que motivo são reservados logo 32 bytes quando a variável cabia perfeitamente num bloco de 16 -- se eu escrevesse isso à mão, faria algo como: ... and $0xfffffff0, %esp sub $16, %esp ; 16 bytes chegam perfeitamente para um short de 2 bytes movw $0xBEEF, 14(%esp) ; "subimos" 14 bytes e escrevemos os nossos 2 bytes nos 2 restantes ... Posto isto... Alguém que perceba de assembly provavelmente poderá esclarecer-nos melhor. EDIT: Ligando as optimizações, o GCC reserva apenas 16 bytes na stack. Reparei também que há bocado te disse que os inteiros ocupavam 8 bytes, mas isso seria verdade se tivesses um processador de 64-bits. Agora que vi melhor, reparei que não é bem assim, uma vez que tens endereços que ocupam 4 bytes: ... 0x08048431 <+21>: mov %eax,0x4(%esp) 0x08048435 <+25>: movl $0x80484e0,(%esp) 0x0804843c <+32>: call 0x80482f0 <printf@plt> ... Edited October 7, 2013 at 06:49 PM by pwseo
int3 Posted October 7, 2013 at 08:03 PM Author Report #527954 Posted October 7, 2013 at 08:03 PM Exato, estou com linux mint de 32bits. embora diga "i686 GNU/Linux" e tenha 4GB de RAM sem PAE ainda não entendi como se está apenas a endereçar 32bits e consigo ter acesso a 4GB. talvez 2³² bits é 4GB. mas no windows apenas tenho 3GB se tiver 32bits outra coisa que não entendo do linux para o windows. De qualquer forma o que acontece então se o endereço onde começa o main seja um múltiplo de 16? já não é necessário alinhar a stack? 🙂
pwseo Posted October 7, 2013 at 08:44 PM Report #527961 Posted October 7, 2013 at 08:44 PM Estamos a misturar coisas. Primeiro, i686 é precisamente uma arquitectura de 32-bits, o que significa que consegues endereçar até 4GB de RAM (232bits). Em Linux, com PAE consegues ter acesso aos 4GB na sua totalidade, algo que não consegues com Windows a 32-bits. Relativamente ao alinhamento, o pré-requisito é que a stack seja alinhada a 16-bytes. Os endereços das funções também podem ser alinhados a 16-bytes, mas não é disso que estávamos a falar, nem podemos assumir que o alinhamento das funções implica o alinhamento da stack ou vice-versa, penso eu. Por outro lado, a minha experiência em assembly é extremamente reduzida, por isso gostaria de ver opiniões de outras pessoas também.
int3 Posted October 7, 2013 at 09:12 PM Author Report #527969 Posted October 7, 2013 at 09:12 PM oh pois é. xD estava a misturar x64 com i686 ehehe Também gostava de ver alguém que soubesse exatamente do que se trata 😄
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now