Calculating LCM in assembly x86

。_饼干妹妹 提交于 2020-12-12 05:35:11

问题


I have the following assembly code

.global _start

.section .text
_start:
    movq a, %rax
    movq b, %rbx
    imul %rbx, %rax
    cmp %rbx, %rax
    je gcd_calculated
    ja l1
    sub %rax, %rbx
    jmp _start
l1:
    sub %rbx, %rax
    jmp _start
gcd_calculated:
    div %rax
    movq %rax, (c)
    

a,b are quads that I need to calculate their lcm and I need to assign the result to c

I get wrong results with the above code and I can't spot why.

generally, i'm relaying on the the lcm = (a*b)/gcd so I store a*b in %rax and then calculate the gcd which will be stored at %eax and finally divide between them.


回答1:


Like 1201ProgramAlarm said, you are calculating and comparing the original values of a and b in each iteration of your loop. If you want to follow your current approach, you would have to store these values in memory each time before looping.

What I would actually do instead is just do the gcd calculation first and then calculate (a*b)/gcd at the end.

_start:
    movq a(%rip), %rbx
    movq b(%rip), %rcx
gcd:
    cmp %rbx, %rcx
    je gcd_calculated
    ja l1
    sub %rcx, %rbx
    jmp gcd
l1:
    sub %rbx, %rcx
    jmp gcd
gcd_calculated:
    movq a(%rip), %rax
    xor %rdx, %rdx
    div %rbx
    imul b(%rip), %rax
    movq %rax, c(%rip)



回答2:


/* x86-64 gcc / clang support the __int128 type: */

/*

#include <stdint.h>

unsigned __int128 lcm (uint64_t a, uint64_t b)
{
    uint64_t u = a, v = b;

    for (uint64_t t = 0; (t = v) != 0; u = t)
        v = u % v;

    if (u != 0) /* gcd(a, b) != (0) : */
        return (((unsigned __int128) a) * (b / u));

    return (0);
}

*/

/* x86-64 Mach-O (OSX) / ELF calling conventions:
 * first arg (a) in %rdi, second arg (b) in %rsi;
 * 128-bit integer returned in %rdx:%rax [hi:lo] */

/* no caller-reserved registers or stack are used: */

        .text
        .globl _lcm
_lcm:
        movq    %rdi, %r8
        movq    %rsi, %rdi
        movq    %r8, %rcx
L_gcd:
        testq   %rdi, %rdi
        je      L_lcm         # %rcx = gcd(a, b)
        movq    %rcx, %rax
        xorl    %edx, %edx
        movq    %rdi, %rcx
        divq    %rdi
        movq    %rdx, %rdi
        jmp     L_gcd
L_lcm:                        # lcm(0, 0) returns (0) :
        xorl    %eax, %eax
        xorl    %edx, %edx
        testq   %rcx, %rcx    # if gcd(a, b) == 0, then:
        je      L_done        # %rdx:%rax = 0:0; return.
        movq    %rsi, %rax
        xorl    %edx, %edx    # %rdx:%rax = 0:b
        divq    %rcx          # %rax = (b / g)
        mulq    %r8           # %rdx:%rax = a * (b / g)
L_done:
        ret


来源:https://stackoverflow.com/questions/64790116/calculating-lcm-in-assembly-x86

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!