[comp.os.vms] Are Transfer Vectors Truly Useful When Creating Shareable Images?

forrest@blia.BLI.COM (Jon Forrest) (07/17/87)

This is something that's been on my mind for a while. I'd like to
talk this through to see if any of you can find something wrong in what
I'm thinking.

The software product my group produces consists partially of
shareable images. Most system managers and users expect shareable
images they receive to be upward compatable, that is, they
don't expect to have to relink with new shareable images
when a new version of a software product arrives. This is because
most shareable images begin with a series of transfer vectors
which allow new versions of shareable images to replace old
ones without relinking for reasons that are documented in
the LINKER manual.

Transfer vectors work fine as long as the only difference
between shareable images is the size of the code size of the
routines in the shareable image. What concerns me is the effect
of a change in the size of any global data structures represented
by universal symbols. It appears to me that such changes would result
in incorrect addresses being used when data appearing after the enlarged
structure is referenced.

For example, let's say that a sharable image contains variable A which
is 10 bytes long and begins at location 100 and variable B which is
20 bytes long and begins at location 110. We can assume both are
universal symbols. The user links an application program that references
both variables with this sharable image. Everything works fine. 
Meanwhile, the software developer who sold the user the shareable
image modifies variable A so that it now is 20 bytes long. This
means that variable A begins at 100, as before, but now variable
B now begins at location 120. Then, the user receives this new
shareable image and, much to his consternation, finds that his
program bombs every time he references location B.

The answer to this problem is probably that the major G.S. match id
should be incremented whenever such a situation occurrs. This, of
course, would require that the application be relinked, which negates
one of the primary benefits of sharable images. Indeed, my company
doesn't even bother with transfer vectors because keeping track of
the sizes of all data structures for which universal symbols exist
is simply too difficult. Unfortunately, users of our software must
relink with each release.

What is actually needed is a "transfer vector" for universal symbols
in addition to entry points. If such a thing were to exist then
universal data could be modified at will. Unfortunately, I can't think
of a way to implement transfer vectors for data without major
modification of the linker.

Have any of you faced this problem? If so, what did you do?
One person I discussed this problem with recommended that
universal symbols never be used directly but instead, a function
would be created whose job it is to return the address of a
universal symbol. This function could be called in a initialization
routine at the beginning of an application so that pointers
to universal symbols could be set before they are used later
in the program.

I'd like to hear anyone's response to this problem.

Jon Forrest

forrest@blia.BLI.COM
ucbvax!mtxinu!blia!forrest
{pyramid|voder}!blia!forrest

rcb@rti.UUCP (Random) (07/17/87)

In article <2961@blia.BLI.COM> forrest@blia.BLI.COM (Jon Forrest) writes:
>For example, let's say that a sharable image contains variable A which
>is 10 bytes long and begins at location 100 and variable B which is
>20 bytes long and begins at location 110. We can assume both are
>universal symbols. The user links an application program that references
>both variables with this sharable image. Everything works fine. 
>Meanwhile, the software developer who sold the user the shareable
>image modifies variable A so that it now is 20 bytes long. This
>means that variable A begins at 100, as before, but now variable
>B now begins at location 120. Then, the user receives this new
>shareable image and, much to his consternation, finds that his
>program bombs every time he references location B.

The solution is really simple. Have a section of code that will
always be at a fixed address and will contain pointers to the data structures.
The pointers will always be 4 bytes and the addresses won't change. You
can change the size of the structure and you could even change it 
at run time and the program won't care since it always accesses it through
the pointer that is in a known location. 
-- 
					Randy Buckland
					Research Triangle Institute
					rcb@rti.rti.org [128.109.139.2]
					{decvax,ihnp4,seismo}!mcnc!rti-sel!rcb

F1142S30%unika2@germany.CSNET (Juergen Renz) (07/21/87)

In article <2961@blia.BLI.COM> forrest@blia.BLI.COM (Jon Forrest) writes:
>For example, let's say that a sharable image contains variable A which
>is 10 bytes long and begins at location 100 and variable B which is
>20 bytes long and begins at location 110. We can assume both are
>universal symbols. The user links an application program that references
>both variables with this sharable image. Everything works fine.
>Meanwhile, the software developer who sold the user the shareable
>image modifies variable A so that it now is 20 bytes long. This
>means that variable A begins at 100, as before, but now variable
>B now begins at location 120. Then, the user receives this new
>shareable image and, much to his consternation, finds that his
>program bombs every time he references location B.

