WedX - журнал о программировании и компьютерных науках

Совместимость скомпилированных структур gcc и tcc

Я пытаюсь запустить libtcc из C++, чтобы использовать C в качестве языка сценариев времени выполнения. Скомпилированный во время выполнения код должен иметь возможность запускать функции из внешнего кода. Это нормально работает при передаче целых чисел, но при передаче структуры из tcc-кода в gcc-код происходят странные вещи.

Пример минимального запуска:

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

Запуск с:

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

Почему скомпилированная версия gcc не печатает ожидаемый 0? Когда я помещаю в структуру только long longs вместо целых чисел, это работает. Выводятся любые другие типы данных и случайные данные.

Сначала я подумал, что это из-за выравнивания или чего-то еще, но это также происходит при использовании только одной переменной в структуре.

Я использую Linux 3.16 x86_64 и tcc 0.9.26.

23.10.2014

  • На какой архитектуре и какой операционной системе? Tinycc лучше работает с 32-битной архитектурой x86 (она же ia32), чем с 64-битной архитектурой x86-64 (она же amd64). 24.10.2014
  • Arch Linux x86_64. Но что значит работать лучше? Это ошибка 64-битной версии? 24.10.2014
  • Я никогда не мог использовать tcc в серьезных программах на x86-64. Мне кажется, что tinycc очень глючит на 64 битах. 24.10.2014
  • См. также это 24.10.2014
  • Какую часть этого вы имеете в виду? Для меня не имеет значения, работает ли машинный код медленно, если он работает так, как ожидалось. 24.10.2014
  • Это дало различные альтернативные решения. Я бы просто создал файл gen123.c на диске; затем скомпилируйте его с помощью gcc -O -g -fPIC -Wall -shared gen123.c -o gen123.so; затем dlopen путь "./gen123.so". И я также упомянул несколько библиотек компиляции JIT, таких как libjit 24.10.2014
  • Вам может понадобиться скомпилировать основную программу с помощью gcc -rdynamic -O -g -Wall test.c -ltcc -ldl -o test_prog 24.10.2014
  • Хм, я думаю, это возможно. Мне просто понравился способ сделать это прямо в памяти, особенно учитывая скорость компиляции и переносимость (Windows) 24.10.2014

Ответы:


1

Похоже, что проблема заключается в том, как C и C++ понимают весь «тест структуры Vec» как параметр. В TCC он считается/предполагается указателем. В С++ похоже, что нужно более четко указать, что это указатель.

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

Вывод выглядит как:

got 5
23.10.2014
  • Что. Разве стандарт C не диктует, как работают структуры? Я имею в виду, что ни один из этих кодов не является даже C++. Спасибо! 24.10.2014
  • @phiresky: структуры передаются по значению. (Если компилятор реализует передачу по значению с помощью указателей, это нормально, если семантика одинакова.) Если функция с параметром struct Vec test изменяет член Test, это изменение не должно влиять на вызывающую программу — и быстрый эксперимент с tcc версии 0.9.25 показывает, что tcc понимает это правильно. (Я не знаю, о чем все эти TCCState вещи.) 24.10.2014
  • Ваш код не будет компилироваться; отсутствуют разделители < и > в директивах #include. 24.10.2014
  • @KeithThompson ну ладно, я думаю, ты каждый день узнаешь что-то новое. TCCState — это просто способ вызова библиотеки tcc из c. 24.10.2014
  • @phiresky: Если бы tcc предположил, что параметр структуры является указателем, то эта программа напечатала бы FAILED. В моей системе с gcc 4.8.2 и 0.9.25 он печатает PASSED, что говорит о том, что этот ответ неверен. Чарльз, я что-то пропустил? 24.10.2014
  • @KeithThompson, с чего бы это? Если tcc знает об этом, он, вероятно, компилирует принимающую функцию, чтобы в действительности использовать указатель, даже не записывая его. Явное написание struct* будет означать, что вам нужна только ссылка. 24.10.2014
  • @phiresky: ответ предполагает, что tcc обрабатывает параметр структуры, как если бы он был параметром указателя на структуру. Если бы это было так, связанная программа напечатала бы FAILED, потому что присваивание param.ok обновило бы arg.ok. Это не так. (Кстати, C не имеет ссылок в стиле С++, если вы это имеете в виду.) 24.10.2014
  • @KeithThompson С чего бы это? Я предполагаю, что он копирует структуру в какое-то другое место, а затем неявно указывает на это место, вместо того, чтобы помещать его по значению в аргументы. Если бы он не скопировал его, он бы не соответствовал стандарту. Разве вы не сказали, что если компилятор реализует передачу по значению с использованием указателей, это нормально, если семантика одинакова? 24.10.2014
  • Вопрос в том, копирует ли он структуру. Что касается семантики языка, все, что имеет значение, это то, что функция работает с копией объекта структуры, а не с объектом, определенным в вызывающей программе. Независимо от того, обращается ли (на уровне машинного кода) функция к этой копии напрямую или через ее адрес, не имеет значения с точки зрения языка (хотя, возможно, это имеет отношение к вашему вопросу). 24.10.2014
  • Этот ответ подразумевает, что tcc фактически передает аргумент структуры по ссылке, предоставляя функции доступ к объекту в вызывающей программе. Это было бы незаконно, и в моем эксперименте tcc этого не делает. Это также подразумевает, что C и C++ имеют разные правила передачи аргументов структуры; на самом деле это не так. 24.10.2014

  • 2

    В новой версии tcc (libtcc) из официального репозитория git он работает как положено (выводит "got 0"). проверено на gcc 4.9.3 и tcc 0.9.26 (коммит 00ba4b).

    07.10.2015
    Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    Для любых предложений по сайту: [email protected]