Chapter Contents |
Previous |
Next |
SAS/C Compiler Changes in Release 7.50 |
Release 7.50 of the SAS/C Compiler and Library includes support for execution in 64-bit addressing mode under Release 1.2 or higher of z/OS.
This support is intended to allow SAS/C customers to gain experience with 64-bit support, and to write applications which allocate and access memory above the bar. However, note that SAS/C 7.50 does not actively exploit 64-bit addressing. While it is possible to allocate 64-bit addressable memory via the SAS/C multiple heap support, the SAS/C library continues to allocate all its other storage in 31-bit addressable memory. A limited number of library functions have been modified to accept 64-bit pointers, and the remainder of the library will never be executed in AMODE 64. For Release 7.50 of SAS/C, the design permits AMODE 31 and AMODE 64 code to coexist within the same application, provided that care is taken in linkages.
A design goal for a future release of the SAS/C library will be to exploit the capabilities of 64-bit addressing. In order to exploit 64-bit addressing SAS/C library control blocks will need to be changed to reflect the larger pointer size, which will prevent previously compiled SAS/C code from working in a future release. In other words, in a future version of SAS/C, it will be impossible to combine old AMODE 31 compiled code with new AMODE 64 compiled code, and old applications will require recompilation if they are to be used in a 64-bit addressing environment. Because Release 7.50 does allow old and new code to be mixed, it may be a useful tool for migrating existing applications gradually to 64-bit addressing, rather than having to modify all components of an application simultaneously.
Compile-Time Support for 64-bit Addressing |
SAS/C support for 64-bit addressing is enabled by use of the HUGEPTRS
option.
When this option is specified, the generated
code targets the z/Architecture, and uses 64-bit pointers for all memory references.
As one would expect, the HUGEPTRS
option implies
the ARCHLEVEL(D)
option, which informs the
compiler that z/Architecture instructions may be generated, and that 64-bit
general purpose registers exist.
Implementations of the C language on systems with 64-bit pointers have
made various choices about the sizes of integers. One popular choice is LLP64,
in which the integer type long
remains a 32-bit
type, like the type int
, and the only 64-bit
integer type is long long
. Another popular
choice is LP64, in which the type long
has
64 bits, like long long
. There are advantages
to either choice. SAS/C has chosen to adopt the LP64 model, in which a long
is a 64-bit type. Thus, use of the HUGEPTRS
option will not
only enable 64-bit pointers, but will also
change the size of long
from 4 bytes to 8.
When you compile with HUGEPTRS
, pointers
are by default 8 bytes in size. You can declare a pointer as a 32-bit (fullword)
pointer by using the type modifier _ _near
.
You can also use the modifier _ _huge
to explicitly declare a 64-bit pointer. The _ _near
and _ _huge
keywords
follow roughly the same placement rules as the const
and volatile
keywords. For instance, the declaration
int _ _near * _ _huge *myaddr;
declares
the variable myaddr
as being a huge (8-byte)
pointer to a near (4-byte) pointer to an int.
When you use _ _near
pointers,
you need to be aware of an important difference between 31-bit addressing
and 64-bit addressing. In 31-bit addressing, the high-order bit of a pointer
is ignored. For this reason, the high-order bit of pointers is frequently
used in assembler applications as a flag. This usage is prevalent in older
system control blocks. In 64-bit addressing mode, the high order bit of a _ _near
pointers is not ignored. Attempting to derefence
a _ _near
pointer with the high-order
bit set will cause a paging exception and an 0C4 ABEND. If your application
processes such pointers, before dereferencing them, you must clear the high-order
bit. The bit can be cleared either by casting to an integral type and using
the "and" operator, or by casting the _ _near
pointer to a _ _huge
pointer, which
also clears the bit. The following code example illustrates both techniques:
_ _near char *impure; _ _near char *purified; _ _huge char *purehuge; purified = (_ _near char *)(((unsigned int) impure) & ~0x80000000); purehuge = (_ _huge char *) impure;
The change in pointer size for 64-bit support also means that certain
standard types defined by C header files will change. The two most important
such types are size_t
and ptrdiff_t
. Without the HUGEPTRS
option, size_t
continues to be defined as unsigned
int
, and ptrdiff_t
as int
. When HUGEPTRS
is specified,
size_t
is unsigned long
and ptrdiff_t
is signed long
, both
of which are 64-bit types.
The table below shows the effect of HUGEPTRS
on the sizes of objects of various types. Types which are not derived from
one of these types can be assumed to be the same regardless of the HUGEPTRS
setting. For instance, the sizes of function pointers
and enums
are not changed.
Type |
NOHUGEPTRSSize | HUGEPTRSSize |
---|---|---|
long |
4 | 8 |
size_t |
4 | 8 |
ptrdiff_t |
4 | 8 |
unqualified pointer |
4 | 8 |
You can use the _ _huge
keyword in a program which you compile without the HUGEPTRS
option
, but the generated code will be unable to dereference
or return a _ _huge
pointer. If you
do not compile with the HUGEPTRS
option, uses
of 8-byte pointers should be limited to use as unreferenced structure elements,
or as arguments which are passed directly to other functions. This limited
support is sufficient to allow AMODE 31 functions to manipulate data structures
which include 64-bit pointers, so long as no attempt is made to dereference
them.
It is possible to call AMODE 64 functions from AMODE 31 functions and
vice versa. In SAS/C Release 7.50 all function calls are made in AMODE 31.
A function compiled with HUGEPTRS
will switch
into AMODE 64 using the SAM64 instruction after the function prolog has executed,
and will switch back to AMODE 31 using the SAM31 instruction before calling
any other function, and before returning to its caller. This allows AMODE
31 and AMODE 64 functions to be arbitrarily mixed in the calling chain, while
assuring that the prolog need not execute additional instructions to avoid
use of the high-order parts of the general purpose registers. This technique
does introduce a performance penalty which would not be present in an environment
which was completely 64-bit enabled.
When developing an application in which some code is compiled with HUGEPTRS
to execute in AMODE 64, and some is compiled
without HUGEPTRS
to execute in AMODE 31, there is significant risk
associated with shared data. Any type and data declarations used by both
AMODE 31 and AMODE 64 code must be carefully constructed to have the same
size and mapping in both AMODEs. Following are some guidelines which may
be helpful here. Do not declare data items as long
or unsigned long
, or as size_t
or ptrdiff_t
. Declare them
as signed int
or unsigned int
if they should be 32-bit integers, or as signed long long
or
unsigned long long
if they should be 64-bit integers. Alternatively, use types defined by the
header file <stdint.h>
such as intfast32_t
, which do not change when HUGEPTRS
is specified.
Similarly, pointers should be explicitly
declared as _ _near
or _ _huge
, as appropriate. In particularly tricky or
complex cases, you may need to code a
#if _O_HUGEPTRS == 1
test to define distinct data
mappings for 31-bit and 64-bit components.
The above considerations also apply to function prototypes. Functions
which can be called from both HUGEPTRS
and NOHUGEPTRS
callers should avoid the use of types like long
,
size_t
and ptrdiff_t
, and define any pointer arguments as explicitly _ _huge
or
_ _near
.
Note: In Release 7.50, function pointers continue to be 4-byte pointers, regardless
of whether HUGEPTRS
is specified.
64-bit Support and Access Register Mode |
With the Systems Programming Environment (SPE), you can specify both
the HUGEPTRS
option and the ARMODE
option. In this case, the code will execute in both
access-register mode and AMODE 64. With Release 7.50, _ _far
pointers continue to be 8 bytes in size, containing a four-byte
address and a four-byte ALET value.
In 31-bit addressing, the high-order bit of the second word of a _ _far
pointer is not significant. In 64-bit
addressing,
this bit is significant. If the bit is set, a dereference of the pointer
will result in an 0C4 ABEND. If your 64-bit application has to process _ _far
pointers which may have this bit set, you can
clear the flag using code similar to that below:
_ _far char *impure; __far char *purified; purified = (_ _far char *)(((unsigned long long) impure) & ~0x80000000ULL);
64-bit Support and Inline Machine Code |
The SAS/C inline machine code feature is supported for programs compiled
with HUGEPTRS
. Inline machine code has access
to all 64 bits of the general purpose registers. When the _ossvc
, _osarmsvc
, or _ospc
function is used to
perform a system call, the compiler
generates code to leave AMODE 64 before the system call and to restore it
afterwards. See Chapter 13, "Inline Machine Code Interface,"
of the
SAS/C Compiler and Library User's Guide and IEEE and 64-Bit Updates to the Inline Machine Code Interface in this document for more
information on the inline machine code facility.
64-bit Support and Communication with Other Languages |
In general, the SAS/C features for communication with assembler language
or with other high-level languages should be used with care by programs compiled
with the HUGEPTRS
option. Specific caveats
are as follows:
_ _near
pointer argument may have the
high-order bit
set (as to indicate the end of a VL argument list), you cannot dereference
the pointer without clearing the bit. See Compile-Time Support for 64-bit Addressing for further information.
_ _asm
keyword may be
used in code compiled with HUGEPTRS
. However,
note that if the last argument in an _ _asm
argument list is a _ _huge
pointer,
the high-order bit will not be set, and the called function will have no
indication of the end of the argument list.
_ _ref
keyword always passes
_ _near
pointers in the argument list. If a _ _huge
pointer argument is specified, it will be converted to a _ _near
pointer, which is passed in its place. Similarly, if an
argument is accessible only via a _ _huge
pointer, its address will be truncated to 31 bits in the argument list.
linkage(OS)
pragma and the
_ _ibmos
keyword are not supported for programs compiled
with HUGEPTRS
.
HUGEPTRS
is strongly discouraged. The
effect of attempting
to pass a _ _huge
pointer, or data addressable
only using a _ _huge
pointer, is both
unpredictable and futile because no IBM language implementation other than
assembler presently supports 64-bit addressing.
64-Bit Support and the SAS/C Library |
SAS/C Release 7.50 provides interim 64-bit addressing support. A significant
subset of the SAS/C library supports _ _huge
pointer arguments and execution in 64-bit mode, but many important areas still
have no such support. For example, there is no way in this release to read
data from a socket into a storage area allocated above the bar.
This is similar to the operating system support (z/OS 1.3) at the time this level of the product was released. While it is possible in z/OS 1.3 to allocate 64-bit addressable memory, z/OS does not yet support reading or writing directly from such memory. In the long run, such support is necessary, but we are able to provide meaningful 64-bit support earlier by delaying such features until a later release of the operating system.
SAS/C library support for AMODE 64 and huge pointers in this release can be summarized as follows:
_ _huge
arguments, and lengths greater than 2
gigabytes.
malloc
function, the palloc
function, and the new multiple heap allocation functions
can be used to allocate memory requiring a _ _huge
pointer for addressibility. Also, the header file <iarv64.h>
provides a low-level interface to the z/OS IARV64 service,
which is used to allocate memory "above the bar".
printf
family of functions
has been extended to format _ _huge
pointer values, and strings accessible via _ _huge
pointers. Similarly, the scanf
family can
read values into areas addressed via a _ _huge
pointer. New format modifiers allow the program to completely control such
formatting.
The following table contains a list of the library functions
that accept _ _huge
pointer arguments.
Attempts to pass _ _huge
pointers to
library functions not in the table will result in their conversion to _ _near
pointers, with possible data loss. A warning
message will be generated by the compiler whenever this occurs.
afread |
afreadh |
afread0 |
afwrite |
afwriteh |
afwrite0 |
atoi |
atol |
atoll |
bsearch |
calloc |
fgets |
format |
fprintf |
fputs |
fread |
fscanf |
fwrite |
gets |
hpalloc |
hpcalloc |
hpfree |
hppoolcreate |
hprealloc |
IARV64 |
malloc |
memcasecmp |
memchr |
memcmp |
memcpy |
memfil |
memlwr |
memmove |
memscan |
memscntb |
memset |
memupr |
memxlt |
nan |
nanf |
nanl |
nanl |
pdel |
pfree |
pool |
printf |
puts |
qsort |
realloc |
scanf |
snprintf |
sprintf |
sscanf |
stcpm |
stcpma |
strcasecmp |
strcat |
strchr |
strcmp |
strcpy |
strcspn |
strlen |
strlwr |
strncasecmp |
strncat |
strncmp |
strncpy |
strpbrk |
strrchr |
strrcspn |
strrpbrk |
strrspn |
strscan |
strscntb |
strspn |
strstr |
strtod |
strtof |
strtok |
strtol |
strtold |
strtoll |
strtoull |
strupr |
strxlt |
TPUT |
TPUT_ASID |
TPUT_USERID |
TGET |
vformat |
vsnprintf |
vsprintf |
vsscanf |
WTO |
WTOR |
WTP |
64-Bit Support and ANSI/ISO Conformance |
When the HUGEPTRS
compiler option is
specified, the SAS/C Compiler and Library are not completely conformant to
the ANSI/ISO standard. The primary reason for this has to do with data types.
For example, the C standard specifies that the second argument to the fseek
function should be a long
.
When the HUGEPTRS
option is specified, a long
is a 64-bit integer. However, the actual implementation
of fseek
in SAS/C Release 7.50 continues to
expect a 32-bit integer. The prototype for fseek
therefore specifies int
for the second argument,
which does not conform to the standard. Similar problems can arise when functions
accept arguments of type size_t
or ptrdiff_t
. For example, the second argument to the fread
function is
defined as having type size_t
. When HUGEPTRS
is specified, size_t
is defined as unsigned
long
,
which is a 64-bit type. Nevertheless, the actual implementation of fread
continues to expect this argument to be a 32-bit integer,
requiring a non-standard prototype for fread
.
One implication of the above is that functions compiled with HUGEPTRS
should not
provide their own prototypes for library
functions. Such functions should always include the appropriate header files
to obtain the SAS/C prototypes to avoid passing an incorrect argument list.
Note that the SAS/C product remains fully ANSI/ISO compliant for applications
which execute in 31-bit mode and do not use the HUGEPTRS
compiler option.
Chapter Contents |
Previous |
Next |
Top of Page |
Copyright © 2004 by SAS Institute Inc., Cary, NC, USA. All rights reserved.