Come posso moltiplicare due numeri a 64 bit che utilizza linguaggio assembly x86?

StackOverflow https://stackoverflow.com/questions/87771

  •  01-07-2019
  •  | 
  •  

Domanda

Come posso fare per...

  • moltiplicazione di due numeri a 64 bit

  • moltiplicazione di due a 16 cifre esadecimali numeri

...in Linguaggio Assembly.

Mi sono solo permesso di utilizzare i registri %eax, %ebx, %ecx, %edx, e la pila.

EDIT:Oh, io sto usando ATT Sintassi su x86
EDIT2:Non è permesso decompilare in assemblea...

È stato utile?

Soluzione

Utilizzare quello che probabilmente dovrebbe essere il vostro corso libro di testo, Randall Hyde "L'Arte del Linguaggio Assembly".

Vedere 4.2.4 - Precisione Estesa Moltiplicazione

Anche se un 8x8, 16x16 o 32x32 moltiplicarsi di solito è sufficiente, ci sono volte in cui si desidera moltiplicare i valori più grandi insieme.Si utilizzerà la x86 singolo operando MUL e IMUL istruzioni per la precisione estesa di moltiplicazione ..

Probabilmente la cosa più importante da ricordare quando si esegue un'precisione estesa di moltiplicazione è che è necessario eseguire anche un più precisione, oltre allo stesso tempo.Sommando tutti i prodotti parziali richiede molte aggiunte che produrrà il risultato.L'elenco riportato di seguito viene illustrato il modo corretto per moltiplicare due a 64 bit su un processore a 32 bit ..

(Vedi il link per intero assembly e illustrazioni.)

Altri suggerimenti

Se questo era 64x86,

function(x, y, *lower, *higher)
movq %rx,%rax     #Store x into %rax
mulq %y           #multiplies %y to %rax
#mulq stores high and low values into rax and rdx.
movq %rax,(%r8)   #Move low into &lower
movq %rdx,(%r9)   #Move high answer into &higher

Visto che sei su x86 hai bisogno di 4 mull istruzioni.Dividere il 64bit quantità in due 32bit parole e moltiplicare il basso parole per il più basso e il 2 ° più bassa parola di risultato, quindi entrambe le coppie di bassa e alta parola da numeri diversi (vanno per il 2 ° e il 3 ° più bassa parola di risultato) e, infine, sia di alta che di parole in 2 massimo parole del risultato.Aggiungere tutti insieme, non dimenticando di affrontare trasportare.Non specificare il layout di memoria degli ingressi e delle uscite, quindi è impossibile scrivere il codice di esempio.

Questo codice si presuppone che si desidera x86 (non x64), del codice), che probabilmente si desidera solo una versione a 64 bit prodotto, e che non si cura di overflow o i numeri con segno.(Una versione firmata è simile).

MUL64_MEMORY:
     mov edi, val1high
     mov esi, val1low
     mov ecx, val2high
     mov ebx, val2low
MUL64_EDIESI_ECXEBX:
     mov eax, edi
     mul ebx
     xch eax, ebx  ; partial product top 32 bits
     mul esi
     xch esi, eax ; partial product lower 32 bits
     add ebx, edx
     mul ecx
     add ebx, eax  ; final upper 32 bits
; answer here in EBX:ESI

Questo non fa onore l'esatta registrazione dei vincoli di OP, ma il risultato rientra interamente nella registri offerti da x86.(Questo codice non è testato, ma credo che sia giusto).

