Titkok

Titkok

Tanulófeladat

Bevezetés

Bitmanipuláció

Egy egész szám minden bitje alkalmas egy bináris érték tárolására. Mivel sok helyzet hordoz bináris információt, például igaz vagy hamis, bevonás vagy kizárás, be vagy ki, egy N bites egész szám bináris reprezentációja tömör módot kínál N elem bináris állapotának kódolására. Emiatt az assemblyben elengedhetetlen, hogy tudjunk bitekkel és bájtokkal manipulálni. Az x86-64 utasításkészlet a bitmanipulációs utasítások széles választékát kínálja.

Egyes bitek manipulálása

Ezek az utasítások egyetlen biten működnek egy operanduson belül.

Mindegyikük két operandust vár; a második adja meg annak a bitnek az indexét, amelyre az első operandusban hatnak. Mindegyikük átmásolja a kiválasztott bitet az átvitel jelzőbitbe (CF).

Név Leírás
bt átmásolja a bitet a CF-be, anélkül hogy módosítaná bármelyik operandust
bts átmásolja a bitet a CF-be, és beállítja a céloperandusban
btr átmásolja a bitet a CF-be, és törli a céloperandusban
btc átmásolja a bitet a CF-be, és invertálja (átbillenti) a céloperandusban

Bitműveletek

A bitműveletek egy operandus összes bitjén hajtódnak végre.

Mindegyikhez tartozik egy utasítás, amelynek a neve megegyezik az elvégzett bitművelet nevével:

Név Leírás
and 1, ha mindkét bit 1
or 1, ha a bitek közül legalább az egyik 1
xor 1, ha a bitek eltérnek
not 1, ha a bit 0 volt; 0, ha a bit 1 volt

A legtöbbjük két operandust vár, bitműveletet végez mindkettőn, és az eredményt a céloperandusban tárolja. Kivétel a not, amely csak egy céloperandust vár.

Maszkok

Amikor az egyest bevonásként, a nullát pedig kizárásként értelmezzük, az egész számot bitmaszknak (vagy egyszerűen maszknak) nevezzük.

A bitmaszk „kiszűri” az elemeket, mert az i-edik biten álló nulla kizárja az i-edik elemet, az egyes pedig bevonja. A bitmaszkot arra is gyakran használjuk, hogy egy egész szám bizonyos bitjeit bevonjuk, másokat pedig kizárjunk.

Például legyen A olyan egész szám, amelynek bináris reprezentációja:

index 7 6 5 4 3 2 1 0
bitek 1 0 0 1 0 1 0 1

Legyen továbbá M olyan egész szám, amelynek bináris reprezentációja:

index 7 6 5 4 3 2 1 0
bitek 0 0 0 0 1 1 0 1

Mindkettő 8 bites egész szám. Ebben az esetben azt mondhatjuk, hogy M kijelöli A 0, 2 és 3 bitjét, a többit pedig kizárja.

A korábban tárgyalt bitműveleti utasítások hasznosak, amikor maszkokkal manipulálunk egész számokat. Például:

  • Ha törölni szeretnéd A azon bitjeit, amelyeket M nem jelöl ki, végezd el a bitenkénti és műveletet: A AND M.
  • Ha be szeretnéd állítani A azon bitjeit, amelyeket M kijelöl, végezd el a bitenkénti vagy műveletet: A OR M.

A TEST utasítás

A test utasítás bitenkénti és műveletet végez a két operandus között, és az eredménynek megfelelően állítja be a jelzőbiteket.

Ha A az első operandus, B pedig a második:

jelzőbit beáll, amikor
CF mindig törlődik
ZF A AND B == 0
SF az A AND B előjelbitje be van állítva
OF mindig törlődik

Ez az utasítás két operandust vár, és frissíti a jelzőbiteket, de nem módosítja az operandusait.

Eltolási műveletek

Ezek az utasítások a céloperandus bitjeit annyi pozícióval mozgatják el, amennyit a második operandus megad. A második operandusnak konstans számnak (egy immediate-nek) vagy a cl regiszternek (az rcx legalsó 8 bitjének) kell lennie.

Név Leírás
shl/sal Balra tolja a biteket
shr/sar Jobbra tolja a biteket

Fontos, hogy a második operandusban szereplő érték 5 bitre van maszkolva, 64 bites céloperandus esetén pedig 6 bitre. Az ezen túli biteket a processzor gyakorlatilag figyelmen kívül hagyja. Ez azt jelenti, hogy a legnagyobb eltolás 31, 64 bites operandus esetén pedig 63.

Shl / Sal

A shl és a sal pontosan ugyanazt a műveletet végzi, az egyik a másik álneve.

Balra tolásnál azok a bitek, amelyek az eltolás hosszánál közelebb vannak a sorozat végéhez, először a CF-be kerülnek, majd elvesznek. Ugyanakkor a sorozat elejére az eltolás hosszával megegyező számú, nullára törölt bit kerül.

Mivel egy egész szám minden bitje a 2 egy hatványát képviseli, az n pozícióval balra tolás megszorozza az egész számot 2ⁿ-nel.

