Putting two numbers into the EAX register

10,444

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

Share:
10,444
Chris
Author by

Chris

Updated on June 04, 2022

Comments

  • Chris
    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
    user786653 over 12 years
    If 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 to C1 E0 10 0F AC D0 10.
  • GJ.
    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
    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
    Peter Cordes over 6 years
    movzx eax,ax is shorter and better than and eax, 0x0000ffff. Or skip it if you know the upper half of EAX was already zeroed before using a 16-bit mul. But yes, as you say, better to use a 32-bit operand-size multiply in the first place. (It's imul eax, edx, though; Intel chose to use the imul mnemonic for the forms that don't produce a high half. Only the high half is different between mul and imul.)