Pergunta

Há algo que não consigo digerir.Estou aprendendo um pouco de assembler e agora estou no capítulo de endereçamento.Eu entendo o conceito de colchetes para desreferenciação, mas de alguma forma, quando vejo seu uso, simplesmente não consigo entender o que está acontecendo.Para ser um pouco mais exato, aqui é onde minha confusão começou:

mov al, [L1]

Aqui suponho que L1 como caso de exemplo seja algum tipo de macro que posteriormente é substituída por um endereço real no código de máquina, certo?

Então o que esta instrução faz é:desreferenciação al registrar (porque dificilmente seria possível alterar o endereço físico) e alterar o valor para aquele armazenado em L1.

Se até agora está tudo bem:

mov [L1], al

isso significaria analogicamente que deve ter havido um endereço armazenado (então fazia sentido fazer isso) e você o altera para algum outro lugar na memória, certo?

Se você pudesse me dizer que está tudo bem, caso não veja nenhum erro, faça-o, isso me permitiria continuar aprendendo.

Uma última coisa, NASM adiciona um monte de 0xAA55 no meu código (essa sequência deveria encerrar o programa, certo?), por que ela está lá tantas vezes?

Foi útil?

Solução

L1 é normalmente/provavelmente um rótulo, associado a um endereço específico na memória.O programador define vários rótulos para sua conveniência, e tais rótulos são usados ​​para representar simbolicamente um local específico na memória (L1 é um nome péssimo;os rótulos são normalmente indicativos da finalidade subjacente do local:digamos, PingCounter, ErrorMessage, Login e similares).

Um rótulo para 1 byte de armazenamento estático é como um compilador C implementaria char L1; em âmbito global.


Na sintaxe NASM, mov edi, L1 se reunirá para o mov eax, imm32 forma de mov, ou sejao endereço do rótulo se tornará um imediato de 32 bits no código de máquina.(O montador não sabe o valor numérico final, mas o vinculador sabe.) Cuidado, pois na sintaxe MASM, isso seria uma carga e você precisaria mov edi, OFFSET L1 para obter um endereço de etiqueta como imediato.

Mas mov al, [L1] será montado em uma instrução diferente, com o endereço de 32 bits incorporado no código de máquina como um endereço a ser desreferenciado.Esta instrução carrega 1 byte do endereço L1 e o coloca em AL.

Na linguagem assembly, esse modo de endereçamento indireto é representado por colchetes no operando de origem ou destino de uma determinada instrução.(Mas não ambos:x86 suporta apenas no máximo um operando de memória explícito por instrução.)

mov al, [L1]

usa o endereço armazenado em L1 para localizar algum local na memória e lê 1 byte (= 8 bits = o tamanho do registrador AL) neste local e carrega-o no registrador AL.

  mov [L1], al

Faz isso ao contrário.ou seja, especificamente, leia o endereço armazenado em L1, use esse endereço para encontrar um local específico na memória e armazene o conteúdo do registrador AL lá.


Desde que você entenda que as informações a seguir estão incompletas e um tanto desatualizadas em relação aos processadores mais recentes da família x86, este cartilha sobre a arquitetura 8086 provavelmente é muito útil para começar a usar a linguagem Assembly para a família x86.
A vantagem de começar com esta "antiguidade de CPU" (ainda em uso, na verdade), é que os conceitos fundamentais estão todos lá, livres dos novos conjuntos de registros, modos de endereçamento sofisticados, modos de operação e outros conceitos.Os tamanhos, recursos e modos maiores das CPUs mais recentes apenas introduzem uma explosão combinatória de opções, todas (a maioria?) úteis à sua maneira, mas essencialmente irrelevantes para uma iniciação.

Outras dicas

É difícil seguir sua pergunta, mas vou tentar ajudar.

Na montagem, um símbolo é apenas um nome para um endereço. Na sua fonte de montagem, L1 é um símbolo definido em outro lugar, que o assembler resolverá como um deslocamento para a memória.

Ao desreferenciar (usando a notação []), você pode desreferenciar um registro (como em "mov al, [ESI]) ou um endereço (como em "mov al, [l1]). Ambas as declarações fazem a mesma coisa, a única diferença é de onde vem o endereço.

Eu recomendo baixar o Documentação da Intel CPU e deslizando através da referência de instrução. Se você não quiser ficar sobrecarregado, comece a ler um processador X86 mais antigo (digamos, 486 ou mais), essa documentação não é exatamente amigável, mas é muito útil ter em mãos.

Não conheço as especificidades do NASM, aprendi a Assembléia há 15 anos com o Turbo Assembler, e esse conhecimento ainda é útil hoje :)

Além disso, posso sugerir que você tente pesquisar no Google para o "tutorial de montagem x86", você encontrará muita documentação relevante que pode ser útil para você.

Ah, e uma última coisa, Nasm adiciona um monte de 0XAA55 no meu código (essa sequência deve terminar o programa, certo?), Por que está lá tantas vezes? Muito obrigado por lê -lo aqui ..

Tenho certeza de que isso só é aplicável se você está criando um carregador de inicialização. É a "assinatura da bota". Digamos que você escreva esse código em um disquete (o código da máquina produzido também é exatamente 512 bytes?), Bem, quando você deseja iniciar o computador com este código de inicialização, o BIOS analisará o disquete e determinará se é um carregador de inicialização real. Para fazer isso, ele olhará para os últimos dois bytes do primeiro setor do disquete, o que deve ser 0xAA55 para indicar que é inicializável .. (Além disso, isso funciona da mesma maneira se você está inicializando com o harddrive, ou o polegar-acionamento ou o que quer que seja um pouco diferente para CDs porque eles têm setores de 4096 bytes)

No seu código -fonte, é como a última linha algo como $(times.. db 0xAA55 ou algo assim? Se você não pretende fazer um carregador de inicialização, pode remover efetivamente essa linha.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top