
A programok adat-struktúrája
----------------------------

Programszegmensek

Egy  Amigához  írt program három részre osztható:  kód, adat és BSS szegmensre.
A kód-szegmens tartalmazza az utasításokat, vagyis magát a tényleges programot.
Az  adat  szegmensbe  a  program  azon  adatai  kerülnek,  amelyeknek egy előre
definiált  értékük  kell  hogy  legyen.   Ezek  az adatok gyakran közvetlenül a
kódszegmensben  helyezkednek  el;  ilyenkor  nincs  szükség adatszegmensre.  Ez
semmiféle  problémát  nem  okoz.   Az  adat  és a kódszegmens megkülönböztetése
azonban  azzal  az  előnnyel  jár,  hogy  a  töltőprogram  a két szegmensfajtát
különböző  memóriaterületekre  helyezheti (attól függően, hogy hol, mennyi hely
van).   Ha  csak egy  összefüggő  kódszegmens létezne és már nem volna elegendő
méretű  folytonosan  szabad  terület  a  memóriában,  akkor  gondot okozhatna a
betöltése.   A  harmadik  szegmens  a  BSS  szegmens.   Ez  olyan adatterületet
definiál,  amelynek  a  kezdő  állapota,  vagyis   tartalma   lényegtelen.    A
töltőprogram  lefoglal  valahol  a memóriában egy akkora területet, amekkorát a
program mint BSS területet megjelölt (hunk_bss, ld.  később).


Programszerkezet (Hunk-ok)

Egy  program  tulajdonképpen  nem más, mint bináris adatok sorozata, melyek így
együtt  egy gépi kódú programot képeznek.  A "jó öreg 8- bitesek"-nél egy ilyen
program  elmentése  semmilyen  problémát nem okozott:  az ember egyszerűen csak
kimentette a programot a memóriából lemezre és már kész is volt.

Egy  olyan gép mint az Amiga, már egy sor olyan problémát vet fel, ami miatt ez
a módszer nem használható.  Az első probléma a memória kiosztása.  Az a memória
terület,  ahol  a program az első alkalommal futott, a következő indításkor már
lehet,  hogy  foglalt ezért a program egyszerű visszatöltése nem lehetséges.  A
program  máshová  fog  töltődni,  ami  egy  átlag gépikódú programnál (mivel az
abszolút  címekre  hivatkozik)  azt  fogja  eredményezni,  hogy  már  nem  lesz
működőképes.   Ezt  a  problémát  az  Amigánál a következőképp oldották meg:  a
lemezre  a program úgy lesz elmentve, hogy az összes abszolút hivatkozás $00000
kezdőcímet feltételez.  Ezután, ha a program mondjuk $20000-re töltődik vissza,
akkor  az  összes  hibás címet a programban helyesbíteni kell, vagyis $20000-el
megnövelni.   Avégett,  hogy  a  DOS,  ami ezt az egészet elvégzi, megtalálja a
megváltoztatandó címeket, a tényleges program egy kiegészítő táblázattal együtt
mentődik  el.   Ebben  a  táblázatban  állnak  az  offsetek (relatív eltolások,
különbségek), amelyek a mindenkori megváltoztatandó duplaszavakra mutatanak.

Ez  magyarázza  azt, hogy egy egyszerű 'kiemelés' a memóriából nem elegendő egy
program  lemezre mentéséhez.  Van már tehát két részlet, amit ismerünk:  maga a
program  és  a  táblázat,  amit  relokációs  táblának neveznek.  Még mindig van
azonban  egy  sor olyan egység amiket az Amiga használ.  Egy egybefüggö, azonos
típusú (kód, adat vagy BSS) programrészt 'Hunk'-nak hívnak.  Egy vagy több Hunk
képezi a program-egységet (program-unit), és ezekből egy vagy több képezheti az
'object-file'-okat.   Végül  pedig  egy  vagy   több   object-file   alkotja  a
'load-file'-t, amely már mint futtatható program jelenik meg.

A  különbség  a  két  file  típus  között az, hogy egy object file egy, még nem
futtatható  programot  tartalmaz,  pl.   egy C-fordítóval vagy egy Assemblerrel
létrehozottat.   Ha  ilyen  file-ból  (vagy  akár  többől) futtatható programot
akarunk  készíteni,  akkor  a 'Linker'-t kell segítségül hívnunk.  Ez egy olyan
program,  ami  az object fileokat egy önálló programmá "kötözi össze" (az angol
'link'  =  összekapcsol),  és  ezután  load-fileként elmenti.  Ez a végeredmény
pedig egyszerűen a neve beírásával elindítható CLI-ből, vagy Shellből.

