[The Old New Thing] Posso usar minha pilha como quiser?

No Windows, a pilha cresce de endereços grandes para menores. Às vezes, é determinado arquitetonicamente e, às vezes, é apenas um acordo aceito. O valor do ponteiro da pilha (registro do processador) é um ponteiro para o valor na parte superior da pilha. E os valores localizados mais profundamente na pilha, respectivamente, estão localizados em endereços grandes. Mas o que acontece com os dados localizados em endereços menores que o ponteiro da pilha?



As convenções para algumas arquiteturas (mas não todas) definem a zona vermelha, que é a área da memória sob o ponteiro da pilha, mas que ainda é válida para uso pelo aplicativo.



Para Windows, o tamanho da zona vermelha varia dependendo da arquitetura do hardware e geralmente é zero.


ArquiteturaTamanho da zona vermelha
x860 bytes
x640 bytes
Itanium16 bytes *
Alpha AXP0 bytes
MIPS320 bytes
Powerpc232 bytes **
ARM328 bytes
ARM6416 bytes

* A plataforma Itanium vale a pena notar um recurso: lá a zona vermelha está localizada acima do ponteiro da pilha e não abaixo dela.
** No caso do PowerPC, a zona vermelha é um efeito colateral do contrato de chamada .


Qualquer memória atrás da zona vermelha (abaixo da pilha) é considerada volátil e pode ser alterada pelo sistema operacional a qualquer momento.


Mas, falando sério, por que o sistema operacional se importa com o que faço com minha pilha? Quero dizer, esta é a minha pilha! O sistema operacional não me diz o que fazer com a memória que eu VirtualAlloc através do VirtualAlloc . O que torna a pilha diferente de qualquer outra memória?


Considere o seguinte código para a plataforma x86 :


  MOV [esp-4], eax ;  eax    MOV ecx, [esp-4] ;     ecx CMP ecx, eax ;  ? JNZ panic ; N:  -  

Explicação do comentário para a instrução JNZ

A convenção de codificação de montagem diz que os comentários das instruções da ramificação devem descrever o resultado se a ramificação for concluída. No exemplo acima, a instrução CMP faz a pergunta "Eles são iguais?". E a instrução JNZ salta se não forem iguais. Assim, o comentário começa com "N:", o que significa que a transição será concluída se a resposta à pergunta anterior for "Não", e o restante do comentário descreve a situação em que a transição é realizada.


Convenção de codificação Assembler?

Sim, temos uma convenção de codificação para assembler.


É possível que uma transição condicional seja implementada?


Como não há zona vermelha no x86, a memória com deslocamentos negativos em relação ao ponteiro da pilha pode ser substituída a qualquer momento. Portanto, para o código acima, a transição para o rótulo de panic é possível.


O depurador pode usar a memória atrás da zona vermelha como um local conveniente para armazenar seus dados. Por exemplo, se você usar o comando .call , o depurador fará uma chamada aninhada na mesma pilha e provavelmente usará parte desse espaço da pilha para salvar os registros, para que possam ser restaurados após o retorno da função chamada. Portanto, todos os dados armazenados fora da zona vermelha serão destruídos.


Mesmo durante a operação normal, o sistema operacional pode substituir os dados a qualquer momento fora da zona vermelha. Aqui, por exemplo, como isso pode acontecer:


Suponha que seu encadeamento execute seu horário imediatamente após salvar os dados atrás da zona vermelha. Enquanto seu encadeamento aguarda a retomada da execução, o gerenciador de memória retira temporariamente uma página física do seu código. No final, seu encadeamento obtém o controle novamente e o gerenciador de memória tenta trocar a página de código de volta (página in). Oh não, ocorre um erro de E / S durante a paginação! O sistema operacional empurra o quadro de exceção para STATUS_IN_PAGE_ERROR na pilha, o que leva à corrupção de dados que você salvou atrás da zona vermelha.


O sistema operacional despacha essa exceção. Ele acessa o manipulador de exceção de vetor ( VEH ), que é outra parte do seu programa. O manipulador foi instalado especificamente para lidar com situações excepcionais decorrentes do possível lançamento do seu programa diretamente de um CD-ROM ou de uma rede não confiável FS. O programa exibe uma solicitação na qual solicita ao usuário que insira o CD novamente e se oferece para tentar novamente. Se o usuário disser o que precisa ser repetido, o manipulador de exceção de vetor retornará EXCEPTION_CONTINUE_EXECUTION e o sistema operacional reiniciará a instrução na qual a exceção ocorreu.


Desta vez, a reinicialização é bem-sucedida porque o CD-ROM está presente (e é lido) e o código pode ser bombeado com êxito para a memória. A instrução a seguir é executada, que carrega o valor fora da zona vermelha no ecx . Mas esse não é o mesmo valor que foi salvo pela instrução anterior, pois a exceção STATUS_IN_PAGE_ERROR substitui. A comparação diz que os dados são diferentes e vamos para o rótulo de panic .


Se você deseja salvar os dados na pilha, coloque-os corretamente: primeiro reduza o ponteiro da pilha e salve o valor na parte válida da pilha. Não esconda dados atrás da zona vermelha, essa memória pode ser alterada a qualquer momento sem o seu conhecimento.

Source: https://habr.com/ru/post/pt435814/


All Articles