[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Tinycc-devel] Two compilers at once

From: Steve Fan
Subject: Re: [Tinycc-devel] Two compilers at once
Date: Fri, 21 Jun 2019 09:51:43 +0800

I’m sorry to intervene in the matter, but as you look at the design of TCC, you will see that it is not designed for re-entrancy.


Foolish younger me, I used to have a hardworking re-entrant fork of TCC working but the one of the project owner denounced my idea, calling me to adapt TLS for each and every global variables instead of rewriting most of the TCC functions to add TCCState for them.


TCC is just a hobbyist bone picked from OTCC by the legend Fabrice Bellard himself, but he has abandoned his child, TCC, ever since.


I used to be like you, I want to research on TCC, but now I do warn you to not touch this egregious code again.


Go figure out your own parser. Maybe learn Bison or ANTLR for a basic parser, then read some paper about register allocation (which is a very bitchy problem for it was actually NP-Complete), read the specs for ELF, and read the respective assembly handbook for each and every codegen backend. You can reuse the ELF/PE code from TCC I reckon, but just don’t try to make anything happen to TCC, a dying project.


From: Karl Yerkes
Sent: Friday, 21 June 2019 9:24 AM
To: address@hidden
Subject: Re: [Tinycc-devel] Two compilers at once


thank you for your replies. your help and insights are much appreciated. 


I'm loving TCC!


however, i've reached the limit of my current hot-swap function hack that uses two state-commingling TCC instances. after a while, the instances stop working properly and I get strange compile errors.


so, i am interested in executing some hack to allow multiple independent TCC instances in the same application. i am certain that "the old trick of just opening a pipe, forking and

then sending back the result" will not work for my purposes. if i can't get one of these hacks working, i have to go look at LLVM and cling again :/


as i understand it, option 2 (from Giovanni Mascellani) is using libtcc to compile libtcc from source into memory. that sounds awesome. i spent most of today trying this on windows.. and also learning to compile TCC on windows. here's my attempt:


// boot.cpp
// tcc version 0.9.27 (x86_64 Windows)
// install: c:/tcc
// include:
//   c:/tcc/include
//   c:/tcc/include/winapi
// libraries:
//   c:/tcc/lib
//   C:/Windows/system32
// libtcc1:
//   c:/tcc/lib/libtcc1-64.a
// build and run with:
//   cd tinycc
//   cl /MD boot.cpp c:\tcc\libtcc64.lib
//   boot.exe
//  fails like this:
//  need 457827 bytes
//  relocating to 21f0a402fd0
//  tcc: error: library 'libtcc1-64.a' not found
//  Assertion failed: dec != nullptr, file boot.cpp, line 69
#include "libtcc.h"

#include <cassert>
#include <iostream>

