【问题标题】:Parity of a number (Assembly) [duplicate]数字的奇偶校验(程序集)[重复]
【发布时间】:2017-11-18 23:39:16
【问题描述】:

所以我试图通过奇偶校验分隔一个八位字节,但我不太明白条件跳转是如何工作的(我单独尝试过,但我不明白它是如何工作的)

这是我想出的:

bits 32
global start
extern exit,printf
import exit msvcrt.dll
import printf msvcrt.dll

segment data use32 class=data

    s db '1', '2', '3', '4','5','7','8','9' ; declararea sirului initial s
l   equ $-s ; stabilirea lungimea sirului initial l
    d1 times l db 0
    d2 times 1 db 0
format db "%s", 0

segment code use32 class=code

start:
mov ecx, l
    mov esi, 0
    jecxz Sfarsit
Repeta:
    ;loop so it gets all the elements from s
mov al, [s+esi]
    mov bl,al
    sub bl,'0'
    cmp bl,2; if is even adds it to d1
    JP et2
    mov [d1+esi], al
inc esi
et2:
    mov bl,al
    sub bl,'0'
    cmp bl,2; if is odd adds it to d2
    JP et1
    mov [d2+esi], al
    inc esi
et1:
    loop Repeta
Sfarsit: ;terminarea programului
    ;Daca dorim si afisarea sirului d, avem urmatoarele:
    push dword d1 ; punem parametrii pe stiva de la dreapta la stanga
    push dword format
    call [printf] ;apelam functia printf
    add esp, 4 * 2 ; eliberam parametrii de pe stiva
    ; exit(0)
    push dword d2 ; punem parametrii pe stiva de la dreapta la stanga
    push dword format
    call [printf] ;apelam functia printf
    add esp, 4 * 2 ; eliberam parametrii de pe stiva
    ; exit(0)
    push dword 0 ; push the parameter for exit onto the stack
    call [exit] ; call exit to terminate the program

我认为问题出在JP,但我不完全确定。

【问题讨论】:

  • 你能描述一下你的代码应该做什么以及它做什么而不是它应该做什么?
  • 我加了一些cmets
  • 奇偶校验不是关于一个数字是偶数还是奇数,你当然不会用cmp bl, 2 测试它。类似于test bl, 1; jz even 的东西应该会更好。此外,您在et2 处复制了代码,您不再需要测试。此外,执行落入et2 你可能想跳到那里。
  • @Skillwalker cmets 没有解决我问你的问题。您希望该程序做什么以及它会做什么?

标签: assembly x86 nasm


【解决方案1】:
    cmp bl,2; if is even adds it to d1
    JP et2

cmp 在这种情况下会执行temp = bl - 2 并丢弃结果,但会影响标志(与sub bl,2 会影响它们的方式相同)。

jp是“jump parity”,即PF=1时会跳转,还有别名jpe或“jump when even”。

但这与结果的低 8 位的位奇偶校验有关,即它计算结果的低 8 位中“1”值的数量,并在有偶数个 1 时设置 PF=1。由于您在算术标志设置指令 (cmp) 中仅使用 8 位,因此整个结果用于计算 PF,但如果您这样做,例如 cmp ebx,2,它会在 PF 中得到相同的结果,因为只有 8 位的结果用于计数。

在您的情况下,处理的值(二进制):

bl          temp (low 8b)    PF
0001 (1)    11111111 (-1)    1 (8 mod 2 = 0)
0010 (2)    00000000 (0)     1 (0 mod 2 = 0)
0011 (3)    00000001 (1)     0 (1 mod 2 = 1)
0100 (4)    00000010 (2)     0 (1 mod 2 = 1)
0101 (5)    00000011 (3)     1 (2 mod 2 = 0)
0111 (7)    00000101 (5)     1 (2 mod 2 = 0)
1000 (8)    00000110 (6)     1 (2 mod 2 = 0)
1001 (9)    00000111 (7)     0 (3 mod 2 = 1)

所以bl 值 1、2、5、7、8 将采用 jp 跳转。

如果你想测试bl的值是否为偶数(bl mod 2 = 0),那么你需要:

    test bl,1           ; mask-out all bit except the lowest one
    jz   even_value     ; when lowest bit is zero, value is even

test 指令执行temp = bl AND 00000001,并丢弃结果(临时),只保留标志。二进制值是偶数,当它们的最低位(位)为零时,因为它的值 20 = 1,所以这使得奇数值成为可能。当您针对 00000001 逐位屏蔽原始值时,您只保留最低位,因此当最低位为零时,jz“跳转零”将发生 -> 值是偶数。


你可能还会遇到更多问题:

d1 times l db 0
d2 times 1 db 0    ; probably "times l db 0" meant?

当它们是偶数时,您想将值拆分为d1 / d2? 但是您使用的是相同的索引esi,因此如果您要修复您的测试和“将值存储到”逻辑,您会将值拆分为两个数组:

d1:    '1', 0, '3', 0, '5', '7', 0, '9'
d2:    0, '2', 0, '4', 0, 0, '8', 0

并且您当前的代码将仅存储设置 PF=0 的值,但会存储到两个数组中,因为您的两个分支具有相同的计算。

要获得如上所述的数组(具有奇数/偶数值,在其原始索引上),您可以这样做:

    mov   edi,d1        ; target array ptr for odd values
    mov   edx,d2        ; target array ptr for even values
    test  al,1          ; test if al has even value
      ; you can test directly the ASCII digit, '0' = 0x30 = even
    cmovz edi,edx       ; edi = target array ptr
    mov   [edi+esi],al  ; store AL into desired array

...我什至宁愿不检查该循环下方的代码,但我认为您应该在调试器中执行它,并单步执行每条指令以查看它的作用(很可能不是,您确实想要什么/期待)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 2015-04-04
    • 2013-06-25
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    相关资源
    最近更新 更多