Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mirror a byte without using other registers?

Tags:

x86

assembly

Let's say I have this byte in AL: 01100001 After applying a mirror function I want the byte to be 10000110.

All ideas that I came up with I have to use other registers, but I am curious if there is a way to mirror a byte without using any other register?

like image 886
Daskus Avatar asked Feb 15 '17 09:02

Daskus


1 Answers

The "storage by immediate in code" variant:

mirror_bits:
    ; handle bits 0 and 7
    TEST    al,0x81
    JPE     bits07same
    XOR     al,0x81
bits07same:
    ; handle bits 1 and 6
    TEST    al,0x42
    JPE     bits16same
    XOR     al,0x42
bits16same:
    ; handle bits 2 and 5
    TEST    al,0x24
    JPE     bits25same
    XOR     al,0x24
bits25same:
    ; handle bits 3 and 4
    TEST    al,0x18
    JPE     bits34same
    XOR     al,0x18
bits34same:
    RET

EDIT: About my comment under question and general answer whether there's a way.

You should always just ask the math theory first. In your case you are deterministically changing 8 bit information into other 8 bit information result, and the minimal modification step needed is "swap of two bits", which is impossible to do without third bit for temporary storage, so you are now looking for a way to supplement temporary storage without extra register ("and memory" I did add to myself).

Thus if you want to mirror al without changing other register (not counting rip and eflags, as that would be 99% impossible completely), you need to "borrow" this extra bit elsewhere.

As the digital computers are turing-like machines, you can exchange missing bits in registers/storage by using bits of code instructions, so theoretically it is possible => QED.

After that basic "validation" of question it was just question to find out, what kind of code structure does provide that extra information bit storage and swap bits.

The most direct brutal way is to have branching per bit-value, ie. test al,0x01 jz bit_0_clear ; else bit_0_set branch follows (each branch can then do the correct set/reset of target bits to make it look like it did swap them)... I wouldn't dare to write the complete code like that (too long, too tedious), but this is one root of the solution above.

The other root of solution was to put this code idea against the "what has to be really done", and that is "swapping bits on particular positions". But that can be optimized out, when the bits already have the same value = no swap needed. And "swapping" two bits when they are different can be achieved by simple xor flipping both of them.

After I merged all those idea-trains to single solution, I got almost what is above, then I just cleaned it a bit (like figuring out the "two bits are same" test can be simplified down to single test + jpe) and verified it works.

But whenever in doubt, just remember how Turing machine works :))) (semi-joke, I wouldn't really want to write any medium-sized algorithm in Turing machine-like language, even a short one would be probably annoying after being used to complex machines/languages like x86 or C++. But it's still good to verify the task at the base level, whether it makes sense turing-wise).

like image 199
Ped7g Avatar answered Oct 09 '22 13:10

Ped7g