int main() {
  TCCState* instance = tcc_new();

  // i'm on Windows 10 x64. what else do i need here?
  tcc_set_options(instance, "-shared");
  tcc_define_symbol(instance, "TCC_TARGET_X86_64", "");
  tcc_define_symbol(instance, "TCC_TARGET_PE", "");
  tcc_define_symbol(instance, "LIBTCC_AS_DLL", "");

  // i needed this define on Windows to get tcc_relocate in the DLL
  tcc_define_symbol(instance, "TCC_IS_NATIVE", "");

  tcc_set_output_type(instance, TCC_OUTPUT_MEMORY);

  // maybe add more source files?
  tcc_add_file(instance, "libtcc.c");

  int size = tcc_relocate(instance, (void*)0);
  void* memory = malloc(size);

  printf("need %d bytes\n", size);
  printf("relocating to %llx\n", (unsigned long long int)memory);
  tcc_relocate(instance, memory);

  // TCCState *tcc_new(void);
  using New = TCCState* (*)(void);
  New _new = (New)tcc_get_symbol(instance, "tcc_new");
  assert(_new != nullptr);

  // int tcc_set_output_type(TCCState *s, int output_type);
  using SetOutputType = int (*)(TCCState*, int);
  SetOutputType _set_output_type =
      (SetOutputType)tcc_get_symbol(instance, "tcc_set_output_type");
  assert(_set_output_type != nullptr);

  // int tcc_compile_string(TCCState *s, const char *buf);
  using CompileString = int (*)(TCCState*, const char*);
  CompileString _compile_string =
      (CompileString)tcc_get_symbol(instance, "tcc_compile_string");
  assert(_compile_string != nullptr);

  // int tcc_relocate(TCCState *s1, void *ptr);
  using Relocate = int (*)(TCCState*, void*);
  Relocate _relocate = (Relocate)tcc_get_symbol(instance, "tcc_relocate");
  assert(_relocate != nullptr);

  // void *tcc_get_symbol(TCCState *s, const char *name);
  using GetSymbol = void* (*)(TCCState*, const char*);
  GetSymbol _get_symbol = (GetSymbol)tcc_get_symbol(instance, "tcc_get_symbol");
  assert(_get_symbol != nullptr);

  // can i delete the instance now??
  // my experiments suggest no.
  // tcc_delete(instance);

  // use the new, relocated instance to compile something
  TCCState* born_in_memory = _new();
  assert(born_in_memory != nullptr);
  _set_output_type(born_in_memory, TCC_OUTPUT_MEMORY);
  _compile_string(born_in_memory, "int dec(int t) { return t - 1; }");
  _relocate(born_in_memory, TCC_RELOCATE_AUTO);
  using Foo = int (*)(int);
  Foo dec = (Foo)_get_symbol(born_in_memory, "dec");
  assert(dec != nullptr);
  printf("dec(2) == %d\b", dec(2));


am i on the right track here? any suggestions would help a lot. i think i could add the path to libtcc1-64.a, but i would rather compile all the .c files i need so there's no need to find libtcc1-64.a at runtime. 




option 1 (from Christian Jullien) is something that i don't quite understand. i am just failing to connect the dots given i the pseudocode:


// tcc1.cpp:
namespace tcc1 {
#include "libtcc.h"

  // does this mean i should compile libtcc as c++ (not c) under the tcc1 namespace?

// tcc2.cpp:
namespace tcc2 {
#include "libtcc.h"

   // does this mean i should compile libtcc as c++ (not c) AGAIN under the tcc2 namespace?

 // OR does this mean i should write a wrapper interface for libtcc here?

// main.cpp:
int main() {
  tcc1::TCCState* a = nullptr;
  char (*A)(int) = nullptr;
  assert((a = tcc1::tcc_new()) != nullptr);
  tcc2::TCCState* b =
      tcc2::tcc_new();  // remove this line to make the program work

also "But it may not be so simple. For some projects it worked flawlessly and failed for some others" is mysterious to me. my apologies for being too ignorant to put it together! a little more help on this option might help me a lot.


sorry for the long email.


-- karl










On Sat, May 25, 2019 at 12:30 AM Giovanni Mascellani <address@hidden> wrote:


Il 25/05/19 06:24, Christian Jullien ha scritto:
> Because Karl uses C++11, it may be /theoretically/ possible for him to
> load two different tcc instances having different C++ namespaces and
> compiled in two distinct translation units.

If you don't mind some quite dirty hacking (and if you mind it you
shouldn't probably use tcc), I also believe that you can have two
instances in the same address space by using the first one to compile
another one (or many others) and relocating them to different addresses.
Then each of them is a completely independent compiler with independent
state. Of course this means that you need tcc's source code at runtime.
Otherwise there is the old trick of just opening a pipe, forking and
then sending back the result.

Have fun, Giovanni.
Giovanni Mascellani <address@hidden>
Postdoc researcher - Université Libre de Bruxelles

Tinycc-devel mailing list


reply via email to

[Prev in Thread] Current Thread [Next in Thread]