L225.DOC Using .REL files with version 2.2.5 of the L2 linker. July 1984 When portions of a C program compiled with the BDS C compiler are to be implemented in assembly language, the present version of L2 provides an alternative to the use of CASM. Formerly, one had to prepare a .CRL file by running CASM, then assembling the resulting preprocessed file. Now the assembly language source file can be assembled with Microsoft's M80, and the .REL file produced by the assembler then linked directly with the other parts of the program. As an example, consider the following assembler source for a function which puts out a character, but substitutes a 'D' for any digit: ndput:: pop d pop h push h push d mov a,l cpi '0' jc .1 cpi '9'+1 jnc .1 mvi l,'D' .1: push h call putchar## pop d ret end Supposing the above text to be in a file NDPUT.MAC, then the procedure to assemble it and link it into a C program CND that calls this function is: A>m80 =ndput A>l2 cnd ndput.rel L2 determines that it is to load a .REL file instead of a .CRL file from the presence of the extension ".rel". L2 will also scan .REL file libraries that are put together using the library manager LIB. Here are some advantages of using M80 and the new version of L2 over the old way of incorporating assembly modules: (1) it's more convenient and straightforward (2) assembler syntax is more flexible (labels can be indented, '$' can be used) (3) conditional assembly instructions and macros are available (4) Z80 source code can be used (5) modules can have multiple entry points (6) assembly modules can make external reference to data in other assembly modules (not just callable functions) (7) an assembly module can request that a .REL file be scanned to satisfy its external references, through the use of the pseudo-operation '.request' (8) it is easier for C modules and assembly modules to make joint use of data in the external area of ram by the use of dseg's (cf. below) (9) external variables can be provided with initial values (also by using dseg's) On the other hand, the loading or scanning of .REL files by L2 is slightly slower than with .CRL files, and this version of L2 is larger by about 1 1/2k, making less ram available to hold the program being linked. M80 partions code into segments, viz. aseg's, cseg's, dseg's, and common. Version 2.2.5 of L2 can deal with only two of these -- cseg's and dseg's. The ordinary case is where code and data are in a cseg. The little example given above was like this, although the 'cseg' directive was not given explicitly. A dseg is useful when a function written in assembler and a C program both need to refer to the same external variable. Here is an example where a C program calls an assembly function to initialize a string to blanks: /* file tstblank.c */ #include char blanks[41]; main() { fillblank(); } ----------------------------- .comment * file fillblan.mac * fillblank:: lxi h,blanks mvi e,40 mvi a,' ' .1: mov m,a inx h dcr e jnz .1 mvi m,0 ret dseg ds 6 ;6 bytes used in bdscio.h blanks: ds 41 end ---------------------------- A>cc tstblank -e1000 A>m80 =fillblan A>l2 tstblank fillblan.rel In such a case, L2 equates the beginning of the dseg with the beginning of the external data area, which in this example was given as 1000H when the program was compiled. When dseg's are used, some address is ordinarily given using the compiler '-e' option, so that L2 can tell what offset to use for the data segment. When the C program was not compiled with the '-e' option, or when the main module is a .REL file, this address can be supplied to the linker using its '-e' option (new to this version): A>cc tstblank A>m80 =fillblan A>l2 tstblank -e 1000 fillblan.rel So long as dseg's contain only labels and 'ds' or 'org' directives, their use will have no impact on the length of the code file produced by L2; however, if any real data is put in a dseg with 'db' or 'dw' directives, the code file will have to be longer to accommodate it. In the following example, the blank initialized string will be incorporated into the .COM file: /* file noth.c */ #include char blanks[41]; main() { /* does nothing */ } ----------------------------- .comment * file exdata.mac * dseg ds 6 ;6 bytes used in bdscio.h rept 40 db ' ' endm db 0 end ---------------------------- A>cc noth -e1000 A>m80 =exdata A>l2 noth exdata.rel Like CLINK, this version of L2 has a '-z' option which prevents the zeroing of the external data area which ordinarily is done at the start of execution of a C program. It might seem that this option should have been used above -- i.e.: A>l2 noth -z exdata.rel It is ok to do this, but not necessary, since L2 would assume that the '-z' option was intended in any case. (Why zero out the initialization data before it can be used?) In the above example, an external symbol 'blanks::' could have been put in the assembly file, but this could not make any difference to the way the program works, unless there were another assembly module referring to this symbol. This is because names associated with external data are lost in the process of compilation. According to M80, external symbols have at most seven significant characters, whereas in .CRL files produced by the BDS C compiler the name of a function can have up to eight significant characters. This difference might occasionally cause a problem. In the first example given in this document, the statement "call putchar##" gives rise to a reference to the external symbol 'PUTCHAR?', where the '?' is wild -- it matches the end of another external symbol or any eighth character in another external symbol. So, if there happened to be a C function called 'putchart', e.g., this might be called instead of the intended function 'putchar'. L2 will not warn you about this. Nasty situation. In case there is an external data area defined through dseg's but not in a compiled main program in C, the linker will have to decide where the external data area ends according to what it finds in the dseg's. To make sure that it decides correctly, define a symbolic address at the end of the last data. E.g. dseg mpointer: ds 2 mbuffer: ds 80h dummy: end Without the symbol 'dummy', L2 would think the data area ended at the beginning of mbuffer, instead of at the end. Large programs that require a 2nd disk phase pass through the .CRL and .REL files and which also have initialization data defined in dseg's will sometimes require all code to be linked in before any dseg's are encountered, and it may also be necessary to arrange the data so that it will be loaded in order of increasing memory addresses. Finally, here are some notes about the source files for version 2.2.5 of L2: L2.C [perhaps called L225.C] The main program, adapted from David Kirkland's version (which came from Scott Layson's version). RDRL.MAC A function to read an item from a .REL file bit stream. SPR.MAC Assembly language version of the standard library function _spr, which is called by printf. Needs about 2 pages less code than the C version. (This and RDRL could fairly easily be converted to .CSM files -- some symbol names with '.' or '_' might have to be changed.) CHARIO.MAC Assembly language version of Scott Layson's CHARIO.C. Needs about 2 pages less code than the C version. BDS.LIB Include file for the .MAC functions. (This is the same as the standard version of this file, but has a few extra symbols defined.) There is a note on compilation and linking in L2.C. If you don't need to make a new L2.COM file, you can easily do so. Well, what I mean to say is that a version 2.2.5 of L2 can be most readily built up if a version 2.2.5 of L2 is already available, in which case the procedure is: A>m80 =rdrl A>m80 =spr A>m80 =chario A>cc l2 -e5100 A>l2 l2 rdrl.rel spr.rel chario.rel If the L2.COM [possibly called L225.OBJ] which accompanies this document is for some reason unusable, a version 2.2.5 could (I suppose) be brought up from the first two of these files and the original CHARIO.C by editing RDRL into .CSM format, and using CASM, ASM, and an older L2 or CLINK. The '-e' address would have to be adjusted upwards. I do not know how, or whether, this version of L2 works with CDB. I have no specific reason to think that it wouldn't work, but I haven't tried it. It is possible that .REL files produced by D.R.'s RMAC can be loaded by L2, but that's something else I haven't tried. Greg Lee 631B 10th Ave Honolulu, HI 96816