@@ -151,22 +151,13 @@ struct NativeCModule::Impl {
151151 // Track injected runtime symbol names (with platform prefix) to filter them
152152 // out from listSymbols.
153153 std::unordered_set<std::string> injectedSymbols;
154- #ifdef _WIN32
155- // On Windows, __imp_<name> cells must outlive the TCCState.
156- std::vector<const void **> impPointers;
157- #endif
158154
159155 ~Impl () {
160156 if (tcc && !disposed) {
161157 callFinalize ();
162158 tcc_delete (tcc);
163159 tcc = nullptr ;
164160 }
165- #ifdef _WIN32
166- for (auto *p : impPointers)
167- delete p;
168- impPointers.clear ();
169- #endif
170161 }
171162
172163 void callFinalize () {
@@ -219,19 +210,28 @@ NativeCModule::NativeCModule(const std::string &code,
219210 for (size_t i = 0 ; i < symbolNames.size (); i++) {
220211 const void *addr = reinterpret_cast <const void *>(symbolAddresses[i]);
221212 tcc_add_symbol ($impl->tcc , symbolNames[i].c_str (), addr);
213+ }
214+
222215#ifdef _WIN32
223- // On Windows, TCC's PE linker requires object symbols to have a
224- // corresponding __imp_<name> IAT entry (a pointer-to-pointer).
225- // We store the pointer in a heap-allocated cell and register it.
226- auto *cell = new const void *(addr);
227- $impl->impPointers .push_back (cell);
228- std::string impName = " __imp_" + symbolNames[i];
229- tcc_add_symbol ($impl->tcc , impName.c_str (), cell);
230- #endif
216+ // On Windows/TCC-PE, tcc_add_symbol registers symbols as DLL imports
217+ // (via pe_putimport). Any extern variable reference in user C code therefore
218+ // must be declared with __declspec(dllimport) so TCC sets the ST_PE_IMPORT
219+ // flag and doesn't error during relocation. Prepend a preamble that forward-
220+ // declares each user symbol as dllimport so the user code doesn't have to.
221+ std::string preamble;
222+ for (size_t i = 0 ; i < symbolNames.size (); i++) {
223+ preamble += " __declspec(dllimport) extern char " ;
224+ preamble += symbolNames[i];
225+ preamble += " [];\n " ;
231226 }
227+ std::string fullCode = preamble + code;
228+ const std::string &codeToCompile = fullCode;
229+ #else
230+ const std::string &codeToCompile = code;
231+ #endif
232232
233233 // Compile
234- if (tcc_compile_string ($impl->tcc , code .c_str ()) < 0 ) {
234+ if (tcc_compile_string ($impl->tcc , codeToCompile .c_str ()) < 0 ) {
235235 std::string msg = " CModule: compilation failed" ;
236236 if (!errors.empty ())
237237 msg += " :\n " + errors;
0 commit comments