Shr / Sar

Két utasítás tolja jobbra a biteket: a shr és a sar.

Bármelyik utasítás használatakor azok a bitek, amelyek az eltolás hosszánál közelebb vannak a sorozat elejéhez, először a CF-be kerülnek, majd elvesznek. Ugyanakkor a sorozat végére az eltolás hosszával megegyező számú új bit kerül.

A kettő közötti különbség, hogy a shr 0-t ír a bal oldali végre, a sar pedig 1-et, ha a legmagasabb helyiértékű bit be volt állítva, egyébként 0-t. Ez azt jelenti, hogy a sar megőrzi az előjelet előjeles egész szám eltolásakor.

Mivel egy egész szám minden bitje a 2 egy hatványát képviseli, az shr utasítással n pozícióval jobbra tolva előjel nélküli osztást végzel 2ⁿ-nel.

Hasonlóképpen a sar utasítással n pozícióval jobbra tolva előjeles osztást végzel 2ⁿ-nel.

Forgási műveletek

Ezek az utasítások a céloperandus bitjeit annyi pozícióval mozgatják el, amennyit a második operandus megad. A második operandusnak konstans számnak (egy immediate-nek) vagy a cl regiszternek (az rcx legalsó 8 bitjének) kell lennie.

A forgatás és az eltolás között az a különbség, hogy a forgatás nem dob el és nem is ad hozzá biteket. Azok a bitek, amelyeket egy eltolás elveszítene, helyette a túloldali végre kerülnek. Így minden bit megmarad, csak helyet cserélnek.

Név Leírás
rol Balra forgatja a biteket
ror Jobbra forgatja a biteket

Fontos, hogy a második operandusban szereplő érték 5 bitre van maszkolva, 64 bites céloperandus esetén pedig 6 bitre. Az ezen túli biteket a processzor gyakorlatilag figyelmen kívül hagyja. Ez azt jelenti, hogy a legnagyobb forgatás 31, 64 bites operandus esetén pedig 63.

További bitmanipulációs utasítások

Vannak más hasznos bitmanipulációs utasítások is:

Név Leírás
popcnt Megszámolja a beállított bitek számát
bsr Megadja a legmagasabb helyiértékű beállított bit indexét. Ha egy bit sincs beállítva, az eredmény nem meghatározott
bsf Megadja a legalacsonyabb helyiértékű beállított bit indexét. Ha egy bit sincs beállítva, az eredmény nem meghatározott

Ezek az utasítások mind 16 bites, 32 bites vagy 64 bites operandusokkal működnek. 8 bites operandusokkal nem használhatók.

Utasítások

A barátod épp most küldött neked egy üzenetet egy fontos titokkal. Mivel nem akarta, hogy mások könnyen elolvashassák, az üzenetet egy sor bitmanipulációval titkosította. Neked kell megírnod azokat a függvényeket, amelyek segítenek visszafejteni az üzenetet.

Note

Ezek az ebben a fogalomban említett egybites utasítások:

Név Leírás
bt átmásolja a bitet a CF-be anélkül, hogy bármelyik operandust módosítaná
bts átmásolja a bitet a CF-be, és beállítja a céloperandusban
btr átmásolja a bitet a CF-be, és törli a céloperandusban
btc átmásolja a bitet a CF-be, és komplementálja (megfordítja) a céloperandusban

Ezek az ebben a fogalomban említett bitenkénti utasítások:

Név Leírás
and 1, ha mindkét bit 1
or 1, ha a bitek közül legalább az egyik 1
xor 1, ha a bitek eltérnek
not 1, ha a bit 0 volt; 0, ha a bit 1 volt

Ezek az ebben a fogalomban említett eltoló utasítások:

Név Leírás
shl/sal A biteket balra tolja el
shr/sar A biteket jobbra tolja el

Ezek az ebben a fogalomban említett forgató utasítások:

Név Leírás
rol A biteket balra forgatja
ror A biteket jobbra forgatja

Ezek az ebben a fogalomban említett egyéb utasítások:

Név Leírás
popcnt Megszámolja a beállított bitek számát
bsr A legnagyobb helyiértékű beállított bit indexét adja vissza. Ha egy bit sincs beállítva, az eredmény nem definiált
bsf A legkisebb helyiértékű beállított bit indexét adja vissza. Ha egy bit sincs beállítva, az eredmény nem definiált

1. A maszk kinyerése

Az üzenet egy 16 bites egész számba van kódolva. Ebből azonban a 8 legmagasabb bit valójában nem része az üzenetnek, hanem egy maszk, amelyet a visszafejtés során kell használni.

Valósítsd meg az extract_higher_bits függvényt, amely egy 16 bites egész számot kap, és visszaadja annak 8 legmagasabb bitjét.

extract_higher_bits(0b1010010011000101)
// => 0b10100100

2. Az üzenet kinyerése

A maszk kinyerésének képessége önmagában nem elég, az üzenetet is el kell különítened.

