286 assembly

Az 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:

 

Hogyan fogja a user dekódolni a file-t?

--- 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:

  1. A dekódolás mindig páros hosszú file-t csinál, esetleg 1 byte-tal hosszabbat, mint amilyen az eredeti volt.
  2. COM esetén az első 4 sorban fontos, hogy a soremelés CRLF (13,10) legyen. A UNIX-féle sima LF csak az 5. sortól támogatott.
  3. COM esetén a kódolt (futtatható) program max 77 byte-nyi paramétert fogadhat. Ha mégis többet kapna, az eredmény nincs definiálva.

Minden egyéb tekintetben tökéletesen működik. A program 1996. szeptember 10-én vette fel végleges formáját.

Revision history

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.

 

Az olvasható .COM file -- technikai leírás

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:

  1. A file három részből épül fel: első dekódoló rutin, 2. dekódoló rutin, adat.
  2. Az első dekódoló rutin dekódolja a 2. dekódoló rutint, majd elindítja.
  3. A 2. dekódoló rutin dekódoja az adatot, majd elindítja. (Az adat tulajdonképpen az eredeti program kódolt változata.)

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ó.