2009-12-22 9 views
7

Sto imparando 80386 da PC Assembly by paul caurterproblema nel capire mul & istruzioni IMUL del linguaggio Assembly

mul source 
  • Se l'operando è byte di dimensioni, che viene moltiplicato per il byte nel registro AL e il risultato viene memorizzato in i 16 bit di AX.

multa.

  • Se la sorgente è 16 bit, è moltiplicata per la parola in AX ed il risultato 32 bit è memorizzato in DX: AX.

Q1: Perché DX: AX? Perché non può essere archiviato in EAX/EDX?

imul è davvero confusa

imul dest, source1 
imul dest, source1, source2 

alt text http://img697.imageshack.us/img697/8976/imul.gif

ho problema nella comprensione del tavolo.

Q2: nella seconda voce della tabella. Ancora una volta, perché DX: AX. Perché non EAX o EDX?

Ora consideriamo seguente frammento di codice:

imul eax ; edx:eax = eax * eax 
mov ebx, eax ; save answer in ebx 
mov eax, square_msg ; square_msg db "Square of input is ", 0 
call print_string ; prints the string eax 
mov eax, ebx 
call print_int ; prints the int stored in eax 
call print_nl ; prints new line 

Q3: suo previsously detto che The notation EDX:EAX means to think of the EDX and EAX registers as one 64 bit register with the upper 32 bits in EDX and the lower bits in EAX. Quindi la risposta si trova anche nella edx, giusto? nel codice precedente non abbiamo considerato alcun EDX ci riferiamo solo a EAX Come funziona ancora?

Q4: Ho problemi con il resto di tutte le voci nella tabella. il caso peggiore di moltiplicazione di due numeri n bit (n = 8/16/32 bit) è 2n bit. Come mai la sua memorizzazione del risultato di due risultati di moltiplicazione 16/32 bit nel registro della stessa dimensione stessa?

risposta

7

Q1/Q2: il set di istruzioni x86 mantiene la cronologia a 16 bit. Quando si esegue una moltiplicazione a 16 bit, la risposta viene memorizzata in DX: AX. È proprio così, perché è così che era in terra a 16 bit.

Q3: il codice che hai mostrato ha un bug se cerchi di calcolare il quadrato di un numero maggiore di 2^16, perché il codice ignora i 32 bit alti del risultato memorizzato in edx.

Q4: Penso che potresti aver frainteso il tavolo. Le moltiplicazioni a 8 bit sono memorizzate in un risultato a 16 bit; Le moltiplicazioni a 16 bit sono memorizzate in un risultato a 32 bit; Le moltiplicazioni a 32 bit sono memorizzate in un risultato a 64 bit. A quale linea ti riferisci specificamente?

+1

@ Q3: lo sapevo. questo è il codice di quel libro di Paul Carter. Puoi dirmi come dovrebbe essere il codice? Sono confuso su come stampare il risultato. – claws

+0

Il codice fornito è solo un esempio; il testo dovrebbe indicare da qualche parte che non calcolerà correttamente il quadrato se l'input è al di fuori dell'intervallo previsto. Dato che stai chiamando una funzione 'print_int' per stampare un intero a 32 bit, vedi se riesci a trovare una funzione' print_int64' per stampare un intero a 64 bit. –

+0

@ Q4: Sì, è così che dovrebbe essere, ma la tabella dice che la moltiplicazione a 16 bit è memorizzata in un risultato a 16 bit. 4a voce: 'dest * = source1' => dest = dest * source1; dest è 16 bit e source1 è 16 bit. Ed è lo stesso caso per tutte le voci della tabella. anche l'ultima entry source1 e source2 sono a 32 bit e dest è anche a 32 bit. – claws

1

Q1/D2: Penso che la ragione sia storica. Prima che 32 bit fossero un'opzione, non c'era né eax né edx. La funzionalità a 32 bit è stata aggiunta per essere compatibile con la retromarcia.

Q3: i bit di ordine basso saranno in eax. Quelli sono gli unici a cui tieni a meno che non ci sia un trabocco nei bit più alti.

Q4: Sicuramente una tabella dispari. Penso che tu capisca comunque.

1

A1:mul era originariamente presente sui processori 8086/8088/80186/80286, che non hanno la E ** (E per estesi cioè 32 bit, registri).

A2: Vedere A1.

Come il mio lavoro come un programmatore linguaggio assembly spostati al Motorola 680x0 famiglia prima di quelli a 32 bit di Intel è diventato un luogo comune, mi fermo lì :-)

+1

Mi piaceva il processore 680x0, li ho trovati più facili da programmare rispetto a X86 :) – Patrick

4

Vabbè ..

Ci sono un sacco di diverse varianti dell'istruzione imul. E per peggiorare le cose funzionano in modo diverso se si scrive codice a 16 bit contro codice a 32 bit.

La variante che si è imbattuto in una moltiplicazione di 16 bit. Moltiplica il registro AX con qualunque cosa passi come argomento per imul e memorizza il risultato in DX: AX.

Una variante a 32 bit funziona come la moltiplicazione a 16 bit, ma scrive il registro in EDX: EAX. Per utilizzare questa variante tutto ciò che devi fare è usare un argomento a 32 bit.

es:

; a 16 bit multiplication: 
    mov ax, factor1 
    mov bx, factor2 
    imul bx ; result in DX:AX 

    ; a 32 bit multiplication: 
    mov eax, factor1 
    mov ebx, factor2 
    imul ebx ; result in EDX:EAX 

Nel codice a 32 bit, è possibile anche scrivere un IMUL sotto forma di tre operandi. Ciò lo rende molto più flessibile e più facile da lavorare. In questa variante è possibile scegliere liberamente il registro di destinazione e gli argomenti, ma il risultato sarà lungo solo 32 bit. Questa variante di imul non esiste per i 16 bit di codice btw ...

mov eax, factor1 
    mov ebx, factor2 
    imul ecx, eax, ebx ; result in ecx 
+1

puoi per favore mostrare come stamperesti risultato di EDX: EAX '; una moltiplicazione a 32 bit: '. – claws

2

Q1: Come altri hanno detto, questo è solo per compatibilità all'indietro. Le istruzioni originali mul/imul sono da x86 a 16 bit che erano arrivate lungo prima che apparisse il set di istruzioni x86 a 32 bit, quindi non potevano memorizzare il risultato su eax/edx poiché non c'era un e-register.

Q4: imul reg16, reg/mem/imm16 o imul reg32, reg/mem/imm32 viene utilizzato quando sono necessari solo i 16/32 bit inferiori del risultato o quando è possibile garantire che il risultato non trabocchi. Ad esempio quando si moltiplicano i due 3234 bit inte 1234 con 567, i 32 bit superiori sono sempre 0, quindi non è necessario salvare e quindi ripristinare (se necessario) edx come quando si usa mul di imul con un operando.

compilatori C (così come molte altre lingue) spesso utilizzano imul anziché mul sia per moltiplicazioni e senza segno perché i bit inferiori sono sempre la stessa per entrambi i casi, e in C moltiplicano due variabili generano una stessa dimensione risultato (int32xint32 → int32, int16xint16 → int16 ...) che è anche la dimensione dei risultati di imul. È raro vedere una moltiplicazione in cui la dimensione del risultato è maggiore degli operandi come questo int a; uint64_t p = (uint64_t)a*123;, quindi imul è adatto allo scopo. Oltre a fare solo i bit più bassi può essere più veloce di ottenere l'intero risultato. E la varietà di moduli di istruzioni imul rende il codice emesso più efficiente e migliora le prestazioni.Di conseguenza le moderne CPU spesso ottimizzano per imul invece di mul