I wrote a function which takes a byte and shifts the bits around. That is, there shall be the same number of 1 bits and 0 bits in the output but the bits will be shifted in position:
global _main
default rel
section .text
_main:
; Given 1 byte, shift the positions of the bits in the form 74652103
mov bl, 0x5A
; 0101 1010
shift_bits:
; 1. bit 7 stays same
; 2. bit 4 (0x10) gets shifted left by 2 - and with 0001 0000, shift left by 2, or with result
; 3. bit 6 (0x40) gets shifted right by 1
; 4. bit 5 (0x20) gets shifted right by 1
; 5. bit 2 (0x4) gets shifted left by 1
; 6. bit 1 (0x2) gets shifted left by 1
; 7. bit 0 (0x1) gets shifted left by 1
; 8. bit 3 (0x8) gets shifted right by 3
; begin 0101 1010
; expect: 0110 0101
; end 0110 0101
mov al, bl
mov cl, 0
and al, 0x80
or cl, al
mov al, bl
and al, 0x10
shl al, 2
or cl, al
mov al, bl
and al, 0x4
shl al, 1
or cl, al
mov al, bl
and al, 0x2
shl al, 1
or cl, al
mov al, bl
and al, 0x1
shl al, 1
or cl, al
mov al, bl
and al, 0x8
shr al, 3
or cl, al
mov al, bl
and al, 0x2
shl al, 1
mov al, bl
and al, 0x40
shr al, 1
or cl, al
mov byte [A], cl ; Store result in A
go_out:
mov rax, 0x2000001 ; exit - macOS specific!
mov rdi, 0
syscall
section .data
A: db 0
Is there a more efficient way to do this with fewer instructions or more performant ones?
mov
from memory, but I guess you are for some reason trying to avoid this (kinda "cheat", but often used in 8b/16b CPU emulators, etc.. to make the processing speed predictable across different types of calculations and also the LUTs are often 10..20 bits to account not only for the source 8b value, but also the "flag" register and calculating in singlemov
results of both together). \$\endgroup\$shrx
and similar? (didn't really try, but I would guess it may be favourable for certain intermediate steps, not affecting flags and specifying both source + destination registers saving a copy instruction). \$\endgroup\$