lbu

lbu

RISC-V Assembly Reference

lyszt.net covers lbu and other RISC-V instructions in more detail.

Encoding format

R
31–25funct7
24–20rs2
19–15rs1
14–12funct3
11–7rd
6–0opcode
I
31–20imm[11:0]
19–15rs1
14–12funct3
11–7rd
6–0opcode
S
31–25imm[11:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:0]
6–0opcode
B
31–25imm[12,10:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:1,11]
6–0opcode
U
31–12imm[31:12]
11–7rd
6–0opcode
J
31–12imm[20,10:1,11,19:12]
11–7rd
6–0opcode

Description

lbu reads one byte (8 bits) from memory as an unsigned value. It pairs with lb, and the two differ only in how they fill the rest of the register. Both read one byte using the same addressing. The lb page covers bytes and the addressing form. The form of lbu appears below.

lbu rd, offset(rs1)

A register holds 32 bits, so a 1-byte load leaves 24 bits to fill. lb copies the top bit of the byte into those bits, which is sign extension and can produce a negative number. lbu fills them with 0s, so the result always falls between 0 and 255. The u stands for the unsigned reading.

Text loads normally use lbu. Character codes are unsigned, and many have their top bit set, including accented letters and various symbols. The sign-extending lb makes those negative and breaks comparisons. The standard text loop uses lbu. It loads a byte, checks whether it is zero, which marks the end of the text, processes it and adds 1 to the address.

The RISC-V manual defines lb and lbu as the 8-bit versions of the halfword loads, with the same effective address of register rs1 plus the sign-extended 12-bit offset. Memory is byte-addressed, so each address names one byte.

lbu also suits other byte data, including color channels in images, raw data buffers and instruction bytes in an interpreter. Bytes loaded this way have no sign to handle, so they combine directly with shifts and ORs when a larger value is rebuilt from single bytes. Use lb only when the 8-bit data is signed.

Example

.data
val: .byte 0xff
.text
la t0, val
lbu t1, 0(t0)   # t1 = 255 (zero-extended)