2013-04-22 12 views
6

Sto lavorando su un progetto cpp. Il progetto deve essere migrato a 64 bit. Contiene un codice assembly Inline che non può essere compilato su x64. Questa è la funzione che contengono il codice assembly:Converti codice assembly inline in C++

void ExternalFunctionCall::callFunction(ArgType resultType, void* resultBuffer) 
{ 
#if defined(_NT_) || defined(__OS2__) 

    // I386 

    // just copy the args buffer to the stack (it's already layed out correctly) 
    int* begin = m_argsBegin; 
    int* ptr = m_argsEnd; 
    int arr[1000], i=0; 
    while (ptr > begin) { 
     int val = *(--ptr); 

     __asm push val 
    } 

    void* functionAddress = m_functionAddress; 

    // call the function & handle the return value. use __stdcall calling convention 
    switch (resultType) { 
    case voidType: 
     __asm { 
      call functionAddress 
     } 
     break; 
    case pointerType: 
    case int32Type: 
     __asm { 
      call functionAddress 
      mov ebx, resultBuffer 
      mov dword ptr [ebx],eax 
     } 
     break; 
    case floatType: 
     __asm { 
      call functionAddress 
      mov ebx, resultBuffer 
      fstp dword ptr [ebx] 
     } 
     break; 
    case doubleType: 
     __asm { 
      call functionAddress 
      mov ebx, resultBuffer 
      fstp qword ptr [ebx] 
     } 
     break; 
    } 

ho usato pila, matrice di migrare questa "asm spinta val", ma non ha funzionato. Sebbene, non genera alcun errore di compilazione ma la logica non ha funzionato.

Quindi, voglio chiedere, Cosa posso usare in C++ invece di "__asm ​​push val". Qualsiasi aiuto sarà apprezzato.

+1

Sicuramente questa non è l'unica istruzione di assemblaggio nel programma? Come si usa il valore spinto? Per il momento non ci sono abbastanza informazioni per aiutarti. –

+1

Avrai bisogno di mostrare più codice in modo da poter sapere cosa si sta facendo con il valore inserito nello stack. –

+2

Il C++ standard non include il linguaggio assembly inline o qualsiasi operazione per modificare direttamente lo stack della CPU .... Hai più possibilità di consigli utili se spieghi cosa sta facendo la tua funzione con lo stack in seguito? Se sta preparando i valori per una chiamata di funzione o qualcosa del genere, potrebbe esserci un altro modo per fornire gli argomenti. È probabilmente altamente specifico per il tuo sistema operativo e/o compilatore, che non hai specificato. –

risposta

0

Ci sono diverse cose che è necessario risolvere. (Ho cercato il tuo codice su un'altra domanda). Come ho capito questo codice è un wrapper per chiamare la funzione piuttosto astratta situata all'indirizzo specificato che si aspetta una certa quantità di dati nello stack e può restituire cose diverse basate su ArgType.

Se si desidera eseguire il wrapping tramite C semplice, è necessario definire diversi prototipi di funzioni (in base al valore restituito) da utilizzare sullo switch, ma è necessario risolvere un altro problema, che è più complesso.

Il problema con il porting di tali elementi in C è che non si conosce in anticipo una quantità di argomenti (dimensione dati) da inserire nello stack, quindi si avranno problemi a definire il prototipo.

Diciamo che func (char c) inserirà definitivamente 1 byte di stack (ma anche non sempre corretto a causa dell'allineamento dei dati) .. nel tuo caso devi pensare a una soluzione che avrà un set di parametri con una dimensione uguale alla dimensione dei dati devi essere in pila. Che a prima vista non è qualcosa che puoi fare subito.

UPD. puoi farlo con func (char [] param); ma ha anche problemi che sono stati spiegati nella risposta sopra.

+0

Sai, non è una cattiva risposta, ma l'ultimo paragrafo, in particolare "devi pensare a una soluzione", è in qualche modo rovinato per me. L'OP non chiederebbe aiuto se potessero pensare a qualcosa. Ovviamente hanno cercato molto duramente di risolverlo da soli. – StoryTeller

+0

Mi spiace deluderti .. Potrebbe essere "devi pensare" in effetti era un po 'difficile, ma ho una scusa per non essere un madrelingua inglese. Voglio dire che davvero non conosco la soluzione esatta per l'ultimo passaggio, e quello che ho scritto era più una sorta di lode su cui riflettere piuttosto che una risposta pronta. E un'altra cosa è che da quello che ho letto nella domanda OP (in realtà entrambi), vorrei considerare di essere 'ovviamente provato molto difficile da risolvere' è applicabile. – evilruff

13

Il problema non è risolvibile in generale; questo perché il commento,

// call the function & handle the return value. use __stdcall calling convention 

indica dipendenza convenzioni a 32 bit chiamata.

In 32bit x86, stdcall significa che tutti argomenti sono passati sullo stack, in ordine inverso (cioè l'ultimo arg viene spinto prima. Cioè, se arg[0] è a addr allora arg[1], non importa suo tipo, è a addr + sizeof(arg[0])). Questo è il motivo per cui il seguente codice nel tuo esempio:

// just copy the args buffer to the stack (it's already layed out correctly) 
int* begin = m_argsBegin; 
int* ptr = m_argsEnd; 
int arr[1000], i=0; 
while (ptr > begin) { 
    int val = *(--ptr); 

    __asm push val 
} 

in realtà in grado di lavorare - perché semplicemente non importa che cosa è esattamente lì, che tipo sono gli argomenti; tutto ciò che è rilevante è che ognuno di loro si trova in una posizione di memoria conosciuta e in una memoria consecutiva. Se sai che l'argomento N è a addr, allora puoi sapere l'argomento N+1 è a addr + sizeof(arg[N]).

Questo è ciò che il commento dice: "è già spiegate correttamente" - purtroppo, questo è non vero in modalità a 64 bit. Quindi il codice non può essere "portato"; non esiste un equivalente a port to.

Chiamare convenzioni basate almeno parzialmente sul registro - come su Win64 su x64 (64 bit x86) si comportano in modo diverso.Per quelli, dipende da quali tipi di argomenti prendono le funzioni chiamate (è possibile, in Windows, passare quattro argomenti di tipo intero nei registri generici più alcuni argomenti di tipo float nei registri XMM). È quindi necessario conoscere più sulla firma (prototipo) della funzione chiamata piuttosto che "ci vogliono gli argomenti N" per poter eseguire correttamente il marshalling degli argomenti da un wrapper di tipo "anycall" come sopra. In modalità 64 bit, per ogni funzione che desideri chiamare tramite il tuo wrapper, devi sapere non solo quanti argomenti ci sono in totale, ma anche quanti sono in reg generici, quanti nei registri XMM e come molti in pila.

Il comando "chiama una funzione tramite un puntatore e copia il valore di ritorno in una posizione nota" è portatile e può essere espresso in semplice C/C++. Ma la parte che ottiene i argomenti per questo, come sopra, non non porta in alcun modo diretto tra i 32bit stdcall e qualsiasi convenzione a 64 bit x86 chiamando che conosco (né Win64/x64 né l'ONU * X x86_64 convenzioni consentono per predire sia le posizioni che l'utilizzo totale della memoria dello stack di tutti gli argomenti per una funzione dato solo il numero e il tipo degli argomenti ma non il loro ordine).

Che cosa esattamente dovete fare dipende molto di più sui chiamanti/utenti di cui sopra class ExternalFunctionCall che sul piccolo piccolo campione di assembly inline hai mostrato. È particolarmente necessario sapere come vengono inizializzati i membri m_argsBegin e m_argsEnd e dove. Puoi fornire qualche dettaglio in più su come si presenta la classe (tutte le variabili/funzioni membro), nonché esempi sul suo uso effettivo?

+0

Grazie Frank, vorrei chiedere ancora una cosa. Non possiamo separare questo codice asm nel file asm/s? Un file asm separato può essere compilato su x64 tramite MASM64.exe. Se possibile, per favore dimmi come possiamo fare questo? Abbiamo migrato tutti gli altri codici asm in cpp, solo "__asm ​​push val" è rimasto.Puoi vedere il codice della funzione completa qui sopra. – vsoni

+0

@ user2118116: come già detto, c'è _more_ to do che semplicemente "sostituisci' __asm ​​push val' con un po 'di 64-bittishness ". Questo "di più" è al di fuori della funzione_ - è _both_ anche in tutta la classe, ed è qui che il tuo più grande lavoro è, _i luoghi reali in cui le istanze di questa classe sono create/utilizzate_. Non è facile uscire qui, mi dispiace. La tua domanda sul porting di questo a 64bit è un po 'come dire "il mio codice x86 usa' lcall' nell'assembly inline e ho bisogno di portarlo su ARM, quindi voglio sapere l'istruzione ARM che esegue 'lcall'". –

+0

@FrankH. Full ACK su questo. Ho suggerito l'OP in un duplicato di questo: 「La cosa migliore che puoi fare è riscrivere l'intera funzione usando [libffi] (http://sourceware.org/libffi/) o [dyncall] (http: // dyncall. org /). Hi – mirabilos

0

Mi rendo conto che questa è una domanda un po 'vecchia, ma mi sono imbattuto in: xbyak.

Forse quello che stai cercando?

+0

Hi Nix, Voglio sostituire il codice asm da questo contesto: int * begin = m_argsBegin; int * ptr = m_argsEnd; int arr [1000], i = 0; while (ptr> begin) { int val = * (- ptr); __asm ​​push val } In pratica, voglio sostituire l'istruzione "__asm ​​push val" con il codice Cpp. Grazie – vsoni

+0

Cosa sono m_argsBegin e m_argsEnd? –

+0

@ Nix - Entrambi sono int * Grazie – vsoni