Search code examples
c++cgccstructtcc

Compatibility of compiled gcc and tcc structs


I'm trying to run libtcc from C++ to use C as a runtime scripting language. The runtime compiled code has to be able to run functions from the outside code. This is working fine when passing ints, but when passing a struct from the tcc-code to the gcc-code, weird things happen.

Minimal running example:

#include <libtcc.h>
#include <stdio.h>
struct Vec {
    int x;
};
void tmp(struct Vec test) {
    printf("got %x\n",test.x);
}
int main() {
    TCCState* tcc; tcc = tcc_new();
    tcc_set_output_type(tcc, TCC_OUTPUT_MEMORY);
    tcc_add_symbol(tcc, "tmp", (void*)&tmp);
    tcc_compile_string(tcc, "\
        struct Vec {int x;};\
        void tmp(struct Vec test);\
        void fun() {\
            struct Vec x = {0};\
            tmp(x);\
        }");
    tcc_relocate(tcc, TCC_RELOCATE_AUTO);
    void (*fun)(void) = (void(*)())tcc_get_symbol(tcc, "fun");
    fun();
}

Running with:

gcc -ltcc -ldl test.c && ./a.out
> got 23b472b0
tcc -ltcc -ldl test.c && ./a.out
> got 0

Why does the gcc compiled version not print the expected 0? When I put only long longs instead of ints into the struct, it works. Any other data type and random stuff is output.

At first I thought it was because of alignment or something, but it also happens when using only a single variable in the struct.

I'm using Linux 3.16 x86_64 and tcc 0.9.26


Solution

  • It appears that the problem centers around the way that C and C++ understand the whole "struct Vec test" as a parameter. In TCC, it is treated/assumed to be a pointer. In C++ it looks like one has to state that it is a pointer more clearly.

    #include libtcc.h
    #include stdio.h
    struct Vec {
        int x;
    };
    void tmp(struct Vec * test) {
        printf("got %x\n",test->x);
    }
    int main() {
        TCCState* tcc; tcc = tcc_new();
        tcc_set_output_type(tcc, TCC_OUTPUT_MEMORY);
        tcc_add_symbol(tcc, "tmp", (void*)&tmp);
        tcc_compile_string(tcc, "\
            struct Vec {int x;};\
            void tmp(struct Vec test);\
            void fun() {\
                struct Vec x = {5};\
                tmp(x);\
            }");
        tcc_relocate(tcc, TCC_RELOCATE_AUTO);
        void (*fun)(void) = (void(*)())tcc_get_symbol(tcc, "fun");
        fun();
    }
    

    Output appears as:

    got 5