2015-10-25 12 views
6

Il codice èRicerca di codice C mancante, dato codice assembly?

int f(int x, int y, int z) { 
    if (/* missing code here */) 
    return z; 
    else 
    return -z; 
} 

e l'Assemblea è

pushl %ebp 
    movl %esp, %ebp 
    movl 8(%ebp), %eax 
    cmpl 12(%ebp), %eax 
    jge .L2 
    movl 16(%ebp), %eax 
    jmp .L3 
.L2: 
    movl 16(%ebp), %eax 
    negl %eax 
.L3: 
    popl %ebp 
    ret 

E la domanda chiede di me per trovare ciò che l'espressione di test mancanti devono essere per ottenere il codice assembly data. Ok, abbastanza facile. Esiste un confronto ovvio tra x e . L'operatore jge preformerà il salto nel corpo del ciclo se 12(%ebp) > %eax.

Le scelte possibili sono

x<=y x>=y x>y x<y

mia risposta è stata x<=y, dal momento che 12(%ebp) è un riferimento a y, ed è la destinazione. Ma questa risposta era sbagliata, e non vedo come. Qualche suggerimento? Grazie mille.

+1

jge non significa: salta maggiore o uguale? '> =' –

+2

Puoi decompilare/disassemblare ma onestamente non c'è molto, quindi potresti probabilmente provare a capire cosa succede tu stesso. Penso che stia facendo x - y ('8 (% ebp)' e '12 (% ebp)' sono i primi due argomenti della funzione fuori dallo stack) e poi saltano se è maggiore di zero. Il che, a mio avviso, implicherebbe che x sia maggiore di y. –

+1

Utilizzando la sintassi intel e lo pseudo codice, il confronto è equivalente a 'cmp x, y'. Da qui, si arriva al ramo 'return -z' se x> = y.Dal momento che vogliamo sapere qual è la condizione testata, semplicemente invertiamo questo test, dandoci così il test che deve risultare vero per il ramo desiderato. Diventa subito chiaro che la condizione effettiva testata era x = y) – enhzflep

risposta

5

Ecco l'assembly x86 annotato:

pushl %ebp ; save the old stack movl %esp, %ebp ; set up your local, new stack movl 8(%ebp), %eax ; take the first function argument and store it into eax cmpl 12(%ebp), %eax ; compare the 2nd function arg with the 1st (in eax)

Dopo questo, c'è un jge che significa, in sostanza, "saltare se maggiore o uguale", che si può fare dopo l'istruzione cmp.

Ciò significa che salta se il primo argomento è maggiore del secondo argomento e, quindi, x >= y.

Tuttavia, questo salto (su L2) annullerà effettivamente z, quindi restituirà z. Quello che in realtà si desidera è il salto a L3, cosa che succederebbe se x < y, che dovrebbe essere il risultato finale.

+0

Mi chiedo perché i parametri vengono passati in pila invece dei registri, secondo la convenzione di chiamata. – edmz

+3

@black, supponendo che Linux, il codice nella domanda sembra essere a 32 bit, quindi i parametri vengono generalmente passati sullo stack (ABI i386 a 32 bit) a differenza del sistema V 64-bit ABI dove i parametri che si adattano possono essere passati nei registri (e se è necessario essere in pila) –

2

Puoi chiedere a GCC, che cosa farà. Creare una fonte con diverse funzioni:

test.c

int f1 (int x, int y, int z) { 
    if (x < y) 
    return z; 
    else 
    return -z; 
} 

int f2 (int x, int y, int z) { 
    if (x > y) 
    return z; 
    else 
    return -z; 
} 

int main (void) 
{ 
    return 0; 
} 

f1 esegue (x < y), f2 esegue (x> y). Ora compila:

gcc test.c -m32 -Wa,-ahln -fno-asynchronous-unwind-tables 

Si vede il gruppo di test.c. Cerca f1: e f2:, che sono i punti di ingresso delle funzioni. Quale corrisponde al tuo snippet? Vedrai che le corrispondenze f1, mentre f2 gestisce con jle.