如何在 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
我对装配还很陌生,在使用不同长度的数字进行基本计算时遇到困难。
这是我添加的代码,适用于长度不超过 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