HLASM Addressing: Base-Displacement and Indexed Addressing

TT

HLASM Addressing: Base-Displacement and Indexed Addressing

z/Architecture uses base-displacement addressing for all storage references. Understanding how the assembler generates addresses — and how base registers work — is fundamental to writing correct HLASM programs.

Base-Displacement Addressing

Every storage reference in a machine instruction is encoded as:

text
Address = Base Register + Displacement

The displacement is a 12-bit unsigned value (0–4095). The base register is a 4-bit field specifying which GPR holds the base address.

So to reference byte 100 of a table that starts at the address in register 12:

hlasm
         L     3,100(12)       Load from address: reg12 + 100

How the Assembler Resolves Labels

When you write:

hlasm
         L     3,MYDATA

The assembler needs to generate a base-displacement pair. It uses the USING directive to know which register holds which base address:

hlasm
MYPROG   CSECT
         LR    12,15           Register 12 = entry point address
         USING MYPROG,12       Register 12 covers MYPROG through MYPROG+4095

MYDATA   DC    F'42'           Say MYDATA is at offset 100 from MYPROG
         L     3,MYDATA        Assembler generates: L 3,100(12)

The assembler subtracts the USING base (MYPROG) from the label address (MYPROG+100) to get the displacement (100), then uses register 12 as the base.

BALR — Branch and Link Register

BALR reg1,reg2 loads the address of the next instruction into reg1, then branches to reg2:

hlasm
MYPROG   CSECT
         BALR  12,0            Load address of NEXT instruction into reg 12
*                              reg2=0 means no branch — just load the address
         USING *,12            * means current location = just past BALR

The * in USING means "current location counter" — the address right after the BALR. This is the standard pre-BASR base register setup idiom.

BASR — Branch and Save Register (modern)

BASR is the 64-bit-safe version of BALR:

hlasm
MYPROG   CSECT
         BASR  12,0            Load address of next instruction into reg 12
         USING *,12

Use BASR in new code; BALR in programs that must run in 24-bit addressing mode.

Multiple Base Registers

A CSECT can span more than 4096 bytes. Use additional base registers:

hlasm
BIGPROG  CSECT
         STM   14,12,12(13)
         LR    12,15           First base: covers bytes 0–4095
         USING BIGPROG,12
         LA    11,2048(12)     Second base: reg12 + 2048 (overlapping coverage is fine)
         USING BIGPROG+2048,11
         LA    10,4096(12)     Third base if needed: covers bytes 4096–8191
         USING BIGPROG+4096,10

DROP — Remove a USING

DROP reg cancels a USING association:

hlasm
         USING MYDSECT,5       Map a DSECT using reg 5
*        ... use MYDSECT fields ...
         DROP  5               Cancel the USING when done

Drop a register when you reuse it for a different base, to prevent the assembler from generating incorrect addresses.

Indexed Addressing

D(X,B) adds an index register to the base-displacement address:

hlasm
* Access element I of a table where each element is 4 bytes
         L     5,INDEX         Load index (element number)
         SLL   5,2             Multiply by 4 (element size = 2^2)
         L     3,TABLE(5,12)   Load from TABLE + reg5 + reg12
*        Equivalent to: address = TABLE_offset + reg5 + reg12
TABLE    DS    10F             10-element table
INDEX    DC    F'3'

Without explicit index: L 3,TABLE(12) — displacement only. With index: L 3,0(5,12) — displacement 0, index in reg 5, base in reg 12.

Absolute Addressing with Explicit Registers

When you know the exact displacement:

hlasm
         L     3,12(13)        Load from save area + 12 (return address)
         L     3,8(13)         Load forward chain pointer from save area
         ST    15,16(13)       Store return code at save area + 16

Frequently Asked Questions

Q: What happens if a label is more than 4095 bytes from the base register? The assembler issues an error: "USING range exceeded" or similar. The displacement field is only 12 bits (0–4095), so if the label is further than 4095 bytes from the nearest base, the assembler cannot generate a valid address. The solution is to add another base register pointing to an address closer to the problematic label, and add a corresponding USING directive.

Q: Can I use register 0 as a base register? No. Register 0 has a special meaning in base-displacement addressing: when the base register field is 0, it means "no base register" and the effective address is just the displacement (0–4095). The assembler will allow USING label,0 but this only covers addresses 0–4095, which are z/OS system areas. In practice, never use register 0 as a base register.

Q: What is the difference between USING and the runtime setup? USING is a purely assembler-time directive — it tells the assembler which register holds which base address when generating address constants. It does NOT generate any machine instructions. You must actually load the correct address into the register at runtime (with BALR, BASR, LR, or L). The USING tells the assembler what you intend to do; the LR/BALR actually does it. Forgetting the runtime setup while having a USING results in incorrect addresses at runtime.


Part of HLASM Mastery Course — Module 13 of 22.