Skip to content

Commit 6f0e5d7

Browse files
fix: prepend dllimport preamble for user symbols on windows tcc
1 parent d179a38 commit 6f0e5d7

1 file changed

Lines changed: 18 additions & 18 deletions

File tree

src/core/bindings/native_cmodule.cc

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)