Como posso multiplicar dois números de 64 bits usando linguagem assembly x86?

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

  •  01-07-2019
  •  | 
  •  

Pergunta

Como eu iria sobre ...

  • multiplicando dois números 64 bits

  • multiplicando dois números hexadecimais 16 dígitos

... usando Assembly Language.

Eu só estou autorizado a usar registros% eax,% ebx, ecx%,% edx, e a pilha.

EDIT: Ah, eu estou usando ATT Sintaxe no x86
EDIT2: Não é permitido descompilar em conjunto ...

Foi útil?

Solução

Use o que provavelmente deve ser o seu livro é claro, Randall Hyde de "The Art of Assembly Language".

Consulte 4.2.4 - Extensão Precision Multiplicação

Apesar de um 8x8, 16x16, 32x32 ou multiplicar é geralmente suficiente, há momentos em que você pode querer valores multiplicam maiores juntos. Você usará o x86 único operando MUL e IMUL instruções para a multiplicação de precisão estendida ..

Provavelmente a coisa mais importante a lembrar ao executar uma multiplicação de precisão estendida é que você também deve executar uma adição de precisão múltipla ao mesmo tempo . Somando-se todos os produtos parciais requer várias adições que irá produzir o resultado. A lista a seguir demonstra a maneira correta de multiplicar dois valores de 64 bits em um processador de 32 bits ..

(Veja o link para a listagem completa montagem e ilustrações.)

Outras dicas

Se este 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

Uma vez que você está em x86 que você precisa 4 instruções Mull. Dividir as quantidades de 64 bits em dois de 32 bits palavras e multiplicam as palavras baixas para o menor e 2º menor palavra do resultado, em seguida, dois pares de baixo e alto palavra de números diferentes (eles vão para a 2ª e 3ª palavra mais baixo do resultado) e finalmente, as duas palavras para o alto de 2 maiores palavras do resultado. Adicioná-los todos juntos não esquecendo de lidar com carry. Você não especificou o layout memória das entradas e saídas por isso é impossível escrever código de exemplo.

Este código assume que você deseja x86 (x64 não código), que você provavelmente só quer um produto de 64 bits, e que você não se preocupam com estouro ou números assinados. (A assinado versão é similar).

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

Esta não honrar as restrições de registro exatas do OP, mas os ajustes de resultado inteiramente nos registros oferecidos pela x86. (Este código não foi testado, mas eu acho que é certo).

[Nota: Eu transferido (meu) esta resposta a partir de uma outra questão que ficou fechado, porque nenhuma das outras "respostas" aqui respondeu diretamente a questão].

Isso depende o idioma que você está usando. Pelo que me lembro de aprender MIPS montagem, há um mover de comando alta e uma mudança de comando Lo, ou MFLO e mfhi. lojas mfhi os principais 64bits enquanto MFLO armazena os 64bits inferiores do número total.

ah montagem, já faz algum tempo desde que eu usei-o. assim que eu estou supondo que o verdadeiro problema aqui é que o microcontrolador (o que eu usei para escrever código no conjunto de qualquer maneira) que você está trabalhando não tem 64 registros de bits? se esse for o caso, você vai ter a quebra os números que você está trabalhando à parte e executar várias multiplicações com as peças.

Isso soa como ele é uma lição de casa do jeito que você redigido, então eu vou não soletrar muito mais longe: P

Basta fazer multiplicação longa normal, como se estivesse multiplicação de um par de números de 2 dígitos, exceto cada "dígitos" é realmente um inteiro de 32 bits. Se você está multiplicando dois números em endereços X e Y e armazenando o resultado em Z, então o que você quer fazer (em pseudocódigo) é:

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

Note que estamos descartando as superiores 64 bits do resultado (uma vez que um número de vezes de 64 bits um número de 64 bits é um número de 128 bits). Também nota que esta está assumindo little-endian. Além disso, tenha cuidado sobre um assinado contra uma multiplicação sem sinal.

Encontre um compilador C que suporta 64bit (GCC faz IIRC) compilar um programa que faz exatamente isso, então, fazer a desmontagem. GCC pode cuspi-la no seu próprio e você pode tirá-lo do arquivo objeto com as ferramentas adequadas.

OTOH seus é um op 32bX32b = 64b em 86

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

tudo transborda

(não testado)

Editar não assinado única

Eu estou apostando que você é um estudante, então veja se você pode fazer este trabalho: Do ??que palavra por palavra, e as mudanças utilização bits. Pense-se a solução mais eficiente. Cuidado com o bit de sinal.

Se você quiser 128 modo de tentar este ...

__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 você quiser de 128 bits multiplicação, em seguida, isso deve funcionar este está no formato AT & T.

__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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top