Egy fájlformátum állapotmezőjében néhány bit jelölheti az érvényességet, mások a feldolgozási módot. A feladat gyakran nem a teljes érték lecserélése, hanem kijelölt bitek kiolvasása, beállítása vagy törlése, miközben minden más bit változatlan marad. Ugyanez jelenik meg jogosultságjelzők, tömörített adatok és protokollmezők kezelésénél.
A bitmaszk (bit mask) olyan bitminta, amely megadja, hogy egy bitenkénti művelet mely pozíciókat érintse. A maszk jelentése a művelettől függ: az egyik művelet megtartja, a másik beállítja, a harmadik törli a maszkkal kijelölt biteket.
Ebben az alfejezetben minden utasítás és regiszternév az A64
ISA, AArch64, ARMv8-A alapprofil része. Az assemblyblokkok GNU
as AArch64-szintaxist használnak; a direktívák
assemblerutasítások, nem processzorutasítások. A labor little-endian
Linux-program, célja qemu-aarch64.
Az előfeltétel a feltételkódok és feltételes kiválasztás ismerete. A példák előjel nélküli, 32 bites bitmintákkal dolgoznak. A bitenkénti műveletek maguk nem értelmeznek előjelet: ugyanazokon a biteken ugyanazt végzik.
Legyen az adat x, a maszk m, mindkettő
uint32_t érték. Az A64 ISA regiszteres alakjai:
| Szándék | C-kifejezés | A64 ISA-művelet | Az eredmény jelentése |
|---|---|---|---|
| Elkülönítés | x & m |
AND Wd, Wn, Wm |
Csak a maszk 1-es helyein maradhat 1 |
| Beállítás | x \| m |
ORR Wd, Wn, Wm |
A maszk 1-es helyein biztosan 1 lesz |
| Átváltás | x ^ m |
EOR Wd, Wn, Wm |
A maszk 1-es helyein megfordul a bit |
| Törlés | x & ~m |
BIC Wd, Wn, Wm |
A maszk 1-es helyein biztosan 0 lesz |
A táblázatban az A64 Wd a cél, Wn az
adatforrás, Wm a maszkforrás. A cél megegyezhet valamelyik
forrással: az utasítás az eredeti forrásértékekből számítja ki az
eredményt.
Egyetlen bitre az igazságtábla:
| Adatbit | Maszkbit | AND | OR | XOR | AND NOT |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 | 0 |
| 1 | 0 | 0 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 | 0 |
Az A64 ISA itt használt AND, ORR,
EOR és BIC alakjai nem módosítják az
NZCV állapotjelzőket. Egy utánuk következő feltételes döntés
ezért nem automatikusan a maszkolás eredményére vonatkozik. A labor
külön összehasonlítással ellenőrzi az eredményeket.
Az A64 AND kétféleképpen is megfogalmazhat egy
feladatot:
Például az előjel nélküli 0x000000AC érték alsó négy
bitjének elkülönítése:
A 0-tól számozott 3. bit törlése ugyanezen a 32 bites értéken:
Az A64 BIC ugyanezt a törlést a
törlendő biteket kijelölő 0x00000008
maszkkal fejezi ki. A komplementálás a műveleti szélességen belül
történik: 32 bites műveletben a maszk 32 bitje fordul meg.
Az A64 ORR beállító művelete idempotens: ugyanazt a
maszkot ismét alkalmazva az eredmény nem változik tovább. Az A64
EOR ezzel szemben átváltást (toggle)
végez: ugyanazzal a maszkkal kétszer alkalmazva visszaadja az eredeti
értéket.
Ez mérnöki szempontból lényeges különbség. Az „érvényes bit legyen 1” feladatra beállítás kell, nem átváltás. Az utóbbi egy már érvényes értéket érvénytelenné tenne.
Az A64 utasítások 32 bitesek. Az opcode, a regiszterazonosítók és más vezérlőmezők mellett nem fér el bennük tetszőleges 32 vagy 64 bites konstans.
A közvetlen operandus (immediate operand) ezért nem
feltétlenül a teljes számot tárolja. Az A64 logikai immediate egy
szabályos bitminta tömör leírása. Kódolása az N,
immr és imms mezőket használja, rendre 1, 6 és
6 biten; nem minden mezőkombináció érvényes.
A megengedett minták előállításának gondolatmenete:
A64 32 bites műveletben legfeljebb 32 bites elem választható, és az
N mező 0. A64 64 bites műveletben a 64 bites elem is
használható.
Az elforgatás miatt az 1-es sorozat „átérhet” az elem végéről az elejére. A teljesen nulla és a teljesen egyes maszk viszont nem kódolható logikai immediate-ként.
| Előjel nélküli, 32 bites maszk | Kódolható? | Indok |
|---|---|---|
0x0000000F |
Igen | 32 bites elemben négy összefüggő 1 |
0xFFFFFFF7 |
Igen | Körkörösen nézve 31 összefüggő 1 |
0x00FF00FF |
Igen | A 0x00FF 16 bites elem ismétlődik |
0x55555555 |
Igen | A 0b01 2 bites elem ismétlődik |
0x80000001 |
Igen | Két szomszédos 1 az elemhatáron át |
0x00000005 |
Nem | Két különálló 1, megfelelő ismétlődés nélkül |
0x00000000 |
Nem | Nincs 1-es sorozat |
0xFFFFFFFF |
Nem | Nincs 0 az elemben |
A korlát tehát nem a szám nagyságáról szól: az 5 nem használható
ilyen immediate-ként, miközben a sokkal nagyobb 0x55555555
igen.
A szélesség is számít. A 0x00FF00FF 32 bites maszk
kódolható, de a 0x0000000000FF00FF 64 bites maszk nem: a 16
bites elem nem ismétlődik végig, és a teljes 64 bites mintában sincs
egyetlen összefüggő 1-es sorozat.
Az A64 AND, ORR és EOR
rendelkezik ilyen immediate-alakkal. Önálló BIC
immediate-utasításkódolás nincs: konstans bitek törléséhez használható a
komplementer maszkkal végzett AND, vagy a maszk regiszterbe
töltése és a regiszteres BIC. Az esetleges
assembler-rövidítéseket nem szabad külön ISA-kódolással
összetéveszteni.
Munkakönyvtár: ~/arm-labor/a64/a032/ —
az alfejezet minden laborfájlja ide kerül, és minden parancs innen
futtatandó (a könyvtárrendet a Labor-alapkörnyezet alfejezet írja le).
mkdir -p ~/arm-labor/a64/a032
cd ~/arm-labor/a64/a032A következő teljes program külön célregiszterekbe számolja az eredményeket, majd összehasonlítja őket a várt értékekkel. Nem ír ki szöveget: siker esetén 0, eltéréskor 1 a kilépési állapot.
Az A64 példában szereplő további konstanskorlátok:
MOVZ: 16 bites immediate; 32 bites alakban opcionálisan
0 vagy 16 bites balra eltolással. Itt nincs eltolás.CMP immediate: 12 bites, előjel nélküli konstans,
opcionálisan 12 bites balra eltolással. Itt minden érték közvetlenül
elfér.SVC: 16 bites immediate; az AArch64 Linux
rendszerhívási mintában itt 0.A GNU AArch64 .p2align 2 direktíva
bájtos igazítást kér.
A fájl neve legyen lab-mask.s:
// A64 ISA, ARMv8-A; GNU as AArch64; little-endian Linux.
.arch armv8-a
.text
.p2align 2
.global _start
.type _start, %function
_start:
movz w0, #0xAC
and w1, w0, #0x0F
orr w2, w0, #0x01
eor w3, w0, #0x08
movz w4, #0x08
bic w5, w0, w4
// A 0x05 nem logikai immediate: regiszteres maszk kell.
movz w6, #0x05
and w7, w0, w6
// XOR-alapú csere két különböző regiszteren.
movz w10, #0x12
movz w11, #0xA5
eor w10, w10, w11
eor w11, w10, w11
eor w10, w10, w11
lab_observe:
cmp w1, #0x0C
b.ne lab_fail
cmp w2, #0xAD
b.ne lab_fail
cmp w3, #0xA4
b.ne lab_fail
cmp w5, #0xA4
b.ne lab_fail
cmp w7, #0x04
b.ne lab_fail
cmp w10, #0xA5
b.ne lab_fail
cmp w11, #0x12
b.ne lab_fail
movz w0, #0
b lab_exit
lab_fail:
movz w0, #1
lab_exit:
movz x8, #93
svc #0
.size _start, .-_start
.section .note.GNU-stack, "", @progbitsA 0x05 előállítására használt A64 MOVZ más
konstanskódolást használ, mint a logikai utasítások: ezért fogadja el
azt, amit az AND immediate-alakja nem.
Az assemble–link–run lépéssor Ubuntu 24.04 x86_64 hoston:
# Target: qemu-user, AArch64 Linux, little-endian.
aarch64-linux-gnu-as -EL -march=armv8-a \
-o lab-mask.o lab-mask.s
aarch64-linux-gnu-ld -EL -e _start \
-o lab-mask.elf lab-mask.o
qemu-aarch64 ./lab-mask.elf
printf 'kilepesi_allapot=%d\n' "$?"
# Target: ugyanennek az AArch64 ELF-nek az elemzése, nem futtatás.
aarch64-linux-gnu-objdump -d lab-mask.elfLevezetett, nem ténylegesen futtatott kimenet:
kilepesi_allapot=0.
A lab_observe címkénél várt állapot:
| A64 regiszternézet | Várt, előjel nélküli érték | Jelentés |
|---|---|---|
W0 |
0x000000AC |
Eredeti adat |
W1 |
0x0000000C |
Alsó négy bit |
W2 |
0x000000AD |
0. bit beállítva |
W3 |
0x000000A4 |
3. bit átváltva |
W5 |
0x000000A4 |
3. bit törölve |
W7 |
0x00000004 |
A 0. és 2. bit elkülönítve |
W10 |
0x000000A5 |
Csere utáni első érték |
W11 |
0x00000012 |
Csere utáni második érték |
A64-en a Wn célregiszterbe írás nullázza a megfelelő
Xn felső 32 bitjét. Ez nem a maszk különleges tulajdonsága,
hanem a 32 bites regiszterírás általános szabálya.
Legyen két különböző A64 regiszter kezdeti bitmintája és . Az XOR tulajdonságai: , illetve .
A labor három lépése:
A csere tehát ideiglenes regiszter nélkül működik, ha a két regiszter különböző. Ha ugyanazt a regisztert adjuk meg mindkét operandusként, az első XOR lenullázza az értéket. Két különböző regiszter azonos tartalma viszont nem hiba.
Ez oktatási azonosság, nem általános optimalizálási ajánlás. A három
A64 EOR egymástól függő művelet; az ideiglenes regiszteres
megoldás rendszerint világosabb. Pusztán az utasításszámból nem
következik ciklusszám vagy gyorsulás, QEMU alatt pedig nem mérhető
megbízhatóan egy fizikai processzor ilyen késleltetése.
A hibakeresés menete: tünet → hipotézis → adatgyűjtés → egy változtatás → ellenőrzés.
| Tünet | Hipotézis | Ellenpróba |
|---|---|---|
| A fordítás elutasít egy kicsi maszkot | Nem logikai immediate-minta | Töltsd regiszterbe, és csak az operandusalakot cseréld |
| Második alkalmazásra eltűnik egy jelző | Beállítás helyett átváltás történt | Ugyanazzal a maszkkal kétszer futtasd |
| Nem a kívánt bit törlődik | A megtartó és törlő maszk összekeveredett | Írd fel a maszkot binárisan |
| A feltételes döntés hibás | Régi NZCV alapján dönt | Vizsgáld meg az utolsó jelzőfrissítő utasítást |
| Eltűnik a 64 bites érték felső fele | 32 bites célregisztert használtál | Ellenőrizd a teljes Xn nézetet |
A laborállapot megfigyeléséhez az első terminálban:
# Target: qemu-user, AArch64; GDB-kapcsolatra vár.
qemu-aarch64 -g 1234 ./lab-mask.elfA második terminálban:
# Target: a fenti qemu-user folyamat távoli hibakeresése.
gdb-multiarch -q ./lab-mask.elf \
-ex 'target remote localhost:1234' \
-ex 'break lab_observe' \
-ex 'continue' \
-ex 'info registers x0 x1 x2 x3 x4 x5 x6 x7 x10 x11 cpsr'A GDB itt a teljes A64 Xn nézeteket mutatja; a táblázat
értékei ezek alsó 32 bitjében várhatók, nulla felső résszel. A
continue debuggerparancs után a helyes program várhatóan
normálisan, 0 állapottal lép ki.
Különösen hasznos ellenpróba a kezdőérték módosítása
0xA4-re. Ekkor az átváltás eredménye 0xAC, a
törlésé továbbra is 0xA4. A két művelet csak az eredeti
adat miatt adott azonos eredményt.
(magyarázó, alapszint — cél:
megértés-ellenőrzés) Melyik művelet kell a 6. bit biztos
beállításához, biztos törléséhez és átváltásához? Miért kódolható a 32
bites 0x80000001, de nem kódolható a
0x00000005 logikai immediate-ként?
(implementációs, középszint — cél: rutinépítés)
Bővítsd a labort úgy, hogy az eredeti adat 0. és 2. bitjét beállítsa, a
7. bitjét törölje, majd a 3. bitjét átváltsa. Az eredmény legyen az A64
W13 regiszterben, alsó négy bitje pedig
W14-ben. Használj regiszteres maszkot ott, ahol szükséges,
és bővítsd az önellenőrzést.
(hibakeresési, középszint — cél: rutinépítés)
Készíts lab-mask-bad.s nevű másolatot. Cseréld az A64
and w7, w0, w6 sort and w7, w0, #0x05 alakra.
Rögzítsd az assembler kilépési állapotát és diagnosztikáját. Miért nem
futásidejű hiba ez? Javítsd egyetlen operandus visszacserélésével, majd
ellenőrizd a programot.
1. megoldás — Segítség. A 6. bit maszkja ; nézd meg az igazságtáblát, hogy a négy művelet közül melyik GARANTÁLJA az 1-et, melyik a 0-t, melyik csak megfordítja. A kódolhatósághoz: fogalmazd meg mindkét mintát mint “egy elem körkörös elforgatva, ismételve”.
1. megoldás — Teljes megoldás. A64-en a 6. bit
maszkja 0x40: beállításhoz ORR, átváltáshoz
EOR használható. Törléshez BIC alkalmazható
regiszterben tartott 0x40 maszkkal, vagy AND a
32 bites 0xFFFFFFBF immediate-maszkkal.
A 0x80000001 két 1-ese körkörösen szomszédos. A
0x00000005 1-esei nem szomszédosak, és kisebb elem
ismétlésével sem állítható elő a teljes bitminta.
2. megoldás — Segítség. Haladj lépésről lépésre a
0xAC kezdőértéktől: először a beállítás (ORR),
majd a törlés (itt a 0x05 maszk sem logikai immediate,
szükség lehet regiszteres alakra vagy a komplementer immediate-re),
végül az átváltás (EOR) — mindig az ELŐZŐ lépés eredményére
építve.
2. megoldás — Teljes megoldás. A
lab_observe címke elé beilleszthető:
// A64 ISA; kiegészítés a teljes lab-mask.s programhoz.
movz w12, #0x05
orr w13, w0, w12
and w13, w13, #0xFFFFFF7F
eor w13, w13, #0x08
and w14, w13, #0x0FA levezetett értéksor: 0xAC → 0xAD → 0x2D → 0x25. Az
alsó négy bit 0x05. A sikeres kilépést előkészítő sor elé
kerüljenek az ellenőrzések:
// A64 ISA; további ellenőrzések a meglévő lab_fail ággal.
cmp w13, #0x25
b.ne lab_fail
cmp w14, #0x05
b.ne lab_failAz eredeti assemble–link–run parancsokat újrafuttatva ismét 0 kilépési állapot várható.
3. megoldás — Segítség. A 0x05 ugyanaz
az érték, amiről a fejezet elején már megállapítottuk, hogy nem logikai
immediate — az assembler ezt mikor veszi észre: fordításkor vagy
futáskor?
3. megoldás — Teljes megoldás. A hibás változat összeszerelési kísérlete:
# Target: qemu-userhez készülő AArch64 objektum.
# Szándékos fordítási hiba; nem követi linkelés vagy futtatás.
aarch64-linux-gnu-as -EL -march=armv8-a \
-o lab-mask-bad.o lab-mask-bad.s
printf 'assembler_allapot=%d\n' "$?"Nem nulla assemblerállapot és az immediate érvénytelenségére utaló diagnosztika várható; pontos szövege verziófüggő. A hibás sorhoz nem készíthető megfelelő utasításkód, ezért ez összeszerelési, nem futásidejű hiba.
Az operandus visszacserélése után:
# Target: qemu-user, AArch64 Linux.
aarch64-linux-gnu-as -EL -march=armv8-a \
-o lab-mask-bad.o lab-mask-bad.s
aarch64-linux-gnu-ld -EL -e _start \
-o lab-mask-bad.elf lab-mask-bad.o
qemu-aarch64 ./lab-mask-bad.elf
printf 'kilepesi_allapot=%d\n' "$?"A várt kilépési állapot 0. Az adat és a maszk nem változott; csak a maszk átadásának kódolható módját állítottuk vissza.
A64-ben az AND megtartja a maszkkal kijelölt biteket, az ORR beállítja, az EOR átváltja, a BIC pedig törli őket. A helyes választást a kívánt állapotváltozás határozza meg, nem az, hogy egyetlen próbaadaton melyik ad megfelelő eredményt. A logikai immediate csak szabályos, elforgatott és szükség esetén ismételt bitmintát írhat le; egy kis szám sem feltétlenül kódolható. Ilyenkor regiszteres maszk használható. A műveleti szélességet mindig ellenőrizni kell, és az eredményvizsgálat nem támaszkodhat véletlenül megmaradt állapotjelzőkre. Az XOR-csere hasznos azonosság, de nem automatikus gyorsítás.
A linkek és a dokumentumverziók közös állapota az Olvasói útmutató forrásállapot-táblájában van; itt csak az alfejezet saját megállapításai szerepelnek.
DecodeBitMasks, regiszterszélességek. Ellenőrizve: a link
él; a fejezetszám és a kiadásbetű az Arm-oldalak közös korlátja miatt
nem ellenőrzött.Ellenőrzési hiányok, amelyek a fenti ellenőrzés után is ténylegesen fennmaradnak: a példák nem kerültek futtatásra. Az Ubuntu 24.04 helyi csomagverzióit, az assembler pontos diagnosztikáját, a GDB-kapcsolatot és a levezetett kilépési állapotokat a hallgató laborjában kell ellenőrizni. Teljesítménymérés vagy mért ciklusszám nem szerepel az alfejezetben.