Domanda

Sto usando Borland Turbo C ++ con un codice assemblatore inline, quindi presumibilmente codice assembly in stile Turbo Assembler (TASM). Vorrei fare quanto segue:

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
SomeLabel:
    // ...
}

Quindi l'indirizzo di SomeLabel viene inserito in EAX. Questo non funziona e il compilatore si lamenta di: simbolo indefinito "SomeLabel".

In Microsoft Assembler (MASM) il simbolo del dollaro ($) funge da contatore della posizione corrente, il che sarebbe utile per il mio scopo. Ma questo non sembra funzionare in Borlands Assember (errore di sintassi delle espressioni).

Aggiornamento: per essere un po 'più specifico, ho bisogno che il compilatore generi l'indirizzo che si sposta in eax come costante durante la compilazione / collegamento e non in fase di esecuzione, quindi verrà compilato come " mov eax, 0x00401234 " ;.

Qualcuno può suggerire come farlo funzionare?

AGGIORNAMENTO: per rispondere alla domanda di Pax (vedi commento), Se l'indirizzo di base viene modificato in fase di esecuzione dal caricatore di Windows, l'immagine del PE DLL / EXE verrà comunque trasferita dal caricatore di Windows e l'indirizzo delle etichette verrà patchato a tempo di esecuzione da parte del caricatore per utilizzare l'indirizzo di base in modo che l'utilizzo di un valore di tempo di compilazione / collegamento per l'indirizzo dell'etichetta non sia un problema.

Molte grazie in anticipo.

È stato utile?

Soluzione

L'ultima volta che ho provato a rendere compatibile con Borland un codice assembly, ho riscontrato la limitazione che non è possibile inoltrare le etichette di riferimento. Non sono sicuro che sia quello che stai incontrando qui.

Altri suggerimenti

Tutto ciò che posso trovare su Borland suggerisce che dovrebbe funzionare. Domande simili su altri siti ( qui e qui ) suggeriscono che Borland può gestire i riferimenti diretti per le etichette, ma insiste su le etichette si trovano all'esterno di blocchi asm. Tuttavia, poiché la tua etichetta era già fuori dal blocco asm ...

Sono curioso di sapere se il tuo compilatore ti permetterebbe di usare questa etichetta all'interno, ad esempio, di un'istruzione jmp. Quando ci giocavo (è vero, su un compilatore completamente diverso), ho trovato una fastidiosa tendenza per il compilatore a lamentarsi dei tipi di operando.

La sintassi è abbastanza diversa, ed è il mio primo tentativo di inline asm da molto tempo, ma credo di averlo mungato abbastanza per funzionare sotto gcc. Forse, nonostante le differenze, questo potrebbe esserti utile:

#include <stdio.h>
int main()
{
    void *too = &&SomeLabel;
    unsigned int out;
    asm
    (
      "movl %0, %%eax;"
      :"=a"(out)
      :"r"(&&SomeLabel)
    );
SomeLabel:
    printf("Result: %p %x\n", too, out);

    return 0;
}

Questo genera:

...
        movl    $.L2, %eax
...
.L2:

L'& amp; & amp; l'operatore è un'estensione non standard, non mi aspetto che funzioni altro che gcc. Spero che questo possa aver suscitato alcune nuove idee ... Buona fortuna!

Modifica: sebbene sia elencato come specifico di Microsoft, qui è un'altra istanza di saltare alle etichette.

3 suggerimenti:

1) metti un '_' davanti a SomeLabel nell'assieme in modo che diventi " mov eax, _SomeLabel & Quot ;. Di solito il compilatore ne aggiunge uno quando traduce C in assembly.

o

2) metti l'etichetta in una sezione di assemblaggio. Ciò impedirà al compilatore di aggiungere '_'.

o

3) commentare l'assembly, compilare e cercare nel file di elenco (* .lst) per vedere come diventa il nome dell'etichetta.

L'ambiente Turbo C ++ ha un modo per impostare le opzioni per TASM (so che alcuni degli IDE di Borland lo hanno fatto)?

In tal caso, verifica se si modifica l'opzione per " Passaggi massimi (/ m) " a 2 o più aiuti (potrebbe essere predefinito 1 passaggio).

Inoltre, se stai utilizzando un nome di etichetta lungo che potrebbe rappresentare un problema - almeno un IDE aveva l'impostazione predefinita impostata su 12. Modifica l'opzione " Lunghezza massima simbolo (/ mv) " ;.

Queste informazioni si basano sull'IDE RAD Studio di Borland:

