<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 第21章 在32位環境中的64位值 在32位環境中的通用寄存器是32位的,所以64位值轉化為一對32位值。 ## 21.1參數的傳遞,加法,減法 ``` #!cpp #include <stdint.h> uint64_t f1 (uint64_t a, uint64_t b) { return a+b; }; void f1_test () { #ifdef __GNUC__ printf ("%lld ", f1(12345678901234, 23456789012345)); #else printf ("%I64d ", f1(12345678901234, 23456789012345)); #endif }; uint64_t f2 (uint64_t a, uint64_t b) { return a-b; }; ``` 代碼 21.1: MSVC 2012 /Ox /Ob1 ``` #!bash _a$ = 8 ; size = 8 _b$ = 16 ; size = 8 _f1 PROC mov eax, DWORD PTR _a$[esp-4] add eax, DWORD PTR _b$[esp-4] mov edx, DWORD PTR _a$[esp] adc edx, DWORD PTR _b$[esp] ret 0 _f1 ENDP _f1_test PROC push 5461 ; 00001555H push 1972608889 ; 75939f79H push 2874 ; 00000b3aH push 1942892530 ; 73ce2ff2H call _f1 push edx push eax push OFFSET $SG1436 ; ’%I64d’, 0aH, 00H call _printf add esp, 28 ; 0000001cH ret 0 _f1_test ENDP _f2 PROC mov eax, DWORD PTR _a$[esp-4] sub eax, DWORD PTR _b$[esp-4] mov edx, DWORD PTR _a$[esp] sbb edx, DWORD PTR _b$[esp] ret 0 _f2 ENDP ``` 我們可以看到在函數f1_test()中每個64位值轉化為2個32位值,高位先轉,然后是低位。加法和減法也是如此。 當進行加法操作時,低32位部分先做加法。如果相加過程中產生進位,則設置CF標志。下一步通過ADC指令加上高位部分,如果CF置1了就增加1。 減法操作也是如此。第一個SUB操作也會導致CF標志的改變,并在隨后的SBB操作中檢查:如果CF置1了,那么最終結果也會減去1。 在32位環境中,64位的值是從EDX:EAX這一對寄存器的函數中返回的。可以很容易看出f1()函數是如何轉化為printf()函數的。 代碼 21.2: GCC 4.8.1 -O1 -fno-inline ``` #!bash _f1: mov eax, DWORD PTR [esp+12] mov edx, DWORD PTR [esp+16] add eax, DWORD PTR [esp+4] adc edx, DWORD PTR [esp+8] ret _f1_test: sub esp, 28 mov DWORD PTR [esp+8], 1972608889 ; 75939f79H mov DWORD PTR [esp+12], 5461 ; 00001555H mov DWORD PTR [esp], 1942892530 ; 73ce2ff2H mov DWORD PTR [esp+4], 2874 ; 00000b3aH call _f1 mov DWORD PTR [esp+4], eax mov DWORD PTR [esp+8], edx mov DWORD PTR [esp], OFFSET FLAT:LC0 ; "%lld12" call _printf add esp, 28 ret _f2: mov eax, DWORD PTR [esp+4] mov edx, DWORD PTR [esp+8] sub eax, DWORD PTR [esp+12] sbb edx, DWORD PTR [esp+16] ret ``` GCC代碼也是如此。 ## 21.2乘法,除法 ``` #!cpp #include <stdint.h> uint64_t f3 (uint64_t a, uint64_t b) { return a*b; }; uint64_t f4 (uint64_t a, uint64_t b) { return a/b; }; uint64_t f5 (uint64_t a, uint64_t b) { return a % b; }; ``` 代碼 21.3: MSVC 2012 /Ox /Ob1 ``` #!bash _a$ = 8 ; size = 8 _b$ = 16 ; size = 8 _f3 PROC push DWORD PTR _b$[esp] push DWORD PTR _b$[esp] push DWORD PTR _a$[esp+8] push DWORD PTR _a$[esp+8] call __allmul ; long long multiplication ret 0 _f3 ENDP _a$ = 8 ; size = 8 _b$ = 16 ; size = 8 _f4 PROC push DWORD PTR _b$[esp] push DWORD PTR _b$[esp] push DWORD PTR _a$[esp+8] push DWORD PTR _a$[esp+8] call __aulldiv ; unsigned long long division ret 0 _f4 ENDP _a$ = 8 ; size = 8 _b$ = 16 ; size = 8 _f5 PROC push DWORD PTR _b$[esp] push DWORD PTR _b$[esp] push DWORD PTR _a$[esp+8] push DWORD PTR _a$[esp+8] call __aullrem ; unsigned long long remainder ret 0 _f5 ENDP ``` 乘法和除法是更為復雜的操作,一般來說,編譯器會嵌入庫函數的calls來使用。 部分函數的意義:可參見附錄E。 Listing 21.4: GCC 4.8.1 -O3 -fno-inline ``` #!bash _f3: push ebx mov edx, DWORD PTR [esp+8] mov eax, DWORD PTR [esp+16] mov ebx, DWORD PTR [esp+12] mov ecx, DWORD PTR [esp+20] imul ebx, eax imul ecx, edx mul edx add ecx, ebx add edx, ecx pop ebx ret _f4: sub esp, 28 mov eax, DWORD PTR [esp+40] mov edx, DWORD PTR [esp+44] mov DWORD PTR [esp+8], eax mov eax, DWORD PTR [esp+32] mov DWORD PTR [esp+12], edx mov edx, DWORD PTR [esp+36] mov DWORD PTR [esp], eax mov DWORD PTR [esp+4], edx call ___udivdi3 ; unsigned division add esp, 28 ret _f5: sub esp, 28 mov eax, DWORD PTR [esp+40] mov edx, DWORD PTR [esp+44] mov DWORD PTR [esp+8], eax mov eax, DWORD PTR [esp+32] mov DWORD PTR [esp+12], edx mov edx, DWORD PTR [esp+36] mov DWORD PTR [esp], eax mov DWORD PTR [esp+4], edx call ___umoddi3 ; unsigned modulo add esp, 28 ret ``` GCC的做法幾乎一樣,但是乘法代碼內聯在函數中,可認為這樣更有效。 GCC有一些不同的庫函數:參見附錄D ## 21.3右移 ``` #!cpp #include <stdint.h> uint64_t f6 (uint64_t a) { return a>>7; }; ``` 代碼 21.5: MSVC 2012 /Ox /Ob1 ``` #!bash _a$ = 8 ; size = 8 _f6 PROC mov eax, DWORD PTR _a$[esp-4] mov edx, DWORD PTR _a$[esp] shrd eax, edx, 7 shr edx, 7 ret 0 _f6 ENDP ``` 代碼 21.6: GCC 4.8.1 -O3 -fno-inline ``` #!bash _f6: mov edx, DWORD PTR [esp+8] mov eax, DWORD PTR [esp+4] shrd eax, edx, 7 shr edx, 7 ret ``` 右移也是分成兩步完成:先移低位,然后移高位。但是低位部分通過指令SHRD移動,它將EDX的值移動7位,并從EAX借來1位,也就是從高位部分。而高位部分通過更受歡迎的指令SHR移動:的確,高位釋放出來的位置用0填充。 ## 21.4從32位值轉化為64位值 ``` #!cpp #include <stdint.h> int64_t f7 (int64_t a, int64_t b, int32_t c) { return a*b+c; }; int64_t f7_main () { return f7(12345678901234, 23456789012345, 12345); }; ``` 代碼 21.7: MSVC 2012 /Ox /Ob1 ``` #!bash _a$ = 8 ; size = 8 _b$ = 16 ; size = 8 _c$ = 24 ; size = 4 _f7 PROC push esi push DWORD PTR _b$[esp+4] push DWORD PTR _b$[esp+4] push DWORD PTR _a$[esp+12] push DWORD PTR _a$[esp+12] call __allmul ; long long multiplication mov ecx, eax mov eax, DWORD PTR _c$[esp] mov esi, edx cdq ; input: 32-bit value in EAX; output: 64-bit value in EDX:EAX add eax, ecx adc edx, esi pop esi ret 0 _f7 ENDP _f7_main PROC push 12345 ; 00003039H push 5461 ; 00001555H push 1972608889 ; 75939f79H push 2874 ; 00000b3aH push 1942892530 ; 73ce2ff2H call _f7 add esp, 20 ; 00000014H ret 0 _f7_main ENDP ``` 這里我們有必要將有符號的32位值從c轉化為有符號的64位值。無符號值的轉化簡單了當:所有的高位部分全部置0。但是這樣不適合有符號的數據類型:符號標志應復制到結果中的高位部分。這里用到的指令是CDQ,它從EAX中取出數值,將其變為64位并存放到EDX:EAX這一對寄存器中。換句話說,指令CDQ從EAX中獲取符號(通過EAX中最重要的位),并根據它來設置EDX中所有位為0還是為1。它的操作類似于指令MOVSX(13.1.1)。 代碼 21.8: GCC 4.8.1 -O3 -fno-inline ``` #!bash _f7: push edi push esi push ebx mov esi, DWORD PTR [esp+16] mov edi, DWORD PTR [esp+24] mov ebx, DWORD PTR [esp+20] mov ecx, DWORD PTR [esp+28] mov eax, esi mul edi imul ebx, edi imul ecx, esi mov esi, edx add ecx, ebx mov ebx, eax mov eax, DWORD PTR [esp+32] add esi, ecx cdq ; input: 32-bit value in EAX; output: 64-bit value in EDX:EAX add eax, ebx adc edx, esi pop ebx pop esi pop edi ret _f7_main: sub esp, 28 mov DWORD PTR [esp+16], 12345 ; 00003039H mov DWORD PTR [esp+8], 1972608889 ; 75939f79H mov DWORD PTR [esp+12], 5461 ; 00001555H mov DWORD PTR [esp], 1942892530 ; 73ce2ff2H mov DWORD PTR [esp+4], 2874 ; 00000b3aH call _f7 add esp, 28 ret ``` GCC生成的匯編代碼跟MSVC一樣,但是在函數中內聯乘法代碼。 更多:32位值在16位環境中(30.4)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看