Initial revision
[ssr] / StraySrc / SDLS / DLLManager / s / dll
1 ;
2 ; dll.s
3 ;
4 ; Handling of DLL data structures
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Dynamic Linking System (SDLS)
12 ;
13 ; SDLS is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
16 ; any later version.
17 ;
18 ; SDLS is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
22 ;
23 ; You should have received a copy of the GNU General Public License
24 ; along with SDLS. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ;----- Standard header ------------------------------------------------------
28
29 GET libs:header
30 GET libs:swis
31
32 GET libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36 GET sh.wSpace
37 GET sh.dllblock
38 GET sh.linkblock
39
40 GET sh.misc
41 GET sh.app
42
43 GET sh.messages
44
45 ;----- External routines ----------------------------------------------------
46
47 AREA |DLLM$$Code|,CODE,READONLY
48
49 GBLL debug
50 debug SETL {FALSE}
51
52 ; --- dll_find ---
53 ;
54 ; On entry: R0 == name of DLL to find
55 ; R1 == minimum version number of DLL
56 ; On exit: R0 == pointer to DLL block, or error
57
58 EXPORT dll_find
59 dll_find ROUT
60
61 STMFD R13!,{R1-R4,R14} ;Preserve registers
62
63 MOV R4,R1 ;Keep hold of version number
64 MOV R1,R0 ;Keep pointer to string
65 LDR R3,dll__list ;Find the list
66
67 00dll_find CMP R3,#0 ;Is this the end of the line?
68 BEQ %40dll_find ;Yes -- give an error
69 LDR R0,[R3,#dl_name] ;Find the name string
70 MOV R2,#0 ;Caseless compare
71 BL misc_strcmp ;Compare the strings
72 LDRNE R3,[R3,#dl_next] ;If no match, move on...
73 BNE %00dll_find ;... and try again
74
75 ; --- We found a name match ---
76
77 LDR R0,[R3,#dl_version] ;Get version of DLL
78 CMP R0,R4 ;Check against version here
79 LDRLT R3,[R3,#dl_next] ;If too low, move on...
80 BLT %00dll_find ;... and try again
81
82 ; --- The name checked out -- return ---
83
84 MOV R0,R3 ;Point to DLL (give handle)
85 LDMFD R13!,{R1-R4,PC}^ ;And return to caller
86
87 ; --- It wasn't there. Return an error ---
88
89 40dll_find MOV R0,R4 ;Get version number
90 BL dll_convertVersion ;Convert it to a string
91 MOV R2,R0 ;Keep pointer to the string
92 ADRL R0,msg_errDLLNotFound ;Couldn't find DLL name
93 BL misc_error ;... create an error message
94 LDMFD R13!,{R1-R4,R14} ;... restore registers
95 ORRS PC,R14,#V_flag ;... and return an error
96
97 LTORG
98
99 ; --- dll_ensure ---
100 ;
101 ; On entry: R0 == pointer to name to load
102 ; R1 == version number of DLL
103 ; On exit: R0 == DLL handle
104
105 EXPORT dll_ensure
106 dll_ensure ROUT
107
108 STMFD R13!,{R1-R5,R9-R11,R14} ;Stash registers somewhere
109
110 ; --- Find the name, and see if it's in memory ---
111
112 MOV R10,R1 ;Save the version number
113 BL dll__createName ;Set up the name
114 CMP R0,#0 ;Was it in memory?
115 LDMNEFD R13!,{R1-R5,R9-R11,PC} ;If so, we should be happy
116 MOV R9,R2 ;Keep pointer to leafname
117
118 ; --- Find the size of the DLL and allocate memory ---
119
120 01dll_ensure MOV R0,#17 ;Read catalogue information
121 SWI XOS_File ;Read the information
122 LDMVSFD R13!,{R1-R5,R9-R11,PC} ;If it failed, return now
123 CMP R0,#1 ;Check that the file was OK
124 BNE %08dll_ensure ;If not, complain properly
125 ADD R3,R4,#dl_extra ;Size of memory to get
126 MOV R0,#6 ;Allocate memory from RMA
127 SWI XOS_Module ;Allocate it
128 LDMVSFD R13!,{R1-R5,R9-R11,PC} ;If no memory, return error
129
130 ; --- Load the DLL into the block ---
131
132 MOV R0,R2 ;Pointer to the block to use
133 MOV R11,R0 ;Keep hold of DLL handle
134 BL dll__load ;Load the DLL into the block
135 BVS %10dll_ensure ;If it failed, return error
136
137 ; --- Check the DLL's version number ---
138
139 LDR R1,[R11,#dl_version] ;Load the DLL's version
140 CMP R1,R10 ;Compare against version
141 BLT %09dll_ensure ;If too old, give an error
142
143 ; --- Link the new DLL into the list ---
144 ;
145 ; This also marks the DLL as being shared, since the shared
146 ; marker is dl_next not being -1.
147
148 LDR R2,dll__list ;Point to list head
149 STR R11,dll__list ;Store the next one
150 MOV R0,#0 ;Ready to zero bits
151 STR R0,[R11,#dl_prev] ;No previous DLL yet
152 STR R2,[R11,#dl_next] ;Fix up next link
153 CMP R2,#0 ;Is there another block?
154 STRNE R11,[R2,#dl_prev] ;If so, fix up prev link
155
156 ; --- Fix up other bits of data ---
157
158 MOV R0,#dl_tentative ;Set DLL's `tentative' bit
159 STR R0,[R11,#dl_clients] ;No clients registered yet
160
161 ; --- Start up any required DLLs ---
162
163 LDR R1,[R11,#dl_dllLimit] ;Find limit of DLL block
164 LDR R0,[R11,#dl_dllBase] ;Find base of same
165 BL app_sfromtbl ;Load any other required DLLs
166
167 ; --- Now return the DLL handle ---
168
169 MOVVC R0,R11 ;Get the DLL handle
170 LDMFD R13!,{R1-R5,R9-R11,PC} ;Return
171
172 ; --- Say that the file wasn't found ---
173
174 08dll_ensure ADRL R0,msg_errFileNotFound ;Point to error skeleton
175 BL misc_error ;Create the message
176 B %10dll_ensure ;Return to an error
177
178 ; --- Create an error about old version ---
179
180 09dll_ensure MOV R0,R10 ;Get the required version
181 BL dll_convertVersion ;Convert to a string
182 MOV R2,R0 ;Make that fillin 2
183 MOV R1,R9 ;Point to DLL name string
184 ADRL R0,msg_errDLLTooOld ;Point to error skeleton
185 BL misc_error ;Set up the error block
186
187 ; --- Free up memory and return an error ---
188
189 10dll_ensure MOV R1,R0 ;Keep hold of the error
190 MOV R0,#7 ;Free the block I allocated
191 MOV R2,R11 ;Point to the DLL block
192 SWI XOS_Module ;Do the free operation
193 MOV R0,R1 ;Put the error pointer back
194 LDMFD R13!,{R1-R5,R9-R11,R14} ;Retreive registers
195 ORRS PC,R14,#V_flag ;Return with an error
196
197 LTORG
198
199 ; --- dll_check ---
200 ;
201 ; On entry: R0 == pointer to name to load <SPACE> version number
202 ; On exit: --
203
204 ; --- The format string for the command line ---
205
206 dll__checkfmt DCB "/a/g,"
207 DCB "/a/g",0
208 ALIGN
209
210 EXPORT dll_check
211 dll_check ROUT
212
213 STMFD R13!,{R1-R5,R9-R11,R14} ;Stack cunning registers
214
215 ; --- Allocate a nice buffer ---
216
217 MOV R10,R0 ;Keep pointer to cmd string
218 MOV R0,#6 ;Allocate some memory
219 MOV R3,#256 ;The size of said memory
220 SWI XOS_Module ;Get it
221 LDMVSFD R13!,{R1-R5,R9-R11,PC} ;Return if we can't have it
222 MOV R11,R2 ;Save the pointer
223
224 ; --- Parse up the command string ---
225
226 ADR R0,dll__checkfmt ;Point to format string
227 MOV R1,R10 ;Point to command string
228 MOV R2,R11 ;Point to my nice buffer
229 MOV R3,#256 ;And do the business
230 SWI XOS_ReadArgs ;Get the OS to parse it up
231 BVS %90dll_check ;If it failed, return
232
233 ; --- Read the version number ---
234
235 LDR R5,[R11,#4] ;Get info about version strng
236 LDRB R4,[R5,#0] ;Get LSB of its length
237 LDRB R3,[R5,#1] ;Get MSB of its length
238 ORR R4,R4,R3,LSL #8 ;Turn this into a length
239
240 MOV R3,#10 ;We're multiplying a lot
241 MOV R10,#0 ;The version as we know it
242 MOV R2,#0 ;Decimal part of version
243 ADD R5,R5,#2 ;Point to the real string
244
245 CMP R4,#0 ;Is there a string there?
246 BEQ %70dll_check ;No -- that's an error
247 00dll_check LDRB R0,[R5],#1 ;Get a character
248 CMP R0,#'.' ;Is it a decimal point?
249 BEQ %01dll_check ;Yes -- next bit please
250 BL %80dll_check ;Convert it to a number
251 MLA R10,R3,R10,R0 ;Add the digit on
252 SUBS R4,R4,#1 ;Decrement length count
253 BNE %00dll_check ;Get another digit if I can
254 B %03dll_check ;Now check for the DLL...
255
256 01dll_check CMP R4,#1 ;Is the string empty now?
257 BEQ %03dll_check ;Yes -- get on with it
258 LDRB R0,[R5] ;Get the next digit
259 BL %80dll_check ;Convert it to a number
260 MUL R2,R3,R0 ;And put it nicely away
261 CMP R4,#2 ;Is there only one char?
262 BEQ %03dll_check ;Yes -- we've done it now
263 LDRB R0,[R5,#1] ;Get the remaining digit
264 BL %80dll_check ;Convert it to a number
265 ADD R2,R2,R0 ;And put it in
266 CMP R4,#3 ;Make sure that's all
267 BNE %70dll_check ;If not, complain
268
269 03dll_check MOV R3,#100 ;Now join the two together
270 MLA R10,R3,R10,R2 ;Now we have a version!
271
272 ; --- Now mangle the name to something usable ---
273
274 LDR R0,[R11,#0] ;Point to name info
275 LDRB R4,[R0,#0] ;Get LSB of name length
276 LDRB R3,[R0,#1] ;Get MSB of name length
277 ORR R4,R4,R3,LSL #8 ;Convert to a real length
278 ADD R0,R0,#2 ;Point to the actual name
279 MOV R1,#0 ;Zero-terminate it
280 STRB R1,[R0,R4] ;Store that in right place
281
282 ; --- Find out a good name to use ---
283
284 MOV R1,R10 ;Get the version number
285 BL dll__createName ;Turn this into a filename
286 CMP R0,#0 ;Was it in memory?
287 BEQ %10dll_check ;No -- continue onwards
288 MOV R0,#7 ;Free that buffer
289 MOV R2,R11 ;Point to it
290 SWI XOS_Module ;Free it for real now
291 LDMFD R13!,{R1-R5,R9-R11,PC}^ ;Return to caller
292
293 ; --- Free the OS_ReadArgs buffer now ---
294
295 10dll_check MOV R9,R2 ;Keep pointer to leafname
296 MOV R0,#7 ;Free that buffer
297 MOV R2,R11 ;Point to it
298 SWI XOS_Module ;Free it for real now
299 ADD R11,R1,#200 ;Keep a pointer to misc_buf
300
301 ; --- Open a file for the DLL ---
302
303 MOV R0,#&4F ;Open, with errors, no path
304 SWI XOS_Find ;Find the file
305 BVS %90dll_check ;If it failed, give error
306 MOV R5,R0 ;Look after the handle
307
308 ; --- Now load a bit of the file ---
309
310 MOV R2,R11 ;Point to the misc_buf
311 MOV R1,R5 ;Get the file handle
312 MOV R3,#20 ;Get the first twenty bytes
313 MOV R4,#0 ;Read from the beginning
314 MOV R0,#3 ;Read bytes from file
315 SWI XOS_GBPB ;Quick, now, do it
316
317 ; --- Close the file ---
318
319 MOV R0,#0 ;Close the file
320 MOV R1,R5 ;Get the file handle
321 SWI XOS_Find ;Close the file
322
323 ; --- Now check the fields in the block ---
324
325 LDR R0,[R11,#dl_magic-dl_extra] ;Get the magic DLL word
326 LDR R1,=dl_MAGIC ;Get the real version
327 CMP R0,R1 ;Check it's kosher
328 BNE %91dll_check ;If not, make an error
329
330 LDR R0,[R11,#dl_bversion-dl_extra] ;Get format version
331 LDR R1,=dl_VERSION ;Get the one we're on now
332 CMP R0,R1 ;Compare the versions
333 BGT %92dll_check ;If too late, complain
334
335 LDR R0,[R11,#dl_version-dl_extra] ;Get DLL version
336 CMP R0,R10 ;Cmp with caller's version
337 BLT %93dll_check ;If too late, complain
338
339 LDMFD R13!,{R1-R5,R9-R11,PC}^ ;Return, job well done
340
341 ; --- Get a digit, and convert ---
342
343 80dll_check CMP R0,#'0' ;Is it less than 0?
344 BLT %70dll_check ;Yes -- that's an error
345 CMP R0,#'9' ;Is it greater than 9?
346 BGT %70dll_check ;Yes -- that's an error
347 SUB R0,R0,#'0' ;Convert to a digit
348 MOVS PC,R14 ;Return to caller
349
350 ; --- Make an error about a mangled version ---
351
352 70dll_check ADRL R0,msg_errBadVersion ;Point to error message
353 B %90dll_check ;Free memory and return error
354
355 ; --- Tidy up after an error and return ---
356
357 90dll_check MOV R9,R0 ;Look after error pointer
358 MOV R0,#7 ;Free that buffer
359 MOV R2,R11 ;Point to it
360 SWI XOS_Module ;Free it for real now
361 MOV R0,R9 ;Point to the error
362 LDMFD R13!,{R1-R5,R9-R11,R14} ;Unstack all the registers
363 ORRS PC,R14,#V_flag ;And return the error
364
365 ; --- A file wasn't a real DLL ---
366
367 91dll_check ADRL R0,msg_errNotADLL ;Point to error
368 MOV R1,R9 ;Point to leafname
369 BL misc_error
370 LDMFD R13!,{R1-R5,R9-R11,R14} ;Unstack all the registers
371 ORRS PC,R14,#V_flag ;And return the error
372
373 ; --- A file had a silly version number ---
374
375 92dll_check ADRL R0,msg_errTooNew ;Point to error
376 MOV R1,R9 ;Point to leafname
377 BL misc_error
378 LDMFD R13!,{R1-R5,R9-R11,R14} ;Unstack all the registers
379 ORRS PC,R14,#V_flag ;And return the error
380
381 ; --- A file was too old for the caller ---
382
383 93dll_check MOV R0,R10 ;Get version number wanted
384 BL dll_convertVersion ;Convert to printable form
385 MOV R2,R0 ;That's fillin number 2
386 ADRL R0,msg_errDLLTooOld ;Point to error
387 MOV R1,R9 ;Point to leafname
388 BL misc_error
389 LDMFD R13!,{R1-R5,R9-R11,R14} ;Unstack all the registers
390 ORRS PC,R14,#V_flag ;And return the error
391
392 LTORG
393
394 ; --- dll_load ---
395 ;
396 ; On entry: R0 == DLL handle (block to load into)
397 ; R1 == filename of DLL
398 ; On exit: --
399
400 EXPORT dll_load
401 dll_load ROUT
402
403 STMFD R13!,{R1,R10,R11,R14} ;Keep link register safe
404
405 ; --- Load the DLL into the block
406
407 MOV R11,R0 ;Keep DLL pointer safe
408 BL dll__load ;Load the DLL
409 LDMVSFD R13!,{R1,R10,R11,PC} ;Return if there's an error
410
411 ; --- If it's late enough, fit it up to the application ---
412
413 LDR R10,[R11,#dl_bversion] ;Get the format version
414 CMP R10,#100 ;Is it the old version?
415
416 LDRGT R1,[R11,#dl_appStubs] ;Find the app stubs table
417 CMPGT R1,R11 ;Is this pointer sensible?
418 BLE %90dll_load ;Yes -- skip this bit
419 LDR R0,[R11,#dl_appStubNames] ;Find the names table
420 CMP R0,R0 ;Clear V flag
421 BL app_fix ;Yes -- fix up the table
422 LDMVSFD R13!,{R1,R10,R11,PC} ;Return if there's an error
423
424 ; --- Load any required shared DLLs ---
425
426 90dll_load LDR R1,[R11,#dl_dllLimit] ;Find limit of DLL block
427 LDR R0,[R11,#dl_dllBase] ;Find base of same
428 BL app_fromtable ;Load any other required DLLs
429 LDMFD R13!,{R1,R10,R11,PC} ;Return to caller
430
431 LTORG
432
433 ; --- dll_appEntry ---
434 ;
435 ; On entry: R0 == pointer to application's entry table
436 ; R1 == pointer to application's name table
437 ; R2 == pointer to entry point name
438 ; On exit: R0 == pointer to entry point (if present)
439
440 EXPORT dll_appEntry
441 dll_appEntry ROUT
442
443 STMFD R13!,{R1-R5,R14} ;Stack registers
444
445 MOV R3,R2 ;Keep pointer to entry point
446
447 ; --- Main matching loop ---
448
449 00dll_appEntry LDRB R4,[R1],#1 ;Get first byte of next name
450 CMP R4,#0 ;Is it a null byte?
451 BEQ %41dll_appEntry ;Yes -- couldn't find entry
452 CMP R4,#1 ;Is it a dummy entry?
453 BEQ %10dll_appEntry ;Yes -- don't check it then
454 01dll_appEntry LDRB R5,[R3],#1 ;Get byte from name too
455 CMP R4,R5 ;Do they match?
456 BNE %02dll_appEntry ;No -- find the next name
457 CMP R4,#0 ;Is this the end?
458 LDRNEB R4,[R1],#1 ;No -- get another name byte
459 BNE %01dll_appEntry ;And go round again
460
461 ; --- We found it ---
462
463 LDR R0,[R0,#0] ;Get the actual entry address
464 LDMFD R13!,{R1-R5,PC}^ ;Return to caller happy
465
466 ; --- Move on to next name in the table ---
467
468 02dll_appEntry CMP R4,#0 ;Is this the end of the name?
469 LDRNEB R4,[R1],#1 ;No -- get another byte
470 BNE %02dll_appEntry ;And go round again
471
472 10dll_appEntry ADD R0,R0,#4 ;Move on to next entry ptr
473 MOV R3,R2 ;Point to start of entry name
474 B %00dll_appEntry ;And try that one out
475
476 ; --- Entry point could not be found ---
477
478 41dll_appEntry MOV R1,R2 ;Point to entry point name
479 ADRL R0,msg_errAppEntry ;Point to error message
480 BL misc_error ;Create the error message
481 LDMFD R13!,{R1-R5,R14} ;Find saved registers
482 ORRS PC,R14,#V_flag ;Return the error to caller
483
484 ALIGN
485
486 ; --- dll_findEntry ---
487 ;
488 ; On entry: R0 == pointer to DLL
489 ; R1 == pointer to entry point name
490 ; On exit: R0 == pointer to entry point
491
492 EXPORT dll_findEntry
493 dll_findEntry ROUT
494
495 STMFD R13!,{R1-R7,R14} ;Stack registers
496
497 ; --- Set up for main loop ---
498
499 LDR R7,[R0,#dl_entries] ;Find number of entry points
500 LDR R3,[R0,#dl_enames] ;Point to start of name table
501 LDR R4,[R0,#dl_eveneer] ;No entry points found yet
502 TST R7,#dl_noNames ;No names?
503 BNE %42dll_findEntry ;Then deal with this
504 BICS R2,R7,#&FF000000 ;Clear entry type flags
505 BEQ %40dll_findEntry ;No entry points -- weird
506
507 ; --- Find whether this name matches ---
508
509 00dll_findEntry MOV R5,R1 ;Point to string to match
510 LDRB R14,[R3,#0] ;Load first byte from name
511 CMP R14,#1 ;Is this a dummy entry?
512 ADDEQ R3,R3,#1 ;Yes -- skip past the byte
513 BEQ %10dll_findEntry ;Yes -- don't check the name
514
515 01dll_findEntry LDRB R6,[R5],#1 ;Read byte from pattern
516 LDRB R14,[R3],#1 ;Read byte from target
517 CMP R6,R14 ;Do they match?
518 BNE %02dll_findEntry ;No -- try another string
519 CMP R6,#0 ;Is this the string end?
520 BNE %01dll_findEntry ;No -- try another char
521
522 ; --- We found the entry point ---
523
524 TST R7,#dl_shortEntries ;Are these APCS veneers?
525 MOVEQ R0,R4 ;Yes -- point to veneer base
526 LDRNE R0,[R4,#0] ;No -- return base address
527 LDMFD R13!,{R1-R7,PC}^ ;Return to caller
528
529 ; --- No luck -- try another entry point ---
530
531 02dll_findEntry CMP R14,#0 ;Is this the end of the name?
532 LDRNEB R14,[R3],#1 ;No -- get another character
533 BNE %02dll_findEntry ;And try again
534
535 10dll_findEntry SUBS R2,R2,#1 ;Decrement entry point count
536 BEQ %41dll_findEntry ;If we ran out, that's it
537
538 TST R7,#dl_shortEntries ;Are these APCS veneers?
539 ADDEQ R4,R4,#16 ;Yes -- move to next veneer
540 ADDNE R4,R4,#4 ;No -- move to next word
541 B %00dll_findEntry ;And try again
542
543 ; --- DLL has no entry points ---
544
545 40dll_findEntry LDR R1,[R0,#dl_name] ;Point to DLL name
546 ADRL R0,msg_errNoEntry ;Point to error message
547 BL misc_error ;Create the error message
548 LDMFD R13!,{R1-R7,R14} ;Find saved registers
549 ORRS PC,R14,#V_flag ;Return the error to caller
550
551 ; --- Entry point could not be found ---
552
553 41dll_findEntry MOV R2,R1 ;Point to entry point name
554 LDR R1,[R0,#dl_name] ;Point to DLL name
555 ADRL R0,msg_errDLLEntry ;Point to error message
556 BL misc_error ;Create the error message
557 LDMFD R13!,{R1-R7,R14} ;Find saved registers
558 ORRS PC,R14,#V_flag ;Return the error to caller
559
560 ; --- DLL has no named entry points ---
561
562 42dll_findEntry LDR R1,[R0,#dl_name] ;Point to DLL name
563 ADRL R0,msg_errNoNames ;Point to error message
564 BL misc_error ;Create the error message
565 LDMFD R13!,{R1-R7,R14} ;Find saved registers
566 ORRS PC,R14,#V_flag ;Return the error to caller
567
568 LTORG
569
570 ; --- dll_showInfo ---
571 ;
572 ; On entry: R0 == pointer to argument string
573 ; On exit: --
574
575 EXPORT dll_showInfo
576 dll_showInfo ROUT
577
578 STMFD R13!,{R1-R4,R14} ;Stack some registers
579
580 ; --- Parse some arguments ---
581
582 MOV R1,R0 ;Point to the command tail
583 ADR R0,dll_sinfoDef ;Point to definition string
584 ADR R2,misc__sharedBuf ;Point to scratch buffer
585 MOV R3,#256 ;Size of my buffer
586 SWI XOS_ReadArgs ;Read the command line
587 LDMVSFD R13!,{R1-R4,PC} ;Return if it didn't work
588
589 MOV R4,#0 ;Clear some flags
590 LDR R14,[R2,#0] ;Load the `full' flag
591 CMP R14,#0 ;Is it clear?
592 ORRNE R4,R4,#1 ;No -- set the flag then
593
594 LDR R0,[R2,#4] ;Load the string pointer
595 CMP R0,#0 ;Is it there?
596 ADREQL R0,synt_DLLInfo - 4 ;No -- point to syntax string
597 LDMEQFD R13!,{R1-R4,R14} ;Restore registers
598 ORREQS PC,R14,#V_flag ;And return to caller
599
600 ; --- Find the DLL ---
601
602 MOV R2,R0 ;Keep hold of the pointer
603 MOV R1,#0 ;Don't care about version
604 BL dll_find ;Find the DLL pointer
605 BVS %10dll_showInfo ;Give an error if not found
606
607 ; --- Show the info :-) ---
608
609 MOV R3,R0 ;Keep pointer to DLL block
610 ADRL R0,msg_dinfoName
611 SWI XOS_Write0
612 LDR R0,[R3,#dl_name] ;Point to the DLL's name
613 SWI XOS_Write0
614 SWI XOS_NewLine
615
616 ADRL R0,msg_dinfoAuthor
617 SWI XOS_Write0
618 LDR R0,[R3,#dl_copyright] ;Point to the DLL's author
619 SWI XOS_Write0
620 SWI XOS_NewLine
621
622 ADRL R0,msg_dinfoVersion
623 SWI XOS_Write0
624 LDR R0,[R3,#dl_version] ;Point to the DLL's version
625 BL dll_convertVersion ;Convert the version number
626 SWI XOS_Write0
627 SWI XOS_NewLine
628
629 ADRL R0,msg_dinfoReferences
630 SWI XOS_Write0
631 LDR R0,[R3,#dl_clients] ;Get client count
632 BIC R0,R0,#dl_tentative ;Clear tentative bit if any
633 SUB R13,R13,#12 ;Give some space for string
634 MOV R1,R13 ;Point to this space
635 MOV R2,#12 ;Size of the buffer
636 SWI XOS_ConvertInteger4 ;Convert it to a string
637 SWI XOS_Write0
638 ADD R13,R13,#12 ;Reclaim workspace
639 SWI XOS_NewLine
640
641 TST R4,#1 ;Do we want to print this?
642 BEQ %02dll_showInfo ;No -- don't then
643
644 ADRL R0,msg_dinfoEntries
645 SWI XOS_Write0
646
647 ; --- Write out entry point names ---
648
649 LDR R2,[R3,#dl_entries] ;Get number of entry points
650 TST R2,#dl_noNames ;No name table?
651 BNE %08dll_showInfo ;No -- tell user
652 BICS R2,R2,#&FF000000 ;Clear type bits
653 BEQ %09dll_showInfo ;No entries -- spooky
654
655 LDR R1,[R3,#dl_enames] ;Point to first entry name
656 00dll_showInfo SWI XOS_WriteI+' ' ;Indent the list a bit
657 SWI XOS_WriteI+' '
658
659 01dll_showInfo LDRB R0,[R1],#1 ;Get a name byte
660 CMP R0,#1 ;Is it a dummy entry?
661 SWIHI XOS_WriteC ;No -- write it out
662 BHS %01dll_showInfo ;And go round for the next
663
664 SWI XOS_NewLine ;Start a new line
665 SUBS R2,R2,#1 ;Done another one
666 BGT %00dll_showInfo ;If more to do, continue
667
668 ; --- Return to caller ---
669
670 02dll_showInfo LDMFD R13!,{R1-R4,PC}^ ;Return with registers nice
671
672 ; --- Entry point table suppressed ---
673
674 08dll_showInfo ADRL R0,msg_dinfoHidden ;Point to the string
675 SWI XOS_Write0 ;Display that on the screen
676 B %02dll_showInfo ;And return to caller
677
678 ; --- No entry points -- freaky ---
679
680 09dll_showInfo ADRL R0,msg_dinfoNone ;Point to the string
681 SWI XOS_Write0 ;Display that on the screen
682 B %02dll_showInfo ;Resume information
683
684 ; --- Couldn't find the DLL ---
685
686 10dll_showInfo MOV R1,R2 ;Point to DLL name
687 ADRL R0,msg_errDLLNotInMem ;Point to the error
688 BL misc_error ;Create error message fully
689 LDMFD R13!,{R1-R4,R14} ;Unstack all registers
690 ORRS PC,R14,#V_flag ;Return to caller with error
691
692 dll_sinfoDef DCB "full/s,",0
693
694 LTORG
695
696 ; --- dll_writeTitle ---
697 ;
698 ; On entry: --
699 ; On exit: --
700
701 EXPORT dll_writeTitle
702 dll_writeTitle ROUT
703
704 STMFD R13!,{R14} ;Stack link register for this
705 ADRL R0,msg_dllHeader ;Point to the header line
706 SWI XOS_Write0 ;Display it nicely
707 LDMFD R13!,{PC}^ ;Return to caller
708
709 LTORG
710
711 ; --- dll_writeInfo ---
712 ;
713 ; On entry: R0 == pointer to a DLL block
714 ; On exit: --
715
716 EXPORT dll_writeInfo
717 dll_writeInfo ROUT
718
719 STMFD R13!,{R1-R3,R14} ;Stack some registers
720 MOV R2,R0 ;Keep hold of pointer
721 MOV R1,#17 ;Length of DLL name
722 LDR R0,[R2,#dl_name] ;Point to the name
723
724 MOV R3,#0 ;Length so far
725 00 LDRB R14,[R0,R3] ;Load a byte
726 CMP R14,#0 ;At the end?
727 ADDNE R3,R3,#1 ;No -- inc length
728 BNE %b00 ;And keep on looping
729
730 CMP R3,#16 ;Is this to long?
731 BL dll_field ;Display the name
732 SWIGT OS_NewLine ;Too long -- print a newline
733 MOVGT R1,#17 ;Print 21 spaces
734 ADRGT R0,dll__nullStr ;Point to the string
735 BLGT dll_field ;And do that thing
736 LDR R0,[R2,#dl_version] ;Load the version
737 BL dll_convertVersion ;Convert it to a string
738 MOV R1,#10 ;Length of version field
739 BL dll_field ;Display it on the screen
740 LDR R0,[R2,#dl_copyright] ;Point to copyright string
741 SWI XOS_Write0 ;Display on the screen
742 SWI XOS_NewLine ;Follow with a newline
743 LDR R2,[R2,#dl_next] ;Point to next one along
744 LDMFD R13!,{R1-R3,PC}^ ;Return to caller
745
746 dll__nullStr DCB 0
747
748 LTORG
749
750 ; --- dll_list ---
751 ;
752 ; On entry: --
753 ; On exit: --
754
755 EXPORT dll_list
756 dll_list ROUT
757
758 STMFD R13!,{R1,R2,R14}
759
760 ; --- Set up for a loop through the list ---
761
762 LDR R2,dll__list ;Point to list
763 CMP R2,#0 ;Check that it's non-null
764 BEQ %01dll_list ;If so, give special message
765
766 ; --- Do a bit of screen set-up ---
767
768 BL dll_writeTitle ;Display the title line
769
770 ; --- Main loop ---
771
772 00dll_list MOV R0,R2 ;Point to DLL block
773 BL dll_writeInfo ;Display info about it
774 LDR R2,[R2,#dl_next] ;Point to next one along
775 CMP R2,#0 ;Is there another one?
776 BNE %00dll_list ;Yes -- display its stuff
777 LDMFD R13!,{R1,R2,PC}^
778
779 01dll_list ADRL R0,msg_noDLLs ;Point to the message
780 SWI XOS_Write0 ;Display that on the screen
781 LDMFD R13!,{R1,R2,PC}^
782
783 LTORG
784
785 ; --- dll_convertVersion ---
786 ;
787 ; On entry: R0 == version number
788 ; On exit: R0 == pointer to version string
789
790 EXPORT dll_convertVersion
791 dll_convertVersion ROUT
792
793 STMFD R13!,{R1-R3,R14} ;Preserve registers
794 MOV R1,#100 ;Divisor
795 BL dll__divide ;Find major and minor version
796 LDMVSFD R13!,{R1-R3,PC} ;Return if there's an error
797 MOV R3,R1 ;Keep minor version
798 ADR R1,misc__sharedBuf ;Point to buffer
799 MOV R2,#16 ;Give it a sensible size
800 SWI XOS_ConvertCardinal3 ;This is excessive, but...
801 LDMVSFD R13!,{R1-R3,PC} ;Return if there's an error
802 MOV R0,#'.' ;To be written to buffer
803 STRB R0,[R1],#1 ;Write the decimal separator
804 SUB R2,R2,#1 ;Another byte used in buffer
805 MOV R0,R3 ;Get minor version number
806 SWI XOS_ConvertCardinal1 ;Can't be more than 100
807 LDMVSFD R13!,{R1-R3,PC} ;Return if there's an error
808 LDRB R2,[R0,#1] ;Get second character
809 CMP R2,#0 ;Is there one?
810 BNE %00dll_convertVersion ;Yes -- skip ahead a bit
811 STRB R2,[R0,#2] ;Leave exactly 2 digits
812 LDRB R2,[R0,#0] ;Get first character
813 STRB R2,[R0,#1] ;Store in second position
814 MOV R2,#'0' ;And write a leading 0
815 STRB R2,[R0,#0] ;In first position
816 00dll_convertVersion
817 ADR R0,misc__sharedBuf ;Point to buffer
818 LDMFD R13!,{R1-R3,PC}^ ;Return to caller nicely
819
820 LTORG
821
822 ; --- dll_field ---
823 ;
824 ; On entry: R0 == pointer to string
825 ; R1 == length of field
826
827 EXPORT dll_field
828 dll_field ROUT
829
830 STMFD R13!,{R1,R2,R14} ;Stash registers
831 MOV R2,R0 ;Keep hold of string ptr
832 00dll_field LDRB R0,[R2],#1 ;Get a string byte
833 CMP R0,#0 ;Check the byte
834 BEQ %01dll_field ;If end, write pad chars
835 SWI XOS_WriteC ;Write the character
836 SUB R1,R1,#1 ;Decrement counter thing
837 B %00dll_field ;If allowed, get the next one
838
839 01dll_field SUBS R1,R1,#1 ;Decrement counter thing
840 LDMLEFD R13!,{R1,R2,PC}^ ;Return if done
841 02dll_field SWI XOS_WriteI+' ' ;Write a space
842 SUBS R1,R1,#1 ;Decrement counter thing
843 BGT %02dll_field ;If allowed, write another
844 LDMFD R13!,{R1,R2,PC}^ ;Return happy :-)
845
846 LTORG
847
848 ; --- dll_compare ---
849 ;
850 ; On entry: R0 == pointer to DLL
851 ; R1 == pointer to name string
852 ; R2 == required version number
853 ; On exit: R0 == 1 for a match, or 0 for no match
854
855 EXPORT dll_compare
856 dll_compare ROUT
857
858 STMFD R13!,{R1,R2,R14} ;Keep registers safe
859 LDR R14,[R0,#dl_version] ;Find the version number
860 CMP R2,R14 ;How does it shape up?
861 BGT %00dll_compare ;If too low, return 0
862 MOV R2,#0 ;Case insensitive bitty
863 LDR R0,[R0,#dl_name] ;Point to DLL's name string
864 BL misc_strcmp ;Compare the strings
865 MOVEQ R0,#1 ;If there's a match, return 1
866 LDMEQFD R13!,{R1,R2,PC}^ ;Return to caller
867 00dll_compare MOV R0,#0 ;No match here
868 LDMFD R13!,{R1,R2,PC}^ ;Return to caller
869
870 LTORG
871
872 ; --- dll_tentative ---
873 ;
874 ; On entry: R0 == pointer to DLL
875 ; On exit: --
876
877 EXPORT dll_tentative
878 dll_tentative ROUT
879
880 STMFD R13!,{R14} ;Store return address
881 LDR R14,[R0,#dl_clients] ;Find the magic counter
882 ORR R14,R14,#dl_tentative ;Set the `tentative' bit
883 STR R14,[R0,#dl_clients] ;And store back again
884 LDMFD R13!,{PC}^ ;Return to caller
885
886 LTORG
887
888 ; --- dll_confirm ---
889 ;
890 ; On entry: --
891 ; On exit: --
892
893 EXPORT dll_confirm
894 dll_confirm ROUT
895
896 STMFD R13!,{R14} ;Store return address
897 LDR R0,dll__list ;Find list base address
898 CMP R0,#0 ;Are there any entries
899 LDMEQFD R13!,{PC}^ ;Return to caller if not
900 00dll_confirm LDR R14,[R0,#dl_clients] ;Find the magic counter
901 TST R14,#dl_tentative ;Is it a tentative one?
902 BICNE R14,R14,#dl_tentative ;Yes -- clear `tentative' bit
903 ADDNE R14,R14,#1 ;Increment the counter
904 STRNE R14,[R0,#dl_clients] ;And store back again
905 LDR R0,[R0,#dl_next] ;Find next DLL in the chain
906 CMP R0,#0 ;Is this the end yet?
907 BNE %00dll_confirm ;Go round again if not
908 LDMFD R13!,{PC}^ ;Return to caller
909
910 LTORG
911
912 ; --- dll_retrace ---
913 ;
914 ; On entry: --
915 ; On exit: --
916
917 EXPORT dll_retrace
918 dll_retrace ROUT
919
920 STMFD R13!,{R1,R14} ;Keep registers safe
921 LDR R0,dll__list ;Find list base address
922 CMP R0,#0 ;Are there any more entries
923 LDMEQFD R13!,{R1,PC}^ ;Return to caller if not
924 00dll_retrace LDR R1,[R0,#dl_next] ;Find the next block along
925 LDR R14,[R0,#dl_clients] ;Load the magic counter
926 BICS R14,R14,#dl_tentative ;Clear the `tentative' bit
927 STR R14,[R0,#dl_clients] ;Store back in structure
928 BLEQ dll__free ;Free the block if no count
929 MOVS R0,R1 ;Point to next block along
930 BNE %00dll_retrace ;If any more to do, do more
931 LDMFD R13!,{R1,PC}^ ;Return to caller
932
933 LTORG
934
935 ; --- dll_freeAll ---
936 ;
937 ; On entry: --
938 ; On exit: --
939
940 EXPORT dll_freeAll
941 dll_freeAll ROUT
942
943 STMFD R13!,{R1,R2,R14} ;Preserve registers nicely
944 MOV R0,#7 ;Freeing memory now
945 LDR R2,dll__list ;Point to first entry
946 CMP R2,#0 ;Is there anything to do?
947 LDMEQFD R13!,{R1,R2,PC}^ ;No -- just leave now
948
949 00dll_freeAll LDR R1,[R2,#dl_next] ;Get next pointer in list
950 SWI XOS_Module ;Free the block
951 MOVS R2,R1 ;Point to the next entry
952 BNE %00dll_freeAll ;If any more to do, do them
953
954 STR R2,dll__list ;Store 0 back into list head
955 01dll_freeAll LDMFD R13!,{R1,R2,PC}^ ;Return to caller
956
957 LTORG
958
959 ; --- dll_dec ---
960 ;
961 ; On entry: R0 == pointer to DLL to decrement
962 ; On exit: --
963
964 EXPORT dll_dec
965 dll_dec ROUT
966
967 STMFD R13!,{R14} ;Preserve link register
968 LDR R14,[R0,#dl_next] ;Find whether it's shared
969 CMP R14,#-1 ;Just check to make sure
970 BEQ %00dll_dec ;If not, give an error
971 LDR R14,[R0,#dl_clients] ;Load the DLL count
972 SUBS R14,R14,#1 ;Chop one off the counter
973 STRNE R14,[R0,#dl_clients] ;Store the count back
974 LDMNEFD R13!,{PC}^ ;Return to caller
975 LDMFD R13!,{R14} ;Pull back return address
976 B dll__free ;Free the DLL -- no clients
977
978 00dll_dec LDR R1,[R0,#dl_name] ;Point to the DLL's name
979 ADRL R0,msg_errNotShared ;Point to error message
980 BL misc_error ;Turn into a real error
981 LDMFD R13!,{R1,R14} ;Pull back return address
982 ORRS PC,R14,#V_flag ;Return the error
983
984 LTORG
985
986 ; --- dll_instvars ---
987 ;
988 ; On entry: R0 == pointer to DLL
989 ; R1 == pointer to data
990 ; On exit: --
991
992 EXPORT dll_instvars
993 dll_instvars ROUT
994
995 STMFD R13!,{R1-R6,R14} ;Stack registers
996
997 ; --- Store pointer if needs be ---
998
999 MOV R3,R0 ;Look after this pointer
1000 LDR R2,[R3,#dl_instBase] ;Find start of data block
1001 SUB R4,R1,R2 ;Calculate relocation
1002 LDR R14,[R3,#dl_next] ;Is there a next pointer?
1003 CMP R14,#-1 ;Is the DLL shared?
1004 BNE %00dll_instvars ;Yes -- don't store reloc
1005 STR R4,[R3,#dl_wspace] ;Store in special offset
1006
1007 ; --- Copy the data across ---
1008
1009 00dll_instvars LDR R0,[R3,#dl_bversion] ;Get the format version
1010 CMP R0,#100 ;Is it too old for this?
1011 BLE %90dll_instvars ;Yes -- skip ahead then
1012
1013 LDR R5,[R3,#dl_zinitBase] ;Get zero-init base address
1014 LDR R6,[R3,#dl_zinitLimit] ;Get zero-init limit address
1015
1016 MOV R0,R1 ;Move destination pointer
1017 MOV R1,R2 ;Find start of data block
1018 CMP R5,R6 ;Is there a zinit area?
1019 MOVLT R2,R5 ;Yes -- use zinit base addr
1020 LDRGE R2,[R3,#dl_instLimit] ;No -- use data end address
1021 SUB R2,R2,R1 ;Convert pointer to length
1022 BL misc_memcpy ;Copy the data across
1023
1024 ; --- If the format supports it, do zero-initing ---
1025
1026 CMP R5,R6 ;Are these sensible?
1027 ADDLT R0,R5,R4 ;Yes -- add relocation
1028 ADDLT R1,R6,R4
1029 BLLT misc_zinit ;And zero-init the area
1030
1031 B %99dll_instvars
1032
1033 ; --- Copy the whole lot across ---
1034
1035 90dll_instvars MOV R0,R1 ;Move destination pointer
1036 MOV R1,R2 ;Find start of data block
1037 LDR R2,[R3,#dl_instLimit] ;Find end of data block
1038 SUB R2,R2,R1 ;Convert pointer to length
1039 BL misc_memcpy ;Copy the data across
1040
1041 99dll_instvars LDMFD R13!,{R1-R6,PC}^ ;Return to caller
1042
1043 LTORG
1044
1045 ; --- dll_findWorkspace ---
1046 ;
1047 ; On entry: R0 == DLL handle
1048 ; On exit: R0 == pointer to workspace for the DLL
1049 ;
1050 ; So that the caller can free it when they kill the DLL
1051
1052 EXPORT dll_findWorkspace
1053 dll_findWorkspace ROUT
1054
1055 STMFD R13!,{R14} ;Stack link register
1056 LDR R14,[R0,#dl_instBase] ;Find workspace base address
1057 LDR R0,[R0,#dl_wspace] ;Find the relocation
1058 ADD R0,R0,R14 ;Relocate the address
1059 LDMFD R13!,{PC}^ ;Return to the caller
1060
1061 LTORG
1062
1063 ; --- dll_convreloc ---
1064 ;
1065 ; On entry: R0 == pointer to DLL
1066 ; R1 == pointer to data block
1067 ; On exit: R0 == relocation offset to use
1068
1069 EXPORT dll_convreloc
1070 dll_convreloc ROUT
1071
1072 STMFD R13!,{R14} ;Keep link register
1073 LDR R14,[R0,#dl_instBase] ;Find base of static data
1074 SUB R0,R1,R14 ;Convert to a relocation
1075 LDMFD R13!,{PC}^ ;Return to caller
1076
1077 LTORG
1078
1079 ; --- dll_info ---
1080 ;
1081 ; On entry: R0 == pointer to DLL
1082 ; On exit: R0 preserved
1083 ; R1 == pointer to DLL name
1084 ; R2 == version number
1085 ; R3 == pointer to copyright string
1086 ; R4 == size of instance variables
1087
1088 EXPORT dll_info
1089 dll_info ROUT
1090
1091 LDR R3,[R0,#dl_instBase] ;Find base of variables
1092 LDR R4,[R0,#dl_instLimit] ;Find limit of variables
1093 SUB R4,R4,R3 ;Turn this into length
1094 LDR R1,[R0,#dl_name] ;Point to DLL's name
1095 LDR R2,[R0,#dl_version] ;Load version number
1096 LDR R3,[R0,#dl_copyright] ;Point to copyright string
1097 MOVS PC,R14 ;Return to caller
1098
1099 LTORG
1100
1101 ; --- dll_datasize ---
1102 ;
1103 ; On entry: R0 == pointer to DLL
1104 ; On exit: R0 == number of bytes to allocate
1105
1106 EXPORT dll_datasize
1107 dll_datasize ROUT
1108
1109 STMFD R13!,{R14} ;Keep link register
1110 LDR R14,[R0,#dl_instBase] ;Find base of area
1111 LDR R0,[R0,#dl_instLimit] ;Find end of area
1112 SUB R0,R0,R14 ;Convert to length
1113 LDMFD R13!,{PC}^ ;Return to caller
1114
1115 LTORG
1116
1117 ;----- Private routines -----------------------------------------------------
1118
1119 ; --- dll__createName ---
1120 ;
1121 ; On entry: R0 == pointer to name to load
1122 ; R1 == version number to check for
1123 ; On exit: R0 == DLL handle if found in memory, or 0
1124 ; R1 == pointer to filename of DLL to use
1125 ; R2 == pointer to leafname of DLL if not in memory
1126
1127 dll__createName ROUT
1128
1129 STMFD R13!,{R9-R11,R14} ;Stash registers somewhere
1130
1131 ; --- Start off by putting `DLL:' in the buffer ---
1132 ;
1133 ; We may not need it, but at least it's there if we do.
1134
1135 MOV R11,R0 ;Remember this name pointer
1136 MOV R10,R1 ;And remember the version
1137 LDR R14,dll__pathPrefix ;Load the path prefix
1138 ADR R0,misc__sharedBuf+8 ;Point to shared buffer
1139 STR R14,[R0],#4 ;And store that away
1140
1141 ; --- Now set up for our search ---
1142
1143 ADR R9,misc__sharedBuf+8 ;Filename assumed to be leaf
1144 MOV R2,R0 ;Assume DLL name is leaf
1145
1146 ; --- The first character is special ---
1147
1148 LDRB R14,[R11],#1 ;Load the next byte out
1149 CMP R14,#'[' ;Is this a new-style leaf?
1150 BEQ %20dll__createName ;Yes -- skip to copy rest
1151
1152 ; --- Now enter the main loop ---
1153
1154 00 CMP R14,#'[' ;Found new-style name delim?
1155 ADREQ R9,misc__sharedBuf+8+4 ;Yes -- ignore `DLL:' bit
1156 MOVEQ R2,R0 ;DLL name starts here
1157 BEQ %20dll__createName ;Yes -- skip to copy rest
1158
1159 STRB R14,[R0],#1 ;Store character in output
1160 CMP R14,#'.' ;Found a path separator?
1161 ADREQ R9,misc__sharedBuf+8+4 ;Yes -- ignore `DLL:' bit
1162 MOVEQ R2,R0 ;DLL name is here or later
1163 CMP R14,#&21 ;Is this the end of it all?
1164 LDRCSB R14,[R11],#1 ;No -- get the next byte
1165 BCS %b00 ;And keep on looping
1166
1167 MOV R14,#0 ;Terminate the string
1168 STRB R14,[R0,#-1] ;Stuff that over old term
1169 B %50dll__createName ;Now go and find the DLL
1170
1171 ; --- Mess about with new-style names ---
1172
1173 20 LDRB R14,[R11],#1 ;Load another byte out
1174 CMP R14,#&21 ;Dropped off the end?
1175 MOVCC R14,#']' ;Yes -- pretend it was right
1176 CMP R14,#']' ;Finished yet?
1177 MOVEQ R14,#0 ;Yes -- zero terminate
1178 STRB R14,[R0],#1 ;Store in the buffer
1179 BNE %20dll__createName ;And keep looping
1180
1181 ; --- We've found all the names now ---
1182
1183 50 MOV R0,R2 ;Point to the DLL leaf
1184 MOV R1,R10 ;Find the version number
1185 BL dll_find ;Try to find the dll
1186 LDMVCFD R13!,{R9-R11,PC} ;It was OK -- return then
1187
1188 MOV R0,#0 ;Couldn't find the DLL
1189 MOV R1,R9 ;Point to the filename
1190 LDMFD R13!,{R9-R11,PC}^ ;Restore registers
1191
1192 dll__pathPrefix DCB "dll:",0 ;Path variable to search
1193 ALIGN
1194
1195 LTORG
1196
1197 ; --- dll__free ---
1198 ;
1199 ; On entry: R0 == DLL handle to release
1200 ; On exit: --
1201
1202 dll__free ROUT
1203
1204 STMFD R13!,{R1,R2,R14} ;Keep registers safe
1205
1206 ; --- Mangle the list nicely ---
1207
1208 LDR R1,[R0,#dl_next] ;Get pointer to next DLL
1209 LDR R2,[R0,#dl_prev] ;And pointer to previous one
1210 CMP R1,#0 ;Is there a next one?
1211 STRNE R2,[R1,#dl_prev] ;Yes -- fix up previous ptr
1212 CMP R2,#0 ;Is there a previous one?
1213 ADREQ R2,dll__list ;No -- point to list head
1214 STR R1,[R2,#dl_next] ;Fix up the pointer
1215
1216 ; --- Free the block ---
1217
1218 MOV R2,R0 ;Point to the block
1219 MOV R0,#7 ;Magic number to free it
1220 SWI XOS_Module ;Free it now
1221 LDMFD R13!,{R1,R2,PC} ;Return to caller
1222
1223 LTORG
1224
1225 ; --- dll__load ---
1226 ;
1227 ; On entry: R0 == pointer to block to load
1228 ; R1 == pointer to filename
1229 ; On exit: --
1230
1231 dll__load ROUT
1232
1233 STMFD R13!,{R1-R5,R9-R11,R14}
1234 MOV R10,R0 ;Keep pointer to block safe
1235 MOV R9,R1 ;And look after the filename
1236
1237 ; --- Load the DLL into the buffer ---
1238
1239 MOV R0,#16 ;Load a file into memory
1240 MOV R3,#(1<<31) ;Resync code areas when done
1241 ADD R2,R10,#dl_extra ;Leave space for extra info
1242 SWI XOS_File ;Try to load the file
1243 LDMVSFD R13!,{R1-R5,R9-R11,PC} ;Return the error if any
1244
1245 ; --- Check that it really is a DLL ---
1246
1247 LDR R0,=dl_MAGIC ;Find the magic DLL number
1248 LDR R1,[R10,#dl_magic] ;Get the version from DLL
1249 CMP R0,R1 ;Check they're the same
1250 BNE %40dll__load ;If not, give an error
1251
1252 LDR R0,=dl_VERSION ;Get known version number
1253 LDR R1,[R10,#dl_bversion] ;Get DLL's version number
1254 CMP R0,R1 ;How do they match up?
1255 BLT %41dll__load ;If too new, complain
1256
1257 ; --- Relocate the image ---
1258
1259 MOV R14,PC ;Set up return address
1260 ADD PC,R10,#dl_relocate ;Perform the relocation
1261
1262 ; --- Fill in the C library stubs ---
1263
1264 LDR R0,[R10,#dl_stubs] ;Get pointer to stubs table
1265 CMP R0,R10 ;If it isn't invalid
1266 BLS %10dll__load ;... don't skip ahead
1267 BL misc_copyStubs ;Copy the clib branch table
1268 LDMVSFD R13!,{R1-R5,R9-R11,PC} ;Return the error if any
1269
1270 ; --- Mark the DLL as being non-shared ---
1271 ;
1272 ; Here we also clear the data relocation for non-shared DLLs
1273 ; since they don't need to be multiply instantiated. We *do*
1274 ; allow extension DLLs to be multiply instantiated, though.
1275 ; Clearing the relocation also has the side effect of
1276 ; clearing a *shared* DLL's client counter.
1277
1278 10dll__load MOV R0,#-1 ;Non-shared is indicated...
1279 STR R0,[R10,#dl_next] ;... by dl_next being -1
1280 MOV R0,#0 ;Also, clear relocation
1281 STR R0,[R10,#dl_wspace] ;(also clears client count)
1282
1283 ; --- That's it, then ---
1284
1285 LDMFD R13!,{R1-R5,R9-R11,PC}^ ;Return to caller
1286
1287 ; --- Give an error about a bad DLL image ---
1288
1289 40dll__load ADRL R0,msg_errNotADLL ;Point to error message
1290 B %49dll__load ;Go to error generation bit
1291
1292 ; --- Give an error about an unrecognised format version ---
1293
1294 41dll__load ADRL R0,msg_errTooNew ;Point to error message
1295 B %49dll__load ;Go to error generation bit
1296
1297 ; --- Create an error and leave ---
1298
1299 49dll__load MOV R1,R9 ;Point to the filename
1300 BL misc_error ;Fill in the error message
1301 LDMFD R13!,{R1-R5,R9-R11,R14} ;Restore registers
1302 ORRS PC,R14,#V_flag ;And return an error
1303
1304 LTORG
1305
1306 ; --- dll__divide ---
1307 ;
1308 ; On entry: R0 == dividend
1309 ; R1 == divisor
1310 ; On exit: R0 == quotient
1311 ; R1 == remainder
1312 ;
1313 ; This routine is mostly uncommented, 'cos I copied from Acorn's Assembler
1314 ; documentation, and it should be accurate. It's not exactly optimised,
1315 ; but it should hold up to the sort of treatment I'm going to be giving it
1316 ; (very delicate and occasional use).
1317
1318 dll__divide ROUT
1319
1320 STMFD R13!,{R2,R3,R14}
1321 CMP R1,#0 ;Check for stupidity
1322 BEQ %10dll__divide ;If stupid, give an error
1323
1324 MOV R3,R1
1325 CMP R3,R0,LSR #1
1326 00dll__divide MOVLS R3,R3,LSL #1
1327 CMP R3,R0,LSR #1
1328 BLS %00dll__divide
1329
1330 MOV R2,#0
1331 01dll__divide CMP R0,R3
1332 SUBCS R0,R0,R3
1333 ADC R2,R2,R2
1334 MOV R3,R3,LSR #1
1335 CMP R3,R1
1336 BCS %01dll__divide
1337
1338 MOV R1,R0 ;Move results into right...
1339 MOV R0,R2 ;... registers
1340 LDMFD R13!,{R2,R3,PC}^
1341
1342 10dll__divide ADRL R0,msg_errDivide ;Point to error message
1343 LDMFD R13!,{R2,R3,R14} ;Retreive registers
1344 ORRS PC,R14,#V_flag ;And returnt the error
1345
1346 LTORG
1347
1348 ;----- That's all folks -----------------------------------------------------
1349
1350 END