C 获取x86的当前指令的地址

C 获取x86的当前指令的地址,c,linux,assembly,64-bit,x86,C,Linux,Assembly,64 Bit,X86,我正在使用Linux和x86(准确地说是64位)。有没有办法得到当前指令的地址。实际上,我想编写自己的简化版的setjmp/longjmp,R发布了一个简化版的longjmp。任何关于如何实现setjmp的想法。一个简化版本,即不考虑异常和信号等。我相信64位代码可以简单地执行lea-rax、[rip] 32位习惯用法是: call next next: pop eax 站点提供了setjmp和longjmp的简单版本,如下所示 #include "setjmp.h" #defi

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

我相信64位代码可以简单地执行
lea-rax、[rip]

32位习惯用法是:

      call next
next: pop eax
站点提供了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
  }
}

当前段寄存器(
EIP
)中的偏移量通常不可访问。然而,有一种黑客的方式可以间接读取它——你欺骗程序将EIP的值推到堆栈上,然后直接读取它。您可以创建如下所示的子例程:

GetAddress:
    mov eax, [esp]
    ret
...
    call GetAddress     ; address of this line stored in eax
或者更简单一点:

    call NextLine
NextLine:
    pop eax             ; address of previous line stored in EAX
如果使用
调用FAR
指令,那么段值(
CS
)也将被推送到堆栈上



如果您使用的是C,那么您可以在上使用各种特定于编译器的C扩展。另请参见。

如果使用GCC,您也可以使用

并且可以在32位中执行类似操作吗?@MetallicPrist:答案已更新。我经常在代码块期间重复要求地址,因此我使用
调用next
并使用
[esp]
访问值,而不是将其弹出到寄存器中。它为您提供了一个额外的免费寄存器供您使用,您只需执行
添加esp,4
(在向下增长的堆栈上)即可在完成后清理堆栈。汇编
mov(r | e)ax,$
mylabel:mov(r | e)ax,offset mylabel
中的另一个选项在NASM 2.10中不起作用。似乎RIP只能间接地与
rel
一起使用,如
lea-rax,[rel\u start]
?这是你问题的答案吗,@metallicpaprest?不一定,我可以勾选你的答案,如果好的话:-p!请记住,为了达到预期效果,您需要将其包装在函数中,否则,您将得到当前堆栈帧的返回地址,而不是当前指令的地址。如果使用GCC,则更容易使用@Jason是正确的,并且还要确保包含_builtin_return_地址的包装函数的定义不在头文件中,并且永远不会内联。@phuclv yes,另请参见:OP询问有关x86_64的信息,它具有相对寻址,因此RIP有“可访问”的指令