Sun Java Solaris Communities My SDN Account Join SDN

Article

ABI Compliance and Global Registers Usage in SPARC V8 and V9 Architecture

 
 

September 2000

This article reviews the restrictions placed on the global registers by SPARC V8, V8PLUS, and V9 ABIs (application binary interface), and discusses some steps that developers can take to conform to the ABIs while making efficient use of available registers.

It also highlights the global registers usage issues related to 64-bit porting of assembly code.

Introduction

Register usage is a critical resource allocation issue for compilers. The SPARC architecture defines a set of 32 general registers. The general register set is partitioned into windowed registers and non-windowed registers.

The windowed registers are used primarily for passing parameters to, and receiving results from, subroutines and for keeping track of the memory stack. The windowed registers are automatically saved between function calls; the caller's registers are saved upon entering the callee and restored upon exit. As a result, there is not register values conflict among functions.

In contrast, the non-window registers are not automatically saved and therefore do require special attention to ensure that the calling routine's live values are not overwritten. On the up side, this provides a mechanism to globally retain live values across several routines. Non-window registers are commonly known as global registers.

Global Registers

There are 8 global registers, designated as %g0 through %g7. Register %g0 is defined to hold the constant 0; it can be written to, but the value will not change. The rest of the global registers, %g1 through %g7, operate as normal registers; they can be written to, and later read.

For V8 and prior versions of the SPARC architecture, the global registers are defined as 32-bit registers. For SPARC V9, their capacity was doubled to 64 bits.

SPARC V8 ABI Restrictions

The SPARC V8 ABI specifies that registers %g2 through %g4 are reserved for application programs and registers %g5 through %g7 are reserved for the system. Software outside the control of the application, including system libraries, cannot modify these registers at any time. Register %g1 is designated as a scratch register, meaning that values stored in it are volatile over function calls.

SPARC V8PLUS ABI Restrictions

The SPARC V8PLUS ABI is an unofficial extension of the V8 ABI for V9 SPARC hardware. Programs compiled with SPARC V8PLUS ABI will run on V9 hardware running a V8 aware Solaris operating environment. For example, a 32-bit program compiled using a Forte compiler with the option -xarch=v8plus or -xarch=v8plusa will run on any of the 64-bit UltraSPARC processor-based Sun servers and workstations that are running SunOS 5.5.1 kernel release or later.

Note: To determine the kernel release of a system, use /usr/bin/uname -r. To find out the list of instruction set executables on a platform, use /usr/bin/isalist.

The SPARC V8PLUS ABI switches register %g5 from a reserved system register to a generally available register. A called function can now use registers %g1 and %g5 without having to save or restore the registers' values. Therefore, both of these registers are assumed to be volatile across functions calls.

The rest of the register restrictions remain unchanged from SPARC V8 ABI. However, the global registers are 64-bit registers and may be used as such by user programs.

Back to Top


SPARC V9 ABI Restrictions

The SPARC V9 ABI better defines the use of registers %g2 through %g4. Register %g4 is free for general use. This makes registers %g1, %g4, and %g5 volatile across function calls. In addition, %g1 and %g5 are volatile between caller and callee, if the call is to an external function that goes through the procedure linkage table (PLT). In other words, %g1 and %g5 may not be used for passing parameters because the dynamic linker might use these if the call is made to an external function in a shared library. Registers %g2 and %g3 are defined as application specific, while registers %g6 and %g7 are reserved for system software.

Note: In a multi-threaded environment, registers %g2 and %g3 are thread local. You do not need to do anything because the system libraries that implement the thread-switching automatically save and restore these registers on a thread switch.

Table 1 summarizes the global registers usage in various SPARC ABIs.

Table 1: Global registers summary

Global Register SPARC V8
(32-bit)
SPARC V8PLUS
(64-bit)
SPARC V9
(64-bit)
%g0 Constant 0 Constant 0 Constant 0
%g1 Scratch Scratch Scratch
%g2 Application Application Application
%g3 Application Application Application
%g4 Application Application Scratch
%g5 System Scratch Scratch
%g6 System System System
%g7 System System System

