This repository has been archived by the owner on Mar 1, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlibload.asm
503 lines (457 loc) · 16 KB
/
libload.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
;=========================================================================
; Copyright (C) 2015-2018 Matt Waltz
; Version 3.0
;
; This library is free software; you can redistribute it and/or
; modify it under the terms of the GNU Lesser General Public
; License as published by the Free Software Foundation; either
; version 3 of the License, or (at your option) any later version.
; See the file COPYING included with this distribution for more
; information.
;=========================================================================
; Performs dynamic relocation for shared libraries and interdependencies
; inputs: de->start of library relocation table
; hl->start of LibLoad
; output: once relocation of program and library dependencies is complete,
; jumps to start of program block after relocation block and begins execution
; note: updated size is added to the copy in ram of the program for libraries
; notes: all code is location independent; no need to relocate to absolute address.
; keeping in archive is safe.
; uses some saferam areas (see below)
;=========================================================================
; includes
include 'include/library.inc'
define VERSION_MAJOR 3
define VERSION_MINOR 0
; global equates
arclibrarylocations = pixelShadow2 ; place to store locations of archived libraries
dependencyqueuelocation = cmdPixelShadow ; queue for keeping track of which libraries still need to be resolved
eSP = pixelShadow ; save sp for errors
totallibsize = pixelShadow+3 ; total size of the library appvar (not used)
extractedsize = pixelShadow+6 ; holds extracted size of the library
arclocation = pixelShadow+9 ; pointer to place to begin extraction from the archive
ramlocation = pixelShadow+12 ; pointer to place to extract in usermem
endarclibrarylocations = pixelShadow+15 ; pointer to end of archived library locations in arclibrarylocations
enddependencyqueue = pixelShadow+18 ; pointer to end of dependency stack
nextlibptr = pixelShadow+21 ; pointer to save location of next lib place that needs to be relocated
jumptblptr = pixelShadow+24 ; pointer to start of function table for each library in the program
vectortblptr = pixelShadow+27 ; pointer to start of archived function vector table
relocationtblptr = pixelShadow+30 ; pointer to start of relocation table
endrelocationtbl = pixelShadow+33 ; pointer to end of relocation table
prgmstart = pixelShadow+36 ; pointer to start of actual program when dealing with dependencies
appvarstartptr = pixelShadow+39 ; pointer to start of library appvar in archive
libnameptr = pixelShadow+42 ; pointer to name of library to extract
; macro definitions
define lib_byte $C0 ; library signifier byte
define jp_byte $C3 ; byte for 'jp' opcode
define libmagic1 $C0 ; library magic byte 1
define libmagic2 $C1 ; library magic byte 2
define libmagic1alt $BF ; alternate library magic byte 1
define libmagic2alt $FE ; alternate library magic byte 2
define asmflag $22 ; flag storage
define prevextracted 0
define foundprgmstart 1
define keeplibinarc 2
macro relocate? name, address*
name.source? := $
name.destination? := address
org name.destination?
macro end?.relocate?
name.length? := $ - name.destination?
org name.source? + name.length?
purge end?.relocate?
end macro
end macro
; The alternate magic bytes were added to allow LibLoad to present itself as a
; library (initially just for the version check, but LibLoad could expose
; functions in the future as well). For compatibility, the LibLoad invocation
; process starts execution from the start of this header, so it needs to be
; harmless when executed. With these magic bytes, the header is decoded as:
; cp a,a
; cp a,VERSION_MAJOR*10+VERSION_MINOR
library 'LibLoad', VERSION_MAJOR*10+VERSION_MINOR, <libmagic1alt,libmagic2alt>
; We *are* the relocator, so we can't use relocations here. Set origin to 0
; (shifted by library stuff before this) and perform any relocations manually.
disable_relocations
ld iy,flags ; make sure iy is correct
push de
push hl
ld bc,69000
ld hl,pixelShadow
call _MemClear ; initialize to wipe out past runs
ld hl,arclibrarylocations
ld (endarclibrarylocations),hl
ld hl,dependencyqueuelocation
ld (enddependencyqueue),hl
pop hl ; restore the pointer to LibLoad
ld de,_libloadstart.source
add hl,de
ld de,_libloadstart.destination
ld bc,_libloadstart.length
ldir ; relocate the actual LibLoad
res foundprgmstart,(iy+asmflag)
jp _libloadstart.destination ; jump to execution block
relocate _libloadstart, plotSScreen
pop hl ; hl->start of library jump table
ld (eSP),sp ; save the stack pointer if we hit an error
ld a,(hl) ; hl->maybe $C0 -- If the program is including libs
cp a,lib_byte ; is there a library we have to extract?
jr z,_startrelocating ; if not, just run it from wherever de was pointing
jp (hl) ; return to execution if there are no libs
_startrelocating:
push hl
call _PushOP1 ; save program name
pop hl
_extractlib: ; hl->NULL terminated libray name string -> $C0,"LIBNAME",0
ld (hl),appVarObj ; change $C0 byte to mark as extracted
push hl
call _Mov9ToOP1 ; move name of library to op1
pop hl
inc hl
res prevextracted,(iy+asmflag)
ld (libnameptr),hl
_isextracted: ; check if the current library has already been extracted
ld de,arclibrarylocations ; de->place to start search, hl->name to search for
_checkextractedloop:
push hl
push de
_searchextractedtbl:
ld a,(de) ; compare characters
cp a,(hl)
jr nz,_nomatch ; do they match?
inc hl
inc de
or a,a ; means we've reached the end of the string
jr z,_match
jr _searchextractedtbl
_nomatch:
pop de
ld hl,(endarclibrarylocations)
call _CpHLDE ; have we reached the end of the table?
push af
ex de,hl
ld de,15 ; size of search entry (9=name, 3=ram ptr, 3=arc vec ptr)
add hl,de
ex de,hl ; check and see if we have reached the end of the extraction table
pop af
pop hl
jr z,_notextracted ; hasn't been extracted yet
jr _checkextractedloop
_match:
set prevextracted,(iy+asmflag) ; set the flag that this library was previously extracted, so we don't resolve absolutes
pop hl
ld de,9
add hl,de
pop de
_donesearch: ; hl->location of library in ram, hl+3->location of library vector table in archive
ld de,(hl) ; de=location of library vector table in archive
ld (vectortblptr),de
inc hl
inc hl
inc hl
ld de,(hl) ; de=location of library in ram
ld (ramlocation),de
ld hl,(libnameptr) ; restore pointer to library name
call _movetostrngend ; move to end of library name
inc hl ; bypass version byte
ld (jumptblptr),hl
jp _resloveentrypoints ; need to resolve the entry points & enqueue dependencies
_notextracted:
ld hl,(libnameptr)
ld de,(endarclibrarylocations)
call _Mov8b ; copy the string. it shouldn't be bigger than this
xor a
ld (de),a
inc de
ld (endarclibrarylocations),de ; now we are looking after the null byte
ld hl,(libnameptr)
call _movetostrngend
push hl ; save the location in the program we are on
_findbinary:
call _ChkFindSym
jr nc,_foundlibrary ; throw an error if the library doesn't exist
jp _missingerror ; jump to the lib missing handler
_foundlibrary:
call _chkinram
jr nz,_libinarc ; if the library is found in ram, archive the library and search again
call _PushOP1
call _Arc_Unarc
call _PopOP1
jr _findbinary
_libinarc:
ex de,hl
ld de,9
add hl,de
ld e,(hl)
add hl,de
inc hl ; hl->size bytes
call _LoadDEInd_s ; de=total size of library
push de
pop bc ; bc=total size of library
; ld (totallibsize),bc
ld (appvarstartptr),hl ; hl->start of appvar in archived memory
assert libmagic1 = libmagic1alt+1
ld a,(hl) ; magic byte check 1
sub a,libmagic1alt+2
add a,2
jr nc,_libmagicerrornz
inc hl
ld a,(hl) ; magic byte check 2
cp a,libmagic2
jr z,_libexists
cp a,libmagic2alt
_libmagicerrornz:
jp nz,_versionerror ; throw an error if the library doesn't match the magic numbers
_libexists:
inc hl ; hl->version byte in library
push hl ; save location of version byte
dec bc
dec bc ; for the two magic bytes
add hl,bc ; hl->end of library
ld bc,-3
add hl,bc
ld de,(hl) ; de=size of library code
ld (extractedsize),de
add hl,bc
ld de,(hl) ; de->offset to start of dependency table
ld (endrelocationtbl),hl ; hl->end of relocation table
ld hl,(appvarstartptr)
add hl,de ; hl->start of dependencies -- need to store each dependency onto the queue.
ld (arclocation),hl ; hl->start of library extraction location
pop de ; de->version byte of library
ld a,(de) ; a=version of library
pop hl ; hl->version of library in the program
cp a,(hl) ; check if library version in program is greater than library version on-calc
jp c,_versionerror ; c flag set if on-calc lib version is less than the one used in the program
_goodversion:
inc hl ; hl->start of program function jump table
inc de ; de->start of archived function vector table
ld (vectortblptr),de ; save the pointer to the archived vector table
ld (jumptblptr),hl ; save the pointer to the function jump table
ld hl,(endarclibrarylocations)
ld (hl),de
inc hl
inc hl
inc hl
ld (endarclibrarylocations),hl
ld hl,usermem ; this is where programs are extracted to
ld de,(asm_prgm_size)
add hl,de ; hl->end of program+libaries
ex de,hl ; de->location to extract to
ld (ramlocation),de ; save this pointer
res keeplibinarc,(iy+asmflag)
ld hl,(arclocation) ; hl->start of library code in archive
ld de,(extractedsize)
add hl,de ; hl->start of library relocation table
ld (relocationtblptr),hl ; store this
ld de,(endrelocationtbl)
call _CpHLDE ; check and see if they match -- if so, this library is going to remain in the archive
jr nz,_needtoextractlib
ld hl,(arclocation)
ld (ramlocation),hl ; okay, not a ram location, but it's use is still the same
set keeplibinarc,(iy+asmflag)
_needtoextractlib:
ld de,(ramlocation)
ld hl,(endarclibrarylocations)
ld (hl),de
inc hl
inc hl
inc hl
ld (endarclibrarylocations),hl
bit keeplibinarc,(iy+asmflag)
jr nz,_resloveentrypoints ; only need to resolve entry points if in the archive
ld hl,(extractedsize)
push hl
push de
push bc
call _EnoughMem ; hl=size of library
pop bc
pop de
pop hl
jp c,_errmemory ; throw a memory error -- need more ram!
call _InsertMem ; insert memory for the relocated library (de)
ld hl,(extractedsize) ; extracted size = dependency jumps + library code
ld de,(asm_prgm_size)
add hl,de
ld (asm_prgm_size),hl ; store new size of program+libraries
ld hl,(arclocation) ; hl->start of library code
ld de,(ramlocation) ; de->insertion place
ld bc,(extractedsize) ; bc=extracted library size
ldir ; copy in the library to ram
_resloveentrypoints:
ld hl,(ramlocation)
call _enqueuealldependencies ; get all the dependency pointers that reside in the ram lib
ld hl,(jumptblptr) ; hl->start of function jump table
_resloveentrypointsloop:
ld a,(hl)
cp a,jp_byte ; jp byte ($C3)
jr nz,_doneresloveentrypoints
inc hl ; bypass jp byte ($C3)
push hl
ld hl,(hl) ; offset in vector table (0,3,6, etc.)
ld bc,3
call __idivs ; originally the offset was just added because vectors were stored in three bytes, now it is just 2 to save space
add hl,hl ; (offset/3) * 2
ld de,(vectortblptr) ; hl->start of vector table
add hl,de ; hl->correct vector entry
call _loaddeind_s ; de=offest in lib for function
ld hl,(ramlocation)
add hl,de ; hl->function in ram
ex de,hl ; de->function in ram
pop hl ; restore jump offset
ld (hl),de ; de=resolved address
inc hl
inc hl
inc hl ; move to next jump
jr _resloveentrypointsloop
_doneresloveentrypoints: ; finished resolving entry points
ld (nextlibptr),hl ; hl->next library in program (if there is one)
bit prevextracted,(iy+asmflag) ; have we already resolved the absolute addresses for the library?
jr nz,_donerelocateabsolutes
bit keeplibinarc,(iy+asmflag) ; we don't need to store anything if we are here
jr nz,_donerelocateabsolutes ; really, this is just a precautionary check -- should work fine without this
_relocateabsolutes:
ld hl,(relocationtblptr) ; restore this
_relocateabsolutesloop:
ld de,(endrelocationtbl)
call _CpHLDE ; have we reached the end of the relocation table
jr z,_donerelocateabsolutes
push hl ; save pointer to relocation table current
ld a,(hl)
inc hl
ld h,(hl)
ld l,a ; hl->offset in ram library to relocate
call _SetHLUTo0
ld de,(ramlocation)
add hl,de ; hl->location in library to relocate
push hl
ld hl,(hl) ; hl=offset we are relocating
ld de,(ramlocation)
add hl,de ; hl=new address
ex de,hl ; de=new address
pop hl
ld (hl),de ; resolved absolute address
pop hl
inc hl
inc hl ; move to next relocation vector
jr _relocateabsolutesloop
_donerelocateabsolutes:
bit foundprgmstart,(iy+asmflag) ; have we found the start of the program?
jr nz,_nosetstart
ld hl,(nextlibptr)
ld a,(hl) ; hl->maybe lib_byte -- If the program is using more libraries
cp a,lib_byte
jp z,_extractlib ; extract the next library
_checkifdependencies: ; the first time we hit this, we have all the dependencies placed onto the queue that the libraries use.
bit foundprgmstart,(iy+asmflag)
jr nz,_nosetstart
ld (prgmstart),hl
set foundprgmstart,(iy+asmflag)
_nosetstart:
ld hl,(enddependencyqueue)
ld de,dependencyqueuelocation
call _CpHLDE ; make sure we are done parsing the dependency queue
; now we need to parse the libraries like they are programs. this will be fun.
jr z,_runpgrm
dec hl
dec hl
dec hl ; hl->dependency $C0,"LIBNAME",0,VERSION,JUMP_TABLE
ld (enddependencyqueue),hl ; store pointer to next dependency
ld hl,(hl) ; valid pointer to $C0 (lib_byte)
jp _extractlib ; extract current dependency if needed, or resolve entry points
_runpgrm:
call _PopOP1 ; restore program name
ld hl,(prgmstart)
jp (hl) ; passed all the checks; let's start execution! :)
_enqueuealldependencies:
bit keeplibinarc,(iy+asmflag) ; we don't need to store anything if we are here
ret nz ; really, this is just a precautionary check -- should work fine without
_enqueuealldependenciesloop:
ld a,(hl)
cp a,lib_byte ; is there a dependency?
jr nz,_checkextracteddependent
ex de,hl
ld hl,(enddependencyqueue)
ld (hl),de ; save pointer to start of this dependency -- one at a time
inc hl
inc hl
inc hl ; move to next pointer
ld (enddependencyqueue),hl ; save next pointer
ex de,hl
_skipdependencystore:
call _movetostrngend
inc hl ; move to start of dependency jump table
_movetonextjump:
ld a,(hl)
cp a,jp_byte
jr nz,_enqueuealldependenciesloop
inc hl
inc hl
inc hl
inc hl ; jp address
jr _movetonextjump
_checkextracteddependent:
cp a,appVarObj
jr z,_skipdependencystore ; keep going
ret
_movetostrngend:
ld bc,0
ld a,c
cpir
ret
_versionerror:
ld hl,_versionlibstr
jr _throwerror
_missingerror: ; can't find a dependent lib
ld hl,_missinglibstr
_throwerror: ; draw the error message onscreen
ld a,lcdBpp16
ld (mpLcdCtrl),a
ld sp,(eSP)
push hl
call _DrawStatusBar
call _ClrScrn ; clean up the screen a bit
call _HomeUp ; if we encounter an error
pop hl
set textInverse,(iy+textFlags)
ld a,2
ld (curcol),a
call _PutS
res textInverse,(iy+textFlags)
call _NewLine
call _NewLine ; make it look pretty
ld hl,_libnamestr
call _PutS
ld hl,OP1+1
call _PutS
call _NewLine
call _NewLine
ld hl,_downloadstr
call _PutS
push hl
call _NewLine
pop hl
call _PutS
_waitkeyloop:
call _GetCSC
cp a,skEnter
jr z,_exitwaitloop
cp a,skClear
jr z,_exitwaitloop
jr _waitkeyloop
_exitwaitloop:
call _ClrScrn
call _HomeUp ; stop execution of the program
jp _PopOP1 ; restore program name
_versionlibstr: ; strings for LibLoad Errors
db "ERROR: Library Version",0
_missinglibstr:
db "ERROR: Missing Library",0
_libnamestr:
db "Library Name: ",0
_downloadstr:
db "Download here: ",0
_urlstr:
db "https://tiny.cc/clibs",0
end relocate
enable_relocations