AUIPC
The AUIPC (Add Upper Immediate to Program Counter) instruction
in RISC-V builds PC-relative addresses by adding a 20-bit upper
immediate (shifted left by 12 bits with lower 12 bits filled
with zeros) to the current program counter, placing the result
in a destination register.
AUIPC Overview and Operation
- Syntax:
auipc rd, imm20
- Operation: R[rd] = PC + (imm20 << 12)
- Format: U-type format
- Details: It takes the 20-bit immediate, shifts it left by
12 bits to form a 32-bit offset (with the lowest 12 bits set to zero),
adds it to the current program counter (PC), and stores the final
32-bit (or sign-extended 64-bit) result into destination register rd.
Key Characteristics & Usage
- Position-Independent Code: Essential for writing
position-independent code (PIC), allowing software to run regardless
of where it is loaded in memory.
- Building 32-bit Offsets: Typically paired with a 12-bit I-type or
S-type instruction (like addi, lw, or sw) to construct a full 32-bit
PC-relative address or perform distant jumps/memory accesses.
- Reading the Program Counter: Because RISC-V does not provide
direct access to the program counter via general-purpose registers,
executing auipc rd, 0 effectively copies the current PC address
into register rd.
Test/Demo Code
# =================================================================
# 32-bit architecture
# =================================================================
# test/demo auipc
# =================================================================
.data
.text
.global main
# -----------------------------------------------------------------
# function: 99
# -----------------------------------------------------------------
func_99:
# -------------------------------------------------------------
# function prologue
# -------------------------------------------------------------
addi sp, sp, -4 # allocate stack frame
sw ra, 0(sp) # save caller's return address
# -------------------------------------------------------------
# function body
# -------------------------------------------------------------
li a0, 99
# -------------------------------------------------------------
# function epilogue (returned is already in a0)
# -------------------------------------------------------------
lw ra, 0(sp) # restore caller's return address
addi sp, sp, 4 # de-allocate stack frame
ret # return to caller
# -----------------------------------------------------------------
# main
# -----------------------------------------------------------------
main:
call func_99 # call func_99
li a7, 10 # syscall, exit program
ecall # syscall