![]() 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 |
unqualifiedpointer |
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. ![[cautionend]](../common/images/cautend.gif)
| 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.