2011-08-16 51 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/ –

相关问题