2015-04-22 15 views
5

devo una funzione extern ed una struct definito token.c:Come chiamare la funzione C extern e ottenere la struttura di ritorno?

#include "stdio.h" 

typedef struct token { 
    int start; 
    int length; 
} t; 

extern t get_token(int, int); 

t get_token(int s, int l) { 
    printf("[C] new token: start [%d] length [%d]\n\n", s, l); 

    t m_T = {}; 
    m_T.start = s; 
    m_T.length = l; 

    return m_T; 
} 

... in modo che posso chiamare _get_token dal mio assemblaggio e ottenere un nuovo token. In make_token.asm ho il seguente:

SECTION .data  ; initialized data 
    mtkn:  db "call: token(%d, %d)", 10, 0 
    mlen  db "length: %d", 10, 0 
    mstt:  db "start: %d", 10, 0 

    mend:  db 10, "*** END ***", 10, 0 

SECTION .text  ; code 
    extern _get_token 

    extern _printf 

    global _main 

    _main: 
     ; stash base stack pointer 
     push ebp 
     mov  ebp,  esp 

     mov  eax,  5 
     mov  ebx,  10 
     push ebx      ; length 
     push eax      ; start 
     call _get_token    ; get a token 
     mov  [tkn],  eax 

     add  esp,  8 

     ; test token properties 
     push DWORD [tkn] 
     push mstt 
     call _printf 

     push DWORD [tkn + 4] 
     push mlen 
     call _printf 

     add  esp,  16 

     .end: 
     push DWORD mend 
     call _printf 
     ; restore base stack pointer 
     mov  esp,  ebp 
     pop  ebp 

SECTION .bss  ; uninitialized data 
    tkn:  resd  1 

Il risultato è:

[C] nuovo token: start [5] lunghezza [10]

inizio: 5
lunghezza : 0

Cosa mi manca per ottenere sia l'inizio che la lunghezza? L'output verifica che la funzione extern in C venga richiamata e che i valori vengano inseriti nella funzione.

+0

Se ho letto [questa tabella] (http://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions) in modo corretto rispetto seconda metà della vostra risposta dovrebbe essere in EDX - "ritorno POD valori 33-64 bit le dimensioni vengono restituite tramite i registri EAX: EDX. " – zch

+0

1) non digitare le definizioni delle struct. 2) poiché quella struttura è dichiarata in un file diverso, la definizione dovrebbe essere in un file di intestazione, che entrambi i file di origine # includono. 3) il riferimento a una funzione esterna non viene eseguito tramite extern. piuttosto in un file di intestazione comune, incluso in entrambi i file di origine in cui è dichiarata la funzione e nel file locale tramite #include. il file di intestazione avrebbe il prototipo, il linker gestirà il resto. 4) l'ordine di ricerca per i file #include dipende da "< ...>" o "" ... "'è utilizzato. le intestazioni di sistema devono sempre utilizzare "<' and '>" – user3629249

+0

questa riga: "return m_T;" non funzionerà correttamente, perché quando la funzione termina, tutto nello stack è 'perso', quindi restituire un elemento che è in pila è un comportamento indefinito. Tuttavia, poiché viene restituita la struttura completa effettiva anziché un puntatore, il compilatore invocherà memcpy() per copiare la struct in un'area di memoria "nascosta" (che non può essere utilizzata per nient'altro) quindi richiamare memcpy() di nuovo in copia dall'area di memoria nascosta alla variabile dei chiamanti. Molto meglio passare un terzo parametro che è un puntatore all'istanza del chiamante della struct e usare quel puntatore – user3629249

risposta

0

ho deciso invece di un singolo token alla volta, che avrei dovuto allocare un buffer e riempirlo: determinare quanti token sono necessari, il buffer malloc, chiamare get_tokens e passare il puntatore al buffer e il numero di token.

Il metodo get_tokens riempie il buffer e restituisce un conteggio di token creati.

L'assieme quindi itera il buffer di token e visualizza i valori - start e length - per ciascun token.

token.c:

#include <stdio.h> 

typedef struct token { 
    int start; 
    int length; 
} t; 

extern int get_tokens(t*, int); 
extern int token_size(); 

/* 
    p_t: pointer to allocated buffer 
    num: number of tokens with which to fill buffer 
*/ 
int get_tokens(t* p_t, int num) { 
    printf("[C] create %d tokens: %d bytes\n", num, token_size() * num); 
    int idx = 0; 

    while (idx < num) { 
     // values are arbitrary for testing purposes 
     t tkn = {idx, idx * 10}; 
     p_t[idx] = tkn; 
     printf("[C] [%d] start: %d; len: %d\n", idx, tkn.start, tkn.length); 

     ++idx; 
    } 

    return idx; 
} 

int token_size() { 
    return sizeof(t); 
} 

make_tokens.asm:

