title Link conversion name ('CLINK') maclib base80 ; Program CLINK ; Copyright (C) Werner Cirsovius ; Hohe Weide 44 ; D-2000 Hamburg 20 ; Tel.:+49/040 4223247 ; Version 1.0, January 1986 ; Converts foreign link format to REL80-format. How to call: ; CLINK {d:}file{.ext} {[options]} entry $memry ext comp3,subhd2,indexa,shfrhl,string,tstlet,crlf ext open,close,delete,create,dskget,puteof,dskput ext rdbfp,wrfcb,wrbuf ; ; Descriptor bits within .OBJ records ; _WRD equ 00001b ; Word reference _DEF equ 00010b ; Defined here _GLOB equ 00100b ; Global _REL equ 01000b ; Relocatable _SHF equ 10000b ; Shift value ; OBJtype equ 1 ; Type of .OBJ item OBJattr equ OBJtype+1 ; Attribute of .OBJ item, start of bitmap OBJref equ OBJattr+1 ; Ref-addr of .OBJ item, name of module OBJglob equ OBJref+2 ; Name of GLOBAL OBJnlen equ 25 ; Max length of global OBJdat equ OBJglob+OBJnlen ; Header length before data ; SYMadr equ 2 ; Pointer to address SYMhd equ 4 ; Header length before symbol SYMlen equ 8 ; Length of symbol CLINK: ld sp,(TPAtop) ; Fetch top of memory for stack ld hl,($memry) ; Get first free address ld (HeapBase),hl ; Set up heap ld (HeapPtr),hl ld (hl),0 ; Clear it ld a,(CCPBUF) ; Get CCP line or a ; Test any there ld de,$NONAME jp z,IllStrg ; Nope, tell it ld a,(FCB+.fdrv) ; Get name of file call tstlet ; Test valid ld de,$ILLFILE jp c,IllStrg ; Nope, tell it ld de,FCB+.fdrv+.fname ld a,(de) cp ' ' ; Test file type given jr nz,SkpEXT ; Yeap ld hl,$OBJ ld bc,.fext ldir ; Give default .OBJ SkpEXT: ld de,FCB call open ; Open file ld de,$NOFILE jp c,IllStrg ; File not found ; ; *** PASS 1 *** ; ; Build symbols from .OBJ file ; PASS1: call RdOBJrec ; Read record from .OBJ file jp c,IllStrg ; Error ld hl,PASS1 push hl ; Set return address ld hl,Pass1Tab call indexa ; Get address from table ex de,hl jp (hl) ; Execute ; ; Type 4 : Reference ; P1.Ref: ld a,(OBJrec+OBJattr); Get attribute of .OBJ item and _GLOB ; Test global definition ret z ; Ignore if not set ld hl,(HeapPtr) ; Get heap pointer ld a,(OBJrec) ; Get length of .OBJ item dec a ; Fix length ld (hl),a ; Store into record dec a ld c,a ld b,0 inc hl ld a,(OBJrec+5) ; Get name of GLOBAL or MSB ; Mark it ld (OBJrec+OBJglob),a ld de,OBJrec+OBJattr; Point to attribute of .OBJ item ex de,hl ldir ; Unpack into heap ex de,hl ld (HeapPtr),hl ; Set heap pointer ld (hl),0 ; Indicate end ret ; ; Type 3 : Data record ; P1.Data: ld a,c ; Get length sub OBJdat ; Strip off header length ld c,a ; Make 16 bit ld b,0 ld hl,(CurrPC) ; Get current PC add hl,bc ; Calculate new one ld (CurrPC),hl ret ; ; Type 2 : Set PC ; P1.SetPC: ld a,(OBJrec+OBJattr); Get attribute of .OBJ item and _REL ; Test relocatble ret z ; Nope ld hl,(OBJrec+OBJref); Get ref-addr of .OBJ item ld (CurrPC),hl ; Set current PC ret ; ; Type 1 : Name of module ; P1.ModName: ld a,c ; Get length cp OBJref+1 ; Test range jr c,TakeFCB ; Empty name sub OBJref ; Strip off length ld (MODlen),a ; Save length of name ld c,a ld b,0 ld hl,OBJrec+OBJref; Point to name field of .OBJ item ld de,MODnam ; Point to name ldir ; Unpack it ret TakeFCB: ld hl,FCB+.fdrv ld de,MODnam ; Point to name ld b,.fname StFCBname: ld a,(hl) ld (de),a ; Unpack filename cp ' ' jr z,FCBrdy inc hl inc de djnz StFCBname FCBrdy: ld a,.fname sub b ; Build length ld (MODlen),a ; Save length of name ret ; ; Type 0 : End of file ; P1.EOF: pop af ; Clean stack ld a,c ; Get length cp OBJattr ; Verify correct one ld de,$CODERR jp nz,IllStrg ; Invalid coded file ; ld a,reclng ld (rdbfp),a ; Force read ld hl,FCBout ld (wrfcb),hl ; Set FCB for output ld hl,DMAout ld (wrbuf),hl ; Set disk buffer ld hl,FCB ld de,FCBout ld bc,.fdrv+.fname ldir ; Unpack name of file ld hl,$REL ld bc,.fext ldir ; Force extension .REL ld de,FCBout call delete ; Delete file call create ; Create file ld de,$NOCREC jp c,IllStrg ; Cannot create it ld de,FCB call open ; Open file again call Put.1 ; Put control bit to .REL file ld a,0010b call Put.MS_link ; Put program name to .REL file ld a,(MODlen) ; Get length of name ld b,a call Put.xxx ; Put to .REL file ld hl,MODnam ; Point to name of file PutMOD: ld a,(hl) call Put.Byte ; Put byte to .REL file inc hl djnz PutMOD call ENT.symbols ; Put entry symbols to .REL file call Put.1 ; Put control bit to .REL file ld a,1010b call Put.MS_link ; Put data size to .REL file ld a,00b call Put.xx ; Put two bits to .REL file ld hl,0 call Put.Word ; Put zero to .REL file call Put.1 ; Put control bit to .REL file ld a,1101b call Put.MS_link ; Put program size to .REL file ld a,01b call Put.xx ; Put two bits to .REL file ld hl,(CurrPC) ; Get current PC call Put.Word ; Put it to .REL file ld hl,0 ld (CurrPC),hl ; Clear current PC ; ; *** PASS 2 *** ; ; Build .REL file ; PASS2: call RdOBJrec ; Read record from .OBJ file ld hl,PASS2 push hl ; Set return address ld hl,Pass2Tab call indexa ; Get address from table ex de,hl jp (hl) ; ; Type 4 : Reference ; P2.Ref: ret ; Not used on pass 2 ; ; Type 3 : Data record ; P2.Data: ld a,(OBJrec) ; Get length of .OBJ item sub OBJdat ; Strip off header length ld (OBJdatlen),a ; Save length ld a,0 ld (BitmapIdx),a ; Init bitmap index ld a,MSB ld (DatRELbit),a ; Init relocation bit ld hl,OBJrec+OBJdat ld (CurDatAdr),hl ; Init address of data NextData: ld a,(BitmapIdx) ; Get bitmap index ld c,a ld b,0 ld hl,OBJrec+OBJattr; Point to bitmap of .OBJ data item add hl,bc ; Point to current bitmap ld a,(DatRELbit) ; Get relocation bit and (hl) ; Mask it jr z,AbsData ; Not to be relocated ; ; Relocateable address reference found ; ld hl,(CurDatAdr) ; Get address of data ld e,(hl) ; Fetch address inc hl ld d,(hl) inc hl ld (CurDatAdr),hl RelWord: call Put.1 ; Put control bit to .REL file ld a,01b ; Set program relative call Put.xx ; Put two bits to .REL file ex de,hl call Put.Word ; Put word to .REL file call Update ; Update values jr UpdateData ; Update twice ; ; Absolute address reference found ; AbsData: call FindPC ; Find current PC in table jp c,ConstData ; Yeap, got it call Put.0 ; Put constant bit to .REL file ld hl,(CurDatAdr) ; Get address of data ld a,(hl) inc hl ld (CurDatAdr),hl call Put.Byte ; Put byte to .REL file jr UpdateData ; ; Constant byte found ; ConstData: call FindCurSym ; Find current symbol push hl pop bc ld hl,(CurDatAdr) ; Get address of data ld e,(hl) inc hl ld d,(hl) inc hl ld (CurDatAdr),hl jr c,SYMData ; Current symbol found ld a,e ; Test offset or d jr z,NoOffsData ; Nope call Put.1 ; Put control bit to .REL file ld a,1001b call Put.MS_link ; Put external offset to .REL file ld a,00b call Put.xx ; Put two bits to .REL file ex de,hl call Put.Word ; Put word to .REL file NoOffsData: call Put.0 ; Put constant bit to .REL file ld a,0 call Put.Byte ; Put byte to .REL file call Put.0 ; Put constant bit to .REL file ld a,0 call Put.Byte ; Put byte to .REL file call Update ; Update values UpdateData: call Update ; Update values jr nz,NextData ; Still more data ret SYMData: ld hl,SYMadr add hl,bc ; Point to address ld e,(hl) ; Fetch it inc hl ld d,(hl) jr RelWord ; Put into .REL file ; ; Type 2 : Set PC ; P2.SetPC: call Put.1 ; Put control bit to .REL file ld a,1011b call Put.MS_link ; Put PC setting to .REL file ld a,01b call Put.xx ; Put two bits to .REL file ld hl,(OBJrec+OBJref); Get ref-addr of .OBJ item ld (CurrPC),hl ; Set current PC call Put.Word ; Put it to .REL file ret ; ; Type 1 : Name of module ; P2.ModName: ret ; Not used on pass 2 ; ; Type 0 : End of file ; P2.EOF: pop af ; Clean stack call ENT.definitions ; Put entry definitions to .REL file call EXT.chn ; Put external chain to .REL file call Put.1 ; Put control bit to .REL file ld a,1110b call Put.MS_link ; Put end of module to .REL file ld a,00b call Put.xx ; Put two bits to .REL file ld hl,0 call Put.Word ; Put zero to .REL file call EmptyByte ; Write remaining bits to .REL file call Put.1 ; Put control bit to .REL file ld a,1111b call Put.MS_link ; Put end of file to .REL file call EmptyByte ; Write remaining bits to .REL file call puteof ; Put eof to file jp c,WrtError ; Write error ld de,FCBout call close ; Close file ld de,$DONE jr nc,IllStrg ; Well done, tell success ld de,FCBout call delete ; Delete file ld de,$NOCLOSE ; Cannot close file ; ; Give final message and exit ; IllStrg: call string call crlf ; Give new line jp OS ; Exit ; ; Read record from .OBJ file - C set indicates error ; Return type in Accu and length in Reg C ; RdOBJrec: call dskget ; Read byte from file jr c,RdErr ; End of file, error ld hl,OBJrec ; Init record pointer ld c,a ; Save length RdLoop: ld (hl),a ; Store into record inc hl dec c ; Test end jr z,RdDone ; Yeap call dskget ; Read byte from file jr nc,RdLoop ; Loop on success RdErr: ld de,$RDERR ret RdDone: ld a,(OBJrec) ; Get back length ld c,a ld a,(OBJrec+OBJtype); Get type cp 4+1 ; Verify correct range ccf ret nc ; Yeap ld de,$CODERR ; Else return code error ret ; ; Update data values - Z set indicates end of data ; Update: ld hl,(CurrPC) ; Get current PC inc hl ; Update it ld (CurrPC),hl ld a,(DatRELbit) ; Get relocation bit or a rra ; Shift into next position ld (DatRELbit),a or a ; Test bits done jr nz,MoreBits ; Nope ld a,MSB ld (DatRELbit),a ; Init relocation bit ld a,(BitmapIdx) ; Get bitmap index inc a ; Update to next map ld (BitmapIdx),a MoreBits: ld a,(OBJdatlen) ; Get length dec a ; Count down ld (OBJdatlen),a ret ; ; Put control bit to .REL file ; Put.1: ld a,1 ; Set bit ld c,1 ; Set count jr Put.Bits ; Put to .REL file ; ; Put constant bit to .REL file ; Put.0: ld a,0 ; Set bit ld c,1 ; Set count jr Put.Bits ; Put to .REL file ; ; Put two bits to .REL file ; Put.xx: ld c,2 ; Set count jr Put.Bits ; Put to .REL file ; ; Put three bits to .REL file ; Put.xxx: ld c,3 ; Set count jr Put.Bits ; Put to .REL file ; ; Put link item to .REL file ; Put.MS_link: push af ld a,00b call Put.xx ; Give prefix pop af ld c,4 jr Put.Bits ; Put item ; ; Put word to .REL file ; Put.Word: ld a,l ; Get lo call Put.Byte ; Put byte to .REL file ld a,h ; Then get hi ; ; Put byte to .REL file ; Put.Byte: ld c,8 ; Set count ; ; Put C bits in Accu to .REL file ; Put.Bits: push de ld e,a ; Save bits ld a,(RELbits) ; Get bit count add a,c ; Add bits cp 8+1 ; Test more than byte jr nc,MoreThanByte ; Yeap ld (RELbits),a ; Save count ld d,a ld a,8 sub d ; Calculate bits to be shifted jr z,ByteBoundary ; It is on byte boundary ShiftByte: rlc e ; Shift bit dec a jr nz,ShiftByte ByteBoundary: ld a,(RELbyte) ; Get current byte or e ; Insert it ld (RELbyte),a pop de ld a,(RELbits) ; Get bit count cp 8 ; Test byte filled ret nz ; Nope ld a,(RELbyte) ; Get current byte ld c,a ld a,0 ld (RELbyte),a ; Clear byte ld (RELbits),a ; Clear bit count ld a,c WrByte: call dskput ; Put byte to file ret nc ; Success ; ; File write error ; WrtError: ld de,FCBout call delete ; Delete file ld de,$WRERR call string ; Tell it call crlf ; Give new line jp OS ; Exit ; ; Process bit write to .REL file if more than 8 bits ; MoreThanByte: push hl ld h,e ; Expand bits ld l,0 sub 8 ; Calculate remaining bits ld (RELbits),a ; Save ld d,a PosByte: call shfrhl ; Shift HL right dec d jr nz,PosByte ld a,(RELbyte) ; Get current byte or h ; Insert bits ld h,a ld a,l ; Get current value ld (RELbyte),a ; Save ld a,h pop hl pop de jr WrByte ; Write byte to file ; ; Write remaining bits to .REL file ; EmptyByte: ld a,(RELbits) ; Get bit count cp 0 ; Test empty ret z ; Yeap ld a,(RELbyte) ; Get current byte ld c,a ld a,0 ld (RELbits),a ; Clear count ld (RELbyte),a ; Clear byte ld a,c jr WrByte ; Write bits ; ; Put entry symbols to .REL file ; ENT.symbols: ld a,FALSE jr ENT.go ; ; Put entry definitions to .REL file ; ENT.definitions: ld a,TRUE ENT.go: ld (ENTtype),a ; Set type ld hl,(HeapBase) ; Get base of free space ENT.defloop: ld a,(hl) ; Get length of symbol or a ret z ; Empty, was last entry inc hl ld a,(hl) dec hl and _DEF ; Test definition jr z,ENT.nxt ; Nope, skip call Put.1 ; Put control bit to .REL file ld a,(ENTtype) cp FALSE ; Test entry symbols jr z,do.symbol ; Yeap ; ; Process entry definitions ; ld a,0111b call Put.MS_link ; Put entry definition to .REL file ld a,01b call Put.xx ; Put two bits to .REL file push hl inc hl inc hl ld e,(hl) inc hl ld d,(hl) ex de,hl call Put.Word ; Put word to .REL file pop hl jr do.name ; Put name ; ; Process entry symbols ; do.symbol: ld a,0000b call Put.MS_link ; Put entry symbol to .REL file do.name: call ENT.name ; Put entry name to .REL file ENT.nxt: ld c,(hl) ; Fetch length ld b,0 add hl,bc ; Point to next symbol jr ENT.defloop ; Process it ; ; Put entry name to .REL file ; ENT.name: ld a,(hl) ; Get length sub SYMhd ; Less header ld b,a call Put.xxx ; Put to .REL file push hl ld de,SYMhd add hl,de ; Point to label name.loop: ld a,(hl) ; Get label character and NOMSB ; Less hi bit call Put.Byte ; Put byte to .REL file inc hl djnz name.loop pop hl ret ; ; Put external chain to .REL file ; EXT.chn: ld hl,(HeapBase) ; Get base of free space EXT.chnloop: ld a,(hl) ; Get length or a ret z ; End if zero inc hl ld a,(hl) ; Get type and _DEF ; Test defined here dec hl jr nz,EXT.nxt ; Yeap EXT.symbol: call FindSymbol ; Test symbol jr nc,EXT.symbol ; Not to be processesd push hl call Put.1 ; Put control bit to .REL file ld a,0110b call Put.MS_link ; Put external chain to .REL file ld a,01b call Put.xx ; Put two bits to .REL file inc hl inc hl ld e,(hl) inc hl ld d,(hl) ex de,hl call Put.Word ; Put word to .REL file pop hl call ENT.name ; Put entry name to .REL file EXT.nxt: ld c,(hl) ; Get length ld b,0 add hl,bc ; Point to next jr EXT.chnloop ; Process next ; ; Find current PC in table - C set says match ; FindPC: ld de,(CurrPC) ; Get current PC ld hl,(HeapBase) ; Get base of free space FindPCLoop: ld a,(hl) ; Get entry or a ; Test empty ret z ; Yeap push hl inc hl ld a,(hl) ; Get attribute and _DEF ; Test definition jr nz,NextPC ; Yeap, ignore inc hl ld a,e cp (hl) ; Compare address jr nz,NextPC ; Not found inc hl ld a,d cp (hl) jr nz,NextPC pop hl scf ; Indicate address found ret NextPC: pop hl ld c,(hl) ; Get length ld b,0 add hl,bc ; Point to next jr FindPCLoop ; Process next ; ; Find current symbol - C set says match ; FindCurSym: push hl ; Save pointer call UnpackSYM ; Unpack symbol pop hl FindCurLoop: push hl ex de,hl ld hl,(HeapBase) ; Get base of free space call subhd2 ; Subtract HL-DE pop hl ret z ; End if start reached FindGLOBAL: dec hl ld a,(hl) and MSB ; Position to global jr z,FindGLOBAL push hl pop de ld bc,-SYMhd add hl,bc ; Position to start of item push hl ex de,hl call CmpSYM ; Compare to current symbol pop hl jr nz,FindCurLoop ; No match, try next scf ret ; ; Find symbol - C set indicates not found ; FindSymbol: call UnpackSYM ; Unpack symbol ld (TempSym),hl ; Save symbol address FindSymLoop: ld a,(hl) ; Get entry or a ; Test end jr nz,FindSymNext ; Nope ld hl,(TempSym) ; Get back symbol address scf ; Indicate end ret FindSymNext: ld c,(hl) ; Get length ld b,0 add hl,bc ; Point to next push hl ld de,SYMhd add hl,de ; Point to symbol call CmpSYM ; Compare to current symbol pop hl push hl pop de ld c,(hl) ; Get length ld b,0 add hl,bc ; Point to next jr nz,FindSymLoop ; No match ex de,hl ; Get address if so or a ret ; ; Compare ^HL to current symbol - Z set if found ; CmpSYM: ld de,SYMcopy ; Point to symbol ld a,(SYMlength) ; Get length of symbol ld c,a call comp3 ; Compare elements ret ; ; Unpack symbol ; UnpackSYM: push hl ld a,(hl) ; Get length sub SYMhd ; Strip off header length ld (SYMlength),a ; Save length ld c,a ld b,0 ld de,SYMhd add hl,de ; Point to symbol ld de,SYMcopy ; Point to symbol buffer ldir ; Unpack symbol pop hl ret dseg $NONAME: db 'File name required',eot $ILLFILE: db 'Illegal file name',eot $NOFILE: db 'File not found',eot $CODERR: db 'Code error',eot $NOCREC: db 'Cannot create file',eot $NOCLOSE: db 'Cannot close file',eot $DONE: db 'Conversion done',eot $RDERR: db 'File read error',eot $WRERR: db 'File write error',eot $OBJ: db 'OBJ' $REL: db 'REL' Pass1Tab: dw P1.EOF,P1.ModName,P1.SetPC,P1.Data,P1.Ref Pass2Tab: dw P2.EOF,P2.ModName,P2.SetPC,P2.Data,P2.Ref $memry: dw 0 HeapBase: dw 0 ; Base of free space HeapPtr: dw 0 ; Heap pointer CurrPC: dw 0 ; Current PC RELbits: db 0 ; .REL file bit count RELbyte: db 0 ; .REL file byte TempSym: dw 0 ; Temp symbol pointer SYMlength: db 0 ; Length of symbol SYMcopy: ds SYMlen ; Copy of symbol OBJdatlen: db 0 ; Length of .OBJ data record BitmapIdx: db 0 ; Bitmap index DatRELbit: db 0 ; Data record relocation bit CurDatAdr: dw 0 ; Current address of data ENTtype: db FALSE ; ENTRY flag MODlen: db 0 ; Length of module name MODnam: ds .fname+2 ; Module name ; ; Object data record - max is 254 bytes ; OBJrec: ds 1 ; + 0 : Length of .OBJ item ds 1 ; + 1 : Type of .OBJ item ds 1 ; + 2 : Attribute of .OBJ item, start of bitmap ds 2 ; + 3 : Ref-addr of .OBJ item, name of module ds 25 ; + 5 : Name of GLOBAL ds 224 ; +30 : Start of data ; FCBout: ds fcblen DMAout: ds reclng end CLINK