286 assemblyAz olvasható .COM file |
Az interpreter típusú architektúrák implementációinak struktutrális vizsgálatába bevont végtelen stackkel rendelkező bináris automatika néhány innovált szekcióját és primitív kockáját teljes adaptív teszntvek vetve alá, azt a konzekvenciát vonhatjuk le, hogy a moduláris taszkosítható szoftverelemek architektúra szintű adaptálásánál követett princípiumok implikálják a felhasználói és egyéb felületeknek már a szoft-, sőt a förmver jellemzők síkján értelmezett közvetlen, nem indirekt illeszkedését, amely egyenes következménye a mikroprocesszoros struktúrák rendszerterveiből fakadó újrahívható szubrutin csomagokkal realizált, sokszintű vektoros megvalósítással nem rendelkező, memóriába ágyazott Input/output perifériák adatátviteli műveletei során diagnosztizált pipeline-regiszterek FPLA-tipusú megvalósításainak. --Vicinális Dugóhúzó |
Mivel mindenki elment kódolni (:-)), EplPáj mesél egyet a .COM fáljok szemmel való olvashatóságáról, meg hogy hogyan csináljunk ilyen file-t.
Amióta világ a világ, csak a 32 és 127 közötti ASCII-kódú karakterek biztonságosak, pl. csak azokat lehet e-mailben elküldeni. A 127-es karaktert egyes oprendszerek nem szabványosan kezelik, ezért ezt is ki kell szedni az e-mailből. A space pedig nem látszik a sor végén, így azt, mint általános célú karaktert körülményes felhasználni. Marad 94 db a [33,126] tartományban.
Tegyük fel, hogy szeretnénk egy bináris file-t elküldeni. A file-unk attól bináris, hogy az összes karakter előfordul(hat) benne. Ahhoz viszont, hogy elküldjük, csak a [33..126] tartományt használhatjuk. Ki kell hát találnuk egy kódo- lást. Ilyenből sok van (atob-btoa, uuencode-uudecode, ...), én mégis egy sajá- tot mutatok be.
A módszerem egy wordből (w) 3 byte-ot (b1, b2, b3) csinál, így az ASCII file mérete 50%-kal nagyobb lesz, mint a binary-é. w így épül fel:
W | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Felső byte (f) | Alsó byte (a) | ||||||||||||||
Felső 4 bit (x) | Felső 6 bit (y) | Alsó 6 bit (z) |
A kódolási folyamat:
beolvas(w) továbbít(x+63) továbbít(y+63) továbbít(z+63)
A dekódolási folyamat:
beolvas(b) w=b-63 beolvas(b) w=w*64+b-63 beolvas(b) w=w*64+b-63 továbbít(w)
Fontos:Mivel wordökkel dolgozunk, csak páros hosszú kódolandó adatot fogadunk el. Ha a felhasználó páratlan hosszú file-t akar kódolni, a dekódolási folyamat utáni utolsó byte lecsípéséről neki kell gondoskodnia.
A fentiek szerint a kódolt adatsorban 63 és 126 közötti (valóban nyomtatható) karakterek lesznek. Ha mégis másfajta érkezne, azt egyszerűen figyelmen kívül hagyhatjuk. Így például a kocsivissza (13) és soremelés (10) karaktereket is. Ezzel a kiterjesztéssel lehetőség nyílik az e-mail reális kihasználására, a kódolt adatsort 78 hosszú sorokba rendezve a textviewerben esztétikus látványt nyújt. Már csak egyetlen gond adódik:
--- EplPáj/PSW: xcom1.com --- Cut here v ampXPZ,2P 0E[0E ,pP[,Eu R^!5+1+1CC+1)5GGHu#PWtl6~!ugH"!rE"!~~0B(m"!4r!!Y~!)E~"0~~Cump!!|d ~E)!~~0B(m"!pq!"G0!!oD!"B~"v Q"! PSW MsrGA Bo?FS?McB?AR?G{?ds?ZF?DBHAO?~hJO?Jl???@GAxJg??GPAFLEtqB}sLkr?AxGl?GfPKvU FG`Gd]MN@?L JBgGF~Ij|F]eJ|OG??LD@IvhLAJMb@AOK?O~M ~??hKIJMb@AOE?O~M ~??KIJB{c B{C@RgMG?JR[Jl???@K}J?AyAe?KvPFG`MkUIifK]JN{dJ[~NXOGBvCz{?Pt?uwIkIDBB?]oAfLJPW KtKKW`G?E?K??]sAFLAW{?xs?AwBLABNZBNHKvQMc`??MB}sLkrF}xJg?G??AFLKtqB}sLkr?AxGl? GnPKvpFG`Ge}MN@J~?G???AsAqkFG~M B??SNZaCAs?EzJg?G??K}JLChAFLHlqKrjMV@?KENzgG?M FS?KWHG?E?K?AuHCFAZBD@WApYD?qB@^DlDCSoAp^D@oApZFTD?gLDxQBS`BCjBCjCLBBCjBShCF FTGD?bFPVBXkAD}EtAHGFG`AHDFw`B@}A`AAHlBO`ADqDc`AD}CShAH}FwoCL}EttADoFo`?tcFwI AdDFw`B@}A`AAHlF?`ADpC[aACoE{`ADCCGaAH}D|uAHPA?`DLO?tV?gI --- Cut here ^
A --- -ok közötti sorokat vágd ki, írd bele egy .COM file-ba, indítsd el, és láss csodát... (ha Unix-ot használsz, ne feledd a 10-et 13, 10-re cserélni). Ja, hogy nem csinál semmit?! Írom, hogy hogyan lehet használni. A standard inputon várja a bemeneti file-t és a standard outputra ír. Azt, hogy pontosan mit csinál, a paraméterek döntik el:
Paraméter nélkül ASCII-kódolt file-ból csinál binárisat, azaz dekódol. Például önmagát is képes dekódolni.
1 byte hosszú paraméterrel .COM fájból ASCII-kódolt .COM file-t készít.
2 byte hosszú paraméterrel adatfile-t ASCII-kódol. Abban különbözik az előző opciótól, hogy a 144 byte-os fejlécet nem adja hozzá. A dekódoló rutin természetesen mindkét tipusú kódolást dekódolja.
A módszer hiányosságai:
Minden egyéb tekintetben tökéletesen működik. A program 1996. szeptember 10-én vette fel végleges formáját.
0.0 | NetRun ötlettől vezérelve néhány nagyon kezdetleges próbálgatás (ekkor jöttem rá, hogy MOV-ot egyáltalán nem lehet használni stb.) |
0.1 | Egy elméleti algoritmus, aminek *működnie kell*. Nem működött. (2 byteból egyet módszer: dest=-*s-s[1]; s+=2) |
0.2 | Finomított 2 byteból egyet módszer: dest=-*s-*s-s[1]; s+=2; Csak debugger alatt működött, mivel önmódosító, de nem törli az instruction fetch-t. |
0.3 | Elméleti terv az új, instr.f.-t figyelembe vevő változatról. A "2. dekódoló rutin" terve. Az egész source matekfüzetbe írva. |
1.0 | Az első működő változat, a maga 170 byte-os headerjével, és dupla 0-t berakó bugos kódjával. Az egész konvertálás batch-file-ból ment, ami 2 Pascal programot, meg az assembly-fordítót hívta meg. A "2. ekódoló rutin"-t is tartalmazta. Még (C) is volt benne. |
1.1 | Minor bugfixes, optimálás, tesztelés, debugolás. |
1.2 | Az "xcom -", akkori néven acom.com. Az első csak önmagát használó, a Pascal kódot nélkülöző mini-konverter. |
1.3 | A dupla 0-s bug kijavítva, eszeveszett, több órás optimálás, a (C) kivétele, a "SUB AL, konstans" bevezetése. Már csak 160 byte a header. Mostmár fogadhat (max 60 byte-nyi) paramétert, thanx to new tech. |
1.4 | Visszakonvertálás: "xcom ", avagy bcom.com. acom+bcom integrálás xcom-má, paraméteres meghívás, adatfile-okat is készít, intelligens formátumfelsmerő "xcom ". Első terjesztett változat. |
2.0 | Egy teljesen új módszernek köszönhetően további 12 byte-ot sikerült kioptimálni mintegy 1 óra alatt. Ehhez a program teljes egészének újraírása volt szükséges, de megérte. Az első dekódoló rutin 64 byte-ja helyett már csak 48 byte(!), ehhez a teljes 2. dekódoló rutint újra kellett kódolni egy intelligensebb, de lassú, Pascal programos módszerrel. |
2.1 | A 2. dekódoló rutin apró optimálása. Mostmár az is csak 48 byte, de mivel kódolva van (1-gt2), ezért 96. Összesen tehát 48+96=144, plusz a 2 byte CRLF az első adatsor előtt. (Mind az első, mind a második dekódoló rutin 2 sort foglal el.) |
2.2 | Egy újabb, szinte zseniálisnak mondható húzással még 22 byte-tal csökkentettem a header méretét, döntően a 2. dekódoló rutin optimálásával. A 22 byte-ból négyet a ' PSW' szövegre használva (PSW=PotterSoftware, az akkori csapatom neve) a kód mérete varázslatosan 128 byte lett. Sőt, ezzel együtt mostmár XT-kompatíbilis a kód!!! | 2.3 | És most jön, ami még nem volt: előzetes: Paraméterhossz-korlátozások teljes megszünetése, Unix alatti LF-et, sőt Amiga-féle CR-t is elfogad már az első 4 sorban, korrekten lekezeli a páratlan hosszú file-okat. Sajnos ezek olyan tulajdonságok, melyek nagyon hosszú kódot eredményeznek. A file-méret (előrejelzés szerint) duplájára fog nőni (256 byte). Emellett megmarad a 128-as Ultra Lights 2.2 is. |
Az 1.0 és 1.1 változatokat Fefe és EplPáj közösen fejlesztette az első tanítási napon. A többi EplPáj műve. Neki küldjétek a levélbombákat a eppa@hotmail.com címre. Köszönet illeti Borlandékat a debuggerükért, Eric Isaacsont és a NetRun íróit. Let the assembly be with you! The real assembly isn't out there.
Ha van egy kis érzéked hozzá, kezdd el debugolni. Semmi debug-ellenes trükk nincsen benne, egyszerű dolgod lesz. Akár át is ugorhatod ezt a fejezetet. Ha jó kódernek gondolod magad, írj egy rövidebbet. Nem fog menni...
Abból indultam ki, hogy a következő utasítások működnek ASCII-ben is:
push regw pop regw inc regw dec regw sub [reg+konstans],reg sub reg,[reg+konstans] xor [reg+konstans],reg xor reg,[reg+konstans] push byte konstans
Ezekből csináltam egy olyan ciklust, amely úgy csinál 2 byte-ból egyet, hogy nullából kivonja az elsőt kétszer, majd ebből a másodikat egyszer. C-ben ez így nézne ki:
char count=64, *source=0x140, *dest=0x80; while (count--) { *dest=2**source; source++; *dest+=*source; *dest=-*dest; source++; dest++; }
Be lehet bizonyítani, hogy minden byte-hoz létezik olyan (b1, b2) számpár, ahol 33lt=b1,b2lt=126 és a fenti dekódolás (b1, b2)-ből az adott byte-ot adja. Persze a jnz-nél, és a dekódolt rutinra történő vezérlésátadásnál kellett egy kicsit cselezni, de az 1.0-ban már ez is működött. A 2.0-ban ez annyiban változott meg, hogy int *source, *dest, azaz wordönként mozgat.
Ez a dekódolás nagyon pocsékló, ezért csak rövid file-okon érdemes használni. Ezért bevezettük a kétlépcsős dekódolást:
Ez a mechanizmus azért így működik, mert ezt használva a 2. dekódoló rutin már akármilyen assembly-utasítást tartalmazhat (0..255), akármilyen bonyolult lehet, sőt, a bonyolult (2-gt3) kódolást is vissza tudja fejteni, korrektül ke- zelheti a CRLF-et, stb. A C-s példa az első dekódoló rutint mutatja. Látszik benne, hogy a paraméterterületre dolgozik, ezért nem fogadhatunk paramétert.
A második dekódoló rutin a fejezet elején leírt módszerrel 3 byteból kettőt csinál, a tűréshatáron kívüli (pl. CR, LF) byte-okkal nem törődve. Ez a rutin a fejlesztés során nem sokat változott. Továbbiakban az elsőre koncentrálunk.
Jöjjön most az első dekódoló rutin kikommentezett A86 (assembly) source-a.
--- EplPáj/PSW: tt.com --- Cut here v ; ;dekod1.8, the Universal ASCII message V2.2 ;(C) September 1996 by FZ/S/PSW,EP/PSW, Hungary ; ;CS=DS=ES=SS; SP=0FFFEh; A verem tetején egy 0 van elpusholva; ;(A dokumentálás során jöttem rá, hogy ki lehetne használni, hogy az első pop ;AX után SP=0. Ekkor 2 byte-ot nyernénk. Pusztán azért nem teszem ezt, mert ;akkor nem lennénk XT-kompatibilisek, másrészt az SP=0FFFEh csak akkor garan- ;tált, ha van elég szabad memória) ;Memóriatérkép: ;[DS:0000h]..[DS:007Fh] DOS-féle PSP, mindenféle jó kis infóval, amit mi most ; nem használunk ki. ;[DS:0080h]..[DS:00BFh] A paraméterterület (DTA) első 64 byte-ja. Ezt nem fog- ; juk felülírni. ;[DS:00C0h]..[DS:00FFh] A paraméterterület második 64 byte-ja. Ide fogjuk de- ; kódolni a 2. dekódoló rutint. ;[DS:0100h]..[DS:012Dh] Az első dekódoló rutin (ez a file lefordítva) ;[DS:012Eh]..[DS:017Bh] A 2. dekódoló rutin kódolt formában (ezt fogjuk mi dekódolni) ;[DS:017Ch]..[DS:017Fh] db ' PSW' ;[DS:0180h].. ADAT. Nincs semmi dolgunk vele. start: db 026h ;ES: Ez egy 'amp' jel, ami az xcom-nak jelzi, ;hogy a 128 byte-os önkicsomagoló rész követ- ;kezik. Különben nem csinál semmit. pop ax ;A verem tetejére a DOS egy nullát helyezett. push ax pop dx ;DX:=0 sub al, 032h ;AX:=0CEh push ax pop di ;DI:=0CEh (ld memtérképen (DI+2)-t) xor [di+059h+2], al ;Az első dummy utasítás dekódolása xor [di+05Dh+2], al ;A 2. dummy utasítás dekódolása sub al, 70h push ax pop bx ;BX:=05Eh sub al, 047h-2 ;AX:=019h (AX-1 word a 2. dek. rutin hossza) db 075h, 00Dh, 00Ah ;jmp l2, újsor kezdése, és az utasításcache ;kinullázása a dummy utasítások miatt. A fő- ;ciklus közepébe ugrunk, de a regiszterek úgy ;lettek beállítva, hogy minden OK. l1: push dx ;==gtFőciklus pop si ;SI:=0 and [di], si ;DI+BX mutat a sourcera, DI a destinationra. ;x=0; sub si, [di+bx] ;x-=*source; sub si, [di+bx] ;x-=*source; inc bx inc bx ;source++; sub si, [di+bx] ;x-=*source; l2: sub [di], si ;*dest=-x; inc di ;source++; inc di ;dest++; dec ax ;count--; db 075h, 0EDh xor 0CEh ;jnz l1 (első dummy utasítás, kódolva) ;===gtFőciklus vége push ax ;Az elején kivett 0-t visszapusholjuk push di ;DI=100h Ez a 2. dek. r.nak kell a kilépéshez db 074h, 0A2h xor 0CEh ;jz 0D0h (2. dummy utasítás, kódolva) ;A 2. dekódoló rutinra ugrunk. --- Cut here ^
Hogy teljes legyen az öröm, leközlöm a 2. dekódoló rutin dekódolt változatát, vagyis azt a változatot, ami [DS:0D0h]-en kezdődik, és amire az első dekódoló rutin utolsó utasítása ugrik.
--- EplPáj/PSW: tt.com --- Cut here v ; ;dekod2.8, the Universal ASCII message V2.2 ;(C) September 1996 by FZ/S/PSW,EP/PSW, Hungary ; ;Emlékezzünk a következőkre: BX= 08Eh, DI= 100h, AX=0 és egy 100h be van push- ;olva. Ez utóbbit majd csak a végén használjuk ki. Figyeljük meg továbbá, hogy ;AH az egész rutin alatt 0 marad. lea si, [di+bx-16] ;SI:=17Eh (CRLF, majd kódolt szöveg) mov cl, 6 ;XT-kompatibilítás l2: lodsb ;Get x sub al, 63 ;Check jc l2 ;Not valid? Get next. mov w[di], ax ;w=(x-63); shl w[di], cl ;w*=64; l3: lodsb ;Get y sub al, 63 ;Check jc l3 ;Not valid? Get next. add w[di], ax ;w+=(y-63); shl w[di], cl ;w*=64; l4: lodsb ;Get z sub al, 63 ;Check jc l4 ;Not valid? Get next. add w[di], ax ;w+=(z-63); scasw ;Store w cmp di, 42666 ;Worked enough? jc l2 ; Nö compute next w. ret ; Yes: start prg at [100h] --- Cut here ^
Úgy érzem, hogy mostmár nincs mit magyaráznom. Mindenesetre kitűzök egy ver- senyt (díj nélkülit, persze): Ugyanezt a programot kell megírni 122 byte-nál rövidebbre. Az enyém valójában 122 byte-os, az utolsó 6 byte csupán dekoratív okokból került bele, kihagyható.
Ez a lap pts oldalai közül való.