Programação em *assembly* x86-64 ******************************** .. Inserir aqui uma secção com os aspetos arquiturais importantes. Copiar algumas coisas dos slides .. Tratar da questão do alinhamento. Tirar do capítulo dos valores e pôr aqui. .. Também se deve inserir uma secção sobre a linguagem assembly Suporte à linguagem C ===================== Valores ------- A arquitetura x86-64 realiza operações com palavras de 8, 16, 32 ou 64 *bits*. Os registos tem nomes próprios que definem as diferentes porções. Por exemplo, AL, AX, EAX e RAX. Para valores operados em memória as instruções aceitam um indicador, em sufixo, que define a dimensão da palavra. ===== ============= ========== **b** *byte* 8 *bits* **w** *word* 16 *bits* **l** *double word* 32 *bits* **q** *quad word* 64 *bits* ===== ============= ========== Existem instruções que estendem a representação num número inferior de *bits* para um número superior de *bits*. +-----------------------+-------------------------------+-----------------------------------------------------------------+ | movs\-\- *src*, *dst* | extensão com o *bit* de sinal | os tracinhos são substituídos pelos indicadores acima | +-----------------------+-------------------------------+ | | movz\-\- *src*, *dst* | extensão com o valor zero | o primeiro indica a dimensão da origem e o segundo a do destino | +-----------------------+-------------------------------+-----------------------------------------------------------------+ Expressões ---------- Alguns exemplos de calculo de expressões numéricas. Considerando **a** um valor expresso a 64 *bit*, previamente carregado em RAX. +-----------------------+----------------------------+---------------------------------------+ | Deslocar p posições | .. code-block:: c | .. code-block:: asm | | para a esquerda | | | | | a << p; | mov p(%rip), %cl | | | | shl %cl, %rax | +-----------------------+----------------------------+---------------------------------------+ | Afetar o bit da | .. code-block:: c | .. code-block:: asm | | posição *p* com zero | | | | | a & ~(1 << p); | mov p(%rip), %cl | | | | mov $1, %rdx | | | | shl %cl, %rdx | | | | not %rdx | | | | and %rdx, %rax | +-----------------------+----------------------------+---------------------------------------+ | Afetar o bit da | .. code-block:: c | .. code-block:: asm | | posição *p* com um | | | | | a | 1 << p; | mov p(%rip), %cl | | | | mov $1, %rdx | | | | shl %cl, %rdx | | | | or %rdx, %rax | +-----------------------+----------------------------+---------------------------------------+ | Testar o valor do | .. code-block:: c | .. code-block:: asm | | bit da posição p | | | | | if (a & (1 << p)) | mov p(%rip), %cl %cl | | | | mov $1, %rdx | | | | shl %cl, %rdx | | | | test %rdx, %rax | | | | jz label | +-----------------------+----------------------------+---------------------------------------+ | Obter o campo de | .. code-block:: c | .. code-block:: asm | | n bits a começar | | | | na posição p. | (a >> p) & ~(~0 << n); | mov $~0, %rdx | | | | mov n(%rip), %cl | | | | shl %cl, %rdx | | | | not %rdx | | | | mov p(%rip), %cl | | | | shr %cl, %rax | | | | and %rdx, %rax | +-----------------------+----------------------------+---------------------------------------+ | Multiplicação por | .. code-block:: c | .. code-block:: asm | | constante | | | | | a * 13; | # rax * 13 = (rax * 3) * 4 + rax | | | | | | | | lea (%rax, %rax, 2), %rdx | | | | lea (%rax, %rdx, 4), %eax | +-----------------------+----------------------------+---------------------------------------+ Considerando **a** um valor expresso a 128 bit previamente carregado em RDX:RAX. +-----------------------+----------------------------+---------------------------------------+ | Deslocar 1 posição | .. code-block:: c | .. code-block:: asm | | para a esquerda | | | | | a <<= 1; | shl $1, %rax | | | | rcl $1, %rdx | +-----------------------+----------------------------+---------------------------------------+ | Deslocar 1 posição | .. code-block:: c | .. code-block:: asm | | para a direita | | | | | a >>= 1; | shr $1, %rdx | | | | rcr $1, %rax | +-----------------------+----------------------------+---------------------------------------+ | Deslocar **p** | .. code-block:: c | .. code-block:: asm | | posições | | | | para a esquerda | a <<= p; | mov p(%rip), %cl | | | | shld %cl, %rax, %rdx | | | | shl $cl, %rax | +-----------------------+----------------------------+---------------------------------------+ | Deslocar **N** | .. code-block:: c | .. code-block:: asm | | posições | | | | para a direita | a >>= N; | shrd $N, %rdx, %rax | | | | shr $N, %rdx | +-----------------------+----------------------------+---------------------------------------+ Controlo da execução -------------------- *if* .... *if* sem *else* +----------------------------------------------------------------+----------------------------------------------------------------+ | .. literalinclude:: ../../../code/assembly_x86_64/control/if.c | .. literalinclude:: ../../../code/assembly_x86_64/control/if.s | | :language: c | :language: asm | | | | | \(a\) | \(b\) | +----------------------------------------------------------------+----------------------------------------------------------------+ *if* com *else* +---------------------------------------------------------------------+---------------------------------------------------------------------+ | .. literalinclude:: ../../../code/assembly_x86_64/control/if_else.c | .. literalinclude:: ../../../code/assembly_x86_64/control/if_else.s | | :language: c | :language: asm | | | | | \(a\) | \(b\) | +---------------------------------------------------------------------+---------------------------------------------------------------------+ switch ...... +---------------------------------------------------------------------+---------------------------------------------------------------------+ | .. literalinclude:: ../../../code/assembly_x86_64/control/switch.c | .. literalinclude:: ../../../code/assembly_x86_64/control/switch.s | | :language: c | :language: asm | | | | | \(a\) | \(b\) | +---------------------------------------------------------------------+---------------------------------------------------------------------+ do while ........ +----------------------------------------------------------------------+----------------------------------------------------------------------+ | .. literalinclude:: ../../../code/assembly_x86_64/control/do_while.c | .. literalinclude:: ../../../code/assembly_x86_64/control/do_while.s | | :language: c | :language: asm | | | | | \(a\) | \(b\) | +----------------------------------------------------------------------+----------------------------------------------------------------------+ while ..... +----------------------------------------------------------------------+----------------------------------------------------------------------+----------------------------------------------------------------------+ | .. literalinclude:: ../../../code/assembly_x86_64/control/while.c | .. literalinclude:: ../../../code/assembly_x86_64/control/while1.s | .. literalinclude:: ../../../code/assembly_x86_64/control/while2.s | | :language: c | :language: asm | :language: asm | | seguinte, representa o endereço da variável ``a``. É codificado como a diferença entre o endereço da instrução e a *label* ``a`` e é calculado adicionando este valor ao RIP. A utilização que se faz do endereço da variável depende da semântica da instrução. No caso de ``movb $0, a(%rip)`` é realizada a escrita do valor 0 na posição de memória com esse endereço. No caso de ``incq i(%rip)`` é realizada uma leitura e uma escrita do valor depois de incrementado. Um valor do tipo ``int`` é representado em memória p | | | | \(a\) | \(b\) | \(c\) | +----------------------------------------------------------------------+----------------------------------------------------------------------+----------------------------------------------------------------------+ for ... +----------------------------------------------------------------------+----------------------------------------------------------------------+ | .. literalinclude:: ../../../code/assembly_x86_64/control/for.c | .. literalinclude:: ../../../code/assembly_x86_64/control/for.s | | :language: c | :language: asm | | | | | \(a\) | \(b\) | +----------------------------------------------------------------------+----------------------------------------------------------------------+ Funções ------- A chamada a função é realizada com a instrução **call** e o retorno é realizado com a instrução **ret**. A instrução **call** empilha o endereço da próxima instrução no topo do *stack*. Nessa altura RIP já contém o endereço da instrução seguinte, designado por endereço de retorno. Depois executa um salto para o endereço de início da função chamada (*callee*). A instrução **call ** é equivalente à sequência **push rip; jmp