chiark / gitweb /
Create readable text `.bas' for each tokenized BASIC `,ffb' file.
[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