2015-04-22 4 views
5

Ich habe eine externe Funktion und ein struct in token.c definiert:Wie C extern Funktion aufrufen und Return-Struktur erhalten?

#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; 
} 

... damit ich _get_token aus meiner Versammlung anrufen und einen neuen Token erhalten. In make_token.asm habe ich folgendes:

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 

Der Ausgang ist:

[C] neues Token: start [5] Länge [10]

Start: 5
Länge : 0

Was fehlt mir, um sowohl Start und Länge zu bekommen? Die Ausgabe überprüft, dass die externe Funktion in C aufgerufen wird und die Werte in die Funktion geschoben werden.

+0

Wenn ich [diese Tabelle] (http://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions) richtig gelesen als die zweite Hälfte Ihrer Antwort sollte in EDX sein - „POD Rückgabewert 33-64 Bits in Die Größe wird über die EAX: EDX-Register zurückgegeben. " – zch

+0

1) Geben Sie keine DEF-Strukturdefinitionen ein. 2) Da diese Struktur in einer anderen Datei deklariert ist, sollte die Definition in einer Headerdatei sein, die beide Quellendateien #include. 3) Referenzieren einer externen Funktion erfolgt nicht über extern. eher in einer gemeinsamen Headerdatei, die sowohl in der Quelldatei, in der die Funktion deklariert ist, als auch in der lokalen Datei über #include enthalten ist. Die Headerdatei hätte den Prototyp, der Linker den Rest. 4) Die Suchreihenfolge für #include-Dateien hängt davon ab, ob '< ...>' oder '...' 'verwendet wird. System-Header sollten immer die '<' and '>' – user3629249

+0

diese Zeile verwenden: 'Return m_T;' wird nicht korrekt funktionieren, denn wenn die Funktion beendet wird, ist alles auf dem Stapel "verloren", so dass das Zurückgeben eines Elements, das sich auf dem Stapel befindet, ein nicht definiertes Verhalten ist. Da jedoch die tatsächliche vollständige Struktur zurückgegeben wird, anstelle eines Zeigers, ruft der Compiler memcpy() auf, um die Struktur in einen "versteckten" Speicherbereich zu kopieren (der für nichts anderes verwendet werden kann), und ruft dann erneut memcpy() auf Kopieren aus dem versteckten Speicherbereich in die Variable des Anrufers. Viel besser, einen dritten Parameter zu übergeben, der ein Zeiger auf die Instanz der Aufrufer der Struktur ist, und verwenden Sie diesen Zeiger – user3629249

Antwort

0

entschied ich mich anstelle eines einzelnen Token in einer Zeit, daß ich zuweisen sollte, Ihr Problem kann wahrscheinlich durch einfaches definieren tkn als

tkn:  resd  2 

oder

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

this helps gelöst werden ein Puffer und füllen Sie es: Bestimmen Sie, wie viele Token benötigt werden, malloc der Puffer, rufen Sie get_tokens und übergeben Sie den Zeiger auf den Puffer und die Anzahl der Token. Die Methode get_tokens füllt den Puffer und gibt die Anzahl der erstellten Token zurück. Die Assembly iteriert dann den Token-Puffer und zeigt für jedes Token die Werte start und length an.

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 

... und die resultierende Ausgabe:

Tokengröße: 8 Bytes
malloc Platz für 3 Tokens: 24 Bytes
[C] create 3 Tokens: 24 Bytes
[C] [0] Start: 0; len: 0
[C] [1] Start: 1; len: 10
[C] [2] Start: 2; len: 20

Erfolg
[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

#ifndef OTHER_FILE_H 
#define OTHER_FILE_H 

struct token 
{ 
    int start; 
    int length; 
}; 

struct token get_token(int, int); 

#endif // OTHER_FILE_H 

in Datei 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; 
} 

in Datei enthält token.c

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

Übrigens muss ich noch etwas extern haben, um von Assembly aufzurufen. Der Beispielcode, den ich in meiner Frage habe, basiert bestenfalls auf sehr skizzenhaften Details und auf der Erstellung einer extern zugänglichen Funktion. – IAbstract

+0

Um ehrlich zu sein, ich sehe wirklich nicht, wie dies eine Lösung für die Frage bietet. – IAbstract

0

ich glaube, das Problem in Ihrem liegt .bss Abschnitt:

SECTION .bss  ; uninitialized data 
    tkn:  resd  1 

Hier legen Sie eine einzige dword Speicher (eine ganze Zahl von Speicher) für das Token beiseite. In Ihrem C-Code definieren Sie jedoch die Token-Struktur mit 2 int s (start und length) oder 2 dword s Speicher. Dies bedeutet, dass Sie nur in einen Teil der Token-Struktur schreiben können (start), und das Element length wird als nicht vorhanden behandelt.)

+0

Ich habe das versucht, aber es hat nicht funktioniert. – IAbstract

Verwandte Themen