Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
928 views
in Technique[技术] by (71.8m points)

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

I'm familiar with memory references of this form:

XXX ptr [base + index * size + displacement]

where XXX is some size (byte/word/dword/etc), both base and index are registers, size is a small power of two, and displacement is a signed value.

amd64 introduced rip-relative addressing. As I understand it, I should be able to use rip as a base register. However, when I try this with clang-900.0.39.2:

mov r8b, byte ptr [rip + rdi * 1 + Lsomething]

I get:

error: invalid base+index expression

mov r8b, byte ptr [rip + rdi * 1 + Lsomething]

Is it impossible to use an index register when using rip as the base register? Do I have to use lea to compute rip + Lsomething and then offset into that?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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 http://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...