Linux 获取 x86 的当前指令地址

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7932287/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 06:53:59  来源:igfitidea点击:

Get address of current instruction for x86

clinuxassembly64-bitx86

提问by MetallicPriest

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 setjmpis implemented. A simplified version that is, without taking into account of exceptions and signals etc...

我在 x86(准确地说是 64 位)上使用 Linux。有没有办法获得当前指令的地址。其实我想编写我自己的setjmp/longjmp的简化版本。在这里,R.. 发布了longjmp的简化版本。任何想法setjmp是如何实现的。一个简化版本,即不考虑异常和信号等...

采纳答案by NPE

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

我相信 64 位代码你可以简单地做lea rax, [rip]

The 32-bit idiom is:

32 位的习惯用法是:

      call next
next: pop eax

回答by MetallicPriest

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

网站提供了一个简单的版本setjmp和longjmp的,这是如下。

#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
  }
}

回答by BlueRaja - Danny Pflughoeft

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:

偏移到当前段寄存器 ( EIP) 通常不可访问。然而,有一种间接读取它的hackish-way - 你欺骗程序将EIP的值推送到堆栈上,然后读取它。您可以创建一个如下所示的子程序:

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 FARinstruction, the segment value (CS) will be pushed on the stack as well.

如果使用CALL FAR指令,段值 ( CS) 也将被压入堆栈。



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

如果您使用 C,则可以在此页面上使用各种特定于编译器的 C 扩展。另请参阅这篇有趣的文章

回答by Basile Starynkevitch

If using GCC, you could also use __builtin_return_address

如果使用 GCC,您还可以使用 __builtin_return_address