One of the significant changes in the SPARC V9 ABI is that user and system functions that use registers %g2, %g3, %g6, and %g7 must indicate how the registers are used. For code written in SPARC assembly and inline templates, a new pseudo-instruction was introduced to specify global register usage, thereby allowing more reliable use of global registers. The underlying mechanism is described in the The SPARC Architecture Manual, Version 9.

In summary, ELF (Executable and Linking Format) register usage records were introduced. SPARC V9 ABI compliant programs are required to use these records to report global register usage. The Forte compilers automatically generate the ELF register records to implement this mechanism. During link time, either static or dynamic, the records are compared to ensure consistent use of global registers between differing linkage objects. If inconsistent usage is detected, an error message will result from the link operation.

Linkers bundled with Solaris, beginning with Solaris 7 release, accept the ELF register records. Linkers bundled with releases prior to Solaris 7 do not accept the new ELF register records and will issue an error message. Since the SPARC assembler may also generate linkage objects, it should also be able to output the ELF register records. Hence, the assembler needs to recognize how the user intends to use the global registers referenced within each input .s and .il file. The new assembler pseudo-instruction provides this functionality and is described in the following sections.

Back to Top


New V9 Pseudo Instruction

The new pseudo-instruction is accepted by the SPARC assembly for any architecture setting but only has effect for V9. This allows the user to write assembly code for V8 and V9 using the new natural assembly pseudo-ops:

   .register %g {2 | 3 | 6 | 7}, {#scratch | symbol name | #ignore}

The SPARC assembler responds to the pseudo-instruction in any of the following circumstances:

  • Under V8 or prior versions of SPARC architecture, the pseudo-instruction is accepted but ignored.

  • Under V9, if the SPARC assembler detects a global register use that is not covered by a new pseudo-instruction, then the SPARC assembler issues an error message.

  • Under V9, if the SPARC assembler detects multiple differing pseudo-ops related to the same global register, then the SPARC assembler issues an error message.

  • Otherwise, the SPARC assembler outputs the appropriate ELF register records as identified by the user. The SPARC assembler may check that the specified usage description is correct, but is not required to do so.

The #ignore form of the .register pseudo-instruction is used only for code that does not change the global registers in a program visible way, such as thread and context switching system code. Such use is highly specialized and rare since it causes the assembler to not output an ELF register record for the named register.

Back to Top


Scenario 1: 64-bit Porting of User Assembly Code and Global Register Usage

This section illustrates the use of the new .register pseudo-instruction when assembly code changes are needed to port an application routine from SPARC V8PLUS to SPARC V9 ABI.

Problem

In order to port an application to 64-bit, the user assembly routine must be made SPARC V9 ABI compliant. A code fragment example is shown below. The V8PLUS assembly code does not violate the global register usage, since the assembly code does not use the ABI reserved registers. Rather the problem lies in the fact that the address computation for .L_NEG_ONE abides by the V8 style of computing the 32-bit address and must be changed for V9 compliance:

!
!     SUBROUTINE FOO(N, A, B, C, AT, NROW, START) 
!
        ... 
                                          ! line 21 
        .seg    "text"                    ! line 22
        ... 
        sethi   %hi(.L_NEG_ONE),%l3       ! line 87 
        ldd     [%l3+%lo(.L_NEG_ONE)],%f0 ! line 88
        ... 
.L_NEG_ONE:
        ... 

If you compile the V8PLUS compliant routine, foo.s, using the -xarch=v9 option before making any modifications for V9, the following error occurs:

% cc -xarch=v9 foo.s main.c 
foo.s: 
main.c: 
ld: fatal: relocation error: R_SPARC_HI22: file foo.o: symbol : value 0x400404 does not fit 

Back to Top


Solution

Assuming that the register %g1 is available, the correct V9 style address computation is:

     ...
     sethi   %hh(.L_NEG_ONE),%l3         ! line 87 
     sethi   %lm(.L_NEG_ONE),%g1 
     or      %l3,%hm(.L_NEG_ONE),%l3 
     sllx    %l3,32,%l3               
     or      %l3,%g1,%l3                 ! line 91 
     ldd     [%l3+%lo(.L_NEG_ONE)],%f0   ! line 92 <-- THIS WAS LINE 88
     ...

Clearly, one more register is needed for this code. If register %g1 is already in use, you can use one of the reserved application-specific registers %g2 or %g3, provided they are available. In order to use any of the ABI reserved registers (here, %g2 or %g3), you must declare the usage to the assembler by using the .register pseudo-instruction:

     ... 
     .register %g2,#scratch              ! line 21 <-- BLANK LINE IN ORIGINAL
     .SEG    "text" 
     ... 
     SETHI   %HH(.L_NEG_ONE),%L3         ! LINE 87 
     SETHI   %LM(.L_NEG_ONE),%G2 
     OR      %L3,%HM(.L_NEG_ONE),%L3 
     SLLX    %L3,32,%L3             
     OR      %L3,%G2,%L3                 ! LINE 91 
     LDD     [%L3+%LO(.L_NEG_ONE)],%F0   ! LINE 92

Failing to include the .register pseudo-instruction causes the assembler to produce the following compilation errors:

% cc -c -xarch=v9 foo.s -o foo.o 
/opt/SUNWspro/SC5.0/bin/fbe: "foo.s", line 87: error: detect global register use not covered .register pseudo-op 
/opt/SUNWspro/SC5.0/bin/fbe: "foo.s", line 91: error: detect global register use not covered .register pseudo-op 

However, with the .register pseudo-instruction, the code compiles successfully.

The following examples demonstrate the use of two other pseudo-instructions, setx and setxhi. These pseudo-instructions are provided as a convenience to programmer and simplify the five instruction sequence of sethi, sethi, or, sllx, or.

You can use setxhi to combine lines 87 through 91 from the above example.

     ...
     setxhi   .L_NEG_ONE, %g2, %l3         ! line 87
     ldd      [%l3+%lo(.L_NEG_ONE)], %f0   ! line 88 <-- THIS WAS LINE 92
     ...

Or, you can use setx, and the code becomes even more streamlined:

     ...
     setx    .L_NEG_ONE, %g2, %l3           ! line 87
     ldd     [%l3], %f0                     ! line 88 <-- THIS WAS LINE 92
     ...

Back to Top


Scenario 2: Global Register in Multi-threaded Applications

Application developers should take care when using global registers in assembly code that is a part of multi-threaded applications. In order to be multi-thread safe, the assembly code needs to be compliant with all SPARC ABI specifications, including global register usage.

Problem

In this scenario, a multi-threaded SPARC V8PLUS compliant application encounters a SIGSEGV error during execution when linked with an object derived from your SPARC assembly code. One possibility is that you used global registers %g6 and %g7 in your assembly code, even though they are reserved for use by system code. In multi-threaded applications, register %g6 is used by system libraries, libthread and libpthread. If your function overwrites the contents of the system register %g6, it can cause out-of-segment address references in one of the system library functions and consequently a SIGSEGV runtime error.

Solution

The error is corrected once the assembly code is rewritten to conform with the latest SPARC ABI specifications by not using the priviledged registers %g6 or %g7. In 64-bit SPARC V9 ABI compliant applications, these errors are identified at link time due to global register usage checking.

Note: Application developers should avoid using application-specific registers in building general purpose libraries, such as system libraries, or those provided by software vendors as third-party libraries, which might be linked with multiple applications. You can instruct the Forte compilers to not use application-specific registers by using the -xregs=no%appl compiler flag.

Back to Top


Resources

Visit Sun Studio Development Tools to learn more about compilers and developer tools.

An extensive discussion on SPARC architecture can be found in The SPARC Architecture Manual, Version 9.

Visit the Solaris ABI Program to ensure that your applications are ABI-conformant binary components.

September 2000

Back to Top


Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.