Обратный порядок байтов регистра EAX

Пример: 0xAABBCCDD превратится в 0xDDCCBBAA

Моя программа вылетает из-за исключения нарушения доступа прямо в первой операции XOR.

Кажется, что есть лучшее наивное решение, использующее смещение или вращение, но в любом случае, вот код:

  ;; #########################################################################

      .486
      .model flat, stdcall
      option casemap :none   ; case sensitive

;; #########################################################################

      include \masm32\include\masm32.inc
      include \masm32\include\kernel32.inc

      includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\masm32.lib


.code
;; The following program will flip the sequence of the bytes in the eax
;; example : 0xAABBCCDD will turn into 0xDDCCBBAA
start:
MOV eax, 0AABBCCDDh 
XOR BYTE PTR [eax], al ;; Swap first byte and last byte
XOR al, BYTE PTR [eax]
XOR BYTE PTR [eax], al 
XOR BYTE PTR [eax+1], ah ;; Swap 2nd byte of eax and 3rd byte
XOR ah, BYTE PTR [eax+1]
XOR BYTE PTR [eax+1], ah
end_prog:
    ;;Exit the program, eax is the exit code
    push eax
    call ExitProcess
END start

Что я здесь делаю неправильно? Есть ли лучшее решение для этого?


person idish    schedule 14.10.2013    source источник


Ответы (3)


Почему бы не просто:

 mov  eax, 0AABBCCDDh
 bswap eax

Я не уверен, что вы пытаетесь сделать в своей программе, но могу сказать, что на самом деле пытается сделать процессор (но не может, и поэтому происходит сбой):

Этот:

XOR BYTE PTR [eax], al 

Пытается вычислить операцию xor значения в регистре AL (размером в байт) и значения байта в памяти по адресу 0AABBCCDDh (содержимое регистра EAX). Пока по этому адресу нет памяти, выделенной ОС, программа вылетает с GPF.

Правильная замена байтов без использования bswap выглядит следующим образом (спасибо X.J):

    xchg  ah, al
    ror   eax, 16
    xchg  ah, al.
person johnfound    schedule 14.10.2013
comment
Потому что я никогда не знал, что есть такой опкод :) и вообще, вы видите, почему программа вылетает? или если есть другое решение без использования кода операции bswap? - person idish; 15.10.2013
comment
Я так и не понял, что не так. Я пытался выполнить операцию XOR между 0xAA и 0xDD. (первый байт и последний байт) - person idish; 15.10.2013
comment
Но вы пытаетесь выполнить операцию XOR между DD (в AL) и некоторым байтом памяти по адресу AABBCCDD. Вы понимаете разницу между памятью и регистрами? Также обратите внимание, что в x86 у вас просто нет байтового доступа к старшим 16 битам регистров. Вы можете, например, сделать XOR AH, AL (без квадратных скобок!), и это сделает XOR 0CCh, 0DDh, но для верхней части EAX нет байтовых регистров. - person johnfound; 15.10.2013
comment
Почему вы не можете получить доступ к верхней части EAX? Как я могу сделать следующее? : MOV BYTE PTR [eax],0h. Не установит ли старший байт eax значение 0x00? Если бы не было такого кода операции, как bswap, как бы вы могли поменять местами байты? Как вы сказали, мы не можем получить доступ к верхней части EAX. Прошу прощения за все эти вопросы, я совсем новичок в ASM - person idish; 15.10.2013
comment
Опять же, mov byte ptr [eax], 0h запишет 0h по некоторому адресу в памяти, а не в старшем байте EAX. Адрес, куда будет записан этот 0h, является значением регистра EAX. Если бы не было bswap, единственный способ поменять местами байты — использовать более 1 регистра и работать с младшими 16 битами (которые доступны как байтовые регистры AH/AL и соответственно BH/BL, CH/CL и DH/DL) . - person johnfound; 15.10.2013
comment
Ааа, теперь понял, спасибо за объяснение. На самом деле, это своего рода домашнее задание, и я не должен был использовать код операции bswap (наверное). Я до сих пор не понимаю, как это можно сделать, используя младшие регистры AH/AL и другие 16-битные регистры. Не могли бы вы опубликовать код, пожалуйста? Я знаю, что прошу слишком многого по этому вопросу .. :) - person idish; 15.10.2013
comment
@idish - я добрый сегодня. :) Ответ отредактирован, читайте там. - person johnfound; 15.10.2013
comment
В качестве улучшения один раз также можно использовать ROR следующим образом: xchg ah,al;ror eax,16;xchg ah;al. - person X.J; 15.10.2013
comment
@X.J - Да, конечно, мне нужно немного поспать, и я так медленно думаю. :) Могу ли я использовать ваше решение? - person johnfound; 15.10.2013
comment
современные процессоры x86 имеют MOVBE, и вам даже не нужен MOV, а затем BSWAP - person phuclv; 09.10.2020
comment
По производительности rol ax, 16 несколько лучше, чем xchg al,ah на современных процессорах. (например, 1 uop вместо 3 в семействе Intel Sandybridge, и AH не переименовывается отдельно от RAX, поэтому ему не потребуется uop слияния AH, чтобы он выдавался в цикле сам по себе, когда вы в следующий раз читаете EAX). О, я только что прокрутил вниз, и уже есть ответ, указывающий на это, и я прокомментировал то же самое 2 года назад. ›.‹ - person Peter Cordes; 06.03.2021

Альтернативное решение, использующее только инструкцию rol:

mov eax,0xAABBCCDDh
rol ax,8            ; 0AABBDDCCh
rol eax,16          ; 0DDCCAABBh
rol ax,8            ; 0DDCCBBAAh

Я считаю, что в большинстве случаев это будет немного быстрее, чем использование инструкции xchg, хотя я не вижу причин не использовать просто bswap, которая чище и, вероятно, быстрее.

person Andrew Hardiman    schedule 21.08.2018
comment
Да, это медленнее, чем bswap, но намного быстрее, чем xchg на современных процессорах, потому что rol reg,imm — это один uop (agner.org /optimize), и потому что он избегает написания AH (Как именно работают частичные регистры в Haswell/Skylake?), поэтому слияние частичных регистров дешевле или отсутствует в семействе Sandybridge. Версия на основе xchg может быть лучше для 386 (меньший размер кода). Используйте это, если вам нужна совместимость с древними процессорами (bswap требуется 486), но позаботьтесь о современных процессорах, где xchg является многопроцессорным. - person Peter Cordes; 21.08.2018

Как насчет...

    mov eax, 0AABBCCDDh
    xchg al, ah ; 0AABBDDCCh
    rol eax, 16 ; 0DDCCAABBh
    xchg al, ah ; 0DDCCBBAAh

Не будет ли это делать то, что нужно в одном регистре? Я вижу, что XJ уже опубликовал это (повернуть влево, повернуть вправо - тот же результат) Надо поторопиться, чтобы победить вас, ребята! :)

person Frank Kotler    schedule 15.10.2013
comment
Вау, это отличное решение, спасибо! Я добавлю вам +1, так как я уже принимаю ответ Джона XD - person idish; 15.10.2013
comment
Это довольно крутое решение, но имейте в виду, что оно может быть медленнее. Использование частичных регистров часто обходится очень дорого, так как большинство процессоров x86 не поддерживают разные регистры и вынуждены выполнять дорогостоящее слияние при каждой частичной записи. - person Leeor; 15.10.2013