News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Best way to invert a dword ?

Started by BlackVortex, November 13, 2008, 03:31:00 AM

Previous topic - Next topic

BlackVortex

By inverting I mean turn  for example 012ABCDEFh into 0EFCDAB12h

The idiotic way I use now is to push the value then take the bytes one by one and put them in a bugger, heh, works, but there must be a better way, right ? 
(priority isn't speed, this only gets executed once, but readability !)

   push edi  ; edi contains the dword I want to invert

   mov al, byte ptr [esp]
   mov byte ptr [buffer] , al
   mov al, byte ptr [esp+1]
   mov byte ptr [buffer+1] , al
   mov al, byte ptr [esp+2]
   mov byte ptr [buffer+2] , al
   mov al, byte ptr [esp+3]
   mov byte ptr [buffer+3] , al

   add esp,4                     ; realign the stack



MichaelW

You could use the bswap instruction, but only on a 32-bit register.
eschew obfuscation

BlackVortex

Quote from: MichaelW on November 13, 2008, 03:37:17 AM
You could use the bswap instruction, but only on a 32-bit register.
:cheekygreen: :cheekygreen: :cheekygreen:
Thanks !   

P.S.: Ok, I need to lay off the booze for a while  :-D

bozo

while we're on the subject, how about doing the same with a 64,128 or even 512 byte buffer?

of course, we could use bswap, but maybe there is faster way using SSE2?
i am guessing it could be done with pshufw/por...anyone tried?

NightWare

Quote from: Kernel_Gaddafi on November 17, 2008, 10:44:31 PM
while we're on the subject, how about doing the same with a 64,128 or even 512 byte buffer?

of course, we could use bswap, but maybe there is faster way using SSE2?
i am guessing it could be done with pshufw/por...anyone tried?
hmm, sse2 isn't really efficient, essentially because of the alignment. otherwise, you just need a string reverse algo :
ALIGN 16
StringReverse PROC StrAddr:DWORD,StrSize:DWORD
push esi
push edi

mov esi,StrAddr
mov eax,StrSize
lea edi,[esi+eax-2]
shr eax,1
sub edi,eax
add eax,-2
js Label2
Label1: mov ecx,DWORD PTR [esi]
mov edx,DWORD PTR [edi+eax]
bswap ecx
bswap edx
mov DWORD PTR [edi+eax],ecx
mov DWORD PTR [esi],edx
add esi,4
add eax,-4
jns Label1
Label2: cmp eax,-1
jne Label3
mov cl,BYTE PTR [edi+2]
mov ch,BYTE PTR [esi]
mov BYTE PTR [edi+2],ch
mov BYTE PTR [esi],cl
Label3:
pop edi
pop esi
ret
StringReverse ENDP


fattypotato

I'm a total new, just wondering if this is along right idea?



   
  .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

   xor eax,eax
   xor ebx,ebx
   mov eax,1234ABCDh

    push eax
    and eax,0000ffffh
    xchg ah,bl
    xchg al,bh

    pop eax
    shl ebx,16
    shr eax,16
    xchg ah,bl
    xchg al,bh
   
    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start

looked up bswap...way better, sorry newguy mistake :red

fattypotato

Took out 3 lines of code at it still seems to work

    .code

start:
   xor eax,eax
   xor ebx,ebx
   mov eax,1234ABCDh

    xchg ah,bl
    xchg al,bh
   
    shl ebx,16
    shr eax,16
   
    xchg ah,bl
    xchg al,bh    ; result is in ebx
   
    exit
   
end start

Tedd

Another simple one, without using bswap..
xchg al,ah
ror eax,16
xchg al,ah
No snowflake in an avalanche feels responsible.

bozo

SHA code will always convert the input data to big-endian format.
Thats the reason i put the question forward, since there has never really been an alternative to BSWAP.
But since CORE2, SSE2 *might* be faster.

NightWare

Quote from: Kernel_Gaddafi on November 19, 2008, 08:14:15 PM
SSE2 *might* be faster.
not fully tested, but this one should do the job :
ALIGN 16
;
; reverse an area
;
; Syntax :
; mov eax,{size of the area}
; mov esi,OFFSET {start address of the area}
; call AreaReverse_Sse2
;
; Return :
; nothing
;
AreaReverse_Sse2 PROC
push esi ;; empiler esi
push edi ;; empiler edi

; tester l'algo à utiliser
mov ecx,esi ;; copier l'adresse dans ecx
mov edx,eax ;; copier la taille dans edx
and edx,00011111b ;; la taille est multiple de 32 ?
jnz AlgoNormal ;; si c'est différent de zéro, aller AlgoNormal
and ecx,00001111b ;; l'adresse est multiple de 16 ?
jnz AlgoNormal ;; si c'est différent de zéro, aller AlgoNormal

; sinon, on peu utiliser les intructions sse2
AlgoSse2:
lea edi,[esi+eax-OWORD] ;; ) placer le milieu du bloc dans edi
shr eax,1 ;; )
sub edi,eax ;; )
; ici, on traite les owords
Label01: movdqa XMM0,OWORD PTR [esi] ;; placer l'oword à l'adresse en esi dans XMM0
movdqa XMM1,OWORD PTR [edi+eax] ;; placer l'oword à l'adresse en edi+eax dans XMM1
; inverser les qwords
movq XMM2,XMM0 ;; ) copier les qwords inférieurs
movq XMM3,XMM1 ;; )
movhlps XMM0,XMM0 ;; ) bouger les qwords supérieurs
movhlps XMM1,XMM1 ;; )
movlhps XMM0,XMM2 ;; ) remplacer les qwords supérieurs
movlhps XMM1,XMM3 ;; )
; inverser les dwords/words
pshuflw XMM0,XMM0,01Bh ;; renverser les words inférieurs de XMM0
pshuflw XMM1,XMM1,01Bh ;; renverser les words inférieurs de XMM1
pshufhw XMM0,XMM0,01Bh ;; renverser les words supérieurs de XMM0
pshufhw XMM1,XMM1,01Bh ;; renverser les words supérieurs de XMM1
; inverser les octets
movdqa XMM2,XMM0 ;; copier XMM0 dans XMM2
movdqa XMM3,XMM1 ;; copier XMM1 dans XMM3
psllw XMM0,8 ;; ) décaler à gauche d'un octet
psllw XMM1,8 ;; )
psrlw XMM2,8 ;; ) décaler à droite d'un octet
psrlw XMM3,8 ;; )
por XMM0,XMM2 ;; ) fusionner les valeurs
por XMM1,XMM3 ;; )
movdqa OWORD PTR [edi+eax],XMM0 ;; placer l'oword en XMM0 à l'adresse en edi+eax
movdqa OWORD PTR [esi],XMM1 ;; placer l'oword en XMM1 à l'adresse en esi
add esi,OWORD ;; ajouter un dword à l'adresse en esi
add eax,-OWORD ;; décrementer eax d'un dword
jnz Label01 ;; tant que eax n'est pas signé, aller Label01

