From 5f7a87341a7a6c42dcb68c33a0f7391eb241d226 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 20 Aug 2026 04:31:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(gen):=20=E6=A8=A1=E5=9D=97=E7=BA=A7?= =?UTF-8?q?=E5=85=A8=E5=B1=80=E5=8F=98=E9=87=8F=E5=91=BD=E5=90=8D=E5=B8=A6?= =?UTF-8?q?=20SHA1=20=E5=89=8D=E7=BC=80=EF=BC=8C=E6=B6=88=E9=99=A4=20ld.ll?= =?UTF-8?q?d=20duplicate=20symbol?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 多个模块声明同名模块级全局(如 _mbuddy)时全部生成裸名强定义(zeroinit) → 链接时 ld.lld duplicate symbol: _mbuddy(大量 warning)。函数名早已 mangled,全局变量漏做。 修复(对齐函数名 _mangle_name,SymTab key 保持裸名查找逻辑零改动): 1. 定义端 TranslatorGenMixin:全局名 = {模块sha1}.{变量名} 2. 模块属性访问 ExprGenAttr:按目标模块 SHA1 前缀精确查找/创建(含嵌套 模块 w32.xxx 与 t 类型对象裸名 linkonce_odr 特例),引用用完整名 3. from-import 全局 ExprGenName:带源模块 SHA1 前缀查找,引用用完整名 4. _find_pool_var 兜底:linkonce_odr + zeroinitializer 定义(每模块独立, 不再依赖裸名链接合并共享;运行时未初始化则真实崩溃暴露,不掩盖) --- App/lib/core/Gen/ExprGenAttr.vp | 38 ++++++++++++++++++++------ App/lib/core/Gen/ExprGenConst.vp | 24 ++++++++++------ App/lib/core/Gen/ExprGenName.vp | 16 ++++++++--- App/lib/core/Gen/TranslatorGenMixin.vp | 12 +++++--- 4 files changed, 66 insertions(+), 24 deletions(-) diff --git a/App/lib/core/Gen/ExprGenAttr.vp b/App/lib/core/Gen/ExprGenAttr.vp index 6d7834f..81f01ac 100644 --- a/App/lib/core/Gen/ExprGenAttr.vp +++ b/App/lib/core/Gen/ExprGenAttr.vp @@ -21,7 +21,9 @@ import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesEnum as HandlesEnum import lib.core.Handles.HandlesClassDef as HandlesClassDef import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesFunctions as HandlesFunctions import lib.core.StubMerger as StubMerger +import lib.core.StubMergerStore as StubMergerStore import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config import lib.Projectrans.Utils as Utils @@ -238,10 +240,16 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): # 检查是否是已导入模块 if HandlesImports.is_module_imported(trans._imported_modules, mod_path_w) == 0: return None - # 在当前模块查找全局变量 (stub 可能已注入) - gv: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, at.attr) + # 在当前模块查找全局变量:优先按"目标模块 SHA1 前缀 + 属性名"精确匹配, + # 避免多模块同名全局(@._mbuddy / @._mbuddy 同时注入)时裸名后缀 + # 匹配返回错误模块的全局(串扰)。目标 sha1 未知时退化裸名(后缀匹配兜底) + gv_q: str = HandlesFunctions._mangle_name_with_sha1( + self._lookup_module_sha1(mod_path_w), at.attr) + gv: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, gv_q) if gv is not None and gv.Ty is not None: - return self.make_global_ref(pool, at.attr, gv.Ty) + # 用 gv.Name(完整名,带 SHA1 前缀时与定义端一致)构造引用, + # 避免裸名 @_mbuddy 在多模块各自带前缀定义下 undefined symbol + return self.make_global_ref(pool, gv.Name, gv.Ty) # 未找到: 创建 external global 声明并添加到模块 # 否则只生成 @_argc 引用而无声明,LLVM 报 "use of undefined value '@_argc'" use_ty: llvmlite.LLVMType | t.CPtr = ty_hint @@ -256,7 +264,14 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): is_t_type_obj: int = 0 if string.strcmp(mod_path_w, "t") == 0: is_t_type_obj = self._is_t_type_object_name(at.attr) - ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, at.attr, use_ty) + # 兜底声明名:t 类型对象(t.py 不编译、无 sha1)保持裸名 linkonce_odr; + # 其他模块属性带目标模块 SHA1 前缀(对齐定义端 mangling,跨模块同名 + # 全局独立命名,消除 duplicate symbol / 串扰) + gv_name_ba: str = at.attr + if is_t_type_obj == 0: + gv_name_ba = HandlesFunctions._mangle_name_with_sha1( + self._lookup_module_sha1(mod_path_w), at.attr) + ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name_ba, use_ty) if ext_gv is not None: if is_t_type_obj != 0: # t.CPtr 等类型对象: 创建带 null 初值的定义(linkonce_odr) @@ -277,7 +292,11 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): ext_gv.Linkage = "external" ext_gv.Initializer = None llvmlite.module_add_global(mod, ext_gv) - return self.make_global_ref(pool, at.attr, use_ty) + return self.make_global_ref(pool, gv_name_ba, use_ty) + def _lookup_module_sha1(self, mod_name: str) -> str: + """查找模块名对应的 SHA1(委托 StubMergerStore,支持包名回退; + None=未找到,调用方退化为裸名)""" + return StubMergerStore.LookupSha1ByModName(mod_name) # ============================================================ # 翻译属性访问 Attribute(value, attr, ctx) — obj.field # @@ -607,11 +626,14 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): if qual_buf is not None: viperlib.snprintf(qual_buf, qual_len, "%s.%s", inner_nm.id, inner_at.attr) if HandlesImports.is_module_imported(trans._imported_modules, qual_buf) == 1: - # 查找全局变量 at.attr (stub 已注入的情况) - gv_nested: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, at.attr) + # 查找全局变量 at.attr(带限定模块 SHA1 前缀精确匹配, + # 避免多模块同名全局后缀匹配串扰;sha1 未知退化裸名) + gv_nested_q: str = HandlesFunctions._mangle_name_with_sha1( + self._lookup_module_sha1(qual_buf), at.attr) + gv_nested: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, gv_nested_q) if gv_nested is not None and gv_nested.Ty is not None: gv_ref_nested: llvmlite.Value | t.CPtr = self.make_global_ref( - pool, at.attr, gv_nested.Ty) + pool, gv_nested.Name, gv_nested.Ty) if gv_ref_nested is not None and gv_ref_nested.Ty is not None: load_ty_nested: llvmlite.LLVMType | t.CPtr = gv_ref_nested.Ty.Pointee if load_ty_nested is not None: diff --git a/App/lib/core/Gen/ExprGenConst.vp b/App/lib/core/Gen/ExprGenConst.vp index 30db3a0..f0c095c 100644 --- a/App/lib/core/Gen/ExprGenConst.vp +++ b/App/lib/core/Gen/ExprGenConst.vp @@ -21,6 +21,7 @@ import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesEnum as HandlesEnum import lib.core.Handles.HandlesClassDef as HandlesClassDef import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesFunctions as HandlesFunctions import lib.core.StubMerger as StubMerger import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config @@ -207,8 +208,12 @@ class ExprGenConst(ExprGenBase.ExprGenBase): alloca = HandlesVar.lookup_var(trans.SymTab, "mb") if alloca is not None: return alloca - # 兜底: 创建外部全局 @_mbuddy 引用(i8** 类型) - # 仅用于函数内动态 list 字面量,@_mbuddy 由入口模块定义并初始化 + # 兜底: 创建当前模块 mangled 的 @_mbuddy 定义(linkonce_odr + zeroinitializer) + # 对齐模块级全局带 SHA1 前缀命名:裸名 @_mbuddy 依赖链接合并共享 + # (--allow-multiple-definition),带前缀后每模块独立。linkonce_odr 允许 + # 链接器合并同模板重复特化定义,zeroinitializer 保证编译链接通过。 + # 运行时若该模块未在入口 main 赋值 _mbuddy(null pool 上动态建 list), + # 由真实崩溃暴露(fail-fast 哲学,不掩盖上游未初始化)。 pool: memhub.MemBuddy | t.CPtr = trans.Pool if pool is None or trans.Module is None or trans.SymTab is None: return None @@ -219,16 +224,19 @@ class ExprGenConst(ExprGenBase.ExprGenBase): # 创建 i8* 类型(t.CVoid | t.CPtr = i8*) i8_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_fb) - # 创建外部全局 @_mbuddy(external linkage,无初始值) - gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, "_mbuddy", i8_ptr_ty_fb) + # 当前模块 mangled 名(@<模块sha1>._mbuddy) + mb_name_fb: str = HandlesFunctions._mangle_name(trans, "_mbuddy") + # 创建 linkonce_odr 定义(可被链接器合并,自给自足保证链接通过) + gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, mb_name_fb, i8_ptr_ty_fb) if gv_ext is not None: - gv_ext.Linkage = "external" + gv_ext.Linkage = "linkonce_odr" + gv_ext.Initializer = "zeroinitializer" llvmlite.module_add_global(trans.Module, gv_ext) - # 创建 Value 引用(@_mbuddy, 类型为 i8**) + # 创建 Value 引用(@<模块sha1>._mbuddy, 类型为 i8**) i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb) - ref_name_fb: str = pool.alloc(16) + ref_name_fb: str = pool.alloc(96) if ref_name_fb is not None: - string.strcpy(ref_name_fb, "@_mbuddy") + viperlib.snprintf(ref_name_fb, 96, "@%s", mb_name_fb) gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb) # 注册到模块作用域,避免重复创建 HandlesVar.define_module_var(trans.SymTab, "_mbuddy", gv_ref_fb) diff --git a/App/lib/core/Gen/ExprGenName.vp b/App/lib/core/Gen/ExprGenName.vp index e9a01d4..cd2f9e1 100644 --- a/App/lib/core/Gen/ExprGenName.vp +++ b/App/lib/core/Gen/ExprGenName.vp @@ -22,6 +22,8 @@ import lib.core.Handles.HandlesEnum as HandlesEnum import lib.core.Handles.HandlesClassDef as HandlesClassDef import lib.core.Handles.HandlesImports as HandlesImports import lib.core.StubMerger as StubMerger +import lib.core.StubMergerStore as StubMergerStore +import lib.core.Handles.HandlesFunctions as HandlesFunctions import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config import lib.Projectrans.Utils as Utils @@ -107,11 +109,14 @@ class ExprGenName(ExprGenBase.ExprGenBase): fi_mod_raw: str = HandlesImports.lookup_from_import( trans._from_imports, nm_id, 0) if fi_mod_raw is not None: + # 带源模块 SHA1 前缀精确查找,避免多模块同名全局后缀匹配串扰 + fi_gv_q: str = HandlesFunctions._mangle_name_with_sha1( + StubMergerStore.LookupSha1ByModName(fi_mod_raw), nm_id) fi_gv: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module( - trans.Module, nm_id) + trans.Module, fi_gv_q) if fi_gv is not None and fi_gv.Ty is not None: fi_ref: llvmlite.Value | t.CPtr = HandlesExpr.make_global_ref( - pool, nm_id, fi_gv.Ty) + pool, fi_gv.Name, fi_gv.Ty) if fi_ref is not None and fi_ref.Ty is not None: fi_pty: llvmlite.LLVMType | t.CPtr = fi_ref.Ty.Pointee if fi_pty is not None: @@ -292,11 +297,14 @@ class ExprGenName(ExprGenBase.ExprGenBase): # stub 已注入全局(精确类型)→ 直接引用;未注入 → fail-fast # (不再创建 external i8* 声明,否则 llc 报 "use of undefined value", # 静默回退掩盖 stub 未注入的上游根因) + # 带源模块 SHA1 前缀精确查找(避免多模块同名全局后缀匹配串扰) + gv_fi_q: str = HandlesFunctions._mangle_name_with_sha1( + StubMergerStore.LookupSha1ByModName(fi_mod), fi_gname) gv_fi: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module( - trans.Module, fi_gname) + trans.Module, gv_fi_q) ref_fi: llvmlite.Value | t.CPtr = None if gv_fi is not None and gv_fi.Ty is not None: - ref_fi = HandlesExpr.make_global_ref(pool, fi_gname, gv_fi.Ty) + ref_fi = HandlesExpr.make_global_ref(pool, gv_fi.Name, gv_fi.Ty) else: HandlesType.fatal_error( node, diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index 4601b43..8f5ebf5 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -497,7 +497,11 @@ class TranslatorGenMixin: # "use of undefined type named 'sha1.ClassName'" 错误 # (如 _mbuddy: memhub.MemManager | t.CPtr → Ptr(Struct("aeb3...MemManager"))) llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty) - gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, var_name, var_ty) + # 模块级全局命名带 SHA1 前缀(对齐函数名 mangling):多个模块声明同名 + # 全局(如 _mbuddy)时各自独立命名,消除 ld.lld duplicate symbol。 + # SymTab 注册 key 保持裸名(查找逻辑零改动),LLVM 符号名用 mangled 名。 + mangled_name: str = HandlesFunctions._mangle_name(trans, var_name) + gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, mangled_name, var_ty) if gv is None: return 0 llvmlite.module_add_global(mod, gv) @@ -551,11 +555,11 @@ class TranslatorGenMixin: # 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type" gv.Initializer = "zeroinitializer" - # 创建 Value 引用(@var_name, 类型为 var_ty*) + # 创建 Value 引用(@mangled_name, 类型为 var_ty*) var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty) - ref_name: str = pool.alloc(64) + ref_name: str = pool.alloc(96) if ref_name is not None: - viperlib.snprintf(ref_name, 64, "@%s", var_name) + viperlib.snprintf(ref_name, 96, "@%s", mangled_name) gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name) # 注册到模块作用域