CMP1130 - Linguagens de Montagem 3a Lista de Exercícios Max Gontijo de Oliveira Dicas: • Construa o fluxograma para orientar a programação. • Dentro dos procedimentos, sempre crie frames de pilha para os procedimentos (instrução enter). Não se esqueça de destruir o frame de pilha antes de finalizar (instrução leave). • Dentro dos procedimentos, sempre faça backup dos registradores antes de começar o código (instrução pusha) e restaure o estado dos registradores antes de finalizar o programa e destruir o frame (instrução popa). – Caso o procedimento tenha que retornar algum valor via registrador, estabeleça uma variável local (via pilha utilizando o primeiro parâmetro da instrução enter) e utilize essa variável para não perder o valor do registrador. Instruções para programação e compilação • Não refaça código desnecessariamente. Utilize os procedimentos já criados sempre que precisar em algum outro procedimento ou programa. • Você poderá criar procedimentos adicionais, caso julgue útil. Não precisam ser procedimentos genéricos. Podem ser procedimentos específicos, apenas para modularizar melhor. • Crie um arquivo separado para codificar os procedimentos genéricos que podem ser utilizados em qualquer programa (tais como, leitura de número, impressão de número, impressão de string, leitura de string, etc). Dê um nome ao arquivo, como por exemplo, lib_nome_aluno.asm. – Esse arquivo contendo os procedimentos genéricos não terá o procedimento main. Terá apenas os procedimentos genéricos. Assim, ele não irá gerar um executável. Todavia, deve ser montado. Mara gerar o arquivo montado, utilize o comando: nasm -f elf lib_nome_aluno.asm ∗ Esse comando efetua a montagem da biblioteca e gera como saída o arquivo lib_nome_aluno.o – Cada procedimento desse arquivo deverá ser declarado como global no topo do arquivo (por exemplo, global ler_int_s, sai_string). – Para que qualquer procedimento desse arquivo seja visível em outros programas/procedimentos de outros arquivos, é necessário declarar que esses procedimentos são externos (extern). • Todos os programas tem extensão .asm e a geração do executável deverá passar por dois comandos: nasm -f elf nome_do_programa.asm – Esse comando efetua a montagem do programa e gera como saída o arquivo nome_do_programa.o gcc -o nome_do_programa nome_do_programa.o lib_nome_aluno.o – Esse comando compila a partir dos arquivos montados (programa e biblioteca) e gera o executável nome_do_programa. 1. Crie um procedimento em Assembly que se chame ler_int_s que receba por parâmetro (via pilha) o endereço de uma variável de 32 bits (dword). O procedimento deverá utilizar a função scanf com o formato "%d" para realizar a leitura de um número inteiro sinalizado e armazenar na variável cujo endereço foi passado por parâmetro. 2. Crie um procedimento em Assembly que se chame sai_int_s que receba por parâmetro (via pilha) um número de 32 bits (dword). O procedimento deverá utilizar a função printf com a string "%d" para imprimir na tela o número inteiro sinalizado passado por parâmetro. 3. Crie um procedimento em Assembly que se chame ler_string que receba por parâmetro (via pilha) o endereço de uma string (cadeia de bytes). O procedimento deverá utilizar a função gets (que recebe o endereço da string) para realizar a leitura da string passada por parâmetro. 4. Crie um procedimento em Assembly que se chame sai_string que receba por parâmetro (via pilha) o endereço de uma string (cadeia de bytes). O procedimento deverá utilizar a função printf com a string "%s" para imprimir na tela a string passado por parâmetro. 5. Crie um procedimento em Assembly que se chame quebra_linha. Esse procedimento não receberá nenhum parâmetro. Ele deverá imprimir na tela uma quebra de linha. Dica: utilize a função printf passando uma string declarada no segment .data que tenha o valor 10 (é equivalente ao "\n"). Por exemplo, quebra db 10,0 6. Crie um procedimento em Assembly que se chame limpa_tela. O procedimento deverá executar uma chamada ao sistema para limpar a tela no terminal. No Linux, utilize no seu procedimento a função system com o parâmetro "clear". 7. Crie um procedimento em Assembly que se chame eh_primo que receba por parâmetro (via pilha) um número inteiro positivo e retorne em EAX 1 caso o número seja primo ou 0 caso contrário. 8. Crie um procedimento em Assembly que se chama media que receba por parâmetro (via pilha) o endereço de um vetor de dword e a quantidade de elementos do vetor. O procedimento deverá calcular a média de todos os elementos e retornar a parte inteira da média em EAX. 9. Crie um procedimento em Assembly que se chama fatorial que calcule o fatorial de um número passado por parâmetro (via pilha). Desafio: Experimente criar o procedimento utilizando um algoritmo recursivo. 10. Crie um PROGRAMA em Assembly que leia um número inteiro positivo e imprima na tela todos os números primos entre 1 e o número lido. 11. Crie um PROGRAMA em Assembly que leia um número inteiro positivo (no máximo 14) e calcule e exiba na tela o fatorial desse número. 12. Crie um PROGRAMA em Assembly que leia todos os 10 elementos (números inteiros sinalizados) de um vetor de dword previamente declarado no segment .bss. Apos a leitura desses elementos, calcule a média aproximada por falta (apenas a parte inteira). Por fim, imprima a média, imprima todos os elementos maiores ou iguais à média e, em seguida, imprima todos os elementos abaixo da média. A saída deverá seguir o exemplo abaixo: Média: 25 Acima ou igual à média 32 42 28 35 50 Abaixo da média 15 12 17 20 2 13. Crie um PROGRAMA em Assembly que leia os elementos de duas matrizes de inteiros (dword) A5×4 e B5×4 e calcule a soma A + B. Considere que ambas as matrizes possuem dimensões iguais e já foram declaradas no segment .bss 14. Crie um PROGRAMA em Assembly que declare no segment .data uma string contendo uma representação visual do que seria uma matriz de dimensões 3 × 4 com todos os seus elementos inicializados com 0. Veja como você pode fazer isso de forma intuitiva. m a t r i z _ v i s u a l db db db db db db db "+−−−+−−−+−−−+−−−+" , 1 0 , " | 0 | 0 | 0 | 0 | " ,10 , "+−−−+−−−+−−−+−−−+" , 1 0 , " | 0 | 0 | 0 | 0 | " ,10 , "+−−−+−−−+−−−+−−−+" , 1 0 , " | 0 | 0 | 0 | 0 | " ,10 , "+−−−+−−−+−−−+−−−+" , 1 0 , 0 O programa deverá: 1. imprimir a string matriz_visual na tela; 2. ler um número inteiro variando de 0 à 1 (linha) e armazenar numa variável I (dword); 3. ler outro número inteiro variando de 0 à 2 (coluna) e armazenar numa variável J (dword); 4. ler um terceiro número inteiro variando de 1 à 9 e armazenar em uma variável X (dword); 5. converter o número inteiro X lido em um número no formato caractere e armazenar esse valor no exato centro da célula da matriz visual representada pela string. 6. limpar a tela e imprimir a string matriz_visual novamente, mas agora, alterada. Exemplo: O programa mandará imprimir a string no passo 1 e o resultado inicial será esse: +−−−+−−−+−−−+−−−+ | 0 | 0 | 0 | 0 | +−−−+−−−+−−−+−−−+ | 0 | 0 | 0 | 0 | +−−−+−−−+−−−+−−−+ | 0 | 0 | 0 | 0 | +−−−+−−−+−−−+−−−+ Se o usuário digitar 1 para a linha I, 2 para a coluna J e 7 para o valor X, quando o programa mandar imprimir novamente a string matriz_visual, o resultado deverá ser esse: +−−−+−−−+−−−+−−−+ | 0 | 0 | 0 | 0 | +−−−+−−−+−−−+−−−+ | 0 | 0 | 7 | 0 | +−−−+−−−+−−−+−−−+ | 0 | 0 | 0 | 0 | +−−−+−−−+−−−+−−−+