pop edi ;; désempiler edi
pop esi ;; désempiler esi
ret ;; retourner (sortir de la procédure)

; ici on va trouver le bon milieu du bloc mémoire
AlgoNormal:
lea edi,[esi+eax-2] ;; ) placer le milieu du bloc dans edi
shr eax,1 ;; )
sub edi,eax ;; )
sub eax,2 ;; ici, on produit un mini-décalage qui nous servira
js Label12 ;; une petite chaîne ?, alors aller Label1 2
nop ;; ) alignement nécessaire pour un meilleur rendement
; nop ;; )
; nop ;; )
; nop ;; )
; nop ;; )
; nop ;; )
; nop ;; )
; nop ;; )
; ici, on traite le cas où la chaine est longue
Label11: mov ecx,DWORD PTR [esi] ;; placer le dword à l'adresse en esi dans ecx
mov edx,DWORD PTR [edi+eax] ;; placer le dword à l'adresse en edi+eax dans edx
bswap ecx ;; échanger les octets en ecx
bswap edx ;; échanger les octets en edx
mov DWORD PTR [edi+eax],ecx ;; placer les octets en ecx à l'adresse en edi+eax
mov DWORD PTR [esi],edx ;; placer les octets en edx à l'adresse en esi
add esi,DWORD ;; ajouter un dword à l'adresse en esi
add eax,-DWORD ;; décrementer eax d'un dword
jns Label11 ;; tant que eax n'est pas signé, aller Label11
; test s'il n'y a qu'une paire d'octets à échanger
Label12: cmp eax,-1 ;; comparer eax à -1
jne Label13 ;; si c'est différent, aller Label13
; ici on traite le cas d'une toute petite chaine
mov dl,BYTE PTR [edi+2] ;; placer l'octet en edi+2 dans dl
mov dh,BYTE PTR [esi] ;; placer l'octet en esi dan dh
mov BYTE PTR [esi],dl ;; placer dl à l'adresse en esi
mov BYTE PTR [edi+2],dh ;; placer dh à l'adresse en edi+2
Label13:
pop edi ;; désempiler edi
pop esi ;; désempiler esi
ret ;; retourner (sortir de la procédure)
AreaReverse_Sse2 ENDP

NightWare

 :red oops...
; inverser les qwords
movq XMM2,XMM0 ;; ) copier les qwords inférieurs
movq XMM3,XMM1 ;; )
movhlps XMM0,XMM0 ;; ) bouger les qwords supérieurs
movhlps XMM1,XMM1 ;; )
movlhps XMM0,XMM2 ;; ) remplacer les qwords supérieurs
movlhps XMM1,XMM3 ;; )

can be changed to :
; inverser les qwords
pshufd XMM0,XMM0,04Eh ;; ) permuter les qwords
pshufd XMM1,XMM1,04Eh ;; )

cmpxchg

SSSE3

;Fasm

align 16
_mask: db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0

movdqa xmm0, [_mask]
movdqu xmm1, dqword [esp]              ;some data to invert
movdqu xmm2, dqword [esp+16]
pshufb xmm1, xmm0
pshufb xmm2, xmm0
movdqu dqword [esp], xmm1              ;save data
movdqu dqword [esp+16], xmm2


an alternative would be 64bit bswap of the LongMode

bozo

nice instruction, pshufb :)

i used this on sse2 before, although i didn't test whether it was faster than using bswap.

movdqa    xmm0,[data_buffer] ; aligned by 16 bytes
movdqa    xmm1,xmm0
psrlw     xmm0,8 ; rotate words by 8 bits
psllw     xmm1,8 ; same as xchg al,ah
por       xmm0,xmm1
movdqa    xmm1,xmm0
psrld     xmm1,16 ; rotate double words by 16 bits
pslld     xmm0,16
por       xmm0,xmm1


interesting code Nightware, i'll probably change the above to what you did.

pshufd    xmm0,[data_buffer],0E4h
pshuflw   xmm0,xmm0,01Bh
pshufhw   xmm0,xmm0,01Bh
movdqa    xmm1,xmm0
psllw     xmm0,8 ; rotate words by 8 bits
psrlw     xmm1,8 ; same as xchg al,ah
por       xmm0,xmm1


would probably still need timing, but looks good.

NightWare

Quote from: Kernel_Gaddafi on December 26, 2008, 08:21:24 AM
still need timing.
from my speed tests, your code appear faster, 6/7 cycles against 9/10 (yep... i use some 2 cycles instructions...)  :wink