[Nota:Ho trasferito il (mio) questa risposta da un'altra domanda che ha chiuso, perché NESSUNA delle altre risposte qui direttamente risposto alla domanda].

Dipende da ciò che la lingua che si sta utilizzando.Da quello che mi ricordo dalla formazione MIPS assemblea, c'è un movimento Dall ' Alto comando e una Mossa Da Lo comando, o mflo e mfhi.mfhi negozi cima ai 64bit mentre mflo negozi in basso a 64 bit del numero totale.

ah assemblea, è stato un po ' dato che l'ho utilizzato.quindi sto assumendo il vero problema qui è che il microcontrollore (quello che ho usato per scrivere il codice in assembly comunque) si sta lavorando non sono a 64 bit registri?se questo è il caso, si sta andando ad avere la pausa i numeri che sta lavorando a parte e di eseguire più moltiplicazioni con i pezzi.

questo suona come un compito a casa dal modo in cui hai formulato, quindi non ho intenzione di magia è molto di più :P

Basta fare la normale lungo la moltiplicazione, come se si stavano moltiplicando un paio di numeri a 2 cifre, ad eccezione di ogni "cifra" è davvero un numero intero a 32 bit.Se sei moltiplicazione di due numeri, gli indirizzi di X e Y e memorizzare il risultato in Z, allora che cosa si vuole fare (in pseudocodice) è:

Z[0..3] = X[0..3] * Y[0..3]
Z[4..7] = X[0..3] * Y[4..7] + X[4..7] * Y[0..3]

Si noti che stiamo scartando superiore a 64 bit del risultato (dal 64-bit numero di volte che un numero a 64 bit è un numero a 128 bit).Nota anche che questo è supponendo little-endian.Fai anche attenzione firmato contro un unsigned si moltiplicano.

Trovare un compilatore C che supporta i 64bit (GCC non IIRC) compilare un programma che fa proprio questo, quindi ottenere lo smontaggio.GCC può sputare fuori e si può ottenere fuori di file oggetto con gli strumenti giusti.

OTOH loro è un 32bX32b = 64b op su x86

a:b * c:d = e:f
// goes to
e:f = b*d;
x:y = a*d;  e += x;
x:y = b*c;  e += x;

tutto il resto overflow

(non testato)

Modifica Unsigned solo

Sono le scommesse si sei uno studente, in modo da vedere se si può fare questo lavoro:Non parola per parola, e utilizzare il bit turni.Penso che la soluzione più efficiente.Guardatevi il bit di segno.

Se si desidera 128 modo di provare questo...

__uint128_t AES::XMULTX(__uint128_t TA,__uint128_t TB)
{
    union
    {
        __uint128_t WHOLE;
        struct
        {
            unsigned long long int LWORDS[2];
        } SPLIT;
    } KEY;
    register unsigned long long int __XRBX,__XRCX,__XRSI,__XRDI;
    __uint128_t RESULT;

    KEY.WHOLE=TA;
    __XRSI=KEY.SPLIT.LWORDS[0];
    __XRDI=KEY.SPLIT.LWORDS[1];
    KEY.WHOLE=TB;
    __XRBX=KEY.SPLIT.LWORDS[0];
    __XRCX=KEY.SPLIT.LWORDS[1];
    __asm__ __volatile__(
                 "movq          %0,             %%rsi           \n\t"       
                 "movq          %1,             %%rdi           \n\t"
                 "movq          %2,             %%rbx           \n\t"
                 "movq          %3,             %%rcx           \n\t"
                 "movq          %%rdi,          %%rax           \n\t"
                 "mulq          %%rbx                           \n\t"
                 "xchgq         %%rbx,          %%rax           \n\t"
                 "mulq          %%rsi                           \n\t"
                 "xchgq         %%rax,          %%rsi           \n\t"
                 "addq          %%rdx,          %%rbx           \n\t"
                 "mulq          %%rcx                           \n\t"
                 "addq          %%rax,          %%rbx           \n\t"
                 "movq          %%rsi,          %0              \n\t"
                 "movq          %%rbx,          %1              \n\t"
                 : "=m" (__XRSI), "=m" (__XRBX)
                 : "m" (__XRSI),  "m" (__XRDI), "m" (__XRBX), "m" (__XRCX)
                 : "rax","rbx","rcx","rdx","rsi","rdi"
                 );
    KEY.SPLIT.LWORDS[0]=__XRSI;
    KEY.SPLIT.LWORDS[1]=__XRBX;
    RESULT=KEY.WHOLE;
    return RESULT;
}

Se si desidera 128bit moltiplicazione, questo lavoro è in AT&T formato.

__uint128_t FASTMUL128(const __uint128_t TA,const __uint128_t TB)
{
    union
    {
        __uint128_t WHOLE;
        struct
        {
            unsigned long long int LWORDS[2];
        } SPLIT;
    } KEY;
    register unsigned long long int __RAX,__RDX,__RSI,__RDI;
    __uint128_t RESULT;

KEY.WHOLE=TA;
__RAX=KEY.SPLIT.LWORDS[0];
__RDX=KEY.SPLIT.LWORDS[1];
KEY.WHOLE=TB;
__RSI=KEY.SPLIT.LWORDS[0];
__RDI=KEY.SPLIT.LWORDS[1];
__asm__ __volatile__(
    "movq           %0,                             %%rax                   \n\t"
    "movq           %1,                             %%rdx                   \n\t"
    "movq           %2,                             %%rsi                   \n\t"
    "movq           %3,                             %%rdi                   \n\t"
    "movq           %%rsi,                          %%rbx                   \n\t"
    "movq           %%rdi,                          %%rcx                   \n\t"
    "movq           %%rax,                          %%rsi                   \n\t"
    "movq           %%rdx,                          %%rdi                   \n\t"
    "xorq           %%rax,                          %%rax                   \n\t"
    "xorq           %%rdx,                          %%rdx                   \n\t"
    "movq           %%rdi,                          %%rax                   \n\t"
    "mulq           %%rbx                                                   \n\t"
    "xchgq          %%rbx,                          %%rax                   \n\t"
    "mulq           %%rsi                                                   \n\t"
    "xchgq          %%rax,                          %%rsi                   \n\t"
    "addq           %%rdx,                          %%rbx                   \n\t"
    "mulq           %%rcx                                                   \n\t"
    "addq           %%rax,                          %%rbx                   \n\t"
    "movq           %%rsi,                          %%rax                   \n\t"
    "movq           %%rbx,                          %%rdx                   \n\t"
    "movq           %%rax,                          %0                      \n\t"
    "movq           %%rdx,                          %1                      \n\t"
    "movq           %%rsi,                          %2                      \n\t"
    "movq           %%rdi,                          %3                      \n\t"
    : "=m"(__RAX),"=m"(__RDX),"=m"(__RSI),"=m"(__RDI)
    :  "m"(__RAX), "m"(__RDX), "m"(__RSI), "m"(__RDI)
    : "rax","rbx","ecx","rdx","rsi","rdi"
);
KEY.SPLIT.LWORDS[0]=__RAX;
KEY.SPLIT.LWORDS[1]=__RDX;
RESULT=KEY.WHOLE;
return RESULT;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top