[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::c_plus_plus

Title:C++
Notice:Read 1.* and use keywords (e.g. SHOW KEY/FULL KIT_CXX_VAX_VMS)
Moderator:DECCXX::AMARTIN
Created:Fri Nov 06 1987
Last Modified:Thu Jun 05 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:3604
Total number of notes:18242

2365.0. "Questions about vectors in VMS sharable images" by ROKFRD::DDAVIES () Wed Jan 11 1995 14:17

T.RTitleUserPersonal
Name
DateLines
2365.1you are correctDECCXX::KIMMELWed Jan 11 1995 16:0622
2365.2must I change sourcesROKFRD::DDAVIESWed Jan 11 1995 17:1119
2365.3is this enough ?ROKFRD::DDAVIESFri Jan 13 1995 13:2739
2365.4working on itDECCXX::KIMMELFri Jan 13 1995 20:0523
2365.5and finally ...ROKFRD::DDAVIESSat Jan 14 1995 09:5112
2365.6hope I have this straight :-)DECCXX::KIMMELMon Jan 23 1995 11:1837
2365.7Exporting C++ data upwardly compatible on VAX/VMS...VAXCPU::michaudJeff Michaud - ObjectBrokerWed Mar 12 1997 01:1249
	Ok, I think I've found almost all the information I need to
	build upwardly compatible shareable images on both VAX/VMS and
	AXP/VMS, except for one thing mentioned in the linker utility
	manual for VAX/VMS:

"Universal Symbols that Represent Data

