目录 ← 首页
CS61C

RISC-V Addressing Modes

Learning Outcomes

  • Contrast PC-relative addressing with absolute addressing.
  • Given assembly code with labels, compute PC-relative offsets for conditional branches and unconditional jumps.

We recommend reviewing RISC-V control flow before continuing.

  • One section describes how by default, the Program Counter (PC) is incremented by 4 bytes, corresponding to the next sequential instruction.
  • Another section describes unconditional jumps (e.g., j Label) and conditional branches (e.g., beq rs1 rs2 Label).

Addressing Modes

There are different addressing modes–that is, ways of using operands and/or addresses encoded in the instruction.

We have seen one addressing mode already with loads and stores. These instructions use base or displacement addressing, which computes addresses as a sum of a register in the register file (x0-31) and a immediate constant encoded in the instruction.

RISC-V uses two addressing modes to compute instruction addresses to update the PC:

  • PC-relative addressing, which computes addresses by summing PC with a signed constant offset, e.g., PC = PC + offset
  • Absolute addressing, which computes addresses from a register, e.g., PC = R[rs1] + imm.

PC-Relative Addressing

In almost all cases, instructions update the PC using PC-relative addressing.

  • Arithmetic instructions, loads, and stores: offset is +4+4
  • Branches
  • J-Type instructions (see a later section)
  • (Effectively, all instructions except jalr)

Why? Position-Independent Code. If all an entire code block, these relative offsets won’t change!

From Labels to PC-Relative Offsets

Recall that in assembly, unconditional jumps and conditional branches uses labels, e.g., j Label and beq rs1 rs2 Label. Labels are not instructions and do not actually “exist” in machine code.

Building machine instructions therefore requires translating labels into numeric constants that can be used for addressing. All branch and jump instructions that use labels use PC-relative addressing.

To translate branch and jump instructions to machine code, we must compute PC-relative offsets, which are numeric constants.

1. beq x19 x10 End, if branch is not taken. In this case, PC updates to the next sequential instruction. The PC-relative offset is +4+4.

2. beq x19 x10 End, if branch is taken. In this case, PC updates to the instruction tagged with the End label. Consider #fig-offsets, which assigns toy addresses to each instruction in the above assembly. Here, the pc updates from beq (at address 0x0C) to End’s instruction (at address 0x1C). This difference is 0x10, or +16. This corresponds to the fourth instruction after beq.

Assembly at memory addresses 0x0c–0x1c: Loop beq x19 x10 End, then add and addi instructions, an unconditional j Loop instruction, and an End label for a target instruction; curved arrows show a forward branch from beq to End and a backward jump from j Loop to Loop.

Code illustrated example with jump operation.

  1. j Loop. In this case, PC updates to the instruction tagged with the Loop label (here, beq). Still considering #fig-offsets, the pc updates from j (at address 0x18) to Loop’s instruction (at address 0x0C). This difference is 12-12. This corresponds to three instructions before j.

Absolute Addressing

By contrast, absolute addressing supplies a new address to overwrite the PC. This addressing mode is position-dependent and is brittle to code movement (as we will see later).

Only jalr (an I-Type instruction) uses absolute addressing by setting PC = R[rs1] + imm. Doing so often involves building a 32-bit immediate, which is possible using the U-Type instruction format we discuss in this chapter.