如何在 x86 linux nasm 程序集中将 2 个不同长度的数字加在一起

How to add 2 numbers together that are of different lengths in x86 linux nasm assembly

我对装配还很陌生,在使用不同长度的数字进行基本计算时遇到困难。

这是我添加的代码,适用于长度不超过 3 个字符的数字。只要两者的长度相同。例如 123 + 123 工作正常并输出 246。但是 12 + 123 不工作并且它输出 253 作为答案。 我怎样才能使用不同长度的数字来实现它?

    sys_exit equ 1
    sys_read equ 3
    sys_write equ 4
    stdin equ 0
    stdout equ 1

    section .data
        newLine db 10
        cquestion db 'Enter a number: ', 0xa
        cqLen equ $ - cquestion

        answer db 'Your answer is: '
        aLen equ $ - answer


    section .bss

        number1 resb 4
        number2 resb 4
        number1Len resd 1
        number2Len resd 1

        answ resb 8

    %macro write_string 2
        mov eax, 4
        mov ebx, 1
        mov ecx, %1
        mov edx, %2
        int 0x80
    %endmacro

    section .text
    global _start
    _start:
    write_string cquestion, cqLen

    mov eax, sys_read
    mov ebx, stdin
    mov ecx, number1
    mov edx, 4
    int 0x80
    mov [number1Len], eax

    write_string cquestion, cqLen

    mov eax, sys_read
    mov ebx, stdin
    mov ecx, number2
    mov edx, 4
    int 0x80
    mov [number2Len], eax

    write_string answer, aLen

    clc
    mov ecx, [number2Len]           ;number of digits
    dec ecx                         ;need to decrease one for some reason?
    mov esi, ecx                
    dec esi                         ;pointing to the rightmost digit.
    .add_loop:

        mov al, [number1 + esi]
        adc al, [number2 + esi]
        aaa
        pushf               ; also no idea what this is here for
        or  al, 30h         ; or this
        popf                ; and this...

        mov [answ + esi], al
        dec esi
        loop addition.add_loop

        mov eax, sys_write
        mov ebx, stdout
        mov ecx, answ
        mov edx, 8
        int 0x80
        
        mov eax, sys_write
        mov ebx, stdout
        mov ecx, newLine
        mov edx, 1
        int 0x80

    mov [answ], DWORD 0
  • 您的循环绝不会执行超过 3 次迭代。如果有最后进位,您将需要额外写入目的地。
  • 如果代码需要处理不同长度的输入,那么您不能使用相同的偏移量 ESI 来寻址两个数字的相应数字。
  • 而且您也不能使用相同的 ESI 来存储输出,因为您可能需要在左侧多一个位置。
  • 关于answ resb 8,两个3位数相加最多只能得到4位数的和。

下面是这个问题的众多解决方案之一

                           ECX=1
                           v
num1:  31 32 0A 00      31 32 30 30
num2:  31 32 33 0A      31 32 33 30
                              ^
                              EDX=2

answ:                   00 00 00 00     --> 30 31 33 35
                                 ^
                                 EDI=3
    mov   ecx, [number1Len]           ; Number of bytes (eg. 3)
    sub   ecx, 2                      ; Offset to 'ones' digit
    lea   eax, [ecx + 1]              ; Offset to the newline
  .more1:
    mov   byte [number1 + eax], 30h
    inc   eax
    test  eax, 3
    jnz   .more1

    mov   edx, [number2Len]           ; Number of bytes (eg. 4)
    sub   edx, 2                      ; Offset to 'ones' digit
    lea   eax, [edx + 1]              ; Offset to the newline
  .more2:
    mov   byte [number2 + eax], 30h
    inc   eax
    test  eax, 3
    jnz   .more2

    mov   edi, 3                      ; 4 iterations
    clc
  .add_loop:
    movzx eax, byte [number1 + ecx]
    adc   al, [number2 + edx]
    aaa
    lahf                              ; Preserves CF gotten from `aaa`
    or    al, 30h                     ; Convert into character "0" to "9"
    mov   [answ + edi], al
    dec   ecx
    and   ecx, 3                      ; Wraparound in number1
    dec   edx
    and   edx, 3                      ; Wraparound in number2
    sahf                              ; Restores CF
    dec   edi
    jns   .add_loop

answ 的结果中,我们最多可以删除 3 个前导零。如果真实结果为0,则answ中的第4个字符必须保留。

    mov   edx, 4
    mov   ecx, answ
  .del:
    cmp   byte [ecx], 30h
    jne   .ok
    dec   edx
    inc   ecx
    cmp   edx, 1
    ja    .del
  .ok:
    mov   ebx, stdout
    mov   eax, sys_write
    int   80h