Valósítsd meg az extract_lower_bits függvényt, amely egy 16 bites egész számot kap, és visszaadja annak 8 legalacsonyabb bitjét.

extract_lower_bits(0b1010010011000101);
// => 0b11000101

3. A redundáns bitek kinyerése

Néhány bit egyszerre van beállítva az üzenetben és a maszkban is. Ez egy nagyon fontos információ, amelyet később felhasználunk.

Valósítsd meg az extract_redundant_bits függvényt, amely egy 16 bites egész számot kap, amely egyszerre kódolja az üzenetet és egy maszkot, és egy olyan 8 bites egész számot ad vissza, amelyben csak a redundáns bitek vannak beállítva. A visszaadott számban egy bit ott legyen 1-re állítva, ahol az az üzenetben és a maszkban is 1. Minden más bitet törölni kell.

extract_redundant_bits(0b1010010011000101);
// => 0b10000100

4. Az üzenet összes bitjének beállítása

Ezután van néhány bit, amelyet a maszknak megfelelően 1-re kell állítani az üzenetben.

Valósítsd meg a set_message_bits függvényt, amely egy 16 bites egész számot kap, amely egyszerre kódolja az üzenetet és egy maszkot, és visszaadja az üzenet bitjei 1-re állításának eredményét. Az üzenet egy bitjét ott kell 1-re állítani, ahol a maszkban lévő bit 1. Minden más bitet változatlanul kell hagyni, hogy beállítva maradjanak, ha már be voltak állítva, és törölve, ha már törölve voltak.

set_message_bits(0b1010010011000101);
// => 0b11100101

5. A privát kulcs elforgatása

Van a rejtvénynek egy darabja, amely nincs benne nyíltan az üzenetben: a 16 bites 0b1011001100111100 szám. Ez a szám a közös privát kulcsod, amelyet a visszafejtéshez kell használnod.

Ehhez először el kell forgatnod a privát kulcsod bitjeit balra egy bizonyos számú pozícióval. A pozíciók száma megegyezik az üzenetben és a maszkban is beállított redundáns bitek számával.

Valósítsd meg a rotate_private_key függvényt, amely egy 16 bites egész számot kap, amely egyszerre kódolja az üzenetet és egy maszkot, és visszaadja a privát kulcsod elforgatásának eredményét. Ez az eredmény egy 16 bites egész szám.

rotate_private_key(0b1010010011000101);
// => 0b1100110011110010
Note

A NASM (The Netwide Assembler, a kurzus által használt assembler) támogatja a bináris formátumú konstansokat 0b előtaggal. Azt is támogatja, hogy egy konstansban alulvonást (_) használj elválasztóként az olvashatóság érdekében:

PRIVATE_KEY equ 0b1011_0011_0011_1100

6. A privát kulcs formázása

Ahhoz, hogy a visszafejtésben használható legyen, a privát kulcsodat formázni kell, hogy különválaszd a releváns biteket.

Egy privát kulcs teljes formázásához a következőket kell tenned:

  • Forgasd el.
  • Különítsd el az elforgatott privát kulcs legalacsonyabb 8 bites részét, ez az alapérték.
  • Különítsd el az elforgatott privát kulcs legmagasabb 8 bites részét, ez egy maszk, amelyet az alapértékre kell alkalmazni.
  • Fordítsd meg azokat a biteket az alapértékben, amelyek a maszkban is be vannak állítva.
  • Fordítsd meg az eredmény összes bitjét.

Egy megfordított bit 1, ha 0 volt, és 0, ha 1 volt.

Valósítsd meg a format_private_key függvényt, amely egy 16 bites egész számot kap, amely egyszerre kódolja az üzenetet és egy maszkot, és visszaad egy teljesen formázott 8 bites privát kulcsot.

format_private_key(0b1010010011000101);
// => 0b11000001

7. A visszafejtés befejezése

Miután megvan az üzenet az összes releváns bittel beállítva, valamint a formázott privát kulcs, ideje összeilleszteni őket, hogy megkapd a végeredményül kapott üzenetet.

A kapott üzenet egy 16 bites egész szám, amelynek:

  • A legmagasabb 8 bitjét a formázott privát kulcs tölti ki.
  • A legalacsonyabb 8 bitjét az üzenet tölti ki, miután minden releváns bitet beállítottál.

Valósítsd meg a decrypt_message függvényt, amely egy 16 bites egész számot kap, amely egyszerre kódolja az üzenetet és egy maszkot, és visszaad egy 16 bites egész számot a teljesen visszafejtett üzenettel.

Ennek a függvénynek fel kell használnia a format_private_key segítségével előállított formázott privát kulcsot, valamint az üzenetet, amelynek minden releváns bitjét a set_message_bits állította be.

decrypt_message(0b1010010011000101);
// => 0b1100000111100101
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg
x86-64 Assembly Exercism

Készen állsz elkezdeni a(z) Titkok feladatot?

Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) x86-64 Assembly nyelvet 22 fogalom130 feladat segítségével, valódi emberi mentorálással, mindez ingyen.