[Return to Library]  [TOC]  [PREV]  SECT--  [INDEX] [Help]

8    Procedure Descriptors

Procedure descriptors serve two functions. They provide:

Every procedure, except for null frame procedures, must have an associated procedure descriptor. (Null frame procedures are discussed in Section 3.1.4.)


Note

The term procedure descriptor also appears in the chapter on the symbol table in the Assembly Language Programmer's Guide. The use of the term in that manual refers to a structure defined in the file /usr/include/sym.h and should not be confused with procedure descriptors used for exceptions, as described in this Digital UNIX calling standard.


This chapter covers the following procedure-descriptor topics:


[Return to Library]  [TOC]  [PREV]  SECT--  [INDEX] [Help]

8.1    Procedure Descriptor Representation

Procedure descriptors on Digital UNIX for Alpha systems use two kinds of structures: code range descriptors and run-time procedure descriptors.

Code range descriptors associate a contiguous sequence of addresses with a run-time procedure descriptor. This mapping can be many-to-one.

Run-time procedure descriptors provide descriptive information about a procedure or part of a procedure.

Several run-time procedure descriptors might be needed if the procedure has multiple entry points, as in FORTRAN. In this case, each entry point consists of the following elements:

Although the prologues might contain different code, they must all achieve the same effect: the same registers saved at the same offset, the same frame size, and so on. There is a run-time procedure descriptor for every entry point, with the last entry point's run-time procedure descriptor covering all the common code of the procedure.

The creation of procedure descriptors involves the combined actions of compilers and assemblers, the linker, and the loader. The sections that follow focus solely on the result of this composite process and describe the resulting descriptors as seen by the executing run-time environment. The figures present the physical representation of the procedure descriptor structures. The logical fields, which have the prefix PDSC_, present the abstract means to access the fields of these structures. The physical representation and the logical fields are defined in the file /usr/include/pdsc.h.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [INDEX] [Help]

8.1.1    Code Range Descriptors

The code-range table is an array of code-range descriptors, as shown in Figure 8-1. There are four fields for each descriptor:
PDSC_CRD_BEGIN_ADDRESS

Specifies the address of the beginning of a code range. The elements of the array are sorted so that the portion of the address space covered by a single element starts at the PDSC_CRD_BEGIN_ADDRESS value contained in that element and extends to, but does not include, the PDSC_CRD_BEGIN_ADDRESS value encoded in the next successive element. Thus, the last array element provides the end address of the last code range and does not start a new range.

PDSC_CRD_PRPD

Specifies the address of the associated run-time procedure descriptor. A PDSC_CRD_PRPD value of zero indicates a null frame procedure for which an implicit run-time procedure descriptor is assumed with the characteristics described in Section 3.1.4.

PDSC_CRD_CONTAINS_PROLOG

Indicates whether the code range begins with a procedure prologue.

PDSC_CRD_MEMORY_SPECULATION

Indicates that memory traps (SIGSEGV, SIGBUS) raised in this procedure should not be delivered.


Figure 8-1: Code Range Descriptor


  1. begin_address

    Contains a longword that is the offset from the base of the code range table to the starting point of the code to which the associated run-time procedure descriptor applies. The low two bits of this longword are reserved for use as flags; they must be masked out before the containing longword is used as an offset.

  2. rpd_offset

    Contains a longword that is the self-relative offset to the associated run-time procedure descriptor. The low two bits of this longword are used as flags; they must be masked out before the containing longword is used as an offset. An rpd_offset value of zero indicates a null frame procedure for which an implicit run-time procedure descriptor is assumed with the characteristics defined in Section 3.1.4.

  3. memory_speculation (bit 1 of rpd_offset)

    Indicates that memory traps (SIGSEGV, SIGBUS) occurring in this procedure should not be delivered.

  4. n (bit 0 of rpd_offset)

    Specifies a flag set to indicate that the code range does not begin with an entry point. This argument might be used for an out-of-line code segment that is not contiguous with the main body of a procedure.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [INDEX] [Help]

8.1.2    Run-Time Procedure Descriptors

Run-time procedure descriptors provide information about a procedure needed for exception handling and other tools. Table 3-1 lists this information. There are two forms: long and short. Both forms encode the same information. The short form is used to save space for the most commonly occurring cases. Figure 8-2 shows the long form; Figure 8-3 shows the short form.

Each figure shows two alternative representations for the first longword. The first representation applies to stack frame procedures and is shown in the main part of the figure. The second representation applies to register frame procedures and is shown as a separate longword at the end of the figure. The PDSC_FLAGS_REGISTER_FRAME flag, which is one of the flags common to both forms, determines which representation applies.

