Estou tentando entender como os quadros de pilha são criados e quais variáveis (parâmetros) são empurradas para empilhar em que ordem? Alguns resultados de pesquisa mostraram que o compilador C / C ++ decide com base nas operações executadas em uma função. Por exemplo, se a função deveria incrementar apenas um valor int passado por 1 (semelhante ao operador ++) e retorná-lo, colocaria todos os parâmetros da função e variáveis locais nos registradores.
Eu estou querendo saber quais registros são usados para retornados ou passar por parâmetros de valor. Como as referências são retornadas? Como o compilador escolhe entre eax, ebx, ecx e edx?
O que eu preciso saber para entender como registros, pilha e referências de pilha são usados, construídos e destruídos durante chamadas de função?
Respostas:
Além do que Dirk disse, um uso importante dos quadros de pilha é salvar os valores anteriores dos registradores para que possam ser restaurados após uma chamada de função. Portanto, mesmo nos processadores em que os registros são usados para passar parâmetros, retornar um valor e salvar o endereço de retorno, os valores desses registros são salvos na pilha antes de uma chamada de função, para que possam ser restaurados após a chamada. Isso permite que uma função chame outra sem sobrescrever seus próprios parâmetros ou esquecer seu próprio endereço de retorno.
Portanto, chamar uma função B da função A em um sistema "genérico" típico pode envolver as seguintes etapas:
Isso não é de forma alguma a única maneira pela qual as chamadas de função podem funcionar (e eu posso ter uma ou duas etapas desordenadas), mas você deve ter uma idéia de como a pilha é usada para permitir que o processador lide com chamadas de função aninhadas.
fonte
push
epop
são as duas operações fundamentais em uma pilha. Uma pilha é uma estrutura de último a entrar, primeiro a sair, como uma pilha de livros. Quando vocêpush
coloca um novo objeto no topo da pilha; quando vocêpop
está tirando um objeto do topo da pilha. Você não tem permissão para inserir ou remover objetos no meio, você só pode operar na parte superior da pilha. Você pode ler mais sobre pilhas em geral e a pilha de programas em particular na Wikipedia.Isso depende da convenção de chamada que está sendo usada. Quem define a convenção de chamada pode tomar essa decisão da maneira que desejar.
Na convenção de chamada mais comum no x86, os registradores não são usados para passar parâmetros; os parâmetros são enviados para a pilha começando com o parâmetro mais à direita. O valor de retorno é colocado em eax e pode usar edx se precisar de espaço extra. Referências e ponteiros são retornados na forma de um endereço em eax.
fonte
Se você entender muito bem a pilha, entenderá como a memória funciona no programa e se entenderá como a memória funciona no programa, entenderá como o armazenamento de funções no programa e se entenderá como o armazenamento de funções no programa entenderá como funciona a função recursiva e se você entende como a função recursiva funciona, entenderá como o compilador funciona e, se entender como o compilador funciona, sua mente funcionará como compilador e você depurará qualquer programa com muita facilidade.
Deixe-me explicar como a pilha funciona:
Primeiro você precisa saber como as funções armazenam na pilha:
Os valores de alocação de memória dinâmica de armazenamento de heap. Valores automáticos de alocação e exclusão de armazenamento de pilha.
Vamos entender com o exemplo:
Agora entenda partes deste programa:
Agora vamos ver o que é pilha e o que são partes da pilha:
Lembre-se de uma coisa: se alguma função obtiver "retorno", não importa que tenha carregado todas as suas variáveis locais ou qualquer coisa que ela retorne imediatamente da pilha, será o quadro da pilha. Significa que quando qualquer função recursiva obtém a condição base e colocamos retorno após a condição base, para que a condição base não espere para carregar variáveis locais que estão localizadas na parte “else” do programa, ela retornará imediatamente o quadro atual da pilha e agora se um quadro retornar próximo quadro está no registro de ativação. Veja isso na prática:
Portanto, agora, sempre que uma função encontrada retorna a instrução, ela exclui o quadro atual da pilha.
enquanto retornar do valor da pilha retornará na ordem inversa da ordem em que foram alocados na pilha.
Essas são descrições muito curtas e, se você quiser saber mais sobre pilha e recursão dupla, leia dois posts deste blog:
Mais sobre a pilha passo a passo
Mais sobre recursão dupla passo a passo com pilha
fonte
O que você está procurando é chamado Application Binary Interface - ABI.
Há uma especificação para cada compilador que especifica a ABI.
Cada plataforma geralmente especifica e ABI para oferecer suporte à interoperabilidade entre compiladores. Por exemplo, as convenções de chamada do x86 explicitam as convenções de chamada típicas do x86 e x86-64. Eu esperaria um documento mais oficial do que a Wikipedia, no entanto.
fonte