2011-10-28 2 views
8

Sto usando Linux con x86 (64 bit per la precisione). C'è un modo per ottenere l'indirizzo dell'istruzione corrente. In realtà voglio scrivere le mie versioni semplificate di setjmp/longjmp. Here, R .. ha pubblicato una versione semplificata di longjmp. Qualche idea su come sia implementato setjmp. Una versione semplificata che è, senza tener conto di eccezioni e segnali ecc ...Ottieni l'indirizzo dell'istruzione corrente per x86

risposta

24

Credo nel codice a 64 bit che puoi semplicemente fare lea rax, [rip].

L'idioma a 32 bit è:

 call next 
next: pop eax 
+0

E 'possibile fare qualcosa di simile a 32 bit? – MetallicPriest

+1

@MetallicPriest: risposta aggiornata. – NPE

+0

Cool trick hun :-p! – MetallicPriest

0

This sito fornisce una semplice versione di setjmp e longjmp, che è la seguente.

#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

È questa la risposta alla tua domanda, @MetallicPriest? – karlphillip

+0

Non necessariamente, posso spuntare la tua risposta, se è buona :-p! – MetallicPriest

4

Il registro offset in-the-corrente-segmento (EIP) non è normalmente accessibile. Tuttavia, c'è un modo hacker di leggerlo indirettamente: si induce il programma a spingere il valore di EIP sullo stack, quindi basta leggerlo. Si potrebbe creare una subroutine che assomiglia a questo:

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

Oppure, ancora più semplice:

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

Se si utilizza un'istruzione CALL FAR, il valore di segmento (CS) sarà spinto sullo stack pure .


Se stai usando C, ci sono vari C-estensioni specifiche del compilatore è possibile utilizzare il this page. Vedi anche this interesting article.

+0

l'OP chiede su x86_64, che ha l'indirizzamento relativo, quindi ci sono istruzioni "accessibili" a RIP –

8

Se si utilizza GCC, si potrebbe anche usare __builtin_return_address

+2

Tieni presente che sarà necessario avvolgerlo in una funzione per avere l'effetto desiderato, altrimenti ti ritroverai con l'indirizzo di ritorno per il frame dello stack corrente anziché l'indirizzo dell'istruzione corrente. – Jason

+2

se usi GCC è più facile usare ['somelabel: return && somelabel;'] (http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html) –

+1

@Jason ha ragione ed anche assicurarti che la definizione della funzione di wrapping che contiene __builtin_return_address non si trova in un file di intestazione e non sarà mai in linea. –