Descriptions of the physical fields follow the figures. These descriptions include the calculations used to obtain the logical field from the physical field. Most fields are common to both procedure descriptor forms. The long form has three additional fields shown in Figure 8-2.


Figure 8-2: Long Form Run-Time Procedure Descriptor



Figure 8-3: Short Form Run-Time Procedure Descriptor


  1. The flags field represents PDSC_RPD_FLAGS and encodes the following flags:

  2. The entry_ra field represents PDSC_RPD_ENTRY_RA and is the number of the register in which the return address is passed to this procedure.

  3. The rsa_offset field is the signed difference in quadwords between the stack frame base (SP or FP as indicated by PDSC_FLAGS_BASE_REG_IS_FP) and the register save area. (See Section 3.1.2 for information on stack frame procedures.)

    PDSC_RPD_RSA_OFFSET = rsa_offset * 8

  4. The sp_set field is the unsigned offset in instructions (longwords) from the entry address of the procedure to the single instruction in the procedure prologue that modifies the stack pointer. This offset must be zero when there is no such instruction because the procedure has a PDSC_RPD_FRAME_SIZE of 0.

    PDSC_RPD_SP_SET = sp_set * 4

  5. The entry_length field is the unsigned offset in instructions (longwords) from the entry address to the first instruction in the procedure code segment following the procedure prologue.

    PDSC_RPD_ENTRY_LENGTH = entry_length * 4

  6. The frame_size field is the unsigned size in quadwords of the fixed portion of the stack frame for this procedure.

    PDSC_RPD_FRAME_SIZE = frame_size * 8

    The value of SP at entry to this procedure can be calculated by adding PDSC_RPD_FRAME_SIZE to the value SP or FP, as indicated by PDSC_FLAGS_BASE_REG_IS_FP. PDSC_RPD_FRAME_SIZE cannot be 0 for a stack frame procedure because the stack frame must include space for the register save area.

    Note: If a procedure needs a frame size that is too large to be represented using the frame_size field, a variable-size stack frame should be used. In this case, the FP register is used to address a fixed size area that needs to be just large enough to include the preserved state. An arbitrarily large stack area can then be covered by the SP register.

  7. The imask field represents PDSC_RPD_IMASK and is a bit vector (0 - 31) specifying the integer registers that are saved in the variable portion of the register save area on entry to the procedure. The least significant bit corresponds to register $0. Bits 31, 30, 28, and the register containing the entry return address of this mask should never be set because $31 is the integer Read-As-Zero register, $30 is the hardware SP, $29 (GP) is always assumed to be destroyed during a procedure call or return, and the return address is saved at known offset zero in the register save area in every stack frame procedure.

  8. The fmask field represents PDSC_RPD_FMASK and is a bit vector (0 - 31) specifying the floating-point registers that are saved in the variable portion of the register save area on entry to the procedure. The least significant bit corresponds to register $f0. Bit 31 of this mask should never be set because it corresponds to the floating-point Read-As-Zero register.

  9. The handler_address field represents PDSC_RPD_HANDLER and is an absolute procedure value (quadword) for a run-time static exception handling procedure. This part of the procedure descriptor is optional. However, it must be supplied if PDSC_FLAGS_HANDLER_VALID is 1. If PDSC_FLAGS_HANDLER_VALID is 0, the contents or existence of PDSC_RPD_HANDLER is unpredictable.

  10. The handler_data_address field represents PDSC_RPD_HANDLER_DATA and is a quadword of data for the exception handler. This part of the procedure descriptor is optional. However, it must be supplied if PDSC_FLAGS_HANDLER_VALID is 1. If PDSC_FLAGS_HANDLER_VALID is 0, the contents or existence of PDSC_RPD_HANDLER_DATA is unpredictable.

  11. The save_ra field represents PDSC_PRD_SAVE_RA and is the number of the register in which the return address is maintained during the body of the procedure. If this procedure uses the standard calling conventions and does not modify $26, both PDSC_RPD_ENTRY_RA and PDSC_RPD_SAVE_RA will specify $26.

The short form run-time procedure descriptor differs from the long form in the following ways:

If any of these restrictions cannot be satisfied, the long form run-time procedure descriptor must be used.


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [INDEX] [Help]

8.2    Procedure Descriptor Access Routines

A thread can obtain information from the descriptor of any procedure in the thread's virtual address space by calling system library functions.