To provide upwardly compatible symbols that represent data locations, you must
also fix these locations within memory.  You can accomplish this by allocating
the data symbols at the end of the transfer vector file.  In this way, when
you fix the location of the transfer vector within an image, the data
locations also remain the same.  See Section 4.2.1.1 for more information."

	Section 4.2.1.1 is the section that follows immediately after the
	above paragraph is is titled "Creating a Transfer Vector (VAX Linking
	Only)".  The only example in this section is a transfer vector
	table, and no example of how to fix symbols that represent data.

	In our case we are trying to export 100+ pointers that are part of
	an industry standard API (ie. we can't change the API).  I've
	extracted just a couple of them here for to illustrate what exactly
	we need to export in an upwardly compatible fashion from our
	shareable image:

class CORBA {
    public:
	class TypeCode;
	typedef TypeCode * TypeCode_ptr;

	static const TypeCode_ptr _tc_null;
	static const TypeCode_ptr _tc_Principal;
}

	CORBA::_tc_null and CORBA::_tc_Principal are defined (storage is
	reserved for) in corba.cxx as such (do note the extra _ in the
	name of the variables these pointers point to):

const CORBA::TypeCode_ptr CORBA::_tc_null = &_tc__null;
const CORBA::TypeCode_ptr CORBA::_tc_Principal = &_tc__Principal;

	The mangled names for these two pointers are:

_TC_NULL__5CORBA
_TC_PRINCIPAL__5CORBA

	How do we "fix these locations within memory" from the .MAR
	source file?  All I understand is that I need some MACRO
	code between the last (does it really  have to be the last as
	long as offsets don't change?) transfer vector and the .END.
2365.8Took me longer than I expected to track this downHNDYMN::MCCARTHYA Quinn Martin ProductionWed Mar 12 1997 09:0649
Jeff,

I'll try to answer this by giving an example of what the class library does
to export "cout".

The below is simplified (hand expanded a large number of .macro directives)
and I may have left out some details:

    .EXTERNAL CXXL$GA_COUT_DATA 	; cout_data must exist somewhere
    .ALIGN QUAD

    .transfer CXXL$GA_COUT		
CXXL$GA_COUT::.ADDRESS	CXXL$GA_COUT_DATA ; cout now exists and points at _data

------------------------------------------------------------------------
Now, CXXL$GA_COUT_DATA is declared in a .cxx file (with the use of 
several #define macros, and the use of "extern_prefix") as

The actual code looks like this:

ostream_withassign __CXXL_XFER_DEF(cout);

Which ends up actually being this:

ostream_withassign CXXL$GA_COUT_DATA

The customers using this would include iostream.hxx which has it 
declared as (using, again strange #defines and __extern_prefix pragmas):

The code looks like this:

extern ostream_withassign __CXXL_XFER_DECL(cout);

which ends up being:

extern ostream_withassign &CXXL$GA_COUT;

And poof, there you have it.  

Our map file shows:

CXXL$GA_COUT as a Relocatable, Universal symbol declared in the macro file and
CXXL$GA_COUT_DATA as a relocatable symbol declared in the .cxx module.

and as the man on the tape always says 

  "good luck.  This tape will self destruct in five seconds"

bjm
2365.9Great, if you can add a level of indirection.WIBBIN::NOYCEPulling weeds, pickin' stonesWed Mar 12 1997 18:1230
Note that .8 defines a pointer in the MACRO file that refers to data
in some C++ source somewhere.  The user's code (after macro expansion)
refers directly to the pointer declared in the MACRO file.  This may or
may not meet Jeff's needs.  Note .8 does not provide a way to "move"
a definition to a new location in the transfer vector.

For the symbols shown in .7 (xxx::_tc_null and xxx::_tc_Principal)
you could eliminate the defining instance from your C++ code and write
it in MACRO instead.  Something like:

_TC_NULL__5CORBA::
	.ADDRESS _TC__NULL
_TC_PRINCIPAL__5CORBA::
	.ADDRESS _TC__PRINCIPAL

where I've blindly assumed that the initial value is globally visible
and doesn't have any namespace problems or mangling.

The other approach is to make sure that your C++ code that provides
the static definitions ends up placing them in the right order at the
right location.  Can C++ use a "#pragma data_psect" or something to
control that?

The basic requirement for upward compatibility on OpenVMS VAX is that
the offset of a symbol from the start of the shareable image remain
the same as you make updates to your shareable image.

It's a little easier on OpenVMS Alpha -- you just need to ensure that
the same ordinal position in the symbol vector is always used for the
same symbol as you make updates to your shareable image.
2365.10VAXCPU::michaudJeff Michaud - ObjectBrokerWed Mar 12 1997 20:4741
> For the symbols shown in .7 (xxx::_tc_null and xxx::_tc_Principal)
> you could eliminate the defining instance from your C++ code and write
> it in MACRO instead.  Something like:
> 
> _TC_NULL__5CORBA::
> 	.ADDRESS _TC__NULL
> _TC_PRINCIPAL__5CORBA::
> 	.ADDRESS _TC__PRINCIPAL

	This does look interesting.  The only question/possible problem
	I see is that without a .TRANSFER directive the assembler won't
	create a linker directive record to make the symbol UNIVERSAL
	automatically like for the procedures in the transfer vector.
	And from the linker documentation it's not clear what would happen
	(such as which order, if it accepted it at all) if one defines all
	the procedures as UNIVERSAL implicitly via the transfer vector,
	and then use UNIVERSAL for the data symbols to export?  Maybe
	one can use UNIVERSAL for procedures even though you are using
	transfer vectors too?

> The other approach is to make sure that your C++ code that provides
> the static definitions ends up placing them in the right order at the
> right location.  Can C++ use a "#pragma data_psect" or something to
> control that?

	There doesn't appear to be any support for that (I was unable
	to find a copy of the DEC C++ manual, but did find a copy of the
	DEC C manual which appear to support the same set of pragmas).
	It's why in topic 3488 I asked about having CXX produce a .MAR.
	I was going to hand edit and put in some .PSECT directives.

	I was however thinking of using the CLUSTER linker .OPTion,
	which is already needed to fix the procedure transfer vector
	to an address, to append the filename.obj of the source module
	that contains the global data of interest to the CLUSTER option
	line right after the name of the .obj containing the transfer
	vectors.  But this comes back to the question of how do I direct
	the linker to make these symbols UNIVERSAL so that their ordinal
	positions are greater than the last transfer vector (and I'll
	make sure to pad the transfer vector with dummy transfer
	vectors/sumbols that can be used if the CORBA API gets bigger)?
2365.11Once it's placed properly, just add UNIVERSAL to your OPTIONSWIBBIN::NOYCEPulling weeds, pickin' stonesWed Mar 12 1997 20:519
For VAX, the only thing that matters is the actual offset of the storage
within the shareable image -- there's no such thing as an "ordinal position."
So you can simply add UNIVERSAL symbols to your linker /OPTIONS file.  All
they do is set a flag for the symbol definitions to make them visible from
outside the image.

For Alpha, *only* the ordinal position matters, and that is set by the order
in which the SYMBOL_VECTOR entries appear -- it's independent of the location
of the storage within the shareable image.
2365.12Danger Will RobinsonDECCXX::AMARTINAlan H. MartinWed Mar 12 1997 21:5411
Re .10:

>	I was however thinking of using the CLUSTER linker .OPTion,
>	which is already needed to fix the procedure transfer vector
>	to an address, to append the filename.obj of the source module
>	that contains the global data of interest to the CLUSTER option
>	line right after the name of the .obj containing the transfer
>	vectors.  ...

See topic 802 - simple use of CLUSTER= can (will?) break static initialization.
				/AHM
2365.13VAXCPU::michaudJeff Michaud - ObjectBrokerWed Mar 12 1997 21:5926
> For VAX, the only thing that matters is the actual offset of the storage
> within the shareable image -- there's no such thing as an "ordinal position."
> So you can simply add UNIVERSAL symbols to your linker /OPTIONS file.  All
> they do is set a flag for the symbol definitions to make them visible from
> outside the image.

	Great, thanks!  I guess it's only implied in the linker manual,
	and being new to VMS (after 9 years, 11 months at Digital, only
	now, right before I'm sold off to another company, do I have to
	do any development on VMS.... and I probably wish I never had to! :-)

	So if all UNIVERSAL does is set a flag, then it shouldn't matter
	if the flag was already set due to a .TRANSFER, or in theory I
	could even declare UNIVERSAL the same symbol (with the UNIVERSAL
	option) more than once and not confuse the linker?

	Too bad the assembler doesn't have a directive similiar to
	.TRANSFER that tells the linker the symbol(s) are UNIVERSAL,
	but without redefining the value of the symbol(s).  Then I
	wouldn't have to auto-generate both a .MAR and a .OPT file :-(

	Thanks again for the info, this may be workable.  Thank goodness
	the only (even though we have 110 of them) exported data we have
	are all pointers, so we don't have to worry about the size of
	any of them changing and then breaking backwards compatibility
	(like Brian has to worry about with the class instances)!
2365.14Will this work, not using CLUSTER or COLLECT?VAXCPU::michaudJeff Michaud - ObjectBrokerWed Mar 12 1997 23:0049
> See topic 802 - simple use of CLUSTER= can (will?) break static initialization

	Arghhhhhhhh!  Mucho thanks for the warning and pointer!

	I think it's time to get out my t-shirt I got at a UNIX trade
	show a while back that says on the front "VMSucks"!! :-)

	I've just finished reading through topic 802 and it looks like
	the hopefully simple (and hopefully supported) solution then
	is to only use the single CLUSTER option to force the transfer
	vector to be at relocatable virtual address 0, and then to
	just list all the .obj's so they go into the default cluster,
	*but* to make sure *all* my exported global data is in a single
	.obj, and to specify that .obj in the list *first*.

	I am assuming the compiler does *not* generate a .PSECT for
	one of the LIB$INITIALIZE PSECTs until it hits a data
	declaration that calls a constructor?

	Here's what I'm planning to put into (cut down to just 2 of the
	110 CORBA::_tc_* that we need to export) the .cxx whose .obj I'll
	list first in the .obj list:

#include "corba.hxx"

struct DUMMY {
    static CORBA::TypeCode _tc__null;
    static CORBA::TypeCode _tc__PrincipalSeq;
};

const CORBA::TypeCode_ptr CORBA::_tc_null = &DUMMY::_tc__null;
const CORBA::TypeCode_ptr CORBA::_tc_Principal = &DUMMY::_tc__Principal;

CORBA::TypeCode DUMMY::_tc__PrincipalSeq(TC_sequence_Principal);
CORBA::TypeCode DUMMY::_tc__null(TC_null);

	Will the compiler generate an object file for this as intended
	(ie. the first PSECT the linker will encounter and place in the
	shareable image will result in CORBA::_tc_null and CORBA::_tc_Principal
	being placed right after the transfer vector)?  I'm assuming since
	the DUMMY::* pieces of data are initialized using a constructor
	that the compiler will emit one or more of the LIB$INITIALIZE
	PSECTs to call the constructor for each of the DUMMY's, but
	they will *follow* the PSECT that CORBA::_tc_* go into?

	BTW, is there anyway that I missed to declare the _tc__* (two
	consecutive underscores) variables before they are referenced,
	with out also defining (and hence allocating storage for) them
	at the same time *and* making them file scope (ala local) only?
2365.15Looks that way to meDECCXX::AMARTINAlan H. MartinThu Mar 13 1997 19:0013
Re .14:

>	I am assuming the compiler does *not* generate a .PSECT for
>	one of the LIB$INITIALIZE PSECTs until it hits a data
>	declaration that calls a constructor?

That's the way it seems to behave, and that's the way the code appears.


>Will this work, ...?

That, I don't know.
				/AHM