Can rip be used with another register with RIP-relative addressing?

No, [RIP + rel32] is the only addressing mode involving RIP. See also Referencing the contents of a memory location. (x86 addressing modes).

If you want maximum efficiency for indexing a static array, you need to make position-dependent code so you can use the table address as a 32-bit absolute disp32 in a normal addressing mode. This is allowed in Linux in position-depended executables, but not shared libraries (which have to be PIC). See 32-bit absolute addresses no longer allowed in x86-64 Linux? for how to use -fno-pie -no-pie when gcc is configured by default to make PIEs.

Otherwise for position-independent array indexing, lea rsi, [rip + Lsomething] and use pointer-increments or [rsi + rdi*1 + constant] addressing modes, or whatever other alternative works. (Non-indexed addressing modes sometimes save a uop on Intel CPUs so pointer-increments can be good, especially if you’re unrolling so an add for each pointer can more than pay for itself, vs. using the same index for multiple arrays.)

It’s not “RIP as a base register” in arbitrary addressing modes; there isn’t room in the machine-code encoding for that. x86-64 has 16 possible base registers, encoded with 3 bits in the ModR/M or SIB byte + 1 bit in the optional REX prefix. Making RIP usable as a base with arbitrary addressing modes would have required bumping out some other register, and creating a lot of differences in effective-address decoding between 32 and 64-bit mode.

x86-32 has 2 redundant ways to encode [0x123456], i.e. no-base + disp32: with or without a SIB byte, because SIB has an encoding for no-base and no-index. See for a nice table, or see Intel’s manuals.

The no-index SIB encoding makes it possible to encode [esp] instead of [esp+esp], because the ModR/M encoding that would mean base=RSP is the escape code that means “there’s a SIB”. They could have designed it so you could use esp as an index for bases other than esp, but nobody wants to use esp as an index in the first place. Fun fact: the no-base (with disp32) encoding uses what would have been the [ebp] with no displacement, which is why [ebp] is actually encoded as [ebp + disp8=0]. In x86-64 mode, this applies to R13 as well.

x86-64 re-purposes the shorter (no SIB) encoding for [disp32] into [RIP + disp32], aka [RIP + rel32].

32-bit absolute addresses ([disp32]) are still encodeable with the longer SIB encoding. (This is what NASM does by default, if you don’t use default rel.) There’s not even a [RIP + disp8] (e.g. for loading nearby code addresses). There is exactly one bit-pattern in the Mod and M fields of the ModR/M byte that encodes a RIP-relative address.

Leave a Comment