Az  előnye  ennek  a  "kerülőnek" az, hogy így több részprogramot, amelyek akár
egymást  is  hívhatják, különállóan lehet megírni és lefordítani.  A pl.  C-ben
írott  főprogram  egyszerűen  meghívhatja  a   más   állományokba   szétosztott
függvényeket.   A  függvények  kitelepítése  a   főprogramból   javítja   annak
áttekinthetőségét,  mivel  a  hossza  lényegesen  rövidebb  lesz, mint a teljes
programé.

A  magyarázata  annak,  hogy  az  egyes  object  fileok  miért  nem futtathatók
önmagukban,  most  már  világos  lehet.   Lehetségesek   olyan  programrészekre
hivatkozások,  amelyek nem is szerepelnek a programban!  Csak a linker lefutása
után  fogja az összes használt függvényt és alprogramot egy önálló program-file
tartalmazni.

Kezdjük  azonban  a  legkisebb  egységekkel, a hunk-okkal.  Egy része ezeknek a
program  - adat egységeknek csak object fileokban fog előfordulni, néhány pedig
csak  load  fileokban.   A  hunkok mindig egy bevezető duplaszó után kezdődnek,
aminek  az értéke a következő táblázatban zárójelek között van megadva.  Jöjjön
tehát az összes létező hunk leírása:

---------------------------------------------------------------------
hunk_unit            ($3E7)
Ezzel  a  résszel  kezdődik  egy  program-egység (unit) az object fileokban.  A
bevezető  $3E7  után  az  egység  nevének a hossza következik, majd maga a név,
aminek duplaszavas határon kell végződnie.

---------------------------------------------------------------------
hunk_name            ($3E8)
A  hunk  neve  előtt  a $3E8 bevezetés áll, utána a név hossza, majd a név, ami
duplaszavas határon kell, hogy végződjön.

---------------------------------------------------------------------
hunk_code            ($3E9)
Ez  a  rész  tartalmazza  a  programot,  ami az abszolút címek korrekciója után
futtatható.  A $3E9 jelzés után itt is először a programblokk hossza következik
(néggyel  osztva,  vagyis  a  blokk  duplaszavainak  a száma), majd a tényleges
program.

---------------------------------------------------------------------
hunk_data            ($3EA)
Itt  egy  olyan  programrész  kezdődik, ami a program azon adatait tartalmazza,
amelyeknek  egy  előre megadott értéket kell tartalmazniuk.  Ezeken az adatokon
is  végrehajtaható  cím-korrekció.  A bevezető után az adatok száma következik,
majd maguk az adatok.

---------------------------------------------------------------------
hunk_bss             ($3EB)
Ezen  rész  adatai,  bár  a  programhoz  tartoznak, nincsen semmilyen definiált
tartalmuk.   Éppen  ezért  a  $3EB  jel után csak a szükséges duplaszavak száma
következik, az adatok már nem (BSS = Block Storage Segment).

---------------------------------------------------------------------
hunk_reloc32         ($3EC)
Ez   a   blokk  tartalmazza  azokat  az  offseteket,  amelyek  a  helyesbítendő
duplaszavakra  mutatnak  a  programon  belül.   Az  offsetek az egész programra
érvényesek.  A blokk felépítése a következő:

A  ismertető $3EC után az első táblázatban lévő offsetek száma jön. A következő
duplaszó  annak a hunk-nak a sorszáma, amelyhez az offsetek tartoznak és ezután
jönnek  maguk  az offsetek.  A rákövetkező duplaszó ismét egy szám, majd megint
egy hunk-sorszám, és így tovább egészen addig, amíg egy nullához nem érünk, ami
a hunk-rész végét jelzi.

Ugyanez, kicsit áttekinthetőbb formában:

			- $3EC  (jelzi a hunk_reloc32 kezdetét)

            - Az offsetek száma
            - A hunk sorszáma (az első hunk a 0.!)
            - Az offsetek...

            - Az offsetek száma (vagy 0, és akkor vége)
            - A hunk sorszáma
            - Az offsetek...

			...

			- 0 Vége a hunk_reloc32-nek

