32位架构下如何实现64位类型和操作的最底层实现?

4

int64_t这样的类型在最低层次即汇编语言级别上是如何实现的呢?我使用的是32位机器,但仍然可以使用int64_t。我的初步假设是64位只是模拟的,因此在32位机器上进行计算时,与32位数据类型相比,这些类型的计算必须具有相当大的开销。

提前感谢您的帮助和问候!


4
您可以查看编译器生成的汇编代码来了解... - Oliver Charlesworth
那其实是一个简单而又棒的想法 ;) - ben
1个回答

7
你说得没错,当你为32位结构编译代码时,必须使用32位操作数模拟64位操作数和操作。
一个8字节的变量(uint64_t只是long long的typedef)存储在2个4字节的寄存器中。
对于加法(和减法),必须先加上低4个字节,然后再对高4个字节执行第二次带进位(或带借位的减法)。由于第二次加法还会加上第一次加法的进位,所以结果是正确的。添加和减去的开销不大。
然而,对于乘法和除法来说情况并不那么简单。通常需要调用例程来执行这些操作,开销显著更大。
让我们看看这段简单的C代码:
int main() {
  long long a = 0x0102030405060708;
  long long b = 0xA1A2A3A4A5A6A7A8;
  long long c = 0xB1B2B3B4B5B6B7B8;

  c = a + b;
  c = a - b;
  c = a * b;
  c = a / b;

  return 0;
}

分析由MSVC生成的汇编代码,我们可以看到:
     2:   long long a = 0x0102030405060708;
012D13DE  mov         dword ptr [a],5060708h  
012D13E5  mov         dword ptr [ebp-8],1020304h  
     3:   long long b = 0xA1A2A3A4A5A6A7A8;
012D13EC  mov         dword ptr [b],0A5A6A7A8h  
012D13F3  mov         dword ptr [ebp-18h],0A1A2A3A4h  
     4:   long long c = 0xB1B2B3B4B5B6B7B8;
012D13FA  mov         dword ptr [c],0B5B6B7B8h  
012D1401  mov         dword ptr [ebp-28h],0B1B2B3B4h  

一个64位的变量被分为两个32位的位置。


     6:   c = a + b;
012D1408  mov         eax,dword ptr [a]  
012D140B  add         eax,dword ptr [b]  
012D140E  mov         ecx,dword ptr [ebp-8]  
012D1411  adc         ecx,dword ptr [ebp-18h]  
012D1414  mov         dword ptr [c],eax  
012D1417  mov         dword ptr [ebp-28h],ecx  
     7:   c = a - b;
012D141A  mov         eax,dword ptr [a]  
012D141D  sub         eax,dword ptr [b]  
012D1420  mov         ecx,dword ptr [ebp-8]  
012D1423  sbb         ecx,dword ptr [ebp-18h]  
012D1426  mov         dword ptr [c],eax  
012D1429  mov         dword ptr [ebp-28h],ecx  

使用add指令对低32位执行求和操作,然后再使用带进位的加法adc对高32位执行相同操作。减法类似:第二个操作是带借位的减法sbb


     8:   c = a * b;
012D142C  mov         eax,dword ptr [ebp-18h]  
012D142F  push        eax  
012D1430  mov         ecx,dword ptr [b]  
012D1433  push        ecx  
012D1434  mov         edx,dword ptr [ebp-8]  
012D1437  push        edx  
012D1438  mov         eax,dword ptr [a]  
012D143B  push        eax  
012D143C  call        __allmul (012D105Ah)  
012D1441  mov         dword ptr [c],eax  
012D1444  mov         dword ptr [ebp-28h],edx  
     9:   c = a / b;
012D1447  mov         eax,dword ptr [ebp-18h]  
012D144A  push        eax  
012D144B  mov         ecx,dword ptr [b]  
012D144E  push        ecx  
012D144F  mov         edx,dword ptr [ebp-8]  
012D1452  push        edx  
012D1453  mov         eax,dword ptr [a]  
012D1456  push        eax  
012D1457  call        __alldiv (012D1078h)  
012D145C  mov         dword ptr [c],eax  
012D145F  mov         dword ptr [ebp-28h],edx  

产品和分割是通过调用特殊例程来执行的。

感谢您的详细回答。 - ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接