如何调用 C extern 函数并获取 return 结构?

How to call C extern function and get return struct?

我在 token.c 中定义了一个外部函数和一个 struct:

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

... 这样我就可以从程序集中调用 _get_token 并获得一个新令牌。在 make_token.asm 我有以下内容:

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

输出为:

[C] new token: start [5] length [10]

start: 5
length: 0

我缺少什么来获得开始和长度?输出验证 C 中的 extern 函数被调用并且值被推送到函数中。

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

在文件中 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;
}

在文件中 token.c

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

我认为问题出在您的 .bss 部分:

SECTION .bss        ; uninitialized data
    tkn:        resd        1

在这里,您为令牌预留了一个 dword(一个整数值的内存)内存。但是,在您的 C 代码中,您将令牌结构定义为具有 2 ints(startlength)或 2 dwords 的内存。这意味着您只能写入令牌结构的一部分 (start),并且成员 length 被视为不存在。您的问题可能可以通过简单地将 tkn 定义为

来解决
    tkn:        resd        2

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

希望对您有所帮助 ;)

我决定不是一次一个标记,而是分配一个缓冲区并填充它:确定需要多少标记,malloc 缓冲区,调用 get_tokens 并传入指向缓冲区的指针和令牌数。

get_tokens 方法填充缓冲区和 returns 创建的令牌计数。

程序集然后迭代令牌缓冲区并显示每个令牌的值 - startlength

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

...结果输出:

token size: 8 bytes
malloc space for 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

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