将此C代码转换为程序集,以便一次移位一位

91zkwejq  于 2023-05-16  发布在  其他
关注(0)|答案(2)|浏览(124)

我正在尝试将此C代码转换为Assembly,以便在不使用除法符号的情况下进行除法运算。C代码已经被证明是有效的。我已经尽我所能完成了C代码到汇编的转换。当除以1或分子中有0时,它将正确工作,但对于除法(如5789217 / 8、10 / 5等)将不工作。它们的输出总是商为0,余数为0。
我试着在这里和那里做一些小的调整,但最终我不确定汇编代码哪里出错了。
下面是C代码:

#include <stdio.h>
#include <stdlib.h>
 
int main (int argc, char *argv[]){
 
    //first command line argument is the dividend
    long long dividend = atoll(argv[1]);
    //second command line argument is the divisor
    long long divisor = atoll(argv[2]);
    //we need the remainder 
    long long remainder = 0;
    //we need the quotient
    long long quotient = 0;

    if (divisor == 1) {
        quotient = dividend;
        remainder = 0;
    } else {
        //runs for 31 iterations as stated in the prompt 
        for(int i = 31; i >= 0; i--){
            remainder <<= 1;
            remainder |= (dividend >> i) & 1;
            if (remainder >= divisor){
                remainder -= divisor;
                quotient |= 1 << i;
            }
        }
    }
 
    //print the results
    printf("%lld / %lld = %lld R %lld\n", dividend, divisor, quotient, remainder);
 
    return 0; 
}

以下是更新的程序集代码:

.global _start

.data
dividend:
    .long 100
divisor:
    .long 100
quotient:
    .long 0
remainder:
    .long 0

.text
_start:
    movl quotient, %eax
    movl remainder, %edx
    movl divisor, %esi # previously ecx
    movl dividend, %ebx
    movl $31, %ecx # previously esi 
    # first if statement that checks if the divisor is 1
    cmpl $1, %esi
    jne for_start

    # divisor is 1, so quotient is dividend and remainder is 0
    movl %ebx, %eax
    xor %edx, %edx
    jmp done

for_start:
    cmpl $0, %ecx
    jle done

    # INSIDE FOR LOOP:

    shll $1, %edx        # shift remainder left
    movl %ebx, %edi      # copy dividend
    shrl %cl, %edi        # shift copy right
    and $1, %edi         # and 1 with the remainder
    orl %edi, %edx       # or the remainder and quotient CHECK THIS
    # start of if statement

    cmpl %esi, %edx       # compare the remainder and the divisor
    jle next_iter         # if remainder is less than divisor, skip subtraction

    sub %esi, %edx        # subtract divisor from remainder 
    movl $1, %edi
    shll %cl, %edi      # Shift quotient left by cl
    orl %edi, %eax     # Or quotient with 1

next_iter:
    decl %ecx             # decrement loop counter
    jns for_start

    # END OF FOR LOOP

done:

    nop
4uqofj5v

4uqofj5v1#

示例汇编代码在this github gist中。(我是几个月前写的。我敢肯定,如果有人盯着我的算法足够长的时间,他们会找到一种方法把它撕成碎片。我终于有一个自己的工作了。
但你的算法完全不同。
你的算法的asm翻译的问题在这里:

shll $1, %edx        # shift remainder left
    shrl $1, %ebx        # shift dividend right
    and $1, %edx         # and 1 with the remainder

在第一次循环之后,%edx是0或1。在第二次循环之后,它必须为0。
它好像想读书

shll $1, %edx        # shift remainder left
    movl %ebx, %edi      # copy dividend
    shrl %esi, %edi        # shift copy right
    and $1, %edi         # and 1 with the remainder

但这行不通,因为移位指令不存在。重做寄存器分配,使i位于%cl中。(把除数放在%esi或类似的地方。

shll $1, %edx        # shift remainder left
    movl %ebx, %edi      # copy dividend
    shrl %cl, %edi        # shift copy right
    and $1, %edi         # and 1 with the remainder
vngu2lb8

vngu2lb82#

我已经研究了一段时间了,但我相信这是答案。

.global _start

.data
dividend:
    .long 100
divisor:
    .long 100
quotient:
    .long 0
remainder:
    .long 0

.text
_start:
    movl quotient, %eax
    movl remainder, %edx
    movl divisor, %esi # previously ecx
    movl dividend, %ebx
    movl $31, %ecx # previously esi 
    # first if statement that checks if the divisor is 1
    cmpl $1, %esi
    jne for_start

    # divisor is 1, so quotient is dividend and remainder is 0
    movl %ebx, %eax
    xor %edx, %edx
    jmp done

for_start:
    cmpl $0, %ecx
    jle done

    # INSIDE FOR LOOP:

    shll $1, %edx        # shift remainder left
    movl %ebx, %edi      # copy dividend
    shrl %cl, %edi        # shift copy right
    and $1, %edi         # and 1 with the remainder
    # start of if statement

    cmpl %esi, %edx       # compare the remainder and the divisor
    jle next_iter         # if remainder is less than divisor, skip subtraction

    sub %esi, %edx        # subtract divisor from remainder 
    orl $1, %eax          # set the lowest bit of quotient to 1

next_iter:
    decl %ecx             # decrement loop counter
    jns for_start

    # END OF FOR LOOP

done:
    nop

相关问题