Overlay.doc A tiny introduction to Overlays ---------------------------------------------------------------------------- © 1997 THOR-Software. Read the licence at the end! $VER: Overlay Doc 1.3, Dec 5th, 1997 ____________________________________________________________________________ Abstract: This doc presents some features of overlay binary files of the AmigaDOS, their hunk structure and a standard overlay manager. In this doc, tradenames and trademarks of some companies and products have been used, and no such uses are intended to convey endorsement of or other affiliations with the documentation. ____________________________________________________________________________ Thanks to Jörg Riemer for the fruitful discussion about the overlay file structure and finding some mistakes in this doc. Thanks to Harry Sintonen for correcting another mistake in the doc about the magic word. ____________________________________________________________________________ i) What are "overlays" ? Overlay binaries are amiga dos executables that are, unlike the usual executables, only partially loaded from disk. Thus overlayed programs will usually occupy less memory and will load faster, because only the needed parts of the executable reside in memory, everything else is kept on disk and loaded only if needed. This mechanism is provided by the LoadSeg() and UnLoadSeg() pro- cedures of the operating system (the dos.library), a small startup- program that is responsible for locating the correct module to reload (the "Overlay-Mananger") plus the linker, which is needed to build the necessary references, i.e. creates the necessary information for the overlay manager which part of the code can be found where. This overlay mechanism is NOT unique to Amiga, and has been used in other computers as well. (In the antique Atari XL, for example, but also in the Macintosh computers and elsewhere). However, it is not very well known and not very well documented for the Amiga. See the literature for more references. The standard overlay segment consists, like every other executable file, of a SINGLE output file that has been generated by the linker. However, internally, this file can be thought to have a tree-like structure. To give an example, consider the following simple tree: overlay manager | | common part / \ / \ node a node b The overlay manager and the "common part" are loaded immediately by the DOS. The overlay manager is used for loading the overlayed nodes, as described below, and is usually provided by the linker, i.e. you don't have to write it. The "common part" of your program consists of symbols (procedures, data structures, whatever) needed by all parts of the executable, and is, like the overlay manager, always loaded and not removed from memory unless the program quits. Thus the "common part" will contain the main() procedure of your program, which is called by the overlay manager in first place. HOWEVER, the data in nodes a and b in this example WON'T be loaded by the dos, and won't waste memory. They will, instead, only be loaded if needed. Consider, for example, that your main program calls a procedure ATest() in node a. Then the overlay manager will notice AT EXECUTION TIME that this procedure is not yet in memory, and will load the node a from the disk, relocate the code and execute it after loading it. This loading is totally transparent to your code, no additional work is needed (this is done by the linker). If you now call a procedure BTest() from node b, the node a is un- loaded, the memory occupied by it is freed and instead node b is loaded into memory. As you can imagine, this will safe some memory, esp. for BIG programs. However, because of this, you won't be able to call a procedure from inside of node a which resides in node b, since the calling procedure must be unloaded. This is usually checked by the linker. You call the nodes a and b the "childs" of the node above, in this case the "common part". This is called to be the "parent" of a and b, and in this case also the "root" of the tree, because it is the topmost node, except the overlay manager. And now a more complex example that is taken from real life: This is the overlay structure of the SetVNC program (which is part of the ViNCEd CON: replacement package and available at my home page, see below). It has a bigger tree: overlay manager | | startup code & argument parsing / | | | | / | | | | / | | | | / | | | | mounter job control help argument prefs loader line and saver printer / \ / \ / \ / \ shell direct editor gui commands | | online help In this case, the root node is the "startup code & argument parsing" node, which does the command line argument parsing. Depending on the argument line, one of the five parents of this node can reside in memory, exclusively. However, one node (the prefs loader) has by itself children that it might load on request. The following rules of loading and unloading apply: If a node must be loaded, all other children of the parent of this node plus all their children will be unloaded. The children of the new node WON'T be loaded. So if you request the "shell direct" commands, the "editor gui" and the "online help" are unloaded. If, after that, you call the "job control" node, the "prefs loader" and the "shell direct" commands are freed and replaced by the job control module. Because of these rules, the following restriction of invokation of nodes apply: You may call: a) each procedure of the parent node b) procedures in the parent of your parent and so on, up to the "common part" or "root" a) and b) says that you may call everything "on top" of your node. This is because all these nodes must have been loaded at invokation time of your node, and all procedures are present. The invokation types a) and b) are "ordinary" function calls in the sense that the overlay manager is not needed. c) Call functions of one of your children. This is a special "overlay" type call, and the overlay manager is needed here. It will find out if the appropriate children node is already in memory, and, if not, will replace or reload it from disk. You may NOT call: a) Functions in nodes that are not in parent nodes of your node, i.e. on top of your node, except direct children. b) Children of your children. Hence, only DIRECT dependencies are traced by the overlay manager. And what about data references: You may refer to memory or data objects of a) and b) your parent or parents of your parent, up to the root level of the tree. This is again no problem, since the overlay manager is not needed to do this work. EXCEPT a) and b) NO OTHER REFERENCES ARE ALLOWED. YOU MAY NOT refer to DATA in your children! This is again a limitation of the overlay manager which assumes that all references to children nodes are code references. However, it's easy to overcome this limitiation if you write a stub procedure in your children that returns a pointer to the data object. Then call this function to get the pointer, thus invoking the overlay manager automatically: main() { my_struct *a; a=getptr(); .... } and in the overlayed node: my_struct *getptr(void) { return &my_data; } Some care must be taken, however. Since the data resides in an overlay module, THIS DATA WILL VANISH if you load another children of your node. Nobody will warn you about this! _____________________________________________________________________________ ii) Custom overlays As I said, the loading of overlayed nodes is done by the overlay manager, which, by itself, uses the LoadSeg() function of the dos to do the stuff. However, you MAY write an own overlay manager with a custom load procedure. Since the data parts behind the root nodes of the overlay tree are never seen by the OS, YOU ARE COMPLETELY FREE in the design of your overlay mechanism. However, for this case, you need a custom linker that builds your overlay file and builds the custom structure needed by the overlay loader. You won't get any support by the OS for loading the overlay structures from memory, so all must done by hand. This method has its powers, and has also been done. For an example, some limitations of the tree like structure above have been broken by the overlay manager of DPaint II (Electronic Arts). This program uses a private overlay manager, but the standard file structure to encode the overlay tree. The EOA overlay manager can hold more than one node of one overlay level, and load all nodes simultanously into memory. This prevents unnecessary disk I/O if enough memory is available and the overlay mechanism is not required. The MAC overlay manager provides, by the way, a similar mechanism of keeping nodes, unless the OS runs out of memory. The default overlay manager is rather clumbsy compared to the highly sophisticated EOA and Mac-Os managers, although EOA stopped supporting it with DPaint IV. Another example is the low-level debugger COP (also by the author of this article) with a much simpler overlay type structure. The overlay part is in this case the resident part of the debugger, and is only loaded if the debugger is not yet in the memory. As you can image, nice tricks can be done by custom overlays, e.g. games displaying a title while loading, or that keep pictures in the overlay nodes and so on. With an amiga, it is absolutely not necessary to put a dozen of files on your HD: Each data needed can be put in the overlay nodes of an overlayed file and can be loaded into the memory on request. However, custom overlays are always a big bunch of work, since you have to develop everything by yourself: The linker, if you need a different file structure, and a private overlay manager, possibly a private segment loader, i.e. a LoadSeg() replacement. Because of these custom structures, overlays can't be crunched safely - the custom structure might need some changes if the length of the file and the position of the nodes change. And this custom structure can't be known by the cruncher. The good part is: This goes for viruses, too. So you may say that an overlayed program is very resistent against viruses. Either it works, or it is infected and does not work at all. _____________________________________________________________________________ ii) How to construct an overlay. As I said above, overlays are build by the linker. Not every linker will support them however, for example the public domain linker BLink of the software distillery won't. I won't go into detail here since this is described better in your linker manual, or in the literature [1]. To make it short, a WITH file is needed for the standard ALink (and also for other custom linker tools). It should not only contain the options, as usual, but also special keywords to start overlay generation. Here is how it looks like for the SetVNC example: ROOT SVC_Startup.o NEWOCV OVLYMGR SVC_OvrlyMngr.o OVERLAY SVC_Mount.o SVC_Prefs.o *SVC_ShellCMDs.o *SVC_Editor.o **SVC_EditHelp.o SVC_JobCtrl.o SVC_Help.o SVC_CLIHelp.o # The ROOT keyword specifies the root node of the overlay tree. This is the "common part" which is initially loaded. The NEWOCV keyword specifies the type of the overlay manager to be used. There are actually two standards: The old one for stack-based calls of C style functions, and the new one with uses registerized parameters and should be prefered. More about this topic later. The OVLYMGR option selects the overlay manager to be linked in front of your code. Some linkers don't support this option and use a overlay manager hard-wired into the linker; others linkers supply a default overlay manager if this keyword is omitted. The overlay manager itself is a standard object module (not an executeable!), see below for an example. The OVERLAY keyword starts the actual description of the overlay tree. It is terminated by the hash-mark in the last row. Each line under the OVERLAY statement is the name of one overlay node, plus some stars in front of the name, that give the "level" of the node in the overlay tree. No stars means children of the "root" note, one star'ed names are children of the node above the non-star'ed, and two-star names are children of the one-star name on top. Thus, these lines will produce exactly the overlay tree example of SetVNC in the first chapter. _____________________________________________________________________________ iii) How overlay files look like on disk. First difference: The HUNK_HEADER hunk of the binary contains the number of hunks, plus the first and the last hunk that must be loaded. Since hunks are counted from 0 up, the last hunk of a usual program is just the number of hunks of the program minus one. THIS IS NO LONGER TRUE FOR OVERLAYS! The third longword of the HUNK_HEADER is the maximal number of hunks that must be kept in memory at a time. If every overlay node contains the same number of hunks, this will be the number of hunks of the longest path from the root to one of the bottommost nodes of the overlay tree. In all other cases, this interpretation may get wrong. The fifth longword contains now the number of the last hunk of the root nodes, i.e. the last hunk that is initially loaded - again counting from zero up. For short: HUNK_HEADER $000003f3 private_dummy 0 (must be here. Is reserved for resident library uses, and also documented for this reason. However, this feature was never implemented. Keep it zero!) TABLE_SIZE n The maximal number of hunks that may reside in memory simultaniously. FIRST_HUNK 0 The first hunk to load. This MUST be the zeroth hunk, since this is the root node. LAST_HUNK m The last hunk to load, thus the last hunk of the root nodes, counting the nodes of the overlay manager, as well. SIZES[m+1] LAST_HUNK+1 longwords specifying the sizes of the hunks in the root. The first number is for hunk zero (thus the size of the overlay manager), the next is the size of the first hunk of the root node and so on. There are m+1 numbers (plus some special bits that can be set there to request CHIP or FAST memory. Bit 30 is CHIP, Bit 31 is FAST.) So far for the HUNK_HEADER. The program starts with a HUNK_CODE. This code-hunk is NOT the first hunk of your code, but the overlay manager. Your code comes in the next hunk (beeing the second, or hunk one in this numbering). Since the dos starts the executables always at hunk zero, the overlay manager is CALLED FIRST and will start your code NEXT. Virus-Checker authors: BE WARNED. This calling ISN'T done thru a relocation entry. Instead, the BCPL hunk linkage provided by the DOS will be used, and the root node is started at its first byte. NO RELOCATION OF THE OVERLAY MANAGER RELATIVE TO THE HUNK #1 WILL HAPPEN. Dirty, but such is life. The overlay manager code is special, again. It is on the first sight just a code segment as every other code segment, but some data in it is read by the OS. First, it contains a "Magic Longword" $0000ABCD, followed by four zero longwords. The Magic Word is parsed by the OS, and the four longs behind it will be filled with important information needed by the overlay manager before the code gets started. It is also needed by UnLoadSeg() to shutdown the overlay mechanism (close the file and free the overlay table). This Magic Word IS NEEDED, and MUST be placed at the second long word of the first hunk. The first longword can be whatever you like, but contains usually a word sized relative jump around this magic, thus something like $6000xxxx. The xxxx is the jump size and may vary from overlay manager to overlay manager. Please do not depend on this size, nor on the jump at all. This magic word isn't parsed by the LoadSeg procedure of the dos library at all - it fills all required information for the overlay manager into the third to the sixth long word of the hunk and will overwrite everything there. The only part of the dos that really cares about it is the UnLoadSeg() routine - if the magic word is present and the data following this long word is correct (to be precise, the GlobVec must match the dos GlobVec, see below), it closes the I/O stream and de-allocates the overlay table - together with the hunks. Everything behind the Magic Word and the four longs is free, in principle. Free in the sense that it is not parsed by the DOS. However, there are some rules how to find out if a custom overlay manager is used or not. The standard overlay managers keep here: 1) Another Magic Longword $00005BA0 2) A seven character BCPL like string, saying "Overlay", thus $074f7665726c6179 The EOA overlay manager doesn't identify itself as "standard" since these identification bytes are missing. Here, another standard ends. This information is, for example, used by COP (my debugger). If everything is present like this, a standard overlay is assumed. For my overlay manager (the code is presented below), the story goes on: 3) two empty longwords. They keep library pointers. 4) A C style string: "THOR Overlay Manager 1.0" The 1.0 is the version number, and may increase in future. Again, these standars in short (counted in longs): HUNK_CODE $000003e9 length n size of the hunk in long-words. jump-instr. $6000xxxx where xxxx may vary. MAGIC WORD $0000abcd A magic cookie. (May well be anywhere in the first hunk for custom overlays) FH $00000000 Becomes the BPTR file handle. OVTAB $00000000 Filled by overlay table ptr by the dos. HT $00000000 Filled with hunk table ptr. GV $00000000 Filled with BCPL GlobVec. LIBWORD $00005ba0 "Magic" lib word (no idea whatfor) STRING $074f7665 $726c6179 The BCPL String "Overlay" SysBase $00000000 Filled with ExecBase by THOR Overlay manager. DOSBase $00000000 Filled with base of dos.library by THOR Overlay. Version The "C-style" string: "THOR Overlay Manager 1.0",0 Beyond that: The code starts. So much for the overlay manager. Behind the manager, the root hunks of the code follow. They are usual hunks, with all the relocation table stuff like in every other executable. The root nodes terminate, with a standard HUNK_END $000003f2. Behind this HUNK_END, a HUNK_OVERLAY $000003f5 is required by the DOS to identify this file as overlayed. The data in this hunk will be loaded, but not parsed, by the LoadSeg procedure of the DOS. Decoding this data is, however, done by the overlay manager. The structure of the HUNK_OVERLAY is free - in principle. The only requirement is that the first long word of the hunk is the size of the hunk in longwords, minus two. This hunk contains the information needed by the overlay manager, e.g., where the overlayed nodes can be found, and which entries must be relocated. The DOS segment loader stops parsing the file after encountering a HUNK_OVERLAY, so the part of the file behind this hunk is again free as it is never seen by the DOS. A standard overlay file will continue with the HUNK_HEADER of the first overlayed node in the overlay tree. Now, let's assume the file uses a standard overlay structure. The HUNK_OVERLAY will now look like this: The first longword of this hunk is the table size of the overlay table. This is the number of longwords in the table, not counting the table size itself and the next longword, the overlay level. Thus, it is the lenght of the data in hunk in longwords, minus two, as described above. The next long is the overlay level, which is the length of the longest path in the overlay tree from the root note to the bottom, couting the overlay manager as well. Thus, for the SetVNC example of section one, this will be five. If the overlay level is n, n-1 empty longwords follow. They are used by the overlay manager and keep information about which of the nodes of the overlay tree are loaded, one for each level. The overlay manager itself is not kept here, but in the first hunk of the file. More about these longs below. For the SetVNC example, four longwords are here. Again, for short the structure: HUNK_OVERLAY $000003f5 OVLR_SIZE n number of longwords here, minus two. REQUIRED! TREE_SIZE m+1 size of the tree, i.e. maximal "depth", counting the overlay manager. TREE_PTRs [m] m longwords, containing zero. OVLR_DATA 8 long sized structures. The remaining part of the overlay table contains of 8 longword sized structures, keeping the references to overlayed functions, one for each reference to an overlay, i.e. references that must be resolved at execution time by the manager by loading data from disk. This structure looks like the following: FILE_POSITION: The zeroth longword contains the offset of the overlay hunk where the symbol resides in. This is really the plain offset of the HUNK_HEADER of this module to the start of the file. WARNING: These longs are the reason why overlays can't be crunched without further care! If you change the size of the overlay manager or the size of the root nodes, these longs MUST be adjusted. However, since custom overlays are possible, KEEP HANDS OFF! RESERVED(2): The next two longs in this structure are reserved, for whatever. OVERLAY_LEVEL: Next is the OVERLAY_LEVEL. This is the depth of the overlay module the symbol is contained in, counting from zero for the root downwards the tree. Thus, for the SetVNC example, a reference to the job control module will have a one here, since it is a direct child of the root. ORDINATE: We continue with the OVERLAY ORDINATE, which is the "horizontal" position of a overlay node within the tree. The overlay ordinates are setup by the linker and are unique to each horizontal layer = level in the overlay tree. They usually start with one, I think. INITIAL_HUNK: The next long is the initial hunk number of this overlay node and describes where in the hunk table the hunk pointers should go. If, for example, the root nodes of the tree plus the overlay manager take up four hunks, counting 0 to 3, and this is a direct child of the root, the initial hunk for loading will be four. If this module has three hunks, the initial hunk of one of the childs of this hunk will be seven, and so on. SYMBOL_HUNK: We come to the next long, the symbol hunk. This is the actual hunk number this overlay reference is relative to. If you call a subroutine of an overlay node, a reference for this procedure will be generated here, and this longword will contain the hunk number where the symbol is kept in the overlay node. In the example above, if the symbol is in the first hunk of the overlay, this longword will be again four, since the first overlayed hunk in the first module is again number four in the total file. If you refer to a symbol in the second hunk of an overlay module, this number will be the initial load hunk plus one, and so on. SYMBOL_OFFEST: The last longword is just the offset of the symbol within the hunk specified above. This value will be added to the hunk base address to get the pointer to the routine you like to call. Here again the overview: FILE_POSITION Offset in the executable of the HUNK_HEADER of the overlay module. RESERVED (2) Two empty longs OVERLAY_LEVEL The level within the overlay tree, zero is the root. ORDINATE The horizontal position in a level of the tree. Only used as an unique ID INITIAL_HUNK First hunk number of the overlayed module. SYMBOL_HUNK The symbol hunk where this reference is pointing to. SYMBOL_OFFSET The offset of the symbol in the hunk. The next data in an overlay file are again executable modules like the first one, again starting with HUNK_HEADER. However, this time the FIRST_HUNK longword of the headers are not zero. They are identical to the INITIAL_HUNK longs in the overlay table, described above. They contain again the hunk number where this module should be placed. The LAST_HUNK is no longer the size of hunks of the module minus one, but the INITIAL_HUNK + the size - 1, thus, the number of the last hunk in this module. Next are the sizes of these hunks, as for a usual HUNK_HEADER. What follows is again HUNK_CODE's, HUNK_DATA's and all the usual stuff to specify data for the overlayed module. This module is terminated by a HUNK_BREAK $000003f6, which tells the overlay manager to stop loading there. WARNING: As a result, an overlayed file never ends with HUNK_END $00003f2, but with HUNK_BREAK $000003f6! _____________________________________________________________________________ iv) How overlayed files look in memory: The overlay manager. Now lets come to the overlay manager, which is executed first when an overlay program gets started. As I said above, the OS expects the Magic Word $0000abcd at offset eight of this hunk, and fills the next four longs with vital data. They are valid as soon as your code gets started, and are no longer zero. Here how they look like: STREAM: The first LW is a standard DOS stream, which is used to operate on the file. Unlike regular executables, the stream REMAINS OPEN until the program quits. You don't need to close it, this is done by UnloadSeg(). OVERLAYTAB: The next long is a usual pointer to the overlay table, the contents of the HUNK_OVERLAY described above. It points to the TREE_SIZE long in this table, so to the second long of the overlay table hunk. HUNKBPTR: The third long is a BCPL BPTR to the overlay hunk table. It is an BCPL array, which is as long in as the maximal number of hunks in the load file. Thus, we have here TABLE_SIZE longs, as specified in the HUNK_HEADER. Each entry in this hunk is a BCPL pointer to the hunk loaded at this position, or zero if this one is empty. GLOBALVEC: The last longword is a BPTR to the dos global vector. This vector is no longer used, and is a BCPL style analogon of the dos.library. It was used by BCPL overlay managers to do the loading, cause library calls are not possible for BCPL. BTW, this global vector contained all the useful argument parsing functions SINCE EVER, EVEN IN KickStart 32.0. They have been made available to the public starting with 2.0, but have been there since ever. Again, a short overview: FILEHANDLE Dos stream (BCPL pointer) to this file. OVERLAYTAB C-pointer to overlay table in HUNK_TABLE. HUNKBPTR BCPL-pointer to the hunk array. GLOBVEC BCPL-pointer to dos global vector. _____________________________________________________________________________ v) What does the overlay manager now do? First, I'm describing here the new style overlay manager. The other one is very similar except that the parameters are kept at different locations. 1) Find out the return address of the overlay call. The index of the overlay reference within the OVERLAYTAB is kept at this address, as it has been placed there by the linker. 2) Get the location of the overlay table entry by this offset. 3) Get the location of the TREEPTRs within the overlay table. They keep the ordinate number of the module currently loaded at this position of the tree. 4) Compare if the overlay node currently loaded does match the tree that was requested. If so, calculate the start address within this module and start the overlay procedure. 5) If the ordinate number does not match, it's either empty (no over- lay module loaded at this position), or it is just the wrong child that is currently loaded. In this case: Unload the node plus all children, and unlink the modules, clear the references in the TREEPTRs array and in the hunk array. 6) Find out the location of the module to load. This is kept in the overlay table. Set the file pointer of the executable file to this position. 8) Load the overlay module. This is done with a very special call to LoadSeg, which is nowhere documented. Unlike usual, the file name is NULL, but the hunk table BPTR is passed in d2 ad the filehandle in d3. This is really a bit tricky... (And this part of the code is broken in the old style overlay manager). 9) Link this module to the already loaded hunks. 10) Calculate the hunk and the position of the overlay reference from the table. Start the module at this position. _____________________________________________________________________________ For experts, I include the documented source of my overlay manager: ;************************************************* ;** SetVNC ** ;** A full screen editor ** ;** The prefs program ** ;** © 1990-97 THOR ** ;** ** ;** Module: Overlay-Manager ** ;** ** ;** ** ;** Version 3.00 ** ;** 15 Jun 1996 ** ;************************************************* include INC:macros.asm ;private macros. include INC:exec_lib.asm include INC:dos_lib.asm ;** Based on the Overlay-Manager by Richard Evans ;** and Tim King ;** Bug corrections by THOR 16.07.1996 xdef @ovlyMgr ;************************************************* ;** Offsets in the overlay-table ** ;************************************************* rsreset ot_FilePosition: rs.l 1 ;File position ot_reserved: rs.l 2 ;for whatever ot_OverlayLevel: rs.l 1 ;Overlay-Level ot_Ordinate: rs.l 1 ;Overlay-Ordinate ot_InitialHunk: rs.l 1 ;Initial hunk for loading ot_SymbolHunk: rs.l 1 ;Hunk containing symbol ot_SymbolOffset: rs.l 1 ;Offset of symbol ot_len: rs.b 0 ;************************************************* ;** Other stuff ** ;************************************************* MajikLibWord = 23456 ;Hey, don't know what this means section NTRYHUNK,CODE ;************************************************* ;** Manager starts here ** ;************************************************* Start: bra.w NextModule ;Jump to the next segment... ;* This next word serves to identify the overlay ;* supervisor to 'unloader', i.e. UnLoadSeg() dc.l $ABCD ;Majik longword for unloader (has to free hunk table, file handles,...) ;* The next four LWs are filled by the loader (LoadSeg()) ol_FileHandle: dc.l 0 ;Overlay file handle (points to me) ol_OverlayTab: dc.l 0 ;Overlay table as found in the overlay hunk ol_HunkTable: dc.l 0 ;BPTR to Overlay hunk table ol_GlobVec: dc.l 0 ;BPTR to global vector (what for ?) dc.l MajikLibWord ;Majik library word as identifier dc.b 7,"Overlay" ;Majik identifier ol_SysBase: dc.l 0 ;additional pointer ol_DOSBase: dc.l 0 ;to libraries dc.b "THOR Overlay Mananger 1.0",0 ;another ID @ovlyMgr: ;Entry-points saveregs d0-d3/a0-a4/a6 ;Saveback register moveq #0,d0 move.l 10*4(a7),a0 move.w (a0),d0 ;get the overlay reference ID from return address move.l ol_OverlayTab(pc),a3 ;get pointer to overlay table move.l a3,a4 ;do a4 ;Upper word MUST zero (check this out in BLink) add.l (a3),d0 ;add length lsl.l #2,d0 ;get offset add.l d0,a3 ;address of overlay entry move.l ot_OverlayLevel(a3),d0 ;get overlay lsl.l #2,d0 adda.l d0,a4 move.l ot_Ordinate(a3),d0 ;get required ordinate level cmp.l (a4),d0 ;compare with current ordinate level beq.s .gotsegment ;not correct level ;clear all other entries behind this move.l d0,(a4)+ ;fill with new overlay entries moveq #0,d1 do ;macros in action! ;-) tst.l (a4) ;terminate, if end of table found break.s eq move.l d1,(a4)+ ;clear this loop.s move.l ot_InitialHunk(a3),d0 ;first hunk number to load add.l ol_HunkTable(pc),d0 ;plus BPTR of hunk table lsl.l #2,d0 ;address of entry in hunk table move.l d0,a4 move.l -4(a4),d0 ;get previous hunk: MUST be present (do not load children before master) beq.s .noprevious lsl.l #2,d0 move.l d0,a2 move.l d1,(a2) ;unlink fields before loading ;now free all hunks move.l ol_SysBase(pc),a6 do move.l (a4)+,d0 ;next hunk ? (terminated by zero) break.s eq lsl.l #2,d0 move.l d0,a1 ;->a1 move.l -(a1),d0 ;get length jsr FreeMem(a6) ;free this hunk (don't check if valid) loop.s ;and now the next .retry: move.l ol_DOSBase(pc),a6 move.l ol_FileHandle(pc),d1 ;get our stream move.l ot_FilePosition(a3),d2 ;get file position moveq #-1,d3 ;relative to beginning of file jsr Seek(a6) ;seek to this position tst.l d0 ;found something ? bmi.s .loaderror ;what to do on failure ? ;now call the loader move.l ol_HunkTable(pc),d2 ;hunk table moveq #0,d1 ;no file (is overlay) move.l ol_FileHandle(pc),d3 ;filehandle jsr LoadSeg(a6) ;load this stuff tst.l d0 ;found (return is in d0, not d1! Buggy old overlay!) beq.s .loaderror move.l d0,(a2) ;add new chain (note that we removed that old bug, value is in d0) ;found this stuff .gotsegment: move.l ot_SymbolHunk(a3),d0 ;get hunk # containing symbol add.l ol_HunkTable(pc),d0 lsl.l #2,d0 ;get APTR to hunk move.l d0,a4 move.l (a4),d0 ;BPTR to hunk lsl.l #2,d0 add.l ot_SymbolOffset(a3),d0 ;Offset move.l d0,10*4(a7) ;Set RETURN-Address loadregs rts ;************************************************* ;** Go here if we find an error ** ;************************************************* .loaderror: saveregs d7/a5 move.l ol_SysBase(pc),a6 move.l #$0700000C,d7 move.l $114(a6),a5 jsr Alert(a6) ;Post alert loadregs bra.s .retry ;Retry or die .noprevious: move.l ol_SysBase(pc),a6 move.l #$8700000C,d7 ;dead end ! move.l $114(a6),a5 jsr Alert(a6) ;Post alert bra.s .noprevious ;************************************************* ;** NextModule ** ;** Open stuff absolutely necessary and ** ;** continue with main program code ** ;************************************************* NextModule: ;why safe registers ? move.l a0,a2 move.l d0,d2 ;keep arguments (BCPL stuff is not kept) lea ol_SysBase(pc),a3 move.l ExecBase,a6 move.l a6,(a3) ;fill in Sysbase lea DOSName(pc),a1 ;get name of DOS moveq #33,d0 ;at least 1.2 MUST be used (no support of antique stuff) jsr OpenLibrary(a6) move.l d0,4(a3) ;Save back DOS base for loader (behind) beq.s .nodosexit ;exit if no DOS here move.l d0,a6 ;as a service, post this to the main code move.l Start-4(pc),a0 ;Get BPTR of next hunk (will be first hunk in the system) adda.l a0,a0 adda.l a0,a0 exg.l a0,a2 ;move to a2 move.l d2,d0 ;restore argument jsr 4(a2) ;jump in ;Gee, I hope the main is clever enough to return here... move.l d0,d2 ;Save return code move.l ol_SysBase(pc),a6 move.l ol_DOSBase(pc),a1 jsr CloseLibrary(a6) ;Close the lib move.l d2,d0 ;Returncode in d0 rts .nodosexit: move.l #$07038007,d7 ;DOS didn't open (this code is supposed to be part of the DOS) move.l $114(a6),a5 jsr Alert(a6) moveq #30,d0 ;Something went really wrong ! rts DOSName: dc.b "dos.library",0 _____________________________________________________________________________ References: [1] : The AmigaDOS Manual (3rd ed.) Bantam Computer Books _____________________________________________________________________________ So, this is all folks. Hope you liked the show.... Thomas November 1997 The THOR-Software Licence This License applies to the documentation known as "Overlay.doc". The "Data", below, refers to such data. The programs and files in this distribution are freely distributable under the restrictions stated below, but are also Copyright (c) Thomas Richter. Distribution of the Data by a commercial organization without written permission from the author to any third party is prohibited if any payment is made in connection with such distribution, whether directly (as in payment for a copy of the Data) or indirectly (as in payment for some service related to the Data, or payment for some product or service that includes a copy of the Data "without charge"; these are only examples, and not an exhaustive enumeration of prohibited activities). However, the following methods of distribution involving payment shall not in and of themselves be a violation of this restriction: (i) Posting the Data on a public access information storage and retrieval service for which a fee is received for retrieving information (such as an on-line service), provided that the fee is not content-dependent (i.e., the fee would be the same for retrieving the same volume of information consisting of random data). (ii) Distributing the Data on a CD-ROM, provided that the files containing the Program are reproduced entirely and verbatim on such CD-ROM, and provided further that all information on such CD-ROM be redistributable for non-commercial purposes without charge. Everything in this distribution must be kept together, in original and unmodified form. Limitations. THE DATA IS PROVIDED TO YOU "AS IS," WITHOUT WARRANTY. THERE IS NO WARRANTY FOR THE DATA, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY OF THE DATA IS WITH YOU. IF YOU DO NOT ACCEPT THIS LICENCE, YOU MUST DELETE ALL FILES CONTAINED IN THIS ARCHIVE.