汇编程序64b部门 [英] Assembler 64b division

查看:120
本文介绍了汇编程序64b部门的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一些简单的方法来在x86的汇编器中除以64b无符号整数。我的号码保存在两个32b寄存器EDX:EAX中,我需要将结果放回EDX:EAX。因子为32b整数。请输入一些代码?

解决方案

如果我正确解释了您的问题(尤其是 Factor在32b中整数),您希望将64位除数除以32位除数并得到64位商。



如果解释是正确的,所以实际上很容易用32位代码完成。



这个想法是,将除数的一半除以除数,然后重新使用



C代码说明了如何做:

  #include< stdio.h> 
#include< limits.h>

#定义C_ASSERT(expr)extern char CAssertExtern [(expr)?1:-1]

#if UINT_MAX> = 0xFFFFFFFF
typedef unsigned int uint32 ;
#else
typedef unsigned long uint32;
#endif
typedef unsigned long long uint64;

typedef无符号长乌龙;

//确保uint32 = 32位和uint64 = 64位
C_ASSERT(sizeof(uint32)* CHAR_BIT == 32);
C_ASSERT(sizeof(uint64)* CHAR_BIT == 64);

int div64by32eq64(uint64 *股息,uint32除数)
{
uint32股息高=(uint32)(*股息> 32);
uint32股息Lo =(uint32)*股息;
uint32 quotientHi;
uint32 quotientLo;

如果(除数== 0)
返回0;

//这可以作为一个32位DIV完成,例如 div ecx
quotientHi =股息Hi /除数;
股息高=股息高%除数;

//可以作为另一个32位DIV完成,例如 div ecx
quotientLo =(uint32)((((((uint64)dividendHi<<<<<<<<<<<<<<<<<<<<<<<<<<<< 32)

*股息=((uint64)quotientHi<<<<<<<<<< 32)+ quotientLo;

返回1;
}

int main(void)
{
静态常量
{
uint64股息;
uint32除数;
} testData [] =
{
{1,0},
{0xFFFFFFFFFFFFFFFFULL,1},
{0xFFFFFFFFFFFFFFULLULL,2},
{0xFFFFFFFF00000000000000ULL ,0xFFFFFFFFUL},
{0xFFFFFFFFFFFFFFFFULL,0xFFFFFFFFUL},
};
int i;

for(i = 0; i< sizeof(testData)/ sizeof(testData [0]); i ++)
{
uint64分派= testData [i] .dividend ;
uint32 divisor = testData [i] .divisor;

printf( 0x%016llX / 0x%08lX =,股息,(除数)除数);

if(div64by32eq64(& dividend,除数))
printf( 0x%016llX\n,股息);
else
printf(除以0错误\n);
}

返回0;
}

输出( ideone ):

  0x0000000000000001 / 0x00000000 =除以0错误
0xFFFFFFFFFFFFFFFF / 0x00000001 = 0xFFFFFFFFFFFFFFFF
0xFFFFFFFFFFFFFFFF / 0x00000002 = 0x7FFFFFFFFFFFFF
0xFFFFFFFF00000000 / 0xFFFFFFFF = 0x0000000100000000
0xFFFFFFFFFF> 0xFFFFFFFFFF>

现在在汇编中等效的除法代码(NASM语法),无需检查除以0:

 ; 64位股息
mov edx,0xFFFFFFFF
mov eax,0xFFFFFFFF

; 32位除数
mov ecx,0xFFFFFFFF

push eax
mov eax,edx
xor edx,edx
div ecx;得到高32位的商
xchg eax,[esp];将它们存储在堆栈中,得到低32位的股息
div ecx;得到低32位的商
pop edx; edx:eax中的64位商现在
; edx:eax现在应该等于0x0000000100000001


I need some easy way to divide 64b unsigned integers in assembler for x86. My number is saved in two 32b registers EDX:EAX and I need to put result back to EDX:EAX. Factor is in 32b integer. Some code, please?

解决方案

If I interpret your question correctly (particularly the part Factor is in 32b integer), you want to divide a 64-bit dividend by a 32-bit divisor and get a 64-bit quotient.

If that interpretation is correct, then it's actually easy to do in 32-bit code.

The idea is that you divide both "halves" of the dividend by the divisor and reuse the remainder from the first division for the second division.

C code illustrating how to do it:

#include <stdio.h>
#include <limits.h>

#define C_ASSERT(expr) extern char CAssertExtern[(expr)?1:-1]

#if UINT_MAX >= 0xFFFFFFFF
typedef unsigned int uint32;
#else
typedef unsigned long uint32;
#endif
typedef unsigned long long uint64;

typedef unsigned long ulong;

// Make sure uint32=32 bits and uint64=64 bits
C_ASSERT(sizeof(uint32) * CHAR_BIT == 32);
C_ASSERT(sizeof(uint64) * CHAR_BIT == 64);

int div64by32eq64(uint64* dividend, uint32 divisor)
{
  uint32 dividendHi = (uint32)(*dividend >> 32);
  uint32 dividendLo = (uint32)*dividend;
  uint32 quotientHi;
  uint32 quotientLo;

  if (divisor == 0)
    return 0;

  // This can be done as one 32-bit DIV, e.g. "div ecx"
  quotientHi = dividendHi / divisor;
  dividendHi = dividendHi % divisor;

  // This can be done as another 32-bit DIV, e.g. "div ecx"
  quotientLo = (uint32)((((uint64)dividendHi << 32) + dividendLo) / divisor);

  *dividend = ((uint64)quotientHi << 32) + quotientLo;

  return 1;
}

int main(void)
{
  static const struct
  {
    uint64 dividend;
    uint32 divisor;
  } testData[] =
  {
    { 1 , 0 },
    { 0xFFFFFFFFFFFFFFFFULL, 1 },
    { 0xFFFFFFFFFFFFFFFFULL, 2 },
    { 0xFFFFFFFF00000000ULL, 0xFFFFFFFFUL },
    { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFUL },
  };
  int i;

  for (i = 0; i < sizeof(testData)/sizeof(testData[0]); i++)
  {
    uint64 dividend = testData[i].dividend;
    uint32 divisor = testData[i].divisor;

    printf("0x%016llX / 0x%08lX = ", dividend, (ulong)divisor);

    if (div64by32eq64(&dividend, divisor))
      printf("0x%016llX\n", dividend);
    else
      printf("division by 0 error\n");
  }

  return 0;
}

Output (ideone):

0x0000000000000001 / 0x00000000 = division by 0 error
0xFFFFFFFFFFFFFFFF / 0x00000001 = 0xFFFFFFFFFFFFFFFF
0xFFFFFFFFFFFFFFFF / 0x00000002 = 0x7FFFFFFFFFFFFFFF
0xFFFFFFFF00000000 / 0xFFFFFFFF = 0x0000000100000000
0xFFFFFFFFFFFFFFFF / 0xFFFFFFFF = 0x0000000100000001

And now the equivalent division code in assembly (NASM syntax) without checking for division by 0:

; 64-bit dividend
mov edx, 0xFFFFFFFF
mov eax, 0xFFFFFFFF

; 32-bit divisor
mov ecx, 0xFFFFFFFF

push eax
mov eax, edx
xor edx, edx
div ecx ; get high 32 bits of quotient
xchg eax, [esp] ; store them on stack, get low 32 bits of dividend
div ecx ; get low 32 bits of quotient
pop edx ; 64-bit quotient in edx:eax now
; edx:eax should now be equal 0x0000000100000001

这篇关于汇编程序64b部门的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