2011-10-28 19 views
8

Estoy usando Linux con x86 (64 bits para ser precisos). ¿Hay alguna manera de que pueda obtener la dirección de la instrucción actual? En realidad, quiero escribir mis propias versiones simplificadas de setjmp/longjmp. Here, R .. publicó una versión simplificada de longjmp. Se implementa cualquier idea de cómo setjmp. Una versión simplificada, es decir, sin tener en cuenta las excepciones y señales, etc ...Obtener la dirección de la instrucción actual para x86

Respuesta

24

Creo en el código de 64 bits que simplemente puede hacer lea rax, [rip].

El idioma de 32 bits es:

 call next 
next: pop eax 
+0

Y es posible hacer algo así en 32 bits? – MetallicPriest

+1

@MetallicPriest: respuesta actualizada. – NPE

+0

truco genial hun :-p! – MetallicPriest

0

This sitio da una versión simple de setjmp y longjmp, que es como sigue.

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

¿Es esta la respuesta a su pregunta, @MetallicPriest? – karlphillip

+0

No necesariamente, puedo marcar su respuesta, si es buena :-p! – MetallicPriest

4

El registro-en offset-la-current-segmento (EIP) no es normalmente accesible. Sin embargo, hay una manera maliciosa de leerlo indirectamente: engañas al programa para que presione el valor de EIP en la pila, y luego lo lees. Se puede crear un subprograma que tiene este aspecto:

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

O, aún más simple:

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

Si utiliza una instrucción CALL FAR, el valor del segmento (CS) será empujado en la pila, así .


Si estás usando C, hay varios C-extensiones específicas del compilador que puede utilizar en this page. Consulte también this interesting article.

+0

OP pregunta acerca de x86_64, que tiene un direccionamiento relativo, por lo que hay instrucciones "accesibles" para RIP –

8

Si se utiliza GCC, también se puede utilizar __builtin_return_address

+2

. Tenga en cuenta que deberá envolverlo en una función para tener el efecto deseado, de lo contrario terminará con la dirección de retorno para el marco de pila actual en lugar de la dirección de la instrucción actual. – Jason

+2

si usa GCC es más fácil de usar ['somelabel: return && somelabel;'] (http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html) –

+1

@Jason tiene razón y también asegúrese de que la definición de la función de envoltura que contiene la __builtin_return_address no está en un archivo de encabezado y nunca estará en línea. –

Cuestiones relacionadas