fix(gen): 模块级全局变量命名带 SHA1 前缀,消除 ld.lld duplicate symbol

多个模块声明同名模块级全局(如 _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 定义(每模块独立,
   不再依赖裸名链接合并共享;运行时未初始化则真实崩溃暴露,不掩盖)
This commit is contained in:
TermiNexus committed 2026-08-20 04:31:39 +08:00
1 parent cf6c917e83
commit 5f7a87341a
4 files changed
+66 -24

No files matched your search

+30 -8
View File
@@ -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 前缀 + 属性名"精确匹配,
# 避免多模块同名全局(@<A>._mbuddy / @<B>._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:
+16 -8
View File
@@ -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)
+12 -4
View File
@@ -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,
+8 -4
View File
@@ -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)
# 注册到模块作用域