This question already has an answer here:
这个问题在这里已有答案:
- Reading program counter directly 6 answers
- 直接阅读程序计数器6个答案
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...
我使用Linux与x86(准确地说是64位)。有没有办法可以得到当前指令的地址。其实我想写自己的简化版本的setjmp / longjmp。在这里,R ..发布了longjmp的简化版本。知道如何实现setjmp。一个简化的版本,没有考虑异常和信号等...
4 个解决方案
#1
25
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
#2
#3
5
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方式 - 你欺骗程序将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 FAR
instruction, 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扩展。另见这篇有趣的文章。
#4
1
This site 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
}
}
#1
25
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
#2
#3
5
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方式 - 你欺骗程序将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 FAR
instruction, 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扩展。另见这篇有趣的文章。
#4
1
This site 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
}
}