Randy Buckland answers:
>The solution is really simple. Have a section of code that will
>always be at a fixed address and will contain pointers to the data structures.
>The pointers will always be 4 bytes and the addresses won't change. You
>can change the size of the structure and you could even change it
>at run time and the program won't care since it always accesses it through
>the pointer that is in a known location.

Your wrong Randy !
One transfer vector takes up to 8 bytes (entry routine):

        .transfer       routine
        .mask           routine
        jmp             L^routine+2

or at least 2 bytes (subroutine):

        .transfer       subroutine
        bsb             subroutine      ! this is not recommended

mostly it takes 6 bytes for subroutines:

        .transfer       subroutine
        jmp             L^subroutine

Refer to the MACRO reference manual for the complete information.

The great advantage of transfer vectors is:
  You need not recompile your programs, if a new version of the shared library
  is build, because the location of the vectors doesn't change.
  The location of the routines will mostly change.

Juergen Renz                                        Universitaet Karlsruhe
Falkengarten 7                                      Institut fuer Informatik IV
D-7530 Pforzheim
West-Germany

rcb@rti.UUCP (Random) (07/22/87)

In article <8707220428.AA22024@ucbvax.Berkeley.EDU> F1142S30%unika2@germany.CSNET (Juergen Renz) writes:
>In article <2961@blia.BLI.COM> forrest@blia.BLI.COM (Jon Forrest) writes:
>Randy Buckland answers:
>>...
>>The pointers will always be 4 bytes and the addresses won't change. ...
>
>Your wrong Randy !
>One transfer vector takes up to 8 bytes (entry routine):
>
>        .transfer       routine
>        .mask           routine
>        jmp             L^routine+2
>
>or at least 2 bytes (subroutine):
>
>        .transfer       subroutine
>        bsb             subroutine      ! this is not recommended
>
>mostly it takes 6 bytes for subroutines:
>
>        .transfer       subroutine
>        jmp             L^subroutine

Next time, try reading the article before flaming. I was not talking about
normal transfer vectors. I was talking about pointers doing the same kind of
job for global data in a shared image that transfer vectors do for procedures.
An example follows:

	.transfer	routine1
	.mask		routine1
	jmp		routine1+2

	.transfer	routine2
	.mask		routine2
	jmp		routine2+2

	data1_ptr::
	    .address	data1
	
	data2_ptr::
	    .address	data2
	
	data3_ptr::
	    .address	data3
	
	.transfer	routine3
	.mask		routine3
	jmp		routine3+3

This is not as easy as transfer vectors, but it will work. The transfer
vector for routine3 should probably have an ".align quad" in front
of it, but it is not needed. Then, in you code, you can simply use

	globalref int *data1_ptr;
	foo = *data1_ptr;

I hope this make things a little clearer.
-- 
					Randy Buckland
					Research Triangle Institute
					rcb@rti.rti.org [128.109.139.2]
					{decvax,ihnp4,seismo}!mcnc!rti-sel!rcb

bengtb@erix.UUCP (Bengt Baeverman) (07/25/87)

Keywords:


The easiest thing I can think of is using a vector, just like the transfer
vector, to access the data. All the UNIVERSAL symbols are really pointers to
the symbols you want to access.

This could be done with (macro) code looking like this:

	datavector:
	data1::	.address	_data1	; Pointer to _data1
	data2::	.address	_data2	; Pointer to _data2
		.
		.
		.
		.blkb	512 - < . - datavector >	; Fill a full page

	_data1:	.long	200
	_data2:	.long	100

This is much more efficient than using a routinecall for every data access.


				Bengt Baverman
				bengtb@erix.se

MCGUIRE@GRIN2.BITNET (07/27/87)

> Date:         25 Jul 87 16:34:27 GMT
> From:         Bengt Baeverman <mcvax!enea!erix!bengtb@seismo.css.gov>
> Subject:      Re: Are Transfer Vectors Truly Useful When Creating Shareable
>               Images?
>
> The easiest thing I can think of is using a vector, just like the transfer
> vector, to access the data. All the UNIVERSAL symbols are really pointers to
> the symbols you want to access.

In fact, you can even maintain compatibility if the data types change, if you
point to a descriptor instead of a data object.  For example, if you decide to
change a word to a longword in your shareable code, you can maintain backward
compatibility by supporting word arguments as long as you like, even while
writing new applications that pass longwords.  Of course, this requires you
to perform conditional branches and conversions based on the data type in the
descriptor.

Ed McGuire
Systems Coordinator
Grinnell College
MCGUIRE@GRIN2.BITNET