SECTION .data  ; initialized data 
    endl:  db 10, 0 
    mszt:  db "token size: %d bytes", 10, 0 
    tk_info: db "[%d]: s[%d] l[%d]", 10, 0 
    mlen  db "length: %d", 10, 0 
    mstt:  db "start: %d", 10, 0 

    mend:  db 10, "*** END ***", 10, 0 

    mt1   db "malloc space for 3 tokens: %d bytes", 10, 0 
    mty   db 10, "success", 10, 0 
    mtn   db 10, "fail", 10, 0 

SECTION .text  ; code 
    extern _get_tokens 
    extern _token_size 

    extern _free 
    extern _malloc 
    extern _printf 

    global _main 

    _main: 
     ; stash base stack pointer 
     push ebp 
     mov  ebp,  esp 

     ; get token size 
     call _token_size 
     mov  [tsz],  eax 

     push DWORD [tsz] 
     push DWORD mszt 
     call _printf 
     add  esp,  8 

     mov  eax,  [tsz] 
     mov  edx,  3    
     mul  edx 
     mov  [tbsz],  eax 

     push DWORD [tbsz] 
     push DWORD mt1 
     call _printf 
     add  esp,  8 

     push DWORD [tbsz]    ; malloc 3 tokens 
     call _malloc 
     mov  [tkn_buf], eax 
     add  esp,  4 

     mov  ecx,  3    ; 3 tokens 
     push DWORD ecx 
     push DWORD [tkn_buf] 
     call _get_tokens 
     add  esp,  8 
     cmp  eax,  3 
     je  .yes 

     .no: 
     push DWORD mtn 
     call _printf 
     add  esp,  4 
     jmp  .end 

     .yes: 
     push DWORD mty 
     call _printf 
     add  esp,  4 

     mov  ecx,  0 
     mov  ebx,  [tkn_buf] 
     .loopTokens: 
      mov  eax, [tsz]  ; determine next token 
      mul  ecx     ; start location => eax 

      mov  edi, ecx   ; preserve counter 

      push DWORD [ebx + eax + 4] ; length 
      push DWORD [ebx + eax]  ; start 
      push DWORD ecx 
      push DWORD tk_info 
      call _printf 
      add  esp, 16 

      mov  ecx, edi 
      inc  ecx 
      cmp  ecx, 3 
      jl  .loopTokens 

     .end: 
     push DWORD [tkn_buf] 
     call _free 

     push DWORD mend 
     call _printf 
     ; restore base stack pointer 
     mov  esp,  ebp 
     pop  ebp 

SECTION .bss  ; uninitialized data 
    tkn_buf: resd  1 
    tbsz:  resd  1 
    tsz:  resd  1 

... e l'output risultante:

dimensione token: 8 byte
spazio malloc per 3 gettoni: 24 byte
[C] creare 3 token: 24 byte
[C] [0] inizio: 0; len: 0
[C] [1] inizio: 1; len: 10
[C] [2] inizio: 2; len: 20

successo
[0]: s [0] l [0]
[1]: s [1] l [10]
[2]: s [2] l [20]

-2
As I stated in a comment. 
it would be far better to pass a pointer to 
an instance of struct token 
rather than the current code. 
The following follows the current code. 
but remember all those hidden calls to memcpy() 
and the hidden ram allocation 

otherfile.h contiene

#ifndef OTHER_FILE_H 
#define OTHER_FILE_H 

struct token 
{ 
    int start; 
    int length; 
}; 

struct token get_token(int, int); 

#endif // OTHER_FILE_H 

nel file di otherfile.c

#include <stdio.h> 
#include "otherfile.h" 

struct token get_token(int tokenStart, int tokenLength) 
{ 
    printf("[C] new token: start [%d] length [%d]\n\n", s, l); 

    struct token m_T = {0,0}; 
    m_T.start = tokenStart; 
    m_T.length = tokenLength; 

    return m_T; 
} 

nel file di token.c

#include <stdio.h> 
#include "otherfile.h" 
... 
    struct token myToken = {0,0}; 
    myToken = get_token(tokenStart, tokenLength); 
... 
+0

BTW, devo ancora avere qualcosa di esterno per poter richiamare dall'assemblaggio. Il codice di esempio che ho nella mia domanda si basa su dettagli molto schematici al meglio e su come creare una funzione accessibile esternamente. – IAbstract

+0

Per essere onesti, non vedo davvero come questo offra una soluzione alla domanda. – IAbstract

0

Credo che il problema sta nella vostra .bss sezione:

SECTION .bss  ; uninitialized data 
    tkn:  resd  1 

Qui, si mette da parte un singolo dword (un valore intero di memoria) di memoria per il token. Tuttavia, nel codice C, si definisce la struttura del token come dotata di 2 int s (start e length) o di 2 dword s memoria. Ciò significa che è possibile scrivere solo su una parte della struttura del token (start) e il membro length viene considerato come inesistente. Il tuo problema può probabilmente essere risolto con la semplice definizione tkn come

tkn:  resd  2 

o

tkn:  resq  1  ;; 1 QWORD == 2 DWORDs 

Spero che questo aiuti;)

+0

Ho provato questo ma non ha funzionato. – IAbstract

Problemi correlati