Issue 260617.1: Clarify Address Classes vs. Address Spaces

Author: Cary Coutant
Champion:
Date submitted: 2026-06-17
Date revised: 2026-06-22
Date closed: 2026-06-22
Type: Clarification
Status: Accepted
DWARF version: 6

This is a clarification proposal to clarify the meaning of address spaces, which are used by the DW_OP_xderef operations, and address classes, which were once used to distinguish "near" and "far" pointers in the old 16-bit x86 world.

This is a prequel to 260211.1 General Support for Address Spaces, and should supercede the section of that proposal that adds a new section 2.12 Address Spaces. Instead of adding a new section and possibly removing the old 2.11 Address Classes, I suggest expanding 2.11 to discuss both concepts together in order to better draw the distinction between the two.

I've also added a short paragraph to define the term "address" in terms of an offset into a memory address space, so that it can be used unambiguously, and to deal with the possibility that addresses might be treated as signed on some architectures, while we've specified that offsets are always unsigned.

Background

PA-RISC had a “long pointer” type that consisted of a 32-bit space id and a 32-bit address, analogous to a “far” pointer on x86. On PA, as on other architectures that used a global address space, the process address space was segmented, but presented to the user space the illusion of a flat 2^32 byte virtual address space. A long pointer was used to access memory outside of that flat address space, and dereferencing one involved moving the space id to a free space register, and then using a load/store instruction specifying that space register explicitly (compared to the standard load that picked a space register based on the top two bits of the address).

In both x86 and PA cases, a pointer with one of these alternate address classes had all the information needed to identify a byte in memory, and the compiler knew, based on the declaration of the pointer, what kind of load or store sequence was needed. The DW_AT_address_class attribute simply relayed that information to the debugger.

Despite the fact that we agreed that the “near” and “far” pointers from the old pre-MMU 16-bit x86 world are obsolete, I think there’s at least a possibility that the concept remains useful on modern architectures, certainly PA, Itanium, and Power, which all use global virtual addressing. Perhaps we should have left in the obsolete class codes, just as an example for other architectures to follow. (They were non-normative anyway.)

In the address space proposal, 260211.1, we have a different situation: we have a pointer that is known to provide an address in a totally different address space, but the pointer itself does not provide that information. That proposal adds the DW_AT_address_space attribute to identify that alternate address space. There are examples outside the GPU world:

In the GPU world, the possibility has been raised that pointers for some address spaces may be larger or smaller than pointers to the default address space. That seems to me to be a separate consideration from the notion of address space, and the width of the pointer should be specified with a DW_AT_byte_size or DW_AT_bit_size attribute, while the address space that the pointer refers to is specified as an address space.

I suggest combining these concepts into one section.

I think we can drop the DW_AT_address_class attribute from subroutines and subroutine types. On legacy x86 systems, a “far” subroutine needed to be called with an intersegment CALL, and would return with an intersegment RET. This really should have been handled with DW_AT_calling_convention, and could be if ever needed again.

Proposal

In Section 2.5, add the following paragraph to the "Memory" bullet under "six kinds of storage":

An address is the offset of an addressable unit (byte or word) in a memory address space. On some systems, an address may be signed, and a negative address is converted to a positive byte or word offset formed by by biasing it by the size of the address space (e.g., in a 2^32 byte address space, using two's complement arithmetic, the address -0x8000 is equivalent to a byte offset of 0xffff8000).

Replace 2.11 Address Classes with the following:

2.11 Address Classes and Address Spaces

Some systems support different classes of addresses. The address class may affect the way a pointer is dereferenced or the way a subroutine is called.

Any debugging information entry representing a pointer or reference type or a subroutine or subroutine type may have a DW_AT_address_class attribute, whose value is an integer constant. The set of permissible values is specific to each target architecture. The value DW_ADDR_none, however, is common to all encodings, and means that no address class has been specified.

Some systems support different classes of addresses. The address class may affect the representation of a pointer and how it is dereferenced. Normally, a pointer is represented as an address in the default memory address space, where the memory can be accessed by standard load and store instruction. On some systems with segmented memory models or global virtual address spaces, an alternative pointer representation may consist of a separate segment identifier and an offset within that segment.

Examples of alternate address classes include:

  • x86 “far” pointers, which consist of a 16-bit segment identifier and either a 16- or 32-bit offset within the segment. Dereferencing a far pointer requires moving the segment identifier to a free segment register and using a segment override for the memory access.

  • PA-RISC “long” pointers, which consist of a 32-bit segment (termed “space” in PA-RISC documentation) identifier and a 32-bit offset. Dereferencing a long pointer requires moving the space identifier to a free space register and using the explicit space register number on the load or store instruction.

Some systems may also support more than one memory address space. There is always a default address space, and the default size of a pointer corresponds to the size of the default address space. The size of any other address space is not necessarily the same as the size of the default address space.

Examples of alternate address spaces include:

  • ”Harvard” architectures with separate code and data spaces.

  • Embedded systems with a separate address space for flash memory.

  • Heterogeneous systems with local memory spaces for each GPU, or where large register files are mapped to their own address space.

Any debugging information entry representing a pointer or reference type may have a DW_AT_address_class attribute, whose value is an integer constant. The set of permissible values is specific to each target architecture. The value DW_ADDR_none, however, is common to all encodings, and means that no address class has been specified (that is, the pointer or reference type uses the standard encoding of an address on the target architecture).

Address spaces are not guaranteed to be independent of one another; for example, one address space might provide an alternate addressing scheme for the same memory as another address space.

Address space identifiers are used by the DW_OP_xderef* operations (see Section 3.13).

[The following two paragraphs to replace the above paragraph with acceptance of 260211.1:]

Any debugging information entry representing a pointer or reference type may also have a DW_AT_address_space attribute, whose value is a non-negative integer constant which identifies the address space to which the pointer refers. The value DW_ASPACE_default identifies the default address space; other values and their uses are assigned by the ABI committee for the target.

Address space identifiers are also used by the DWARF operations DW_OP_mem (see Section 3.7), DW_OP_aspace_bregx (see Section 3.7), and DW_OP_aspace_deref* (see Section 3.13).

In Section 4.3.3 Subroutine and Entry Point Locations, remove the following paragraph:

Subroutines and entry points may also have a DW_AT_address_class attribute, if appropriate, to specify the addressing mode to be used in calling that subroutine.

In Section 6.3 Type Modifier Entries, after the paragraph "A modified type entry describing a pointer or reference type ... may have a DW_AT_address_class attribute...", add the following paragraph:

A modified type entry describing a pointer or reference type (using DW_TAG_pointer_type, DW_TAG_reference_type or DW_TAG_rvalue_reference_type) may have a DW_AT_byte_size or DW_AT_bit_size attribute whose integer constant value (see Section 2.20) is the amount of storage needed to hold the pointer value.

(These attributes are already explicitly listed for these types in Appendix A, Attributes by Tag.)

In Appendix A, Attributes by Tag, remove DW_AT_address_class from the following TAG entries:


2026-06-18: Revised to address review comments.

2026-06-22: Revised to add DW_AT_byte_size and DW_AT_bit_size for pointer and reference types.

2026-06-22: Accepted. In example for address-to-offset conversion, added note about two's complement arithmetic.