Converter o programa C em código de montagem

Como é que converto este programa C em código de montagem? Estou tendo dificuldade em entender este processo ou como iniciá-lo. Sou novo nisto. Qualquer ajuda seria apreciada!

while(a!=b){
     if(a > b){
        a = a - b;
       }
        else{
          b = b - a;
    }
  }
   return a;
   }

nota lateral: suponha que dois inteiros positivos a e b já estão inscritos nos registos R0 e R1.
Pode deixar comentários a explicar como o fez?

 3
Author: Sam, 2014-09-29

5 answers

Se estiver a utilizar gcc, pode obter a montagem como gcc -S -o a.s a.c se o seu código-fonte for a.c. Se estiver a usar o Visual Studio, pode obtê-lo quando depurar, seleccionando a janela de "desmontagem". Aqui está a saída do Visual studio (eu nomeei a sub-rotina / função chamada "comum" é por isso que "comum" aparece):

    while(a!=b){
    003613DE  mov         eax,dword ptr [a]  
    003613E1  cmp         eax,dword ptr [b]  
    003613E4  je          common+44h (0361404h)  
         if(a > b){
    003613E6  mov         eax,dword ptr [a]  
    003613E9  cmp         eax,dword ptr [b]  
    003613EC  jle         common+39h (03613F9h)  
            a = a - b;
    003613EE  mov         eax,dword ptr [a]  
    003613F1  sub         eax,dword ptr [b]  
    003613F4  mov         dword ptr [a],eax  
         }
         else{
    003613F7  jmp         common+42h (0361402h)  
             b = b - a;
    003613F9  mov         eax,dword ptr [b]  
    003613FC  sub         eax,dword ptr [a]  
    003613FF  mov         dword ptr [b],eax  
        }
      }
    00361402  jmp         common+1Eh (03613DEh)  
       return a;
    00361404  mov         eax,dword ptr [a]  
    }

Aqui a variável a é guardada na memória inicialmente e assim é b (dword ptr [b]).

 10
Author: CS Pei, 2014-09-29 02:27:16
O professor que me ensinou a programação do sistema usou o que ele chamou de "atomic-C" como um trampolim entre C e montagem. As regras para atomic-C são (tanto quanto me lembro):
  1. apenas expressões simples permitidas, ou seja a = b + c; é permitido a = b + c + d; não é permitido porque existem dois operadores lá.
  2. apenas expressões booleanas simples são permitidas numa declaração if, ou seja if (a < b) é permitido, mas if (( a < b) && (c < d)) não é permitido.
  3. só se houver declarações, mais ninguém. bloco.
  4. não é permitido fazer ou fazer enquanto é permitido, apenas goto e label

Então, o programa acima se traduziria em;

 label1:
     if (a == b) 
         goto label2;

     if (a < b)
         goto label4;

     a = a - b;
     goto label3;

 label4:
     b = b - a;

 label3:
     goto label1; 

 label2:
     return a;
Espero ter percebido. correct...it tem sido quase vinte anos desde que eu tive que escrever atomic-C. agora assumindo que o acima está correto, vamos começar a converter algumas das declarações atomic-C em MIPS (assumindo que é o que você está usando) montagem. A partir do link fornecido por Elliott Frisch, podemos quase imediatamente traduzir o passos de subtracção:
a = a - b     becomes R0 = R0 - R1 which is: SUBU R0, R0, R1
b = b - a     becomes R1 = R1 - R0 which is: SUBU R1, R1, R0

Usei subtracção sem sinal devido tanto a como b serem inteiros positivos.

As comparações podem ser feitas desta forma:

if(a == b) goto label2 becomes if(R0 == R1) goto label2 which is: beq R0, R1, L2?

O problema aqui é que o terceiro parâmetro do Código op-beq é o deslocamento que o PC move. Não saberemos esse valor até terminarmos a montagem manual aqui.

A desigualdade é mais trabalho. Se deixarmos as instruções do pseudo-Código, primeiro precisamos usar o op-code set on less than que coloca um no registo de destino se o primeiro registo for inferior ao segundo. Uma vez que tenhamos feito isso, podemos usar o branch on equal como descrito acima.
if(a < b)              becomes    slt R2, R0, R1  
    goto label4                   beq R2, 1, L4?        
Os saltos são simples, são apenas j e depois a etiqueta para onde ir. Então,
goto label1 becomes j label1
A última coisa que temos de resolver é o regresso. O retorno é feito movendo o valor que queremos um registro especial V0 e, em seguida, saltar para a próxima instrução após a chamada para esta função. O problema é que os MIPS não têm um registo para register move command (ou se ele faz eu esqueci - lo) assim que nos movemos de um registro para RAM e, em seguida, de volta novamente. Finalmente, usamos o registro especial R31 que contém o endereço de retorno.
return a     becomes   var = a      which is SW R0, var
                       ret = var    which is LW var, V0
                       jump RA      which is JR R31
