Modulo VI Escrevendo cdigo em Linguagem de Montagem











![Formato do modo_de_endereçamento LDR{<cond>} <Rd>, <modo_de_endereçamento> § [<Rn>, #+/-<offset_12>] – O endereço é o Formato do modo_de_endereçamento LDR{<cond>} <Rd>, <modo_de_endereçamento> § [<Rn>, #+/-<offset_12>] – O endereço é o](https://slidetodoc.com/presentation_image/e99f5865522de662db3f9127ba9c7546/image-12.jpg)
![Formato do modo_de_endereçamento LDR{<cond>} <Rd>, <modo_de_endereçamento> § [<Rn>, +/- <Rm>]! – O endereço é Formato do modo_de_endereçamento LDR{<cond>} <Rd>, <modo_de_endereçamento> § [<Rn>, +/- <Rm>]! – O endereço é](https://slidetodoc.com/presentation_image/e99f5865522de662db3f9127ba9c7546/image-13.jpg)
![Formato do modo_de_endereçamento LDR{<cond>} <Rd>, <modo_de_endereçamento> § [<Rn>] +/-<Rm> - O endereço é o Formato do modo_de_endereçamento LDR{<cond>} <Rd>, <modo_de_endereçamento> § [<Rn>] +/-<Rm> - O endereço é o](https://slidetodoc.com/presentation_image/e99f5865522de662db3f9127ba9c7546/image-14.jpg)






























![Evite o Apelidamento de Variáveis [Aliasing of Variables] int Alias. Taken(int indx) { Trans. Evite o Apelidamento de Variáveis [Aliasing of Variables] int Alias. Taken(int indx) { Trans.](https://slidetodoc.com/presentation_image/e99f5865522de662db3f9127ba9c7546/image-45.jpg)


- Slides: 47
Modulo VI Escrevendo código em Linguagem de Montagem (Assembly)
Conjunto de Instruções § Arquitetura RISC § Reduced Instruction Set Computer § Operação com dados se dão nos registradores, nunca na memória § Instruções de carga (Load) de dados da memória em registradores § Instruções de armazenagem (Store) de dados de registradores para a memória
Formato Típico das Instruções Assembly MOV{<cond>}{S} <Rd>, <operador_de_deslocamento> § Itens entre { } são opcionais § Itens entre < > são uma breve descrição sobre um tipo de valor que será passado pelo programador § Muitas instruções podem ser executadas condicionalmente § Isso pode evitar os desvios (branch). Desvios podem prejudicar o desempenho de arquiteturas com muitos níveis no pipeline
Formato Típico das Instruções Assembly MOV{<cond>}{S} <Rd>, <operador_de_deslocamento> § Muitas instruções podem alterar ou não os bits de estados dependendo da forma da instrução § Facilita a comparação de dados (pos, neg, zero. . ) § Operações aritméticas em dados não relacionados podem ocorrer durante uma pendência, sem alterar os bits de estados § O último operando é um operador de deslocamento, outros são registradores.
Formato Típico das Instruções Assembly Em C if (a > b) c = a; else c = b; Considere que R 0, R 1 e R 2 estão carregados com os valores de a, b e c, respectivamente Em Assembly cmp ble mov b R 0, R 1 L 1 R 2, R 0 L 2 mov R 2, R 1 L 1: L 2: cmp R 0, R 1 movgt R 2, R 0 movle R 2, R 1 ou
Formato do operador_de_deslocamento MOV{<cond>}{S} <Rd>, <operador_de_deslocamento> § #<immediate> - Valor pode receber somente certos valores § <Rm> - Conteúdo de Rm § <Rm>, LSL #<shift_imm> - Conteúdo de Rm deslocado logicamente à esquerda por um valor imediato, exemplo: R 2, LSL #5 § <Rm>, LSL <Rs> - Conteúdo de Rm é deslocado logicamente à esquerda por um valor contido em Rs
Formato do operador_de_deslocamento MOV{<cond>}{S} <Rd>, <operador_de_deslocamento> § <Rm>, LSR #<shift_imm> - Conteúdo de Rm é deslocado logicamente à direita por um valor imediato § <Rm>, LSR <Rs> - Conteúdo de Rm é deslocado logicamente à direita por um valor contido em Rs § <Rm>, ASR #<shift_imm> - Conteúdo de Rm é deslocado para direita aritmeticamente por um valor imediato, com ou sem sinal § <Rm>, ASR <Rs> - Conteúdo de Rm é deslocado aritmeticamente à direita por um valor contido em Rs, com ou sem sinal
Formato do operador_de_deslocamento MOV{<cond>}{S} <Rd>, <operador_de_deslocamento> § <Rm>, ROR #<shift_imm> - Conteúdo de Rm é rotacionado à direita por um valor imediato § <Rm>, ROR <Rs> - Conteúdo de Rm é rotacionado à direita por uma quantidade Rs § <Rm>, RRX – Conteúdo de Rm é deslocado um bit à direita, o bit de Carry é deslocado para alto e o bit 0 de Rm é colocado no bit de carry As operações de deslocamento não mudam o conteúdo de Rm, apenas o valor do resultado usado como o operando
Operador de deslocamento: Formas do ROR 4 bits Imediato 8 bits imediato § Pode rotacionar à direita um valor imediato de 8 bits por qualquer número par de bits § O campo de rotação tem seu valor multiplicado por dois, dessas forma é possível deslocar até 30 bits § Apenas valores especiais de constantes podem ser representados § 0 x. FF (possível) § 0 x. FF 0 (possível) § 0 x. FF 1 (Não) § 0 x 1 FE (Não) § Pode ser necessário formar constantes em mais de uma etapa, por exemplo: 0 x. FFFF § Evite, se for possível, criar espaços para dados constantes
Formato do operador_de_deslocamento #<immediate> mov add mov ldr R 0, #127 R 0, R 1, #0 x 7 f R 2, #125952 R 2, =125951 ; R 0 = 127 ; R 0 = R 1 + 127 ; R 2 = 125952 = 123*4*4*4 ; R 2 = 125951 = 123*4*4*4 - 1 LDR R 2, =125951 é uma instrução que é desdobrada pelo montador em um carregamento (LDR) de uma posição de memória com o valor 125951 mov add mov R 0, #257 R 0, R 1, #0 x 101 R 2, #125951 ; erro! ; 125951 = 123*4*4*4 -1 erro!
Formato típico de uma instrução LDR/STR LDR{<cond>} <Rd>, <modo_de_endereçamento> § LDR - Usado para carregar um valor da memória para um registrador § STR - Usado para armazenar o valor em um registrador na memória § Pode ser executado condicionalmente § Não altera os bits de estados CSPR (Current Status Program Register) § Usa modo_de_endereçamento para endereçar o dado na memória
Formato do modo_de_endereçamento LDR{<cond>} <Rd>, <modo_de_endereçamento> § [<Rn>, #+/-<offset_12>] – O endereço é o conteúdo de Rn mais ou menos o offset_12 de 12 bits com sinal § [<Rn>, +/-<Rm>] – Endereço é o conteúdo de Rm mais ou menos o conteúdo de Rm § [<Rn>, +/-<Rm>, <shift> <shift_imm>] – O endereço é o conteúdo de Rn mais ou menos conteúdo de Rm deslocado por um operador <shift> pelo número de bits em <shift_imm> § [<Rn>, #+/-<offset_12>]! – O endereço é o conteúdo de Rn mais ou menos um offset_12 de 12 bits com sinal, endereço é escrito de volta para Rn (pré-indexado)
Formato do modo_de_endereçamento LDR{<cond>} <Rd>, <modo_de_endereçamento> § [<Rn>, +/- <Rm>]! – O endereço é o conteúdo de Rn mais ou menos o conteúdo de Rm, endereço é escrito de volta para Rn (pré-indexado) § [<Rn>, +/-<Rm>, <shift> <shift_imm>]! – O endereço é o conteúdo de Rn mais ou menos o conteúdo de Rm deslocado por um operador <shift> pelo número de bits em <shift_imm>, o endereço é escrito de volta para Rn (pré-indexado) § [<Rn>], #+/-<offset_12> - O endereço é o conteúdo de Rn, o valor offset_12 de 12 bits com sinal é adicionado a Rn, escrito de volta para Rn (pós-indexado)
Formato do modo_de_endereçamento LDR{<cond>} <Rd>, <modo_de_endereçamento> § [<Rn>] +/-<Rm> - O endereço é o conteúdo de Rn, Rm é adicionado ou subtraído de Rn, escrito de volta para Rn (pós-indexado) § [<Rn>] +/-<Rm>, <shift> <shift_imm> - O endereço é o conteúdo de Rn, conteúdo de Rm é deslocado operador <shift> pelo número de bits em <shift_imm> o valor é adicionado ou subtraído de Rn (pósindexado)
Formato do modo_de_endereçamento ; Coloca o valor apontado por R 0 em R 1 e incrementa R 0 para ; indicar o próximo inteiro de 32 bits ldr R 1, [R 0], #4 ; Incrementa o conteúdo de R 2 fazendo-o apontar para o próximo ; inteiro de 32 bits, esse inteiro é atribuído para R 3 ldr R 3, [R 2, #4]! ; O endereço é o valor R 5 deslocado 4 bytes, o resultado aponta ; para o próximo inteiro de 32 bits, esse inteiro é atribuído para R 4. ; R 5 não é alterado ldr R 4, [R 5, #4] ; O mesmo endereçamento pode ser usado pela instrução STR str R 1, [R 0], #4 str R 3, [R 2, #4]! str R 4, [R 5, #4]
Instruções Dignas de Atenção § BIC – Bit Clear § desliga os bits indicados na mascara § CLZ – Count Leading Zeros § ideal para determinar o número de bits necessários para representar um número § LDM/STM – Load/Store Multiple § usado para salvar e recuperar registradores na pilha § especialmente útil: STMDB, LDMDB § RSB – Reverse Substract Operand Order § permitem que o operador_de_deslocamento seja subtraídos do registrador
Registradores § R 0 até R 3 – Propósito geral, salvos pelo chamador da rotina § R 4 até R 11 – Propósito geral, salvos pela rotina chamada § R 12 – Frame Pointer (algumas vezes) § R 13 – Stack Pointer (SP – Apontador da Pilha) § R 14 – Link Register (LR) § R 15 – Program Counter (PC) § CSPR – Currente Status Program Register, contém a sinalização de overflow, zero, underflow, . . .
Registradores § Pode ser desejável dar nomes mais sugestivos aos registradores, para isso usa-se a diretiva RN contador RN R 0 resultado RN R 1 § Pode ser desejável também colocar nomes as constantes literais (valores imediatos) mascara EQU 0 x 000000 ff minimo EQU 0 maximo EQU 32767 § Usando: mov contador, #minimo cmp contador, #maximo
Convenção da Pilha § A Pilha cresce “para baixo” § Dados colocados na pilha têm endereços de memória menores que os dados colocados previamente § O armazenamento dos dados na pilha é pré-decrementado. § Ponteiro da pilha aponta para o último elemento colocado nela. Topo SP SP + 4 SP + 8 SP + 12 SP + 16 Crescimento da pilha
Assembly: Estrutura do Arquivo ; cpenable. asm Comentários se iniciam com ; AREA CPENABLE, CODE, READONLY EXPORT é usado para exportar o nome da função para uso externo Rótulos começam na coluna 1, PROC é uma diretiva usada para identificar funções Informações sobre a área que será usada ; CP 15 Routines EXPORT Get. CP 0 Enable ; Retorna valor escrito em r 0 Get. CP 0 Enable PROC MRC p 15, 0 x 0, r 0, c 15, c 1, 0 x 0 mov pc, lr ENDP END indica onde o arquivo acaba ENDP mostra onde a função acaba
Chamando um Módulo em Assembly § Por convenção no C para o ARM os quatro primeiros parâmetros são passados nos registradores R 0 – R 3 § O restante é passado na pilha, da esquerda para a direita, sendo que o parâmetro mais à esquerda está no topo da pilha § O registrador Stack Pointer aponta para o 5º parâmetro se ele estiver presente § Ajustes são necessários se a função não for uma função folha § Para funções folha, podemos usar o stack pointer tanto para pilha quanto para frame pointer § Para funções não folha o stack pointer será ajustado, ou usa-se R 12 como frame pointer ou ajusta-se as referências das variáveis colocadas na pilha pelo chamador
Exemplo da Manipulação de Parâmetros em uma função Asm Parâmetros de a-d estão em R 0 -R 3, respectivamente O parâmetro e é o mais baixo na pilha, o ponteiro da pilha stack pointer aponta para ele. Agora, ele está em R 4. ; parms. asm AREA PARMS, CODE, READONLY ; Routines Salva os EXPORT Parms ; Parms (a, b, c, d, e, f) registradores R 4 Parms PROC e R 5 na pilha stmdb sp, {r 4, r 5} ldr r 4, [sp] ldr r 5, [sp, #4] Parâmetro f é o ; o código vai aqui ldmdb sp, {r 4, r 5} próximo na pilha, mov pc, lr assim, stack ENDP pointer+4 é END atribuido para R 5
Retornando da Função em Assembly Restaura os valores de R 4 e R 5, ajuste o stack pointer se necessário Restaura o PC com o conteúdo do Link Register. Lembre-se de salvar o conteúdo de LR se esta função não for uma função folha ; count. asm AREA PARMS, CODE, READONLY ; Routines EXPORT Count PROC stmdb sp, {r 4, r 5} mov r 4, #0 mov r 5, #0 x. F 8 loop Valores de add r 4, #1 retorno da cmp r 4, r 5 blt loop função são passados em R 0 mov r 0, r 4 ldmdb sp, {r 4, r 5} mov pc, lr ENDP END
Exemplo da Manipulação de Parâmetros em uma função Asm Soma os dois parâmetros e retorna o resultado pela função ; soma 2. asm AREA SOMA, CODE, READONLY ; Routinas EXPORT soma 2 ; int soma 2(int, int) soma 2 PROC add R 0, R 1 ; R 0 = R 0 + R 1 mov pc, lr ENDP END
Retornando da Função em Assembly Soma os seis parâmetros e retorna o resultado pela função ; soma 6. asm AREA SOMA, CODE, READONLY ; Routinas EXPORT soma 6 ; int soma 6(int, int, int) soma 6 PROC stmdb add add ldr add ldmdb mov ENDP END SP, {R 4, R 5} R 0, R 1, R 2, R 3 R 0, R 1 R 4, [SP] R 5, [SP, #4] R 1, R 4, R 5 R 0, R 1 SP, {R 4, R 5} PC, LR
Retornando da Função em Assembly Soma os seis parâmetros e retorna o resultado no sétimo parâmetro Observe que os registradores R 4 e R 5 não estão mais sendo usados. ; soma 7. asm AREA SOMA, CODE, READONLY ; Routinas EXPORT soma 7 ; int soma 7(int, int, int *) soma 7 PROC add add ldr str mov ENDP END R 0, R 1, R 2, R 3 R 0, R 1, [SP] R 2, [SP, #4] R 1, R 2 R 0, R 1, [SP, #8] R 0, [R 1] PC, LR
Retornando da Função em Assembly AREA SOMA, CODE, READONLY EXPORT soma 7 ; int soma 7(int, short int, short int *) soma 7 Soma os seis parâmetros e retorna o resultado no sétimo parâmetro PROC stmdb add add ldrh add ldr strh ldmdb mov ENDP END SP, {R 4, R 5, R 6} R 0, R 1, R 2, R 3 R 0, R 1 R 4, [SP] R 5, [SP, #4] R 1, R 4, R 5 R 0, R 1 R 5, [SP, #8] R 0, [R 5] SP, {R 4, R 5, R 6} PC, LR Observe que os três últimos parâmetros têm 16 bits cada
Passando vetor parâmetro em Assembly Retorna o endereço de um elemento em um vetor int vet[10]; int p*; int * procura(int v[ ], int x) { int i; for (i=0; i<10; i++) if (v[i]==x) return &v[i]; return NULL; } void main(void) {. . . p=procura(vet, 1234); . . } procura AREA VETOR, CODE, READONLY EXPORT procura PROC mov R 2, #0 laco ldr cmp addeq moveq add cmp movge b ENDP END R 3, [R 0, R 2, LSL #2] R 1, R 3 R 0, R 2 PC, LR ; return &v[i] R 2, #10 R 0, #0 ; return NULL PC, LR laco
Passando ponteiro por parâmetro em Assembly Iniciação de uma lista linear simplesmente encadeada typedef struct s_no { long dado; struct s_no *prox; } no; no *lista; void inicia. Lista(no *d=NULL; } void main(void) {. . . inicia. Lista(&lista). . . } **d) { &lista, d R 0 lista, *d [R 0] ? antes *d [R 0] depois AREA LISTA, CODE, READONLY EXPORT inicia. Lista PROC mov R 1, #0 str R 1, [R 0] mov PC, LR ENDP END
Exportando uma função Assembly de uma DLL AREA. drectve DRECTVE DCB “-export: Count” DCB é usado para definir uma string na qual contém diretivas para o ligador ajustar o código como sendo uma exportação. dll A diretiva deve estar na área DRECTVE em uma seção chamada. drectve ; count. asm AREA COUNT, CODE, READONLY ; Rotinas EXPORT Count PROC stmdb sp, {r 4, r 5} mov r 4, #0 mov r 5, #0 x. F 8 loop add r 4, #1 cmp r 4, r 5 blt loop mov r 0, r 4 ldmdb sp, {r 4, r 5} mov pc, lr ENDP END
Usando Assembly na IDE § Clique na pasta Source files, adicione um arquivo. asm no projeto § Selecione ‘All Files’ na caixa de diálogo, assim você pode ver os arquivos. asm § Clique com o botão direito no arquivo ASM na pasta source do projeto, vá para settings § Na aba Custom Build § Digite armasm para chamar o montador § Utilize a opção xscale cpu se estiver chamando mnemônicos xscale (armasm –cpu xscale) § Use o caminho relativo ao arquivo como o apresentado no arquivo de entrada (input File) § Use apenas o nome do arquivo com a extensão. obj como saída
Melhorando as Dependências Usando LDR add r 1, r 2, r 3 ldr r 0, [r 5] add r 6, r 0, r 1 sub r 8, r 2, r 3 mul r 9, r 2, r 3 ldr r 0, [r 5] add r 1, r 2, r 3 sub r 8, r 2, r 3 add r 6, r 0, r 1 mul r 9, r 2, r 3 Com o dado na Cache, três ciclos são necessários para a transferência do valor ao registrador Como o dado pode não estar na cache, o LDR deve ser colocado o mais cedo possível antes do ponto de utilização
Instruções LDRD/STRD § Lê e armazena 64 bits em dois registradores § O Endereço deve estar alinhado em 8 bytes (64 bits) § Os registradores devem ser os pares: § R 0, R 1; R 2, R 3; R 4, R 5; . . . add sub ldrd orr mul r 6, r 5, r 0, r 8, r 7, r 6, [r 3] r 1, r 0, r 8 r 9 #0 xf r 7 ldrd add sub mul orr r 0, r 6, r 5, r 7, r 8, [r 3] r 7, r 6, r 0, r 1, r 8 r 9 r 7 #0 xf LDRD necessita de 3 ciclos para disponibilizar os dados nos registradores
Instruções LDM/STM § 2 a 20 ciclos para disponibilizar os valores nos registradores, § depende do número de registradores envolvidos na troca de dados § A latência é de 2 ciclos mais 1 ciclo por registrador envolvido § A próxima instrução é atrasada um ciclo (com ou sem dependências e acessos à memória)
Utilizando LDM ou LDRD § Soma de dois valores de 64 bits § r 0 endereço do primeiro valor § r 1 endereço do segundo valor ldm r 0, {r 2, r 3} ldm r 1, {r 4, r 5} adds r 0, r 2, r 4 adc r 1, r 3, r 5 ldrd r 2, [r 0] ldrd r 4, [r 1] adds r 0, r 2, r 4 adc r 1, r 3, r 5 Mais rápido para executar
Indo além do básico em Assembly § Estude o ARM (ARM Architecture Reference Manual), também disponível no formato pdf em www. arm. org § Estude o help do EVC++, tópico ARM Assembly § Compile seu código com a opção de disassembly ativada e veja o que o compilador gera: § Misture código C com assembly § Desligue as otimizações do compilador
Indo além do básico em Assembly: Use o e. VC++ Vá em Project Settings-> C/C++ tab -> Selecione Listing Files Coloque List Assembly with Source
Quando e onde substituir o código por Assembly § Apenas em regiões do código críticas no desempenho § Para tirar maior proveito do pipeline do processador Intel® XScale™ § O número de variáveis envolvidas for grande § O compilador é incapaz de fazer um bom uso de muitos registradores § O compilador está armazenando valores locais em memória § Quando esses valores poderiam ser mantidos nos registradores § Há instruções muito melhores em Assembly para: § Melhor acesso a overflow § Melhor acesso a instruções DSP
Quando for escrever o código em Assembly § Utilize muitos comentários § Inclua o código em C, que o Assembly estiver substituindo, como comentário § Use as diretivas RN e EQU para dar nomes esclarecedores aos registradores e aos valores imediatos § Sempre salve e recupere os conteúdos Registradores usados pela função que faz a chamada se você os usa § Cuidado ao trabalhar com funções que não são do tipo folha § Salve o conteúdo de LR § Observe as alterações em SP
Quando for escrever o código em Assembly § Tome cuidado com o alinhamento de dados § Para ler dados do tipo short em um vetor use as instruções LDRH ou LDRSH § Use STRH para escrever dados do tipo short em um vetor § Assim como com os tipos short, tenha certeza de estar usando LDRB para vetores de bytes § Desconsiderar essas instruções para dados do tipo short ou byte pode causar problemas de alinhamento de dados Erros de alinhamento em geral causam o travamento da máquina, deixando-o sem pistas do que pode ter dado errado com o seu programa
Otimizando Código em Assembly § Não armazena dados de volta a pilha § Mantenha as variáveis em registradores o máximo de tempo possível § Observe a tabela de latências § Ordene as instruções tendo em mente o tempo de latência de cada uma delas § Tente desenrolar o laço § Tente usar Pre. Load também em Assembly (Instrução PLD) § Lembre-se que algumas instruções aritméticas levam mais de 1 ciclo de clock § Não deixe de tirar proveito das instruções de execução condicional § Repita pequenos pedaços de código se isso conseguir evitar desvios (branches)
Modulo VI Técnicas de Otimização Considerações sobre o código Compilado
Evite o uso desnecessário de Shorts int Test(void) { short x, y; x = 3; y = 4; Observe que o compilador realiza dois deslocamentos para estender o sinal do valor de Short. Sum para retornar o valor de Test. Perda de tempo! ; depois de retornar de Short. Sum mov r 1, r 0, lsl #16 mov r 0, r 1, #asr #16 mov pc, lr ENDP Short. Sum PROC ; start return Short. Sum(x, y); } mov r 0, lsl #16 mov r 2, r 0, asr #16 mov r 1, lsl #16 short Short. Sum(short a, short b) add r 0, r 2, r 1, asr #16 { mov r 2, r 0, lsl #16 return a+b; } Diversos mov’s para truncar e estender o sinal dos operandos e do resultado mov r 0, r 2, asr #16 mov pc, lr ; return ENDP
Corrija as suas variáveis shorts int Test(void) { int x, y; Se necessário manter o mesmo range de short, use cast ; Depois de retornar de Shot. Sum mov r 1, r 0, lsl #16 mov r 0, r 1, #asr #16 x = 3; mov pc, lr y = 4; ENDP return (short)Short. Sum(x, y); } Short. Sum PROC ; start add r 0, r 1 int Short. Sum(int a, int b) { mov pc, lr ; return a+b; } ENDP
Evite o Apelidamento de Variáveis [Aliasing of Variables] int Alias. Taken(int indx) { Trans. Index(&indx); indx += 5; indx += Displace. Index(indx); indx += Dither. Index(indx); return indx; } Já que usamos o endereço de indx, o compilador é conservador em mantê-lo em um registrador, causando vários acessos à memória ; Trans. Index(&indx) add r 0, sp, #8 bl Trans. Index ; indx += 5; ldr r 3, [sp, #8] add r 0, r 3, #5 str r 0, [sp, #8] ; indx += Displace. Index(indx); bl Displace. Index ; 00000028 mov r 3, r 0 ldr r 0, [sp, #8] add r 0, r 3 str r 0, [sp, #8] ; indx += Dither. Index(indx); bl Dither. Index ; 0000003 C mov r 3, r 0 ldr r 0, [sp, #8] add r 0, r 3
Aperfeiçoando o Código int Alias. Taken(int indx) ; ref = indx; mov r 4, r 0 ; Trans. Index(&ref); { add r 0, sp, #0 inf ref = indx; str r 4, [sp] Trans. Index(&ref); bl Trans. Index indx += 5; indx += Displace. Index(indx); ; indx += 5; add r 4, #5 indx += Dither. Index(indx); ; indx += Displace. Index(indx); return indx; mov r 0, r 4 bl Displace. Index ; 00000028 add r 4, r 0 } Observe que a variável indx é mantida agora em r 4, sem exigir repetidos STR/LDR para [sp, #0] ; indx += Dither. Index(indx); mov r 0, r 4 bl Dither. Index ; 00000034 add r 0, r 4
Módulo VI Laboratório