[Info-vax] Compatibility and 64-bit
David Froble
davef at tsoft-inc.com
Sun Mar 15 18:58:48 EDT 2015
JF Mezei wrote:
> On 15-03-15 03:08, David Froble wrote:
>
>> About the string descriptors ....
>
>
> Question:
>
> Say i have a C program.
>
> I define
>
> mydescriptor struct dsc$descriptor ; (forgot the actial precise name).
>
> That descriptor contains (from memory, pardon lack of precision)
>
> char type;
> char class;
> short lenght;
> void *pointer ; (or is it unsignec char *pointer ?)
>
>
> Why would my program care whether "pointer" was allocated as 4 or 8 bytes ?
>
> If the program is compiled with a switch that makes all pointers 64
> bits, then all my operations to move pointers around should be 64 bits
> and this is transparent to me.
>
> If I dynamically allocate memory to make an array of descriptors, then I
> will likely use sizeof(struct dsc$descriptor) when calculating how much
> memory to allocate, so whether compiled in 32 or 64 bits, the code will
> still work.
>
> And when I manipulate a pointer, I am expected to always use pointer
> variables, right ? I am NOT supposed to move a pointer to an integer,
> have fun with it as integer and then move it back to a pointer variable,
> right?
>
> Ever since VMS started to support both 32 and 64 bits, I have been weary
> of assuming the size of any variable and always use sizeof when I need
> to knwo it size.
>
> Yeah, when dealing with integers, you want to make sure you have the
> right incantation to have the right bit size. For instance, for VMS
> time, you can safely use a quadword, but if you know the language well
> enough, you can also allocate a 64 bit integer and do the math directly
> to it , instead of calling the routines that add/subtract time.
>
> But for pointers, I am not sure I understand where the problem is.
Some people do weird stuff ...
Consider:
.TITLE DAS_RECREAD Read record by record number
.IDENT /1-001/
;++
;
; Copyright (C) 1984 by Dave Froble Enterprises, Inc.
;
; Facility: Database Access System (DAS)
;
; Abstract:
;
; This subroutine reads the data record specified from a DAS file.
; The record is labelled by a dynamic string array specified.
;
; Modifications:
;
; 10-MAY-1984 DAS Original
;
; Argument list format:
;
; (AP) = Argument count
; 4(AP) = Address of a longword containing a user channel #
; 8(AP) = Address of a longword specifying the record # to read
; 12(AP) = Address of a longword containing processing options:
; Bit 0: Set to leave record locked after read
; Bit 1: Set to force disk seek
; Bit 2: Set to inhibit record labeling
; 16(AP) = Address of the descriptor of the dynamic string array to
; use to label the record. This parameter may be omitted
; when the processing options inhibit labeling.
Ok, here is something non-standard. The address of an array descriptor,
for an array of string descriptors. These things are going to be used
as labels in an I/O buffer.
; 20(AP) = Address of a longword to receive completion status
;--
.PSECT DAS_PURECODE,CON,EXE,GBL,NOWRT,PIC,RD,REL,SHR,PAGE
.ENTRY DAS_RECREAD,^M<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>
TSTL (AP)+ ; Skip argument count
MOVL @(AP)+,R2 ; Channel number
MOVL @(AP)+,R3 ; Record number
MOVL @(AP)+,R4 ; Processing options
MOVL (AP)+,R5 ; Address of labeling descriptor
; AP -> Address for completion code
.GETIFDA CHAN=R2, IFDA=R9 ; Validate channel & get IFDA
address
MOVL #DAS_IVRECNUM,R0 ; Assume failure
TSTL R3 ; Record index zero?
BEQLU 000$ ; Yes, return with error
CMPL IFDA_L_MAXREC(R9),R3 ; Within file's limitations
(records)?
BGEQU 010$ ; Yes, continue
000$: BRW RETURN ; Branch aid to 'RETURN'
;+
; Calculate the block # containing the record
; & base of segment for MBC
; & offset in buffer (blocks) to block containing record
; & offset if block (records) to record
;-
010$: SUBL3 #1,R3,R6 ; Offset (records) to record
DIVL2 IFDA_L_RECBLK(R9),R6 ; Offset (blocks) to record
DIVL3 IFDA_L_ORGMBC(R9),R6,R7 ; Offset (buffers) to block
MULL2 IFDA_L_ORGMBC(R9),R7 ; Base of segment-1
SUBL3 R7,R6,R8 ; Block offset in buffer to record
MULL3 IFDA_L_RECBLK(R9),R6,R10 ; Offset in blocked record to
record
SUBL3 R10,R3,R6 ; Offset+1 in block to record
(records)
DECL R6 ; Offset in block to record
(records)
INCL R7 ; Base VBN of segment
ADDL2 IFDA_L_DATOFF(R9),R7 ; Don't forget data offset
ASHL #9,R8,R8 ; Make block offset bytes
MULL2 IFDA_L_RECLEN(R9),R6 ; Make record offset bytes
ADDL2 R8,R6 ; Total byte offset in buffer
to record
MOVL R6,IFDA_L_RECOFF(R9) ; Set current record offset
;+
; A seek must be done if:
;
; * The processing options force a seek
; * The record requested is not in the incore segment
; * The record requested is in the incore segment, the incore segment
; is unlocked by the current process, and the processing options
; specify that the record should be left locked.
;-
100$: BBS #1,R4,200$ ; Force seek
CMPL R7,IFDA_L_CURDBK(R9) ; Is the required segment incore?
BNEQU 200$ ; No, seek
BBC #0,R4,110$ ; Use incore buffer if no lock req.
.VDACHLK CHAN=R2, VBN=R7, NBLOCKS=IFDA_L_ORGMBC(R9)
BLBC R0,200$ ; Incore segment not locked, seek
110$: BRW 230$ ; Skip over seek stuff
; Also branch aid to skip seek
;+
; Do a disk read for the buffer required:
;
; * Write the current incore buffer if the pending write flag is set
; * Unlock the current segment (always)
; * Lock the segment if requested
; * Read the required segment
;
;-
200$: BBC #0,IFDA_L_CFLAGS(R9),210$
MOVL R2,WRK_L_CURCHN ; Set channel number
PUSHL (AP) ; Address of completion code
PUSHAL WRK_L_CURCHN ; Address of channel number
CALLS #2,G^DAS_RECUPD ; Write incore segment
TSTL R0 ; Error?
BNEQU 000$ ; Return on error
210$: .VDAUNLK CHAN=R2 ; Unlock current segment
BLBS R0,215$ ; Continue if successful
BRW ERRORS ; Return on error
215$: BBC #0,R4,220$ ; Skip locking if not requested
.VDALOCK CHAN=R2, VBN=R7, NBLOCKS=IFDA_L_ORGMBC(R9)
BLBS R0,220$ ; Continue unless error
BRW RETURN ; Else return
220$: .VGET CHAN=R2, VBN=R7, NBLOCKS=IFDA_L_ORGMBC(R9), -
BUFADR=@IFDA_L_DABADR(R9), RCOUNT=IFDA_L_RCOUNT(R9)
BLBS R0,230$ ; Continue if no errors
PUSHL R0 ; Preserve error code
.VDAUNLK CHAN=R2 ; Else unlock D/A on error
POPL R0 ; Restore error code
225$: BRW RETURN ; Return error
230$: MOVL R7,IFDA_L_CURDBK(R9) ; Remember current data block
MOVL R3,IFDA_L_CURREC(R9) ; Remember current record
ADDL2 IFDA_L_DABADR(R9),R6 ; Virtual address of record in
memory
BBS #2,R4,400$ ; Don't do labeling
;+
; Label the data record
;-
At this point the descriptors are tested, and if they pass the tests,
then the code steps through each field in the data record, and sets the
address and length into each respective string descriptor int he array
of descriptors.
Now, could the descriptors be analyzed to determine what and where the
appropriate data is in the descriptor, and the size of the pointer?
Don't know, never researched it. But you can see, some pretty strong
assumptions are made. Length of the pointer. Location of the pointer.
MOVL #DAS_IVLABARR,R0 ; Assume failure
CMPB #DSC$K_CLASS_A,DSC$B_CLASS(R5) ; Array descriptor?
BNEQU 225$ ; No, return
CMPB #DSC$K_DTYPE_DSC,DSC$B_DTYPE(R5) ; Array of descriptors?
BNEQU 225$ ; No, return
CMPB #1,DSC$B_DIMCT(R5) ; One dimensional?
BNEQU 225$ ; Exit if not
CMPL IFDA_L_NUMFLD(R9),DSC$L_M1(R5) ; Large enough?
BGEQU RETURN ; No, return
MOVL IFDA_L_NUMFLD(R9),R7 ; # of fields to label
MOVAW IFDA_W_FLDOFF(R9),R10 ; Field offsets
MOVAW IFDA_W_FLDLEN(R9),R11 ; Fields lengths
MOVL DSC$A_POINTER(R5),R8 ; Address of first descriptor
;+
; Field element zero of the array
;-
CMPB #DSC$K_CLASS_S,DSC$B_CLASS(R8) ; Scalar string?
BEQLU 250$ ; Yes, continue
TSTW DSC$W_LENGTH(R8) ; Space allocated to this string?
BEQLU 240$ ; No, continue
MOVL #DAS_IVLABARR,R0 ; Set completion code
BRW RETURN ; Return
240$: MOVB #DSC$K_CLASS_S,DSC$B_CLASS(R8) ; Mark string as scalar
250$: MOVL R6,DSC$A_POINTER(R8) ; Offset in record this field
MOVW IFDA_L_RECLEN(R9),DSC$W_LENGTH(R8) ; Set length of
field into dr
ADDL2 #8,R8 ; Point to next descriptor
300$: CMPB #DSC$K_CLASS_S,DSC$B_CLASS(R8) ; Scalar string?
BEQLU 320$ ; Yes, continue
TSTW DSC$W_LENGTH(R8) ; Space allocated to this string?
BEQLU 310$ ; No, continue
MOVL #DAS_IVLABARR,R0 ; Set completion code
BRW RETURN ; Return
310$: MOVB #DSC$K_CLASS_S,DSC$B_CLASS(R8) ; Mark string as scalar
320$: MOVZWL (R10)+,DSC$A_POINTER(R8) ; Offset in record this field
ADDL2 R6,DSC$A_POINTER(R8) ; From start of record
MOVW (R11)+,DSC$W_LENGTH(R8) ; Set length of field into
descriptor
ADDL2 #8,R8 ; Point to next descriptor
Consider that assumption, the total size of the descriptor ...
SOBGTR R7,300$ ; Loop for the count
400$: CLRL R0 ; Set completion code
MOVL IFDA_L_DELFLD(R9),R7 ; Delete field index
BEQLU RETURN ; None, exit
DECL R7 ; Adjust for indexing
MOVZWL IFDA_W_FLDOFF(R9)[R7],R7 ; Offset in record to delete field
CMPB #255,(R6)[R7] ; Deleted record?
BNEQU RETURN ; No, return
MOVL #DAS_RECDEL,R0 ; Yes, set error code
BRB RETURN ; Return
ERRORS:
RETURN: MOVL R0,@(AP) ; Return completion code
RET
.END
This is just one example. The people still on VMS just may have similar
things, that made any idea of a port, a hard sell, and, make the loss of
compatibility a serious issue.
Probably the biggest and first offender was the MACRO-32 compiler. We
know why it was developed. But it extended the life of the VAX
environment and software.
I know what Steve is saying, and I understand. But the other side of
the issue is the many VMS systems running production with stuff like the
above, and how useless those systems become if their applications stop
running.
Things like DAS were a decent product in 1984. That doesn't hold for
2015, and I myself can make a good argument for replacing it with a
modern database. But, that isn't an easy, nor inexpensive, thing to do.
And the current users are still getting what they need. There is no
business argument for such a change.
Now extend that to many other VMS sites, and perhaps you can see the
problem with throwing out the baby with the bath water.
More information about the Info-vax
mailing list