Putting two numbers into the EAX register
Solution 1
Like this:
; 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
The reason why this works is that ax
refers to the 16 least significant bits of eax
. Fore more detail see this SO question and the accepted answer. This method will also work for imul
, but usually you have to be careful when dealing with signed numbers in assembly code.
A complete example:
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
Compile with:
nasm -f elf32 -g -o test.o test.asm
gcc -m32 -o test test.o
Update:
On 32-bit machines it is usually easier and preferable to deal with 32-bit values if it is reasonable in the context. For example:
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
Which also shows the usage of one of the newer, easier to use, mul
instructions. You can also do as you're doing now and mov ax, [input1]
and then later extend the size with movzx eax, ax
.
Solution 2
The shortest way is...
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;
result in eax = $01020304
I you want oposite then...
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;
result in eax = $03040102
Chris
Updated on June 04, 2022Comments
-
Chris almost 2 years
Im trying to multiply two 16 bit numbers with the following NASM codes:
mov ax, [input1] mov bx, [input2] mul bx
The result of the previous codes is stored in DX:AX
Im trying to print the integer to the screen using a function from a separate library "print_int". But print_int requires that the integer must be in the EAX register.
How can i put the 32-bit integer in the EAX register?
Update
I came up with this
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
-
user786653 over 12 yearsIf we're really pushing for the shortest way I propose the following (evil)
66 52 66 50 58
(push dx; push ax; pop eax
). For reference yours compiles toC1 E0 10 0F AC D0 10
. -
GJ. over 12 years@user786653: but you need three instructions... :) Push and pop instruction are memory involved instructions and takes much more cpu cycles than only registers involved instructions!
-
Peter Cordes over 6 years@user786653: push16/push16 / pop32 is compact, but slow. Two narrow stores can't forward efficiently to a wider load, so you get a store-forwarding stall, with ~11 cycle latency (vs. 5 cycle latency for normal store/reload) on Intel Sandybridge-family CPUs for example. agner.org/optimize
-
Peter Cordes over 6 years
movzx eax,ax
is shorter and better thanand eax, 0x0000ffff
. Or skip it if you know the upper half of EAX was already zeroed before using a 16-bitmul
. But yes, as you say, better to use a 32-bit operand-size multiply in the first place. (It'simul eax, edx
, though; Intel chose to use theimul
mnemonic for the forms that don't produce a high half. Only the high half is different betweenmul
andimul
.)