T.R | Title | User | Personal Name | Date | Lines |
---|
2365.1 | you are correct | DECCXX::KIMMEL | | Wed Jan 11 1995 13:06 | 22 |
2365.2 | must I change sources | ROKFRD::DDAVIES | | Wed Jan 11 1995 14:11 | 19 |
2365.3 | is this enough ? | ROKFRD::DDAVIES | | Fri Jan 13 1995 10:27 | 39 |
2365.4 | working on it | DECCXX::KIMMEL | | Fri Jan 13 1995 17:05 | 23 |
2365.5 | and finally ... | ROKFRD::DDAVIES | | Sat Jan 14 1995 06:51 | 12 |
2365.6 | hope I have this straight :-) | DECCXX::KIMMEL | | Mon Jan 23 1995 08:18 | 37 |
2365.7 | Exporting C++ data upwardly compatible on VAX/VMS... | VAXCPU::michaud | Jeff Michaud - ObjectBroker | Tue Mar 11 1997 22:12 | 49 |
| 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.8 | Took me longer than I expected to track this down | HNDYMN::MCCARTHY | A Quinn Martin Production | Wed Mar 12 1997 06:06 | 49 |
| 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.9 | Great, if you can add a level of indirection. | WIBBIN::NOYCE | Pulling weeds, pickin' stones | Wed Mar 12 1997 15:12 | 30 |
| 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.10 | | VAXCPU::michaud | Jeff Michaud - ObjectBroker | Wed Mar 12 1997 17:47 | 41 |
| > 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.11 | Once it's placed properly, just add UNIVERSAL to your OPTIONS | WIBBIN::NOYCE | Pulling weeds, pickin' stones | Wed Mar 12 1997 17:51 | 9 |
| 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.12 | Danger Will Robinson | DECCXX::AMARTIN | Alan H. Martin | Wed Mar 12 1997 18:54 | 11 |
| 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.13 | | VAXCPU::michaud | Jeff Michaud - ObjectBroker | Wed Mar 12 1997 18:59 | 26 |
| > 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.14 | Will this work, not using CLUSTER or COLLECT? | VAXCPU::michaud | Jeff Michaud - ObjectBroker | Wed Mar 12 1997 20:00 | 49 |
| > 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.15 | Looks that way to me | DECCXX::AMARTIN | Alan H. Martin | Thu Mar 13 1997 16:00 | 13 |
| 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
|