Get address of current instruction for x86

20,808

Solution 1

I believe in 64-bit code you can simply do lea rax, [rip].

The 32-bit idiom is:

      call next
next: pop eax

Solution 2

If using GCC, you could also use __builtin_return_address

Solution 3

The offset-into-the-current-segment register (EIP) is not normally accessible. However, there is a hackish-way to read it indirectly - you trick the program into pushing the value of EIP onto the stack, then just read it off. You could create a subroutine that looks like this:

GetAddress:
    mov eax, [esp]
    ret
...
    call GetAddress     ; address of this line stored in eax

Or, even simpler:

    call NextLine
NextLine:
    pop eax             ; address of previous line stored in EAX

If you use a CALL FAR instruction, the segment value (CS) will be pushed on the stack as well.


If you're using C, there are various compiler-specific C-extensions you could use on this page. See also this interesting article.

Solution 4

This site gives a simple version of setjmp and longjmp, which is as follows.

#include "setjmp.h"

#define OFS_EBP   0
#define OFS_EBX   4
#define OFS_EDI   8
#define OFS_ESI   12
#define OFS_ESP   16
#define OFS_EIP   20

__declspec(naked) int setjmp(jmp_buf env)
{
  __asm
  {
    mov edx, 4[esp]          // Get jmp_buf pointer
    mov eax, [esp]           // Save EIP
    mov OFS_EIP[edx], eax
    mov OFS_EBP[edx], ebp    // Save EBP, EBX, EDI, ESI, and ESP
    mov OFS_EBX[edx], ebx
    mov OFS_EDI[edx], edi
    mov OFS_ESI[edx], esi
    mov OFS_ESP[edx], esp
    xor eax, eax             // Return 0
    ret
  }
}

__declspec(naked) void longjmp(jmp_buf env, int value)
{
  __asm
  {
    mov edx, 4[esp]          // Get jmp_buf pointer
    mov eax, 8[esp]          // Get return value (eax)

    mov esp, OFS_ESP[edx]    // Switch to new stack position
    mov ebx, OFS_EIP[edx]    // Get new EIP value and set as return address
    mov [esp], ebx

    mov ebp, OFS_EBP[edx]    // Restore EBP, EBX, EDI, and ESI
    mov ebx, OFS_EBX[edx]
    mov edi, OFS_EDI[edx]
    mov esi, OFS_ESI[edx]

    ret
  }
}
Share:
20,808
MetallicPriest
Author by

MetallicPriest

Updated on October 29, 2020

Comments

  • MetallicPriest
    MetallicPriest over 3 years

    I am using Linux with x86 (64 bit to be precise). Is there a way I can get the address of the current instruction. Actually I want to write my own simplified versions of setjmp/longjmp. Here, R.. posted a simplified version of longjmp. Any idea how setjmp is implemented. A simplified version that is, without taking into account of exceptions and signals etc...

  • MetallicPriest
    MetallicPriest over 12 years
    And is it possible to do something like that in 32 bit?
  • NPE
    NPE over 12 years
    @MetallicPriest: Answer updated.
  • karlphillip
    karlphillip over 12 years
    IS this the answer of your question, @MetallicPriest ?
  • MetallicPriest
    MetallicPriest over 12 years
    Not necessarily, I may tick your answer, if its good :-p!
  • Jason
    Jason over 12 years
    Keep in mind you'll need to wrap that in a function in order to have the intended effect, otherwise you'll end up with the return address for the current stack frame rather than the address of the current instruction.
  • Polynomial
    Polynomial over 12 years
    I often require the address repeatedly during a block of code, so I do call next and access the value using [esp] rather than by popping it into a register. It gives you an extra free register to use and you can just do add esp, 4 (on a downward growing stack) to clean up the stack when you're done.
  • Alexey Frunze
    Alexey Frunze over 11 years
    Another option in assembly mov (r|e)ax, $ or mylabel: mov (r|e)ax, offset mylabel.
  • phuclv
    phuclv over 10 years
    if using GCC it's easier to use somelabel: return &&somelabel;
  • phuclv
    phuclv over 10 years
    the OP asks about x86_64, which has relative addressing, so there are instructions "accessible" to RIP
  • phuclv
    phuclv over 9 years
    this idiom is actually not recommended blogs.msdn.com/b/oldnewthing/archive/2004/12/16/317157.aspx
  • Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com about 9 years
    lea rax, [rip] did not work in NASM 2.10. It seems that RIP can only be used indirectly with rel as in lea rax, [rel _start]?
  • Michal Fapso
    Michal Fapso almost 7 years
    @Jason is right and also make sure the definition of the wrapping function containing the __builtin_return_address is not in a header file and will never be inlined.
  • Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com almost 5 years