A  módszerből következik, hogy az összes hunk, amiből a memóriába kerülő és ott
futó program felépül, lefedhető, elérhető.

---------------------------------------------------------------------
hunk_reloc16         ($3ED)
Ez  a  táblázat  pontosan  ugyanúgy épül fel, mint a hunk_reloc32, csak ezek az
offsetek  16  bites címekre vonatkoznak.  Ilyen címek a PC-relatív címzésmódnál
merülnek fel.

---------------------------------------------------------------------
hunk_reloc8          ($3EE)
Ez  a táblázat is olyan formátumú, mint a hunk_reloc32.  Az itt lévő offsetek 8
bites címeket használnak fel, amik szintén a PC-relatív címzésnél lépnek fel.

---------------------------------------------------------------------
hunk_ext             ($3EF)
Ebbe  a  blokkba  a külsö hivatkozások nevei kerülnek bele.  Ilyen hivatkozások
csak  az  object  fileoknál fordulhatnak elő.  Akkor van erre szükség, amikor a
szóban  forgó  függvények és alprogramok helye még nem ismert, és majd a linker
feladata lesz a behelyettesítés.

A bevezető után több, úgynevezett "symbol data unit" következik, majd egy nulla
jelzi a hunk végét.  A szimbólum definíciók szerkezete a következő:

	- 1 Byte: szimbólum típusa. A lehetséges értékek:

	  érték   	név				típus
	------------------------------------------------------------

		0		ext_symb	szimb. tábla hibakereséshez
		1		ext_def         korrigálandó definíció
		2		ext_abs		abszolút definíció
		3		ext_res		hivatkozás rezidens könyvtárra
      129		ext_ref32		32 bites korrekció
      130		ext_common		általános 32 bites korrekció
      131		ext_ref16		16 bites korrekció
	  132		ext_ref8		8 bites korrekció

	- 3 Byte a nevek hosszának (duplaszavakban kifejezve)

	- Szimbólumnév

	- Szimbólum érték és a további adatok

A  név  után  következő  adatoknak  háromféle  felépítése  lehet,   függően   a
szimbólumtípustól.   A _def, _abs és _res esetében a név utolsó duplaszava után
egyedül a szimbólum abszolút értéke következik, mint duplaszó.

A  három  _ref  típus  nevét  viszont  egy  olyan  duplaszó  követi,  amelyik a
rákövetkező referenciaértékek számát tartalmazza.

Ugyanez  mondható el az ext_common-ról is, csak itt a név és ez a számláló közt
még a common-blokkok nagysága fekszik.


---------------------------------------------------------------------
hunk_symbol             ($3F0)
Ebben  a  blokkban  szintén  szimbólumok  vannak  névvel  és  értékkel.  Ezek a
szimbólumok  azonban  nem  a linker számára szükségesek, hanem egy debuggernek,
amivel  a  program  hibáit kereshetjük meg.  Egy ilyen programban ezután ha egy
rutint  tesztelünk,  akkor  annak  a  címe  nem  mint  szám, hanem mint név fog
megjelenni éppúgy, mint a változóknak kijelölt memóriaterület.  A $3F0-t itt is
egy symbol data unit követi, egy nullával lezárva.

---------------------------------------------------------------------
hunk_debug              ($3F1)
Ennek   a   hunk-nak   a  tartalma  nincs  részletesen  előírva.    A   program
debuggolásához  szükséges  információkat  itt  lehet  elhelyezni.   A  blokknak
$3F1-el kell kezdődnie, majd a bennefoglalt duplaszavak száma jön.

---------------------------------------------------------------------
hunk_end                ($3F2)
Ez  az  egyetlen a hunk-ok közül, amelyik okvetlenül szükséges.  Egyedül csak a
$3F2  jelből áll, következésképp ez is az utolsó duplaszava egy programnak vagy
egy object-filenak, amikor az már lemezen van.

