
|
Werken in REL mode Genic Clubguide, 00-00-00
REL:
W E R K E N I N D E R E L M O D E
==========================================
Nvdr. De schrijver van dit artikel is ons onbekend, maar
omdat er over deze materie niet veel gepubliseerd is,
zijn we toch maar tot publicatie over gegaan. Wij
hopen dat de auteur hier geen bezwaren tegen heeft.
Als we een machinetaal programma maken met een compiler, dan
is het een goed gebruik om deze meteen naar een .COM of .BIN
file te compileren. Het nadeel op een MSX tekstverwerker is
echter dat er, zeker onder de CP/M editors, maar 20 a 30 kB
tekst kunnen verwerker in een keer (Nvdr. in TED kan bijna
al het aanwezige geheugen worden gebruikt, zelfs het VRAM!)
Hier is echter al lang wat op gevonden: INCLUDE files. Dit
zijn files, die tijdens het compileren door de compiler
erbij geladen kunnen worden. In de source moet dan even de
regel INCLUDE naam.ext worden opgegeven en alles loopt weer
soepel. De .ext is overigens optioneel, maar is wel handig
te vermelden, want de GEN80 compiler verwacht de extensie
.GEN en de M80 compiler verwacht de .MAC extensie achter de
namen van de sourcefiles.
Het editten van tekst is nu wel eenvoudiger geworden, omdat
we met kleine blokken tekst kunnen werken, maar het
compileren duurt nog steeds lang. Een programmatekst van een
kilobyteje of 100 duurt toch al gauw 5 minuten. Dit kunnen
wij ons als top-programmeurs en snel-werkers niet
veroorloven. De meest gebruikte oplossing is dan meestal, om
meteen maar naar een ramdisk te grijpen.
Dat is natuurlijk niet DE oplossing, het zou makkelijker
zijn als we de source in kleine stukken zouden kunnen
compileren, om ze daarna in een keer bij elkaar te stoppen.
Dit is mogelijk met de rel-mode, die de gen80 en m80
compiler ondersteunen. We moeten dan echter aan het eind
alle kleine, apart gecompileerde, files weer aan elkaar
kopppelen, dit doen we met l80. Het linken duurt maar een
paar seconden. De meeste tijd gaat meestal zitten in het
inladen en wegschrijven van de bestanden. Het linken duurt
echt niet langer als een paar seconden. Het laden van de
bestanden duurt trouwens ook niet zo lang, zo zijn op een
bepaalde manier gecomprimeerd, waardoor ze heel erg kort
blijven, terwijl de source-files veel langer zijn en veel
meer tijd kosten om te compileren, omdat alles twee keer
moet worden ingeladen.
Nu zou je denken dat er zich een probleem voordoet. Als alle
programma's vanaf hetzelfde adres gecompileerd zijn, dan kan
je ze natuurlijk nooit op een ander adres gebruiken, dus kan
je ze ook niet koppelen.
Om dit toch te kunnen doen, zijn de, in rel-mode,
gecompileerde programma's niet als opcode stroom opgeslagen,
maar zijn ze op een speciale manier, nog compact ook,
opgeslagen. Een aantal tellers binnen die file geven precies
aan welk adres welke waarde moet krijgen, ten opzichte van
het begin van de file.
Daarom heet het nu ook rel-mode. REL staat voor relocatable,
oftewel verplaatsbaar. Het programma kan door die speciale
interne tellers op iedere adres in het geheugen worden
geplaatst, de tellers zorgen er bij het linken voor dat
alles op de juiste plaats komt.
Er zijn meerdere soorten tellers. De belangrijkste is zeker
de cseg-teller, cseg staat voor code-segment. Deze teller
houd bij waar de source moet komen te staan. Een andere
teller, de dseg (data-segment) teller houd bij maar de data
moet komen. De data wordt bij het linken altijd VOOR de code
geplaatst. Dit wil niet zeggen dat alle variabelen voor de
code zelf komt, want de variabelen kunnen we ook gewoon als
code compileren. We geven zelf met de CSEG en DSEG opcodes
aan, welk deel van de source we in CSEG en welk deel in DSEG
willen compileren.
In praktijk komt het er op neer dat er alleen in CSEG mode
gewerkt zal worden, welke overigens staandaard ingesteld
staat. In de file van de linker wordt dan aangegeven dat de
code-segment-counter op dat punt op 0000 staat. De rest van
de source wordt dan relatief aan dat adres gecompileerd.
Allerlei pointers geven aan welke adressen welke waarden
moeten krijgen. Om hier wat meer inzicht in te krijgen, zal
ik eerst het volgende even uiteen zetten:
PUBLIC EN EXTERNAL DEFINITIES
Als we in rel-mode werken en we willen dan we routines en
variabelen uit andere files kunnen gebruiken, dan moeten we
voor de compiler aangeven, dat hij deze niet in deze files
hoeft te zoeken, waar dat die buiten dit blok code om
gemaakt zullen worden. De linker controleert er natuurlijk
op of dit ook zo is, anders komt deze met een melding
aanzetten, dan een van de gevraagde routines of variabelen
niet te vinden is. De linker weet het verschil overigens
tussen een routine of variabele niet, het is hem allemaal
eender.
Het zal inmiddels wel duidelijk zijn hoop ik, dat alle
blokken code in rel-mode gecompileerd moeten zijn.
Als we een routine, die in dit blok code zit, door andere
routines willen laten gebruiken, dan declareren we deze als
PUBLIC. Willen we een routine gebruiken, die in een ander
blok zit, dan declareren we deze als EXTERNAL, meestal
afgekort tot EXTRN (gen80) of EXT (m80).
Het is overzichtelijk om alle public en external definities
aan het begin van het programma te zetten, maar ze mogen
natuurlijk ook overal en nergens in het programma voorkomen,
maar de kans op fouten is dan groter. Een public declaratie
kan bij gen80 ook door twee keer een dubbele punt achter het
label te zetten.
FUNCTIES
Het gebruik maken van de rel-mode betekent niet alleen dat
je in kleine stukken kan compileren, maar je kan er ook kant
en klare modules mee maken. Een muismodule bijvoorbeeld. Je
geeft in je documentatie die je erbij levert dan even aan
welke routines je hoe en wanneer moet aanroepen, an hij kan
zo in de commandline van de linker wordt geplaatst.
HET COMPILEREN
Hoe m80 precies werkt, is in de manual ervan te lezen, deze
gebruik ik zelf zoveel, daarom zal ik de voorbeelden,
compatible voor gen80 maken.
Om de gen80 compiler te laten weten dat we in rel-mode
willen werken, moeten we een option switch meegeven. Dit is
de R+ switch. Deze kan achter een punt-komma achter de naam
worden opgegeven, maar kan ook als first-line-command in de
source worden opgegeven. Verder is er die lastige .err file
die gen80 aanmaakt en alleen door ed80 gelezen kan worden,
deze kunnen we uitzetten met de Q switch. Een Q- en de hele
.err file is weg.
HET LINKEN
Het linken doe ik wel met het macro-80 pakket, met l80 om
precies te zijn. Hierbij moeten ook een aantal switches
worden opgegeven in de command line. In de voorbeelden in
precies te zien waar welke moeten staan. De switches zijn:
/N - Name: Dit is de naam waaronder de .com file moet worden
opgegeven. Deze naam moet apart van de rest van de filenames
worden opgegeven. Er mag GEEN extensie worden opgegeven, de
linker slaat simpelweg vast als het wel wordt opgegeven.
/E - Exit: Dit is het commando voor de linker, als hij klaar
is met linken. De gelinkte file wordt dan weggeschreven en
de linker worden verlaten, anders wordt de command-mode
actief en moet deze met de hand worden verlaten.
/P - Program addres: Hierop wordt begonnen met het linken.
Standaard staat deze op adres 0103h (voor comfiles dus). De
eerste drie bytes staan op 00 om daar later (handmatig) een
jump neer te zetten, om het dseg blok heen. Gebruiken we
deze niet, dan is het handig om de /P:100 op te geven.
ENKELE VOORBEELDEN
GEN80 MIJNFILE ;R+, Q- ev:MIJNFILE.GEN
GEN80 BINNAAM.BIN=MIJNFILE ;Q-
Of: Eerste regel van de source:
*B 4, Q-, R+
* is een aanduiding voor de first-line-commands. B 4,
betekent dat we maar 4Kb symbole table willen gebruiken
(ruim genoeg!) Q- zet de .err file uit en R+ zet de rel-mode
aan.
De switches achter de ; hoeven dan niet meer te worden
meegegeven, dus:
GEN80 MIJNFILE
Linken:
L80 SAVENAME/N,MIJNFILE/E/P:100,FILE2,FILE3,FILE4
Dit linkt de files mijnfile, file2, file3 en file4 aan
elkaar vanaf adres 100h en schrijft het daarna weg onder de
naam savename.com
Een voorbeeld programma, twee aparte files worden gelinkt:
PROG1:
*B 4, Q-, R+
;
; PROG1
;
CSEG
;
EXTRN PRINT
;
PROG1 LD DE,TEKST
CALL PRINT
RET
;
TEKST DEFM "Hallo !!$"
;
PROG2:
*B 4, Q-, R+
;
; PROG2
;
CSEG
;
PUBLIC PRINT
;
PRINT PUSH BC
LD C,9
CALL BDOS
POP BC
RET
;
Compileren:
GEN80 PROG1
GEN80 PROG2
Linken:
L80 PROG/N,PROG1/E/P:100,PROG2
Opstarten:
PROG
Let op: Het vertalen van programma's die met het
include-files principe gemaakt zijn, naar programma's die
met rel-mode gecompileerd en gelinkt worden, is heel veel
werk. Ik heb er laatst nog eens een hele avond aan besteed,
want je mist binnen de korste keer een aantal routines en
variabelen. Het is eenvoudiger om te beginnen met een
programma en dan meteen in rel-mode te gaan werken, als
achteraf alles te moeten vertalen.
Het is natuurlijk nog steeds mogelijk om include-files te
blijven gebruiken. Het gebruik maken van de rel-mode wil
niet zeggen dat de include-files niet meer ondersteund
worden.
Nog enkele wenken:
De labels lengte van de linker is 6 tekens! Houd dat goed in
je achterhoofd, want voor je het weet heb je labels gemaakt
als prtext1 en prtext2. De linker komt dan meteen met een
%mutiple label definition: prtext% aanzetten.
Het gaat heel eenvoudig als je met een batch-file
compileert. MSX-DOS vergeet namelijk alle tekst die achter
een [ of ] wordt opgegeven. Dus door met de tekst editor
even een [ voor een van de regels in de batch te zetten,
wordt een van de files niet meer gecompileerd. Mijn batch
van ymodem20 ziet er zo uit:
TURBO
PAUSE (wil ik wel gaan compileren?)
[GEN80 YMODEM (de volgende worden niet gecompileerd,
[GEN80 WINDOWS ze moeten nog een keer worden compileerd)
[GEN80 CRTIO
[GEN80 DSKIO
[GEN80 MENU
[GEN80 ROMUSE
[GEN80 UTILS
[GEN80 BELLEN
GEN80 TERMINAL (hier ben ik nu mee bezig)
GEN80 ANSICONV (hier ook)
PAUSE (ivm met afbreken na foutmeldingen)
L80 YMODEM/N,YMODEM/E/P:100,WINDOWS,ROMUSE,CRTIO,DSKIO,MENU
,UTILS,BELLEN,TERMINAL,ANSICONV
PAUSE
YMODEM
Auteur onbekend
|