2011-08-16 54 views
2

林試圖以下列NASM碼相乘兩個16位數字:把兩個數字到EAX寄存器

mov ax, [input1] 
mov bx, [input2] 
mul bx 

先前代碼被存儲在DX的結果:AX

進出口試圖使用來自單獨庫「print_int」的函數將整數打印到屏幕上。但是print_int要求整數必須在EAX寄存器中。

我怎樣才能把32位整數在EAX寄存器中?

更新

我想出了這個

mov cx, dx ;move upper half(16 bits) of result in cx 
shl ecx, 16 ;shift the contents of ecx 16 bits to the left 
mov cx, ax ;move lower half(16 bits) of result in cx 
+0

我想知道是否可以先將DX:AX的內容放入內存中,然後執行mov eax,[mem32]' – Chris

+0

當然:'mov [myInt],ax; mov [myInt + 2],dx; mov eax,[myInt]' – user786653

回答

2

像這樣:

; Before: 
; Result is in DX:AX on the form ABCD:EFGH 
; EAX = ????EFGH : AX contains EFGH, upper part of EAX has unknown content 
; EDX = ????ABCD : DX contains ABCD (the 16 most siginficant bits 
;         of the multiplication result) 
;         like with EAX the upper (=most siginifcant) 
;         16 bits of EDX also has unknown content. 

and eax, 0x0000ffff ; clear upper bits of eax 
; EAX = 0000EFGH 

shl edx, 16 ; shift DX into position (will just shift the upper 16 junk bits away) 
; EDX = ABCD000 

or eax, edx ; combine in eax 
; EAX = ABCDEFGH 

之所以這樣,工作原理是,axeax 16個最低顯著位。詳情請參閱this SO問題和接受的答案。此方法也適用於imul,但通常在處理彙編代碼中的帶符號數字時必須小心。

一個完整的例子:

bits 32 

    extern printf 
    global main 

    section .text 
main: 
    push ebx 
    mov ax, 0x1234 
    mov bx, 0x10 
    mul bx 
    and eax, 0x0000ffff ; clear upper bits of eax 
    shl edx, 16 ; shift DX into position 
    or eax, edx ; and combine 
    push eax 
    push format 
    call printf 
    add esp, 8 
    mov eax, 0 
    pop ebx 
    ret 

    section .data 
format: db "result = %8.8X",10,0 

編譯:

nasm -f elf32 -g -o test.o test.asm 
gcc -m32 -o test test.o 

更新:

在32位機器上它通常更容易和優選處理32位值,如果在上下文中是合理的。例如:

movzx eax, word [input1] ; Load 16-bit value and zero-extend into eax 
    movzx edx, word [input2] ; Use movsx if you want to work on signed values 
    mul eax, edx ; eax *= edx 

這也說明了較新的,更易於使用,mul一條指令的用法。您也可以像現在這樣做,然後mov ax, [input1],然後再用movzx eax, ax擴大尺寸。

+0

'movzx eax,ax'短於'和eax,0x0000ffff'。或者如果你知道EAX的上半部分在使用16位mul之前已經被清零,就跳過它。但是,正如你所說,首先使用32位操作數大小乘法更好。 (儘管如此,它是'imul eax,edx';英特爾選擇使用'imul'助記符表示不會產生高一半的形式,只有'mul'和'imul'之間的高一半是不同的。) –

1

的捷徑是...

asm 
//load test values in eax and exb 
     mov  eax, $00000102 
     mov  ebx, $00000304 
//merge ex and bx to eax 
     shl  ebx, 16 
     shld eax, ebx, 16 
end; 

結果EAX = $ 01020304

我想要oposite然後...

asm 
//load test values in eax and exb 
     mov  eax, $00000102 
     mov  ebx, $00000304 
//merge ex and bx to eax 
     shl  eax, 16 
     shrd eax, ebx, 16 
end; 

結果EAX = $○三○四○一○二

+1

如果我們真的推動最短路,我會提出以下(邪惡)'66 52 66 50 58'('push dx; push ax; pop eax')。爲了您的參考編譯爲'C1 E0 10 0F AC D0 10'。 – user786653

+0

@ user786653:但是你需要三條指令...... :)按壓和彈出指令是涉及內存的指令,並且比只涉及寄存器的指令花費更多的CPU週期! –

+0

@ user786653:push16/push16/pop32很緊湊,但速度很慢。例如,兩個狹窄的存儲庫不能有效地轉發到更大的負載,因此,例如,在Intel Sandybridge系列CPU上,存在一個存儲轉發延遲,延遲時間爲〜11週期(正常存儲/重新加載的週期延遲爲5個週期)。 http://agner.org/optimize/ –

相關問題