assembly CMP函数在NASM中比较后始终返回jg

vfhzx4xs  于 2023-08-06  发布在  其他
关注(0)|答案(3)|浏览(109)

我有以下代码,我在这个website上在线运行:

section .bss
    num resq 1
section .text
    global _start       
_start:                     
    mov eax, 4      
    mov ebx, 1      
    mov ecx, msg
    mov edx, len    
    int 0x80        
      
    mov eax, 3       
    mov ebx, 0       
    mov ecx, num
    mov edx, 8   
    int 0x80
    
    mov eax,[num]
    cmp eax,0
    jl negative_label
    je equal_label
    jg positive_label
    
equal_label:
    mov eax,4
    mov ebx,1
    mov ecx,equal_text
    mov edx,3
    int 0x80
    jmp exit
positive_label:
    mov eax,4
    mov ebx,1
    mov ecx,pos_text
    mov edx,3
    int 0x80
    jmp exit
negative_label:
    mov eax,4
    mov ebx,1
    mov ecx,neg_text
    mov edx,3
    int 0x80
    jmp exit
exit:
    mov eax,1
    mov ebx,0
    int 0x80
section .data

msg db  'Hello, world!',0xa,0
len equ $ - msg
pos_text db "Poz"
neg_text db "Neg"
equal_text db "Nul"

字符串
我想检查用户输入的数字是正数、负数还是零。基本上,我想做一个程序,让用户输入数字,直到他们输入零(0),它打印出之前输入的所有数字的总和。
因此,如果用户的输入是:“1,-3,3,4”,预期输出将是“5”,因为这是上述数字的总和。
我尝试执行sub指令将 num 值转换为number,但要么我做错了,要么这不是正确的方法。
请随意批评我的代码,我是一个初学者和解决方案将是伟大的。

6rqinv9w

6rqinv9w1#

如果用户输入text“1,-3,3,4”,则 num 处的存储器将保存以下8个字节:0x31、0x2C、0x2D、0x33、0x2C、0x33、0x2C、0x34。
您的指令mov eax,[num]将检索前4个字节,以便EAX寄存器包含0x 332 D2 C31。EAX中的这个值并不反映您感兴趣的任何单个个位数,因此在对(个位数)数字进行分类的上下文中,将 this EAX与零进行比较没有意义。
需要做的是在字符串上循环,同时验证,分类,转换,求和...

这是我的建议

section .bss
    res   resd 1
    num   resb 8
section .text
    global _start
_start:              

    ...

    mov   ebx, num            ; Address of the text
    xor   ecx, ecx            ; Sum
.a: movzx eax, byte [ebx]     ; Current character
    sub   eax, '0'            ; Convert to digit [0,9] IF it is ["0","9"]
    jz    .d                  ; Null '0' provides an early out
    cmp   eax, 9              ; Comma ',' and Minus '-' get skipped here
    ja    .c                  ;  together will everything else
    cmp   byte [ebx - 1], '-' ; Has [1,9] a minus prepended?
    jne   .b                  ; Go add positive
    neg   eax                 ; From [1,9] to [-1,-9], go add negative
.b: add   ecx, eax
.c: inc   ebx                 ; Move to next character
    cmp   ebx, num + 8        ; Continu the loop while not at the end
    jb    .a
.d: mov   [res], ecx

字符串
只有当ECX中的最终总和恰好是一位数时,才可以使用下一个简化打印输出:

mov   eax, 4      
mov   ebx, 1      
mov   ecx, res
add   byte [res], '0'
mov   edx, 1    
int   0x80


上面的代码片段表明,编写此任务并不是特别困难。我真的不能同意其他的答案之一,使用的话:
如果你是一个初学者,你应该从一个简单的程序开始
。组装起来不容易
。也很难
。也很难

dnph8jn4

dnph8jn42#

子方法仅适用于0 ≤ num ≤ 9。
mov eax, [num]将4个字节(4个字符)移动到eax,因为eax是一个DWORD(4字节)寄存器(我在前面的回答中忘记了)。
这导致eax将包含0x332D2C31(因为'1' = 0x 31;',' = 0x2C;'-' = 0x2D;'3' = ASCII中的0x 33,并且小端字节顺序反转字节顺序)。使用al寄存器代替eax(因为它是一个1字节寄存器)。所以你的代码应该看起来像这样:

...

mov al, [num]   ; Move the 1st byte of 'num' into al
sub al, 48      ; Convert ASCII char to number

cmp al, 0
jl negative_label
je equal_label
jg positive_label

...

字符串
并且(这是可选的,它不会影响代码,但是)您应该使用resb 8而不是resq 1。它做同样的事情,但看起来更好,如果你保留8个1字节的值(8个字符),而不是保留1个8字节的值(= C中的uint64_t)。
More about little endian and byte orders的数据。

mec1mxoz

mec1mxoz3#

跳转到jg是因为:

输入的数字存储为ASCII字符,而不是数字,例如,如果我尝试比较ASCII '0'字符(在ASCII表中为48,在内存中存储为48),它将始终大于数字0(在内存中存储为0)。
如果你只处理1位数和无符号数,你可以通过从eax(sub eax, 48)中减去48来转换它。

你的代码将无法从这里开始工作(这只是汇编中一个功能齐全的求和程序的一个步骤),因为还有更多的困难:

以下文档和网站可以帮助您入门:

相关问题