Com esta informação, o programa torna-se. E também podemos ajustar os saltos que não conhecíamos antes.
           L1:
 0x0100        BEQ R0, R1, 8
 0x0104        SLT R2, R0, R1                 ; temp = (a < b)  temp = 1 if true, 0 otherwise
 0x0108        LUI R3, 0x01                   ; load immediate 1 into register R3
 0x010C        BEQ R2, 1, 2                   ; goto label4         
 0x0110        SUBU R0, R0, R1                ; a = a - b
 0x0114        J L3                           ; goto label3
           L4:
 0x0118        SUBU R1, R1, R0                ; b = b - a;
           L3:
 0x011C        J L1                           ; goto lable1
           L2:
 0x0120        SW R0, ret                     ; move return value from register to a RAM location
 0x0123        LW ret, V0                     ; move return value from RAM to the return register.
 0x0124        JR R31                         ; return to caller
Faz quase vinte anos desde que tive que fazer coisas como esta (agora um dia, se precisar de montagem, só faço o que outros sugeriram e deixo o compilador fazer tudo pesado). Estou certo de que cometi alguns erros ao longo do caminho, e ficaria feliz por quaisquer correções ou sugestões. Eu só entrei nesta longa discussão porque eu interpretei a pergunta do OP como fazendo uma tradução manual -- algo que alguém poderia fazer como eles estavam aprendendo montagem. Saúde.
 9
Author: thurizas, 2014-09-29 17:04:58
Eu traduzi esse código para um conjunto de 16 bits NASM:
loop:
    cmp ax, bx
    je .end;        if A is not equal to B, then continue executing. Else, exit the loop
    jg greater_than;    if A is greater than B...

    sub ax, bx;     ... THEN subtract B from A...

    jmp loop;       ... and loop back to the beginning!

.greater_than:
    sub bx, ax;     ... ELSE, subtract A from B...

    jmp loop;       ... and loop back to the beginning!

.end:
    push ax;        return A

Eu usei {[1] } em vez de r0 e bx em vez de r1

 1
Author: SirPython, 2015-03-17 00:07:52
ORG 000H                   // origin
MOV DPTR,#LUT              // moves starting address of LUT to DPTR
MOV P1,#00000000B          // sets P1 as output port
MOV P0,#00000000B          // sets P0 as output port
MAIN: MOV R6,#230D         // loads register R6 with 230D
      SETB P3.5            // sets P3.5 as input port
      MOV TMOD,#01100001B  // Sets Timer1 as Mode2 counter & Timer0 as Mode1 timer
      MOV TL1,#00000000B   // loads TL1 with initial value
      MOV TH1,#00000000B   // loads TH1 with initial value
      SETB TR1             // starts timer(counter) 1
BACK: MOV TH0,#00000000B   // loads initial value to TH0
      MOV TL0,#00000000B   // loads initial value to TL0
      SETB TR0             // starts timer 0
HERE: JNB TF0,HERE         // checks for Timer 0 roll over
      CLR TR0              // stops Timer0
      CLR TF0              // clears Timer Flag 0
      DJNZ R6,BACK
      CLR TR1              // stops Timer(counter)1
      CLR TF0              // clears Timer Flag 0
      CLR TF1              // clears Timer Flag 1
      ACALL DLOOP          // Calls subroutine DLOOP for displaying the count
      SJMP MAIN            // jumps back to the main loop
DLOOP: MOV R5,#252D
BACK1: MOV A,TL1           // loads the current count to the accumulator
       MOV B,#4D           // loads register B with 4D
       MUL AB              // Multiplies the TL1 count with 4
       MOV B,#100D         // loads register B with 100D
       DIV AB              // isolates first digit of the count
       SETB P1.0           // display driver transistor Q1 ON
       ACALL DISPLAY       // converts 1st digit to 7seg pattern
       MOV P0,A            // puts the pattern to port 0
       ACALL DELAY
       ACALL DELAY
       MOV A,B
       MOV B,#10D
       DIV AB              // isolates the second digit of the count
       CLR P1.0            // display driver transistor Q1 OFF
       SETB P1.1           // display driver transistor Q2 ON
       ACALL DISPLAY       // converts the 2nd digit to 7seg pattern
       MOV P0,A
       ACALL DELAY
       ACALL DELAY
       MOV A,B             // moves the last digit of the count to accumulator
       CLR P1.1            // display driver transistor Q2 OFF
       SETB P1.2           // display driver transistor Q3 ON
       ACALL DISPLAY       // converts 3rd digit to 7seg pattern
       MOV P0,A            // puts the pattern to port 0
       ACALL DELAY         // calls 1ms delay
       ACALL DELAY
       CLR P1.2
       DJNZ R5,BACK1       // repeats the subroutine DLOOP 100 times
       MOV P0,#11111111B
       RET

DELAY: MOV R7,#250D        // 1ms delay
 DEL1: DJNZ R7,DEL1
       RET

DISPLAY: MOVC A,@A+DPTR    // gets 7seg digit drive pattern for current value in A
         CPL A
         RET
LUT: DB 3FH                // LUT starts here
     DB 06H
     DB 5BH
     DB 4FH
     DB 66H
     DB 6DH
     DB 7DH
     DB 07H
     DB 7FH
     DB 6FH
END
 0
Author: denish, 2017-02-17 12:37:35

Https://ctoassembly.com

Tente executar o seu código aqui. Basta copiá-lo dentro da função principal, definir as variáveis a e b antes do seu ciclo while e você está pronto para ir.

Você pode ver como o código é compilado para montagem com uma quantidade razoável de explicação, e então você pode executar o código de montagem dentro de uma CPU hipotética.

 0
Author: darijan, 2017-06-18 17:00:37