In the course of running and debugging a program, there are times when it is necessary to identify which procedure is currently executing. During normal thread execution, the current procedure must be determinable any time an exception arises so that the proper handlers will be invoked. In addition, a debugger must know which procedure invocation is currently executing so it can obtain information about the current state of the execution environment.

To determine precisely the current execution context, two pieces of information are required:

This context of the current procedure and the specific instance of that procedure invocation are referred to as the current procedure invocation or simply, current procedure. At any point in the execution of a thread, only one procedure is considered to be the current procedure.

In this calling standard, the value in the PC is used to indicate the current procedure by means of the code range table described in Section 8.1.1.

The following system-supplied routine is used to obtain the address of the procedure descriptor that corresponds with any given PC value within the current address space.

exc_lookup_function_entry (ControlPC)

Arguments:


ControlPC  Specifies a PC value in the current address space for which the procedure value is to be returned. 

Function Value:


PROC_DESC  Specifies the address of the code range descriptor for the procedure containing the requested PC. If the return value is null, the PC is not currently mapped. 

The following system-supplied routine is used to obtain the address of the base of the code range array for the procedure descriptor that corresponds B to any given PC value within the current address space.

exc_lookup_function_table (ControlPC)

Arguments:


ControlPC  Specifies a PC value in the current address space for which the code range base address is to be returned. 

Function Value:


PROC_CRD  Specifies the address of the base of the code range descriptor array for the procedure descriptor of the procedure containing the requested PC. If the return value is null, the PC is not currently mapped. 

At times, it is useful to acquire the GOT segment value for a procedure; that is, the value of the GP register. The following system-supplied routine is used to obtain the GP value corresponding to any given PC value within the current address space.

exc_lookup_gp (ControlPC)

Arguments:


ControlPC  Specifies a PC value in the current address space for which the GP value is to be returned. 

Function Value:


GP_VALUE  Specifies a GP value for the procedure containing the requested PC. If the return value is null, the PC is not currently mapped. 


[Return to Library]  [TOC]  [PREV]  --SECT  SECT--  [INDEX] [Help]

8.3    Run-Time Generated Code

Code generated at run time is important for applications that include:

To maintain stack traceability when code generated at run time is executed, procedure descriptors must be provided for that code. Such procedure descriptors must describe correctly the characteristics of the code and the environment within which that code executes.

Before run-time generated code that uses any exception facilities (directly or indirectly) can be executed, system library functions must be called to communicate the code ranges, procedure descriptors, and GP values to the execution environment. This communication is accomplished by calling the following two system-supplied routines:

exc_add_pc_range_table (PROC_DESC_ADDR, LENGTH)

Arguments:


PROC_DESC_ADDR  Specifies the base address of the code range array for the procedure descriptors. 
LENGTH  Specifies the number of code range elements in the array. 

An exception is raised if the exc_add_pc_range() operation cannot be completed successfully.
exc_add_gp_range (BEGIN_ADDRESS, LENGTH, GP_VALUE)

Arguments:


BEGIN_ADDRESS  Specifies the first address for which GP_VALUE applies. 
LENGTH  Specifies the number of bytes from BEGIN_ADDRESS for which GP_VALUE applies. 
GP_VALUE  Specifies the GP value to be associated with the addresses in the range BEGIN_ADDRESS .. BEGIN_ADDRESS + LENGTH + 1

An exception is raised if the exc_add_gp_range() operation cannot be completed successfully.

When procedure information is no longer valid or if the code will not be executed again, two system library routines should be called to remove the procedure mapping information. These system library routines are defined as follows:

exc_remove_pc_range_table (PROC_DESC_ADDR)

Arguments:


PROC_DESC_ADDR  Specifies the base address of the code range array for the procedure descriptors. 

An exception is raised if the exc_remove_pc_range_table() operation cannot be completed successfully.

exc_remove_gp_range (BEGIN_ADDRESS)

Arguments:


BEGIN_ADDRESS  Specifies the beginning address for which GP-value information should be removed. 

An exception is raised if the exc_remove_gp_range() operation cannot be completed successfully.

The following steps show how run-time code should be constructed and released:

  1. Allocate memory for the code.

  2. Write the code and any procedure descriptors to memory.

  3. Call exc_add_pc_range_table() and exc_add_gp_range().

  4. Invoke an imb (instruction memory barrier) operation as required by the Alpha architecture.

  5. Execute the code.

  6. Call exc_remove_pc_range_table() and exc_remove_gp_range().

  7. Deallocate the memory containing the code.


 [TOC]  --SECT