Documentation for DLINK and DLOC versions 1.2 by Roger Warren May '87 Update History Version 1.2 - May '87 - A *LARGE* improvement in the LINKER (DLINK) performance has been provided by the addition of a HASHED symbol table! The BENCHMARK (the linking of DLINK by itself) has realized a 240% improvment in performance (or, conversely, it takes about 42% of the time it *FORMERLY* took.) - Both programs have been reduced in size (and increased in speed) by the use of the free-format BASIC constructs (no line numbers except when necessary.) Version 1.1 - Feb '87 - A few very MINOR changes affecting speed and scratch file sizes (faster and smaller, respectively). Perhaps noticable on floppy systems...but still *SLOW*. - Expanded ZERO FILL to optionally zero PROGRAM area, too, before commencing LOAD function. This became necessary because SOME commercial and PD assemblers Zero fill for DS directives (therefore, switching assemblers makes a difference for sloppy programmers who expect uninitialized areas to contain ZEROs). Ditto for SOME commercial and PD linkers. Several Zero fill ALL uninitialized areas. DEFAULT for DLOC is ZERO FILL DATA area only (same as L80). Part I - The Whys and Wherefores DLINK and DLOC were originally generated to approximate the functioning of the LD80 program (a disk-based linking loader). The need for such a function arises when generating moderately sized programs (especially compiled programs) on a machine with a relatively small TPA. In such a situation, L80 (the Microsoft memory-based linking loader) runs out of memory and cannot complete its function. If you've ever run into this limitation, the only solution is to either: a) trim code, or b) beg (or borrow or steal) the use of (or a copy of) LD80 from a friend. The author, not having a convenient source of LD80 and not wanting to trim features from programs, decided to roll-his-own. The resulting programs are released to the Public Domain for non-commercial use. Being disk-based, compiler-generated (BASIC) programs, they have two drawbacks: they're relatively large and they're SLOW! The user who NEEDS to use these programs will probably be willing to overlook these drawbacks. The programs have been tested against the L80 program and have produced equivalent object code files. Of more interest is the fact that the later versions of the programs HAD to be generated with the previous versions, due to the author's machine's 48K TPA. One feature that comes with being a home-grown, Public Domain program: it can be enhanced in response to need. The author will entertain all reasonable requests for enhancements to the programs, as long as these enhancements will benefit the typical user (try to get Micropro or Microsoft to do that!) Part II - Overview of Functionality The functions of linking and locating Microsoft-compatible .REL files has been split into two programs: a link editor (DLINK) and a locator/loader (DLOC). This partitioning of functionality was done to simplify development and reduce memory requirements. DLINK performs both forced loads (plain old loading of .REL files) and selective loads from libraries (modules are loaded only if they contain an entry point that is required by a previous module). In doing this, DLINK produces two output files on the current default drive: DLINK.LKS and DLINK.LKR. DLINK.LKR is, itself, a Microsoft compatible .REL file that contains all of the linked modules edited into one file. DLINK.LKS is the linker's working file. It holds ALL of the symbol names plus other module information required by DLOC. DLOC performs the function of creating a memory-image (.COM) file from the DLINK.LKR and DLINK.LKS files. It generates an output called (by default) IMAGE.COM on the default drive. The user may specify the output file device/name instead of using the default. DLOC does not erase the DLINK.LK? files! The decision to NOT erase them arises from the fact that DLINK is slow. If DLOC were to erase the files, then the user could not run DLOC again on the same data (if he made a mistake in running DLOC) without first running DLINK - too great a penalty to pay for the convenience of not having to "clean-up" temporary files. By virtue of the implementation, DLINK and DLOC offer a few features not available when using L80: COMMON blocks may have their length redefined by various program modules. The LARGEST specified length for a particular COMMON block will be used by DLOC. ALL DATA and COMMONS are combined into one contiguous memory space, as are all PROGRAM segments. COMMONS are assigned to the lower end of the DATA area. BLANK COMMON is always assigned first. (This can be done with L80, but in doing so, compiler-generated code or other code that uses the $MEMRY feature may not work if you don't have an intimate knowledge of L80's inner workings.) The $MEMRY feature IS supported. This is important for those who use the Microsoft compilers or portions of the Z-SYSTEM software. Related to the previous paragraph, DLOC has a feature which supports user control of the assignment of the content of the $MEMRY variable (more on this later for those of you who wonder why your code steps on itself when using $MEMRY and trying to combine all DATA segments!) All .REL file features are supported EXCEPT the extension link items. Quite frankly, there was not enough information available on them to allow their implementation. BASCOM version 5.3 will generate extension link items when the /O compiler switch IS NOT used and M80 will ALSO generate such items when constructs like: MVI a,HIGH(label) are used when 'label' is a RELOACATABLE code label. COBOL will also generate extension link items. DLINK will print a message and stop if it encounters one. If this happens, kindly foreward your source and object to me so that the feature can be studied and supported. Any information on the extension link operations would be appreciated. Finally, although the programs are not speedy, this is a bother ONLY with compiler-generated code, where there are literally HUNDREDS of ENTRY/EXTERNAL links. Speed of execution increases as more SYMBOLS must be maintained. My benchmark is the link/locate of DLINK, itself: the whole program has about 1150 symbols and takes about 10 minutes to link and 5 minutes to locate on a 5-1/4" 96 TPI floppy run by a 4 MHz Z80. DLINK and DLOC should be an acceptable substitute for L80 if compiler- generated code is not used, when there are a few hundred symbols, or on hard disk systems! Part III - System Requirements The object of these programs is to free the user from memory restrictions. The programs need little memory in addition to the space required for code. A 48k TPA is known to be sufficient, and a 32-36k TPA is probably sufficient! Disk space is not a great concern. The default drive must have sufficient space for the DLINK.LKR file (less than your combined .REL files plus libraries), DLINK.LKS file (12 bytes for each UNIQUE entry/external symbol), and two locator scratch files (each with 12 bytes per symbol reference/definition). DLINK inputs and the DLOC output do not need to be on the default drive. Part IV - DLINK: Care and Feeding When invoked, DLINK will announce itself and prompt for a command. The commands are: L - load file This command causes the specified file to be loaded into the output file and any externals or entries to be noted in the symbol file. ALL modules in the file will be loaded, so don't LOAD a library unless you really want to! S - search library This command causes the specified file to be searched for entries that can be used to satisfy outstanding external references. If found, the associated program module in the library is loaded to the output file and the symbol table is updated. Note: the Microsoft compiler libraries seem to have been arranged so that a single pass through the file is sufficient to find all references. If you build your own libraries and routines reference each other, you may require multiple passes. DLINK does not perform multiple passes, but leaves the decision to the user. M - map This command causes the symbol table to be printed on the consol device. Satisfied references are simply reported, while undefined or multiply defined items are noted as such. U - list undefined symbols This command is similar to the M command, except that only undefined and multiply defined items are listed. V - verbose mode toggle Entering this command alternately turns on and off the verbose mode. In this mode ALL link information in data sent to the output file and activity on the symbol file are reported to the consol. This feature is for debugging and for gathering information about program operation should the user need to report a BUG. The report is not pretty and does not do anything interesting for the user. Do not use the verbose mode unless you have a burning desire to watch information scrolling off your consol. E - exit program Closes all files and exits. DLINK reports any library requests to the consol when encountered, but does not record them internally. It does not automatically search for any libraries (as L80 does). You must feed it the proper libraries, if needed. DLINK reports each module scanned in the input file and whether it was loaded to the output file or skipped. This can cause a lot of dialog to the consol when scanning libraries, but its been left in for two reasons. First, it give the user a nice warm feeling that the program is, indeed, working and not just randomly exercising the disk. Second, it allows a way of aborting the program without resetting the processor: Press the control-S key on the consol and wait for disk activity to stop then press the control- C key. This will abort the program without trashing your disks. There are a few other reports generated, most are self-explanatory. Encountering an extension link item causes the program to halt. In addition, certain checks are made on other data fields in the input file. If any seem to be in conflict, DLINK will report an error and abort. Should any of these occur, you can first assume that your input file has been damaged somewhere along the line. Get a fresh copy from your (meticulously maintained) backup library and start again. There's a possibility that you (or your compiler) have managed to use the .REL file in some new way that I haven't anticipated. If the error report persists, report it (see below) and perhaps the new use can be supported! NOTE: DLINK does not "clean up" after itself if it aborts. This is done intentionally so that information necessary to do a post-mortem is maintained, so there will be disk files left behind. Finally, DLINK and DLOC expect you to be "honest" with them, so don't try to exit DLINK with undefined/multiple references and enter DLOC. DLOC will notice such things, but only at the end when the references are resolved. You'll just waste a lot of time if you do this! Part V - DLOC: Care and Feeding When invoked, DLOC will announce itself and begin tabulating the information left by DLINK. After this is done, DLOC will prompt for a command. The commands are: G - go Normally, you'll use only this command (and the N command). If you've set no other parameters, a CP/M object file will be created. Go starts the process of generating the memory image file. When the process is completed, DLOC returns to CP/M. B - file base address select This command allows you to optionally select the base address for the image file. This is set by default to 100h, so that the first byte of the file will be at 100h of the memory image (normal CP/M assumption). If you have a need, you can change it. For example, you may perform the MLOAD function with .REL files if you wish by using this command in combination with the P and D commands. P - set program and data address This command functions similarly to the P command of L80. The address specified with the P command is used to set both the DATA and PROGRAM origin. Use the D command to set the DATA origin separately. The PROGRAM/DATA origins default to 103h (same as L80). D - set data address This command functions similarly to the D command of L80. The address specified sets the DATA origin independently from the PROGRAM origin. Default is 103h. M - memory ($MEMRY) location toggle Microsoft uses a reserved symbol, $MEMRY, as a pointer to a 16-bit location into which L80 places the ADDRESS of the beginning of FREE memory. This feature is used by several compilers and some programmers. The rub is that L80 declares FREE MEMORY to be just PAST the last used DATA location. If you don't use any L80 controls, this will also be past the end of your program. If, however, you need to combine data segments using L80 and you place DATA lower in memory than PROGRAM, $MEMRY will point to the end of the DATA segment, and any use of MEMORY can step on the PROGRAM area. This is true of compiler-generated code and potentially true if you use Z-SYSTEM libraries in your home-grown applications (but not true of the Z-SYSTEM, itself). This command supplies a feature not supported by L80: the ability to specify where FREE MEMORY begins. In its default setting, FREE MEMORY is assigned to the HIGHEST available address in the memory image (what you probably want!) It may be toggled to be assigned to the end of the DATA segment (you'll want this if you're generating ROM-able code and DATA is physically lower in the target machine's address space). Z - zero fill selection This command allows the user to specify whether or not the DATA and PROGRAM segments will be filled with zeros prior to building the memory image. This default selection is ZERO FILL for the DATA segment only. This copies L80 functionality and should be used in most cases (especially when your compiler or application program expects that variables contain zeros when first referenced!) NO ZERO FILL of the DATA segment is useful when that segment is high in memory and you're SURE that your code doesn't expect variables to begin with zero values. In this case, you can reduce the size of the image file, as space is not consumed if the image area is not written to. A ZERO FILL for the PROGRAM segment has been provided beginning with version 1.1. Some commercial and PD linkers Zero fill the program segment, too. If you're one of those who "coded around" this feature and expect variables in your PROGRAM segment to be initially zero, you'll have to opt for this. If not, NO Zero Fill for the program segment keeps the image file as small as possible, as space is not consumed if trailing DSs in the PROGRAM are not initialized. E - force entry point Via this command, the user may optionally specify a starting point in the program created. This assumes that your settings of the B, P and D commands allow 3 bytes at the beginning of the image file for DLOC to put a JMP instruction. You may specify an address (in HEX) or a label (entry point in a module). The value input here is not validated until program end time... so type carefully or much time will be lost. The entry point (if there's room for the JMP) defaults to the beginning of the PROGRAM segment or the FIRST start address found in the input file. If the input file contains more than one start, the subsequent ones are ignored. This command is useful if you want program execution to begin at one of these ignored points! N - name output file Entering this command allows the user to select the name of the memory image file to be generated. The default is IMAGE.COM on the default drive. S - symbol map toggle This command toggles the symbol map ON and OFF. The default is OFF. The map, if selected, will be printed after all external references and offsets have been resolved. The map is useful in finding module addresses for debugging purposes. V - verbose mode toggle Entering this command alternately turns on and off the verbose mode. In this mode ALL link information in the DLINK.LKR file, ALL activity on the memory image file, and ALL operations performed during the sorting, linking and offsetting of ENTRY/EXTERN references are reported to the consol (a LOT of dialog!) This feature is for debugging and for gathering information about program operation should the user need to report a BUG. The report is not pretty and does not do anything interesting for the user. Do not use the verbose mode unless you have a burning desire to watch information scrolling off your consol. When supplying parameters to DLOC, DLOC will show you the current setting of that parameter in its prompt (enclosed in parentheses). You MUST supply a parameter, even if you don't want to change it. (A won't work). If you're trying to do something fancy with the B,P and D commands, you will get a warning message if one of the origins is below the file BASE. This is O.K. However, if any information is loaded BELOW the file BASE, an error is reported and DLOC aborts. For example, you may start the file at 8000h, set the program to 8000h, and set the data segment to 0. As long as your code puts no constants into the data segment this will work as expected. NOTE: in this case you MUST turn the zero-fill of the data segment OFF!) When generating a symbol map, DO NOT be alarmed when the symbol map does not appear to be in sorted order (especially since you just waited patiently for the sort to be performed.) The symbols ARE sorted according to the needs of the program -- not for the viewing pleasure of the user. (Actually, there IS a pattern that can be recognized if you try!) DLOC is not as wordy as DLINK, but various progress reports are provided. Error messages that you may encounter will have two sources: the user and program/data file brain damage. Errors that are user caused can occur because the user is not "honest" with DLINK/DLOC. DLOC has the same sanity checks on the input data files as DLINK, so giving an input file to DLOC that has, for example, undefined references will cause DLOC to generate an error message and stop. Brain damage to data files can cause DLOC to report an error and stop. The input data files are fully decoded by DLOC (that is, DLOC doesn't take for granted that the data is valid), so any truly nonsense information will eventually be trapped. Brain damage to DLOC will cause various internal errors. Examples are reports of errors during the SORT, ILLEGAL PARAMETER errors, etc. Get a fresh copy from your (meticulously maintained) backup library and start again. There's a possibility that you (or your compiler) have managed to use the .REL file in some new way that I haven't anticipated. If the error report persists, report it (see below) and perhaps the new use can be supported! NOTE: DLOC does not "clean up" after itself if it aborts. This is done intentionally so that information necessary to do a post-mortem is maintianed, so there will be disk files left behind. Part VI - Automated Operation Many will be unhappy that these programs do not accept any and all operational parameters from the command line tail. Although it's a relative PAIN not having single command line invocation, ALL input is buffered consol input and, as such, can be fed to the program via SUBMIT/XSUB, EX, or ZEX. Thus, a .SUB or .ZEX file can be quickly designed to supply the repetitive program input, avoid the possibility of erroneous keystrokes, and, in general, automate the use of DLINK and DLOC. Part VII - Fixes and Undocmented Features (BUGs) This is the first revision of these programs in 15 months. No BUG reports have been received in that time. This revision has occurred ONLY to add requested features. None the less, there may still be undocumented features lurking about. If you feel that you've found one, try to document it by turning on the VERBOSE mode and recording the output and saving your program source code, all .REL files, and the files left behind by DLINK/DLOC. Once this is done, describe the bug briefly in a note to me at the following RCP/M: Z-Node of San Diego 619-270-3148 to: Sysop I'll reply with advice and/or an address of where to send your info for examination. ALSO, anyone encountering an extension link item, or having documentation on their use will help greatly by contacting me in order to get the capability integrated into this package. Part VIII - CP/M There is a BUG in CP/M 2.2 related to random I/O. DLINK/DLOC use random I/O so you'd better fix it if it isn't already. This bug manifests itself by occasionally NOT writing the last block written to a data file to disk when the file is closed. The user finds that data gets "lost!" This bug is known by DRI and, although they haven't fixed it, they advise those who sell CP/M on how to fix it in their distribution copies. To find out if the patch is installed in your system, find out the base of your BDOS then, under DDT, examine the code at BDOS+0AD2 . If you see: NOP NOP LXI H,xxxx then the recommended patch is in. If you see: DCR C DCR C JNZ xxxx then the recommended patch isn't in. If you see anything else, then you're not using CP/M 2.2 or you've used the wrong address. If the patch is in, you're O.K. If the patch doesn't seem to be in AND you're experiencing problems, contact your computer vendor. I WILL NOT advise anyone to change their operating software or how to do it! If the patch doesn't seem to be in and you don't experience any problems then either you're using 128 byte/sector blocks on your disk (the problem won't occur in this case) or your vendor has shot the bug in some other way. Roger Warren, San Diego, CA May '87