---------------------------------------------------------------------
hunk_header             ($3F3)
Ezzel  a  blokkal  kell  kezdődnie  egy  load-filenak.  Itt van megadva, hogy a
töltendő  program  hány hunk-ból áll és hogy ezek mekkora méretűek.  Ezen kívül
tartalmazza  a  programmal  együtt betöltendő rezidens könyvtárak neveit is.  A
felépítése a következő:

    - $3F3	(hunk_header)

	- Az első hunk nevének hossza duplaszavakban (0: vége, nincs név)
    - hunk-név

    - A második hunk nevének hossza (vagy ha 0, akkor vége)
    - hunk-név

	...

	- 0: a név-lista vége

	- legnagyobb hunk-sorszám + 1 (vagyis a hunkok száma)

	- az elsőként betöltendő hunk sorszáma (az első hunk száma a 0.!)
	- az utolsóként betöltendő hunk sorszáma
	- a hunkok hosszai (felsorolás)

	- kezdődnek a programhoz tartozó hunkok

---------------------------------------------------------------------
hunk_overlay            ($3F5)
Ez  a  hunk  akkor szükséges, ha overlay technikát használunk.  Ez azt jelenti,
hogy  egy  program  által  már  foglalt memóriaterületre egy másik program vagy
adatszegmenst  töltünk.  A táblázat a $3F5 után tartalmazza a táblázat méretét,
a rátelepülések legmagasabb szintjét (a felülírási esetek számát) és magukat az
utántöltendő adatokat.


---------------------------------------------------------------------
hunk_break              ($3F6)
Ez az önmagában álló jel egy overlay programrész végét jelzi.
---------------------------------------------------------------------
---------------------------------------------------------------------
---------------------------------------------------------------------

Ezek után pedig lássunk minderre egy példát:

  az 1.3-as WB parancsai közül a 'Why'-t (ez jó rövid) kilistázva
  (type c:why opt h) ezt kapjuk:  



   Hunk-header     név   #hunkok  első hunk sorszáma
            ^        ^        ^        ^
0000: 000003F3 00000000 00000002 00000000    ................

     utolsó h.  hossz 1  hossz 2  hunk_code
            ^        ^        ^        ^
0010: 00000001 0000004F 00000034 000003E9    .......O...4....

      hossz(.L) ($24 + $4F * 4 = $160)
            ^     ez a rész már a code_hunk első hasznos duplaszava
			|        ^
0020: 0000004F 286A0164 700C4E95 2401223C    ...O(j.dp.N.$."<
0030: 00000095 49FAFFEE 286CFFFC 2F0C2F02    ....I...(l.././.
0040: D9CCD9CC 200C6714 202C0004 E580B2B4    .... .g. ,......
0050: 08006C04 22340800 285460E4 2C010681    ..l."4..(T`.,...
          .
          .
          .
          .
0120: 70207200 4E957000 2E00221F 670E2641    p r.N.p...".g.&A
0130: 49EA0218 700F26DC 51C8FFFC 220AE481    I...p.&.Q..."...
0140: 04810000 0032286A 0078700C 4E952007    .....2(j.xp.N. .
0150: 4E754A9F 4A9F70FF 4E752001 60CA0000    NuJ.J.p.Nu .`...

      hunk_end  hunk_code  hossz ($16C + $34 * 4 = $23C) 
            ^        ^        ^
0160: 000003F2 000003E9 00000034 00000034    ...........4...4
0170: 7204D289 E4892281 76012401 47EC0058    r.....".v.$.G..X
0180: 220BE489 7018286A 01384E95 4AAA0218    "...p.(j.8N.J...
0190: 66000016 47EC0070 220BE489 7018286A    f...G..p"...p.(j
01A0: 01244E95 6000001E 47EC009C 220BE489    .$N.`...G..."...
01B0: 7018286A 01244E95 222A0218 7018286A    p.(j.$N."*..p.(j
01C0: 01A04E95 4ED64E71 15547970 65203C63    ..N.N.Nq.Type <c
01D0: 723E2074 6F206B6E 6F77202E 2E2E0000    r> to know .....
01E0: 2B546865 206C6173 7420636F 6D6D616E    +The last comman
01F0: 64206469 64206E6F 74207365 74206120    d did not set a 
0200: 72657475 726E2063 6F64650A 1C4C6173    return code..Las
0210: 7420636F 6D6D616E 64206661 696C6564    t command failed
0220: 20626563 61757365 20000000 00000000     because .......

                                 hunk_end (és egyben prg. end)
                                       ^
0230: 00000001 00000004 00000086 000003F2    ................

Látható  tehát,  hogy  a  Why  parancs mindössze két code_hunkból áll, és az is
rögtön  feltűnik,  hogy  a  második  hunk  nemcsak programot, hanem adatokat is
tartalmaz.


                                                 THK, 1991. 04. 11.
