Chapter Contents

Previous

Next
SAS/C Compiler Changes in Release 7.50

64-Bit Support

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]


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:


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:

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.