Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does jmpq of x86-64 only need 32-bit length address?

As I use objdump -D to disassemble a binary, the typical code of jmpq is like e9 7f fe ff ff, which is used for representing a negative offset. However, the address of x86-64 is 64(48)-bit (to my knowledge), so how can this 32-bit address 7f fe ff ff represent the negative offset of 64-bit absolute address?

Additionally, are there any other instructions like jmp and jmpq, but have 64-bit address displacement? How can I find the instructions in Intel's or AMD's manual (I searched for jmpq but found nothing)?


As I searched, it seems to be called RIP-relative addressing. And it seems that not all instructions do this. Is there 64-bit relative addressing? If it is an indirect jump, the 64-bit absolute address would be in a register or memory, right?

like image 676
WindChaser Avatar asked Nov 16 '14 08:11

WindChaser


People also ask

How long is x86 64 address?

The AMD64 architecture defines a 64-bit virtual address format, of which the low-order 48 bits are used in current implementations. This allows up to 256 TiB (248 bytes) of virtual address space.

What does * mean in x86?

It's a jump to an address contained in memory. The address is stored in memory at address rax*8+0x402680 , where rax is the current rax value (when this instruction executes).

When did 64-bit architecture start?

Who's Doing What? Intel has been the microprocessor industry's 800-pound gorilla from the beginning. The company began 64-bit development in 1991, and the first systems with its 64-bit Itanium CPUs shipped in 2001.

What is a far jump?

Far jump—A jump to an instruction located in a different segment than the current code segment but at the same privilege level, sometimes referred to as an intersegment jump.


Video Answer


1 Answers

As others have noted, the "jmp relative" instruction for x86-64 is limited to a 32 bit signed displacement, used as a relative offset with respect to the program counter.

OP asked why there is no relative jump with a 64 bit offset. I can't speak for the designers at Intel, but it seems pretty clear that this instruction would simply not be very useful, especially with the availability of the 32-bit relative jmp. The only time it would be needed is when your program was 2+ gigabytes in size, so that the 32 bit relative jmp could not reach all of it from any point within it. Seen any 2Gb object files recently? So the apparent utility for such instructions seems really small.

Mostly when programs get really large, they start to be broken into more manageable elements that can evolve at different rates. (DLLs are an example of this). Interfacing between such elements is done by more arcane means (jump vectors, etc) to ensure that the interfaces stay constant in the face of evolution. An extremely-long jmp relative could be used to reach from an application to an entry point in another module, but the actual cost of loading an absolute address into a register and doing an register-indirect call, is small enough in practice that it isn't worth optimizing. And modern CPU design is all about optimizing where you put your transistors to maximize performance.

Just to be complete, the x86 (many flavors) have very short jmp relative instructions (8 bit signed offset), too. In practice, even the 32 bit jmp relative instructions are rarely needed, especially if you have a good code generator that can rearrange code blocks. Intel arguably could have left these out for the same reason; I suspect their utility is marginally high enough to justify the transistors.

The question of "big literal operands" shows up in funny ways in many architectures. If you examine the distribution of literal values in code, you'll discover that small values (0,1, ascii character codes) cover a pretty good percentage; almost everything else are memory addresses. So you kind of don't need "big literal values" in programs but you do have to handle memory addresses somehow. The Sparc chip famously has "load literal value low into register" (meaning "small constants") and less often used "load literal value high" (to fill upper bits in a register) used as a second instruction to make big constants, and used less often. This keeps the code small, except when you need a big constant; small code means higher effective instruction fetch rates and that contributes to performance.

like image 159
Ira Baxter Avatar answered Oct 21 '22 08:10

Ira Baxter