2015-02-19 21 views
6

Il punto di questo problema è di eseguire il reverse engineering del codice c che è stato effettuato dopo aver eseguito il compilatore con l'ottimizzazione di livello 2. Il codice originale c è la seguente (calcola il massimo comun divisore):Tecnico di retromarcia ottimizzato codice c dal gruppo

int gcd(int a, int b){ 
    int returnValue = 0; 
    if (a != 0 && b != 0){ 
     int r; 
     int flag = 0; 
     while (flag == 0){ 
      r = a % b; 
      if (r ==0){ 
       flag = 1; 
      } else { 
       a = b; 
       b = r; 
      } 
     } 
     returnValue = b; 
    } 
    return(returnValue); 
} 

quando ho eseguito il compilazione ottimizzato ho eseguito dalla riga di comando:

gcc -O2 -S Problem04b.c 

per ottenere il file di assiemi per questo codice ottimizzato

.gcd: 
    .LFB12: 
     .cfi_startproc 
     testl %esi, %esi 
     je .L2 
     testl %edi, %edi 
     je .L2 
    .L7: 
     movl %edi, %edx 
     movl %edi, %eax 
     movl %esi, %edi 
     sarl $31, %edx 
     idivl %esi 
     testl %edx, %edx 
     jne .L9 
     movl %esi, %eax 
     ret 
     .p2align 4,,10 
     .p2align 3 
    .L2: 
     xorl %esi, %esi 
     movl %esi, %eax 
     ret 
     .p2align 4,,10 
     .p2align 3 
    .L9: 
     movl %edx, %esi 
     jmp .L7 
     .cfi_endproc 

ho bisogno di convertire il codice assembly di nuovo al codice C qui è dove mi trovo in questo momento:

int gcd(int a int b){ 
    /* 
     testl %esi %esi 
     sets zero flag if a is 0 (ZF) but doesn't store anything 
     */ 
    if (a == 0){ 
     /* 
      xorl %esi %esi 
      sets the value of a variable to 0. More compact than movl 
      */ 
     int returnValue = 0; 
     /* 
      movl %esi %eax 
      ret 

      return the value just assigned 
      */ 
     return(returnValue); 
    } 
    /* 
     testl %edi %edi 
     sets zero flag if b is 0 (ZF) but doesn't store anything 
     */ 
    if (b == 0){ 
     /* 
      xorl %esi %esi 
      sets the value of a variable to 0. More compact than movl 
      */ 
     int returnValue = 0; 
     /* 
      movl %esi %eax 
      ret 

      return the value just assigned 
      */ 
     return(returnValue); 
    } 

    do{ 
     int r = b; 
     int returnValue = b; 

    }while(); 


} 

Qualcuno può aiutarmi a scrivere di nuovo in codice c? Sono praticamente perso.

+0

Si dovrebbe essere perso, c'è un rason, perché non ci sono strumenti di automazione inversa utili fino ad ora. Tuttavia, sono ancora curioso di questo e di eventuali risposte. – icbytes

+1

Si potrebbe trarre beneficio (forse solo un po ') visualizzando l'assemblaggio generato, che viene mescolato con il codice C. All'interno di 'gdb' puoi usare' disas/m gcd', o un altro modo è 'objdump' con' -S' flag. –

+0

Dovresti compilare con 'gcc -fverbose-asm -O2 -S Problem04b.c' e potresti usare' -fdump-tree-all' per ottenere molti file di dump intermedi che rappresentano le rappresentazioni interne nelle varie fasi della compilazione. –

risposta

7

Prima di tutto, i valori sono mischiati nel codice. %esi inizia con il valore b e %edi inizia con il valore a.

Si può dedurre dalla linea testl %edx, %edx che %edx viene utilizzato come condizione variabile per il ciclo inizia con .L7 (se %edx è diverso da 0 allora il controllo viene ceduto al blocco .L9 e poi restituito al .L7). Faremo riferimento a %edx come remainder nel nostro codice di retroingegnerizzazione.


Cominciamo reverse-engineering del ciclo principale:

movl %edi, %edx 

Dal %edi negozi a, questo equivale a inizializzare il valore di remainder con a: int remainder = a;.

movl %edi, %eax 

Conservare int temp = a;

movl %esi, %edi 

Eseguire int a = b; (ricordiamo che è %edia e %esi è b).

sarl $31, %edx

Questa istruzione shift aritmetico sposta i nostri remainder variabili 31 bit verso destra mantenendo il segno del numero. Spostando 31 bit si imposta remainder su 0 se è positivo (o zero) e su -1 se è negativo. Quindi è equivalente a remainder = (remainder < 0) ? -1 : 0.

idivl %esi

Dividere %edx:%eax da %esi, nel nostro caso, dividere remainder * temp da b (variabile). Il resto verrà memorizzato in %edx o nel nostro codice remainder.Quando si combina questo con l'istruzione precedente: se remainder < 0 quindi remainder = -1 * temp % b, o altrimenti remainder = temp % b.

testl %edx, %edx 
jne .L9 

Verificare se remainder è uguale a 0 - se non è, passare alla .L9. Il codice semplicemente imposta b = remainder; prima di tornare a .L7. Per implementare questo in C, manterremo una variabile count che memorizzerà la quantità di volte in cui il ciclo ha iterato. Eseguiremo b = remainder all'inizio del ciclo ma solo dopo la prima iterazione, ovvero quando count != 0.

Ora siamo pronti a costruire il nostro ciclo C completa:

int count = 0; 
do { 
    if (count != 0) 
     b = remainder; 
    remainder = a; 
    temp = a; 
    a = b; 
    if (remainder < 0){ 
     remainder = -1 * temp % b; 
    } else { 
     remainder = temp % b; 
    } 

    count++; 
} while (remainder != 0) 

E dopo il ciclo termina,

movl %esi, %eax 
ret 

restituirà il MCD che il programma calcolato (nel nostro codice e' saranno memorizzati nella variabile b).

+0

grazie per il tuo aiuto ma che cos'è temp2? – scottybobby

+0

@scottybobby Oops, vedi la mia modifica. –

+1

Lo vedo ora. Grazie per l'aiuto! – scottybobby