1

So I'm trying to separate an octet by parity and I don't quite understand how the conditional jumps work(I tried it separately and I don't understand how it works it)

Here is what I came up with:

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

I think the problem is the JP but I'm not completely sure.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
Skillwalker
  • 37
  • 1
  • 4
  • 1
    Can you describe what your code should do and what it does instead of what it should do? – fuz Nov 18 '17 at 23:44
  • I added some comments – Skillwalker Nov 18 '17 at 23:46
  • 1
    Parity is not about whether a number is even or odd, and you certainly don't test that with a `cmp bl, 2`. Something along the lines of `test bl, 1; jz even` should work better. Also, you have duplicated code, at `et2` you no longer need to test. Furthermore, the execution falls through into `et2` you probably want a jump there. – Jester Nov 18 '17 at 23:47
  • 2
    @Skillwalker The comments do not address the question I asked you. What do you expect the program to do and what does it do instead? – fuz Nov 19 '17 at 00:27

1 Answers1

2
    cmp bl,2; if is even adds it to d1
    JP et2

cmp in this case does temp = bl - 2 and throws away the result, but keeps the flags affected (same way as sub bl,2 would affect them).

And jp is "jump parity", which means it will jump when PF=1, it has also alias jpe or "jump when even".

But that's about bit-parity of the low 8 bits of result, i.e. it counts number of "1" values in low 8 bits of result and sets PF=1 when there's even number of ones. As you use only 8 bits in the arithmetic flag setting instruction (cmp), the whole result is used to calculate PF, but if you would do for example cmp ebx,2, it would have same result in PF, as only 8 bits of result are used to count ones.

In your case the values processed (in binary):

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)

So bl values 1, 2, 5, 7, 8 will take jp jump.

If you want to test bl if the value is even (bl mod 2 = 0), then you need:

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

The test instruction does temp = bl AND 00000001, and throws away result (temp), keeps only flags. Binary values are even, when their lowest digit (bit) is zero, because that one has value 20 = 1, so that's the one which makes odd values possible. When you bit-wise mask the original value against 00000001, you keep only the lowest bit, so jz "jump zero" will happen when that lowest bit was zero -> value was even.


also probably some more problems you will encounter:

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

And you wanted to split values into d1 / d2 when they are even odd? But you are using the same index esi, so if you will fix your test, and your "store value into" logic, you will split the values into two arrays:

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

And your current code will store only values which set PF=0, but into both arrays, as both your branches have identical calculation.

To get the arrays as described above (with odd/even values, on their original index) you can do:

    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

... and I will rather not even check code below that loop, but I think you should execute it in debugger, and single-step over each instruction to see, what it does (very likely NOT, what you did want/expect).

Ped7g
  • 16,236
  • 3
  • 26
  • 63