Un altro paio di cose (scatti nel buio) da provare:

  • verifica se l'utilizzo delle seguenti istruzioni di assemblaggio aiuta:

    mov eax, offset SomeLabel
    
  • la maggior parte dei compilatori può produrre un elenco di assiemi del codice che generano (non sono sicuro che Turbo C ++ sia in grado, poiché Codegear / Embarcadero lo posizionano come un compilatore gratuito e non professionale).

    Prova a produrre un elenco con codice C che utilizza un'etichetta (ad esempio come destinazione goto ), con alcuni assembly inline nella stessa funzione, ma non provare ad accedere all'etichetta dall'assemblea. In questo modo è possibile ottenere un compilatore senza errori e un elenco di assiemi. Qualcosa del tipo:

    int foo()
    {
        int x = 3;
        printf( "x =%d\n", x);
        goto SomeLabel;
                               //
        __asm {
            mov eax, 0x01
        }
                               //
    SomeLabel:
        printf( "x =%d\n", x);
                               //
        return x;
    }
    

    Guarda l'elenco dell'assembly e vedi se l'assembly generato decora il nome dell'etichetta in un modo che potresti essere in grado di replicare nell'assembly in linea.

Da quello che ricordo, non è possibile utilizzare un'etichetta esterna (C ++) nell'assembly inline, anche se è possibile avere etichette in stile TASM nel blocco asm a cui si può fare riferimento dalle stesse istruzioni di assemblaggio. Penso che userei un flag e un'istruzione switch post-assemblatore per gestire la ramificazione. Ad esempio:

int result=0;

__asm__ {
    mov result, 1
}

switch (result){
    case 1:  printf("You wanted case 1 to happen in your assembler\n"); break;
    case 0:  printf("Nothing changed with the result variable.. defaulting to:\n");
    default: printf("Default case!\n"); break;
}

Non conosco specificamente il tuo compilatore / assemblatore, ma un trucco che ho usato un po 'è chiamare la posizione successiva e quindi inserire lo stack nel tuo registro. Assicurati che la chiamata che fai spinga solo l'indirizzo di ritorno.

Penso che il problema che stai riscontrando sia che un'etichetta all'interno del blocco __asm ?? e l'etichetta nel codice C ++ sono due cose completamente diverse. Non mi aspetto che tu possa fare riferimento a un'etichetta C ++ in quel modo dall'assemblaggio in linea, ma devo dire che è passato molto tempo da quando ho usato Turbo C ++.

Hai provato l'istruzione lea invece di mov ?

Indovina solo perché non ho usato l'assemblatore inline con nessun compilatore C / ++ ...

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
    __asm
    {
      SomeLabel:
      // ...
    }
    // ...
}

Non conosco l'esatta sintassi di TASM.

Questa è una variante del suggerimento di Ivan, ma provalo:

void foo::bar( void )
{
    __asm
    {
      mov eax, offset SomeLabel
      // ...
    }
    // ...
    __asm SomeLabel:
    // ...
}

Ecco un possibile metodo:

// get_address
// gets the address of the instruction following the call
// to this function, for example
//     int addr = get_address (); // effectively returns the address of 'label'
//   label:
int get_address ()
{
    int address;
    asm
    {
        mov eax,[esp+8]
        mov address,eax
    }
    return address;
}
// get_label_address
// a bit like get_address but returns the address of the instruction pointed
// to by the jmp instruction after the call to this function, for example:
//     int addr;
//     asm
//     {
//       call get_label_address // gets the address of 'label'
//       jmp label
//       mov addr,eax
//     }
//     <some code>
//   label:
// note that the function should only be called from within an asm block.
int get_label_address()
{
    int address = 0;
    asm
    {
        mov esi,[esp+12]
        mov al,[esi]
        cmp al,0ebh
        jne not_short
        movsx eax,byte ptr [esi+1]
        lea eax,[eax+esi-1]
        mov address,eax
        add esi,2
        mov [esp+12],esi
        jmp done
    not_short:
        cmp al,0e9h
        jne not_long
        mov eax,dword ptr [esi+1]
        lea eax,[eax+esi+2]
        mov address,eax
        add esi,5
        mov [esp+12],esi
        jmp done
    not_long:
        // handle other jmp forms or generate an error
    done:
    }
    return address;
}
int main(int argc, char* argv[])
{
    int addr1,addr2;
    asm
    {
        call get_label_address
        jmp Label1
        mov addr1,eax
    }

    addr2 = get_address ();
Label1:
    return 0;
}

È un po 'confuso ma funziona nella versione di Turbo C ++ che ho. Quasi certamente dipende dal compilatore e dalle impostazioni di ottimizzazione.

una delle opzioni sarebbe quella di utilizzare separatamente "nudo". (prolog-less) procedura SomeLabel invece di etichetta

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top