У xorpd есть некоторые загадки, похожие на куски ассемблерного кода здесь. В этом посте я разберу загадки 0x12, 0x0d и 0x0e, которые имеют некоторые общие черты. Давайте приступим!

xorpd загадка 0x12

Вот код:

mov      rcx,rdx
and      rdx,rax
or       rax,rcx
add      rax,rdx

Давайте пошагово:

mov      rcx,rdx  ; rcx =  x
and      rdx,rax  ; rdx =  x && y
or       rax,rcx  ; rax =  y || x
add      rax,rdx  ; rax = (y || x) + (x && y)

Интересным фактом об этом выражении является то, что оно эквивалентно или. Чтобы показать вам это, я проведу несколько тестов. Представляя каждое неизвестное значение как один бит, вероятные случаи:

| X | Y |
---------
| 0 | 0 |
| 0 | 1 |
| 1 | 0 |
| 1 | 1 |

Разобрав выражение, легко заметить, что:

  • Последняя часть (x && y) будет true только в том случае, если обе переменные true
  • Первая часть (x || y) будет false только в том случае, если обе переменные имеют значение false.

Мы можем ясно видеть, что эти наблюдения пересекаются с некоторыми операторами +(добавить мнемонику), фактически, если мы вычислим таблицу истинностидля всего выражения (с именем exp) и addмы видим, что они эквивалентны:

| X | Y | =>  | exp | add |
---------    -------------
| 0 | 0 |  => |   0 |   0|
| 0 | 1 |  => |   1 |   1|
| 1 | 0 |  => |   1 |   1|
| 1 | 1 |  => |  10 |  10|

xorpd загадка 0x0d

На этот раз код выглядит так:

mov      rdx,rbx
xor      rbx,rcx
and      rbx,rax
and      rdx,rax
and      rax,rcx
xor      rax,rdx
cmp      rax,rbx

Что тут происходит? У нас есть 3 неизвестных значения из регистров rbx, rcx и rax. Назовем их X, Y, Z. Если мы заменим регистр для переменных в фрагменте кода, мы получим следующее:

mov      rdx,rbx  ; rdx = X
xor      rbx,rcx  ; rbx = X ^ Y
and      rbx,rax  ; rbx = Z & (X ^ Y)
and      rdx,rax  ; rdx = Z & X
and      rax,rcx  ; rax = Z & Y
xor      rax,rdx  ; rax = (Z & Y) ^ (Z & X)
cmp      rax,rbx  ; ((Z & Y) ^ (Z & X)) - (Z & (X ^ Y))

Проследив этот поток операций xor и and, мы приходим к следующему упрощенному сравнению в конце:

cmp (Z & (X ^ Y)), ((Z & Y) ^ (X & Z))

В итоге оба выражения будут иметь одинаковое значение, вне зависимости от начальных значений регистров. Это происходит из-за распределительного свойства и над xor, которое вытекает из законов де Моргана.

xorpd загадка 0x0e

Проанализируем третий:

mov      rcx,rax
and      rcx,rbx
not      rcx
not      rax
not      rbx
or       rax,rbx
cmp      rax,rcx

Замена неизвестных значений переменными X и Y дает нам некоторое представление:

mov      rcx,rax  ; rcx = X
and      rcx,rbx  ; rcx = X & Y
not      rcx      ; rcx = !(X && Y)
not      rax      ; rax = !X
not      rbx      ; rbx = !Y
or       rax,rbx  ; rax = !X || !Y 
cmp      rax,rcx  ; cmp !X || !Y, !(X && Y)

Мы видим, что, как и в предыдущей загадке, последнее утверждение всегда будет истинным, поскольку оно соответствует следующему Закону Де Моргана:

!X || !Y is equivalent to !(X && Y)

Таким образом, независимо от начальных значений rax и rbx, rax и rcx будут иметь одно и то же значение в конце.