[lld] [LLD][COFF] Prevent to emit relocations for discarded weak wrapped symbols (PR #156214)
Tomohiro Kashiwada via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 5 06:16:22 PDT 2025
https://github.com/kikairoya updated https://github.com/llvm/llvm-project/pull/156214
>From 992b29f953b90f29a8e89e227e351107afb8f255 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Tue, 12 Aug 2025 18:06:31 +0900
Subject: [PATCH 01/12] application test
---
lld/test/COFF/weak-wrap-import.test | 360 ++++++++++++++++++++++++++++
1 file changed, 360 insertions(+)
create mode 100644 lld/test/COFF/weak-wrap-import.test
diff --git a/lld/test/COFF/weak-wrap-import.test b/lld/test/COFF/weak-wrap-import.test
new file mode 100644
index 0000000000000..a4c4d56fc7597
--- /dev/null
+++ b/lld/test/COFF/weak-wrap-import.test
@@ -0,0 +1,360 @@
+REQUIRES: x86, shell
+
+RUN: rm -f %t.dir/* && split-file %s %t.dir/ && cd %t.dir
+
+RUN: llc rtdll.ll -o rtdll.o --filetype=obj
+RUN: ld.lld -m i386pep -shared -o rtdll.dll rtdll.o --entry= --out-implib rtdll.dll.a --dynamicbase
+
+RUN: llvm-mc -filetype=obj -triple=x86_64-mingw crt0-x86_64-mingw.s -o crt0.o
+RUN: llvm-mc -filetype=obj -triple=x86_64-mingw dllcrt0-x86_64-mingw.s -o dllcrt0.o
+RUN: llc crt1.ll -o crt1.o --filetype=obj
+
+RUN: llc overrider.ll -o overrider.o --filetype=obj
+RUN: llvm-ar rc somelib.a overrider.o
+RUN: llvm-as overrider.ll -o overrider.bc
+
+RUN: llc somedll.ll -o somedll.o --filetype=obj
+RUN: ld.lld -m i386pep --dynamicbase --entry _start --wrap theweak \
+RUN: -shared -o somedll.dll somedll.o dllcrt0.o crt1.o rtdll.dll.a --out-implib somedll.dll.a
+
+RUN: env NAME=noref DEPS= sh run.sh CHECK
+RUN: env NAME=use DEPS= sh run.sh CHECK,CHECK-IMP
+RUN: env NAME=override-only DEPS=overrider.o sh run.sh CHECK,CHECK-IMP-LLD,CHECK-REL
+RUN: env NAME=override-use DEPS=overrider.o sh run.sh CHECK,CHECK-IMP,CHECK-REL
+RUN: env NAME=linklib-noref DEPS=somelib.a sh run.sh CHECK,CHECK-IMP-LLD,CHECK-REL
+RUN: env NAME=linklib-use DEPS=somelib.a sh run.sh CHECK,CHECK-IMP,CHECK-REL
+RUN: env NAME=linkdll-noref DEPS=somedll.dll.a sh run.sh CHECK,CHECK-IMP-LLD,SOMEDLL
+RUN: env NAME=linkdll-use DEPS=somedll.dll.a sh run.sh CHECK,CHECK-IMP,CHECK-REL-LLD,SOMEDLL,SOMEDLL-IMP-LLD
+
+#--- check-lld.txt
+CHECK: 0200[[#%x,ADDR:]] D ref_theweak
+CHECK: File
+SOMEDLL: Import {
+SOMEDLL-NEXT: Name: somedll.dll
+SOMEDLL-IMP: Symbol: theweak
+SOMEDLL-IMP-LLD: Symbol: theweak
+SOMEDLL: }
+CHECK: Import {
+CHECK-NEXT: Name: rtdll.dll
+CHECK-IMP: Symbol: __wrap_theweak
+CHECK-IMP-LLD: Symbol: __wrap_theweak
+CHECK: }
+CHECK: BaseReloc [
+CHECK-REL: Type: DIR64
+CHECK-REL-NEXT: Address: 0x[[#%X,ADDR]]
+CHECK-REL-LLD: Type: DIR64
+CHECK-REL-LLD-NEXT: Address: 0x[[#%X,ADDR]]
+CHECK: ]
+
+#--- check-bfd.txt
+CHECK: 0200[[#%x,ADDR:]] D ref_theweak
+CHECK: File
+CHECK: Import {
+CHECK-NEXT: Name: rtdll.dll
+CHECK-IMP: Symbol: __wrap_theweak
+CHECK-IMP-BFD: Symbol: __wrap_theweak
+CHECK: }
+SOMEDLL: Import {
+SOMEDLL-NEXT: Name: somedll.dll
+SOMEDLL-IMP: Symbol: theweak
+SOMEDLL-IMP-BFD: Symbol: theweak
+SOMEDLL: }
+CHECK: BaseReloc [
+CHECK-REL: Type: DIR64
+CHECK-REL-NEXT: Address: 0x[[#%X,ADDR]]
+CHECK-REL-BFD: Type: DIR64
+CHECK-REL-BFD-NEXT: Address: 0x[[#%X,ADDR]]
+CHECK: ]
+
+#--- run.sh
+set -ex
+RUNBIN=true
+LINKER=lld
+run() {
+ if [ "$ASLR" = ON ]; then
+ dynamicbase=--dynamicbase
+ ASLR=.aslr
+ else
+ dynamicbase=
+ ASLR=
+ fi
+ ld.$LINKER -m i386pep $dynamicbase --entry _start --subsystem console --wrap theweak --image-base 0x02000000 \
+ -o $NAME$LTO$ASLR.exe crt0.o crt1.o $NAME.o $DEPS rtdll.dll.a
+ llvm-nm $NAME$LTO$ASLR.exe > $NAME$LTO$ASLR.dump
+ llvm-readobj --hex-dump=.data --coff-basereloc --coff-imports $NAME$LTO$ASLR.exe >> $NAME$LTO$ASLR.dump
+ FileCheck --input-file=$NAME$LTO$ASLR.dump check-$LINKER.txt --allow-unused-prefixes --check-prefixes=$1 \
+ --implicit-check-not=.dll --implicit-check-not="Symbol: {{[a-z_]*}}theweak" --implicit-check-not=DIR64
+ [ -z "$RUNBIN" ] || ./$NAME$LTO$ASLR.exe
+}
+if ! uname -a | grep -E -iq 'cygwin|mingw|msys|wsl'; then
+ RUNBIN=
+fi
+llc $NAME.ll -o $NAME.o --filetype=obj
+run "$@"
+[ -z "$RUNBIN" ] || ASLR=ON run "$@"
+if [ $LINKER = lld ]; then
+ llvm-as $NAME.ll -o $NAME.bc
+ LTO=.lto run "$@"
+ [ -z "$RUNBIN" ] || LTO=.lto ASLR=ON run "$@"
+fi
+
+#--- noref.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+declare dllimport i32 @is_overridden() nounwind
+define dso_local i32 @main() nounwind {
+ %1 = call i32 @is_overridden()
+ %3 = icmp ne i32 %1, u0x00
+ %4 = zext i1 %3 to i32
+ ; return success if not overridden
+ ret i32 %4
+}
+
+#--- use.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+declare i32 @theweak(i32) nounwind
+
+declare dllimport i32 @is_overridden() nounwind
+define dso_local i32 @main() nounwind {
+ %1 = call i32 @is_overridden()
+ %2 = call i32 @theweak(i32 %1)
+ %3 = icmp ne i32 %2, u0x02
+ %4 = zext i1 %3 to i32
+ ; return success if not overridden and used fallback
+ ret i32 %4
+}
+
+#--- overrider.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+define dso_local i32 @theweak(i32 %i) nounwind {
+ %1 = or i32 %i, u0x04
+ ret i32 %1
+}
+define i32 @anchor(i32 %i) nounwind {
+ ret i32 %i
+}
+
+#--- override-only.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+declare i32 @theweak(i32) nounwind
+
+declare dllimport i32 @is_overridden() nounwind
+define dso_local i32 @main() nounwind {
+ %1 = call i32 @is_overridden()
+ %3 = icmp ne i32 %1, u0x01
+ %4 = zext i1 %3 to i32
+ ; return success if overridden
+ ret i32 %4
+}
+
+#--- override-use.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+declare i32 @theweak(i32) nounwind
+
+declare dllimport i32 @is_overridden() nounwind
+define dso_local i32 @main() nounwind {
+ %1 = call i32 @is_overridden()
+ %2 = call i32 @theweak(i32 %1)
+ %3 = icmp ne i32 %2, u0x5
+ %4 = zext i1 %3 to i32
+ ; return success if overridden and used local obj
+ ret i32 %4
+}
+
+#--- linklib-noref.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+declare i32 @theweak(i32) nounwind
+declare i32 @anchor(i32) nounwind
+
+declare dllimport i32 @is_overridden() nounwind
+define dso_local i32 @main() nounwind {
+ %1 = call i32 @is_overridden()
+ %3 = icmp ne i32 %1, u0x01
+ %4 = zext i1 %3 to i32
+ %5 = call i32 @anchor(i32 %4)
+ ; return success if overridden
+ ret i32 %4
+}
+
+#--- linklib-use.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+declare i32 @theweak(i32) nounwind
+declare i32 @anchor(i32) nounwind
+
+declare dllimport i32 @is_overridden() nounwind
+define dso_local i32 @main() nounwind {
+ %1 = call i32 @is_overridden()
+ %2 = call i32 @theweak(i32 %1)
+ %3 = icmp ne i32 %2, u0x5
+ %4 = zext i1 %3 to i32
+ %5 = call i32 @anchor(i32 %4)
+ ; return success if overridden and used local obj
+ ret i32 %4
+}
+
+#--- linkdll-noref.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+declare i32 @theweak(i32) nounwind
+declare i32 @anchor(i32) nounwind
+
+declare dllimport i32 @is_overridden() nounwind
+define dso_local i32 @main() nounwind {
+ %1 = call i32 @is_overridden()
+ %3 = icmp ne i32 %1, u0x01
+ %4 = zext i1 %3 to i32
+ %5 = call i32 @anchor(i32 %4)
+ ; return success if overridden
+ ret i32 %4
+}
+
+#--- linkdll-use.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+declare i32 @theweak(i32) nounwind
+declare i32 @anchor(i32) nounwind
+
+declare dllimport i32 @is_overridden() nounwind
+define dso_local i32 @main() nounwind {
+ %1 = call i32 @is_overridden()
+ %2 = call i32 @theweak(i32 %1)
+ %3 = icmp ne i32 %2, u0x9
+ %4 = zext i1 %3 to i32
+ %5 = call i32 @anchor(i32 %4)
+ ; return success if overridden and used from dll
+ ret i32 %4
+}
+
+#--- crt0-x86_64-mingw.s
+ .text
+ .globl _start
+ .p2align 4
+_start:
+ call premain
+ sub $64, %rsp
+ xor %r8, %r8
+ movq %r8, 40(%rsp)
+ lea 40(%rsp), %rdx
+ mov %rdx, 48(%rsp)
+ movq %r8, 56(%rsp)
+ addq $8, %rdx
+ mov $1, %ecx
+ call main // ret = main(1, { "", nullptr });
+ cmp $127, %eax
+ mov $1, %edx
+ cmovbe %eax, %edx // ret = (unsigned)ret >= 128 ? 1 : ret
+ mov $-1, %rcx
+ mov %rcx, %r10
+ mov $0x2C, %eax
+ syscall // ExitProcess(-1, ret)
+ jmp .
+
+ .section .data,"rw"
+ .globl _dummy_data
+_dummy_data:
+ .quad 0x1122334455667788
+
+ .section .rdata,"r"
+ .globl _dummy_rdata
+_dummy_rdata:
+ .quad 0x1122334455667788
+
+#--- crt1.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+ at ref_theweak = dso_local global ptr @__real_theweak
+declare extern_weak i32 @__real_theweak(i32) nounwind
+
+declare dllimport void @do_override(ptr %fn) nounwind
+
+define dso_local void @premain() nounwind {
+ %1 = load ptr, ptr @ref_theweak
+ call void @do_override(ptr %1)
+ ret void
+}
+
+ at __RUNTIME_PSEUDO_RELOC_LIST__ = external dso_local constant ptr
+ at __RUNTIME_PSEUDO_RELOC_LIST_END__ = external dso_local constant ptr
+
+define dso_local i32 @_pei386_runtime_relocator() {
+ ret i32 trunc(i64 sub(i64 ptrtoint(ptr @__RUNTIME_PSEUDO_RELOC_LIST_END__ to i64),
+ i64 ptrtoint(ptr @__RUNTIME_PSEUDO_RELOC_LIST__ to i64)) to i32)
+}
+
+#--- rtdll.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+ at fn_ptr = dso_local global ptr null
+define dllexport void @__main() nounwind {
+ ret void
+}
+define dllexport void @do_override(ptr %fn) nounwind {
+ %n = icmp eq ptr %fn, null
+ br i1 %n, label %fin, label %do
+do:
+ store ptr %fn, ptr @fn_ptr
+ br label %fin
+fin:
+ ret void
+}
+define dllexport i32 @is_overridden() nounwind {
+ %fn = load ptr, ptr @fn_ptr
+ %ne = icmp ne ptr %fn, null
+ %r = zext i1 %ne to i32
+ ret i32 %r
+}
+define dllexport i32 @__wrap_theweak(i32 %i) nounwind {
+ %fn = load ptr, ptr @fn_ptr
+ %n = icmp eq ptr %fn, null
+ br i1 %n, label %eq, label %ne
+eq:
+ %1 = tail call i32 @fallback(i32 %i)
+ ret i32 %1
+ne:
+ %2 = tail call i32 %fn(i32 %i)
+ ret i32 %2
+}
+define dso_local i32 @fallback(i32 %i) nounwind {
+ %1 = or i32 %i, u0x02
+ ret i32 %1
+}
+
+#--- dllcrt0-x86_64-mingw.s
+ .text
+ .globl _start
+ .p2align 4
+_start:
+ call premain
+ jmp dllmain
+
+#--- somedll.ll
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-gnu"
+
+define dso_local void @dllmain() nounwind {
+ ret void
+}
+define dllexport i32 @theweak(i32 %i) nounwind {
+ %1 = or i32 %i, u0x08
+ ret i32 %1
+}
+define dllexport i32 @anchor(i32 %i) nounwind {
+ ret i32 %i
+}
>From 720b0cb3fada39af66c4be9f8c54ea6b7debd15d Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sun, 27 Jul 2025 22:25:25 +0900
Subject: [PATCH 02/12] add logs for tracing
---
lld/COFF/Chunks.cpp | 5 +++++
lld/COFF/MinGW.cpp | 8 +++++++-
lld/COFF/SymbolTable.cpp | 10 ++++++++++
lld/COFF/Symbols.h | 2 +-
lld/COFF/Writer.cpp | 1 +
5 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 39fc25047f3b1..d4ff65dad1e1a 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -566,6 +566,11 @@ void SectionChunk::getBaserels(std::vector<Baserel> *res) {
Symbol *target = file->getSymbol(rel.SymbolTableIndex);
if (!target || isa<DefinedAbsolute>(target))
continue;
+ if (target && target->getName().size() > 2)
+ Log(file->symtab.ctx)
+ << "base reloc for " << target->getName() << ": " << target->kind()
+ << ',' << !!target->isUsedInRegularObj << " (in " << file->getName()
+ << ")";
res->emplace_back(rva + rel.VirtualAddress, ty);
}
diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp
index e7117cbea2e88..135c428c64e51 100644
--- a/lld/COFF/MinGW.cpp
+++ b/lld/COFF/MinGW.cpp
@@ -226,6 +226,8 @@ void lld::coff::addWrappedSymbols(SymbolTable &symtab,
Symbol *sym = symtab.findUnderscore(name);
if (!sym)
continue;
+ Log(symtab.ctx) << "adding wrapped symbol entry for: " << name << ": "
+ << sym->kind() << ',' << !!sym->isUsedInRegularObj;
Symbol *real =
symtab.addUndefined(mangle("__real_" + name, symtab.machine));
@@ -269,6 +271,7 @@ void lld::coff::wrapSymbols(SymbolTable &symtab) {
// (We can't easily distinguish whether any object file actually
// referenced it or not, though.)
if (imp) {
+ Log(symtab.ctx) << "wrapping imported symbol: " << imp->getName();
DefinedLocalImport *wrapimp = make<DefinedLocalImport>(
symtab.ctx, saver().save("__imp_" + w.wrap->getName()), d);
symtab.localImportChunks.push_back(wrapimp->getChunk());
@@ -281,7 +284,10 @@ void lld::coff::wrapSymbols(SymbolTable &symtab) {
parallelForEach(symtab.ctx.objFileInstances, [&](ObjFile *file) {
MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
for (auto &sym : syms)
- if (Symbol *s = map.lookup(sym))
+ if (Symbol *s = map.lookup(sym)) {
+ Log(symtab.ctx) << "overriding " << sym->getName() << " by "
+ << s->getName() << " (in " << file->getName() << ")";
sym = s;
+ }
});
}
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 0a88807c00dd5..cce0075b6cfb2 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -257,6 +257,8 @@ void SymbolTable::loadMinGWSymbols() {
}
for (auto sym : undefs) {
+ Log(ctx) << "trying fixup " << sym->getName() << ": " << sym->kind() << ','
+ << !!sym->isUsedInRegularObj;
auto *undef = dyn_cast<Undefined>(sym);
if (!undef)
continue;
@@ -459,6 +461,13 @@ void SymbolTable::resolveRemainingUndefines(std::vector<Undefined *> &aliases) {
for (auto &i : symMap) {
Symbol *sym = i.second;
+
+ if (auto name = sym->getName(); !name.ends_with("__") &&
+ !name.starts_with("__guard") &&
+ !name.starts_with("__nm_"))
+ Log(ctx) << "checking for " << name << ": " << sym->kind()
+ << " used: " << (sym->isUsedInRegularObj != 0);
+
auto *undef = dyn_cast<Undefined>(sym);
if (!undef)
continue;
@@ -525,6 +534,7 @@ void SymbolTable::resolveRemainingUndefines(std::vector<Undefined *> &aliases) {
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
+ Log(ctx) << "inserting " << name;
bool inserted = false;
Symbol *&sym = symMap[CachedHashStringRef(name)];
if (!sym) {
diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h
index c86ded860876b..9e8cd4aa0cfdc 100644
--- a/lld/COFF/Symbols.h
+++ b/lld/COFF/Symbols.h
@@ -56,7 +56,7 @@ class Symbol {
DefinedAbsoluteKind,
DefinedSyntheticKind,
- UndefinedKind,
+ UndefinedKind, // = 7
LazyArchiveKind,
LazyObjectKind,
LazyDLLSymbolKind,
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 21ab9d17a26f9..9664215f4bdc8 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1299,6 +1299,7 @@ void Writer::createImportTables() {
<< file->symtab.printSymbol(impSym);
delayIdata.add(impSym);
} else {
+ Log(ctx) << "populating import entry for " << impSym->getName();
idata.add(impSym);
}
}
>From 9b7600fb3fc9dc5dad0db2430a572cd55c764864 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 30 Aug 2025 08:59:52 +0900
Subject: [PATCH 03/12] test for "inherit weak"
---
lld/test/COFF/wrap-inherit-weakness.ll | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 lld/test/COFF/wrap-inherit-weakness.ll
diff --git a/lld/test/COFF/wrap-inherit-weakness.ll b/lld/test/COFF/wrap-inherit-weakness.ll
new file mode 100644
index 0000000000000..e050e8fda37f2
--- /dev/null
+++ b/lld/test/COFF/wrap-inherit-weakness.ll
@@ -0,0 +1,16 @@
+; REQUIRES: x86
+
+; Check that 'weak' attribute will be inherited to the wrapped symbols.
+
+; RUN: llc %s -mtriple x86_64-mingw -o %t.o --filetype=obj
+; RUN: ld.lld -m i386pep -shared -o %t.dll %t.o --entry= --wrap fn
+
+declare extern_weak dso_local void @__real_fn() nounwind
+declare dso_local void @fn() nounwind
+declare dso_local void @__wrap_fn() nounwind
+
+define dllexport void @caller() nounwind {
+ call void @__real_fn()
+ call void @fn()
+ ret void
+}
>From c08ec16dd3950d4da98c1cd6855a0e6341ea4740 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Wed, 13 Aug 2025 21:23:46 +0900
Subject: [PATCH 04/12] inherit weak
---
lld/COFF/MinGW.cpp | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp
index 135c428c64e51..24c75997aa737 100644
--- a/lld/COFF/MinGW.cpp
+++ b/lld/COFF/MinGW.cpp
@@ -235,6 +235,19 @@ void lld::coff::addWrappedSymbols(SymbolTable &symtab,
symtab.addUndefined(mangle("__wrap_" + name, symtab.machine));
v.push_back({sym, real, wrap});
+ if (auto *usym = dyn_cast<Undefined>(sym)) {
+ if (auto *ureal = dyn_cast<Undefined>(real);
+ ureal && ureal->weakAlias && !usym->weakAlias) {
+ Log(symtab.ctx) << "inheriting weak alias to: " << usym->getName();
+ usym->weakAlias = ureal->weakAlias;
+ }
+ if (auto *uwrap = dyn_cast<Undefined>(wrap);
+ uwrap && usym->weakAlias && !uwrap->weakAlias) {
+ Log(symtab.ctx) << "inheriting weak alias to: " << uwrap->getName();
+ uwrap->weakAlias = usym->weakAlias;
+ }
+ }
+
// These symbols may seem undefined initially, but don't bail out
// at symtab.reportUnresolvable() due to them, but let wrapSymbols
// below sort things out before checking finally with
>From da17b36d1294400e081c425d179f39c9f7f364e8 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 30 Aug 2025 09:33:37 +0900
Subject: [PATCH 05/12] test for "reuse existing symbol when wrapping imports"
---
lld/test/COFF/wrap-dllimport.s | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/lld/test/COFF/wrap-dllimport.s b/lld/test/COFF/wrap-dllimport.s
index d7662b29fdc78..a1b4521fd75fa 100644
--- a/lld/test/COFF/wrap-dllimport.s
+++ b/lld/test/COFF/wrap-dllimport.s
@@ -1,42 +1,59 @@
// REQUIRES: x86
// Check that we can wrap a dllimported symbol, so that references to
-// __imp_<symbol> gets redirected to a defined local import instead.
+// __imp_<symbol> gets redirected to a symbol already exists or a defined local import instead
// RUN: split-file %s %t.dir
// RUN: llvm-mc -filetype=obj -triple=i686-win32-gnu %t.dir/main.s -o %t.main.obj
// RUN: llvm-mc -filetype=obj -triple=i686-win32-gnu %t.dir/other.s -o %t.other.obj
-// RUN: lld-link -dll -out:%t.dll %t.other.obj -noentry -safeseh:no -export:foo -implib:%t.lib
-// RUN: lld-link -out:%t.exe %t.main.obj %t.lib -entry:entry -subsystem:console -debug:symtab -safeseh:no -wrap:foo -lldmap:%t.map
+// RUN: lld-link -dll -out:%t.dll %t.other.obj -noentry -safeseh:no -export:foo -export:bar -implib:%t.lib
+// RUN: lld-link -out:%t.exe %t.main.obj %t.lib -entry:entry -subsystem:console -debug:symtab -safeseh:no -wrap:foo -wrap:bar -lldmap:%t.map
// RUN: llvm-objdump -s -d --print-imm-hex %t.exe | FileCheck %s
// CHECK: Contents of section .rdata:
-// CHECK-NEXT: 402000 06104000
+// CHECK-NEXT: 402000 0c104000
// CHECK: Disassembly of section .text:
// CHECK-EMPTY:
// CHECK: 00401000 <_entry>:
// CHECK-NEXT: 401000: ff 25 00 20 40 00 jmpl *0x402000
+// CHECK-NEXT: 401006: ff 25 00 00 00 00 jmpl *0x0
// CHECK-EMPTY:
-// CHECK-NEXT: 00401006 <___wrap_foo>:
-// CHECK-NEXT: 401006: c3 retl
+// CHECK-NEXT: 0040100c <___wrap_foo>:
+// CHECK-NEXT: 40100c: c3 retl
+// CHECK-EMPTY:
+// CHECK-NEXT: 0040100d <___wrap_bar>:
+// CHECK-NEXT: 40100d: c3 retl
-// The jmpl instruction in _entry points at an address in 0x402000,
+// The first jmpl instruction in _entry points at an address in 0x402000,
// which is the first 4 bytes of the .rdata section (above), which is a
// pointer that points at ___wrap_foo.
+// The second jmpl instruction in _entry points the null since the referenced symbol
+// `__imp____wrap_bar` is declared as a weak reference to prevent pull a reference
+// from an external DLL.
+
#--- main.s
.global _entry
_entry:
jmpl *__imp__foo
+ jmpl *__imp__bar
.global ___wrap_foo
___wrap_foo:
ret
+.weak __imp____wrap_bar
+.global ___wrap_bar
+___wrap_bar:
+ ret
+
#--- other.s
.global _foo
-
_foo:
ret
+
+.global _bar
+_bar:
+ ret
>From 6bf8c44ce87373610ef59a989ecdc7ed1733b6ad Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Wed, 13 Aug 2025 10:43:37 +0900
Subject: [PATCH 06/12] reuse existing symbol when wrapping imports
---
lld/COFF/MinGW.cpp | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp
index 24c75997aa737..47029ad18594c 100644
--- a/lld/COFF/MinGW.cpp
+++ b/lld/COFF/MinGW.cpp
@@ -278,17 +278,27 @@ void lld::coff::wrapSymbols(SymbolTable &symtab) {
map[w.sym] = w.wrap;
map[w.real] = w.sym;
if (Defined *d = dyn_cast<Defined>(w.wrap)) {
+ Log(symtab.ctx) << "checking for importing with unwrapping: "
+ << d->getName();
Symbol *imp = symtab.find(("__imp_" + w.sym->getName()).str());
// Create a new defined local import for the wrap symbol. If
// no imp prefixed symbol existed, there's no need for it.
// (We can't easily distinguish whether any object file actually
// referenced it or not, though.)
if (imp) {
- Log(symtab.ctx) << "wrapping imported symbol: " << imp->getName();
- DefinedLocalImport *wrapimp = make<DefinedLocalImport>(
- symtab.ctx, saver().save("__imp_" + w.wrap->getName()), d);
- symtab.localImportChunks.push_back(wrapimp->getChunk());
- map[imp] = wrapimp;
+ if (Symbol *wrapimp =
+ symtab.find(("__imp_" + w.wrap->getName()).str())) {
+ Log(symtab.ctx) << "using unwrapped imported symbol: "
+ << imp->getName();
+ map[imp] = wrapimp;
+ } else {
+ Log(symtab.ctx) << "create local unwrapped imported symbol: "
+ << imp->getName();
+ DefinedLocalImport *localwrapimp = make<DefinedLocalImport>(
+ symtab.ctx, saver().save("__imp_" + w.wrap->getName()), d);
+ symtab.localImportChunks.push_back(localwrapimp->getChunk());
+ map[imp] = localwrapimp;
+ }
}
}
}
>From 2c5d613094bc0d2509f0188087daa0c0de40ee17 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sat, 30 Aug 2025 18:46:54 +0900
Subject: [PATCH 07/12] test for "skip undefined baserel"
---
lld/test/COFF/reloc-undefined-weak.s | 52 ++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
create mode 100644 lld/test/COFF/reloc-undefined-weak.s
diff --git a/lld/test/COFF/reloc-undefined-weak.s b/lld/test/COFF/reloc-undefined-weak.s
new file mode 100644
index 0000000000000..5f9baa7a3dfb0
--- /dev/null
+++ b/lld/test/COFF/reloc-undefined-weak.s
@@ -0,0 +1,52 @@
+// REQUIRES: x86
+
+// Check that base-relocations for unresolved weak symbols will be omitted.
+
+// RUN: rm -rf %t.dir && split-file %s %t.dir && cd %t.dir
+// RUN: llvm-mc -filetype=obj -triple=x86_64-mingw main.s -o main.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-mingw other.s -o other.o
+
+// RUN: ld.lld -m i386pep -dll -o other.dll other.o -entry= --export-all-symbols --out-implib other.dll.a
+// RUN: ld.lld -m i386pep -o main.exe main.o other.dll.a -e entry --wrap foo --verbose
+// RUN: llvm-readobj --sections --symbols --coff-imports --coff-basereloc main.exe | FileCheck %s --implicit-check-not=other.dll
+
+// CHECK: Number: 4
+// CHECK-NEXT: Name: .data
+// CHECK-NEXT: VirtualSize:
+// CHECK-NEXT: VirtualAddress: 0x[[#%x,SECTOP:0x4000]]
+// CHECK: Name: ref_foo
+// CHECK-NEXT: Value: [[#%d,SYMVAL:]]
+// CHECK: BaseReloc [
+// CHECK-NOT: Address: 0x[[#%x,SECTOP+SYMVAL]]
+
+#--- main.s
+.global entry
+entry:
+ movq ref_foo(%rip), %rax
+ call *%rax
+
+.global __wrap_foo
+__wrap_foo:
+ ret
+
+.data
+.global ref_foo
+.p2align 3
+ref_foo:
+ .quad __real_foo
+
+.globl _pei386_runtime_relocator
+_pei386_runtime_relocator:
+ movl __RUNTIME_PSEUDO_RELOC_LIST__(%rip), %eax
+ movl __RUNTIME_PSEUDO_RELOC_LIST_END__(%rip), %eax
+
+.weak __real_foo
+.addrsig
+.addrsig_sym __real_foo
+.addrsig_sym ref_foo
+
+#--- other.s
+.global foo
+
+foo:
+ ret
>From 54a710952f9f9e25f0acd3adb14c9584e4c589a7 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Wed, 13 Aug 2025 10:44:08 +0900
Subject: [PATCH 08/12] skip undefined baserel
---
lld/COFF/Chunks.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index d4ff65dad1e1a..259fffc847590 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -564,7 +564,7 @@ void SectionChunk::getBaserels(std::vector<Baserel> *res) {
if (ty == IMAGE_REL_BASED_ABSOLUTE)
continue;
Symbol *target = file->getSymbol(rel.SymbolTableIndex);
- if (!target || isa<DefinedAbsolute>(target))
+ if (!isa_and_nonnull<Defined>(target) || isa<DefinedAbsolute>(target))
continue;
if (target && target->getName().size() > 2)
Log(file->symtab.ctx)
>From ca3488caec539244f982f859b02fb10b97c9cd9a Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Sun, 31 Aug 2025 07:41:30 +0900
Subject: [PATCH 09/12] cleanup
Revert "add logs for tracing"
Revert "application test"
---
lld/COFF/Chunks.cpp | 5 -
lld/COFF/MinGW.cpp | 15 +-
lld/COFF/SymbolTable.cpp | 10 -
lld/COFF/Symbols.h | 2 +-
lld/COFF/Writer.cpp | 1 -
lld/test/COFF/weak-wrap-import.test | 360 ----------------------------
6 files changed, 2 insertions(+), 391 deletions(-)
delete mode 100644 lld/test/COFF/weak-wrap-import.test
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 259fffc847590..cb5cba5c414a1 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -566,11 +566,6 @@ void SectionChunk::getBaserels(std::vector<Baserel> *res) {
Symbol *target = file->getSymbol(rel.SymbolTableIndex);
if (!isa_and_nonnull<Defined>(target) || isa<DefinedAbsolute>(target))
continue;
- if (target && target->getName().size() > 2)
- Log(file->symtab.ctx)
- << "base reloc for " << target->getName() << ": " << target->kind()
- << ',' << !!target->isUsedInRegularObj << " (in " << file->getName()
- << ")";
res->emplace_back(rva + rel.VirtualAddress, ty);
}
diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp
index 47029ad18594c..7c6f4281145ce 100644
--- a/lld/COFF/MinGW.cpp
+++ b/lld/COFF/MinGW.cpp
@@ -226,8 +226,6 @@ void lld::coff::addWrappedSymbols(SymbolTable &symtab,
Symbol *sym = symtab.findUnderscore(name);
if (!sym)
continue;
- Log(symtab.ctx) << "adding wrapped symbol entry for: " << name << ": "
- << sym->kind() << ',' << !!sym->isUsedInRegularObj;
Symbol *real =
symtab.addUndefined(mangle("__real_" + name, symtab.machine));
@@ -238,12 +236,10 @@ void lld::coff::addWrappedSymbols(SymbolTable &symtab,
if (auto *usym = dyn_cast<Undefined>(sym)) {
if (auto *ureal = dyn_cast<Undefined>(real);
ureal && ureal->weakAlias && !usym->weakAlias) {
- Log(symtab.ctx) << "inheriting weak alias to: " << usym->getName();
usym->weakAlias = ureal->weakAlias;
}
if (auto *uwrap = dyn_cast<Undefined>(wrap);
uwrap && usym->weakAlias && !uwrap->weakAlias) {
- Log(symtab.ctx) << "inheriting weak alias to: " << uwrap->getName();
uwrap->weakAlias = usym->weakAlias;
}
}
@@ -278,8 +274,6 @@ void lld::coff::wrapSymbols(SymbolTable &symtab) {
map[w.sym] = w.wrap;
map[w.real] = w.sym;
if (Defined *d = dyn_cast<Defined>(w.wrap)) {
- Log(symtab.ctx) << "checking for importing with unwrapping: "
- << d->getName();
Symbol *imp = symtab.find(("__imp_" + w.sym->getName()).str());
// Create a new defined local import for the wrap symbol. If
// no imp prefixed symbol existed, there's no need for it.
@@ -288,12 +282,8 @@ void lld::coff::wrapSymbols(SymbolTable &symtab) {
if (imp) {
if (Symbol *wrapimp =
symtab.find(("__imp_" + w.wrap->getName()).str())) {
- Log(symtab.ctx) << "using unwrapped imported symbol: "
- << imp->getName();
map[imp] = wrapimp;
} else {
- Log(symtab.ctx) << "create local unwrapped imported symbol: "
- << imp->getName();
DefinedLocalImport *localwrapimp = make<DefinedLocalImport>(
symtab.ctx, saver().save("__imp_" + w.wrap->getName()), d);
symtab.localImportChunks.push_back(localwrapimp->getChunk());
@@ -307,10 +297,7 @@ void lld::coff::wrapSymbols(SymbolTable &symtab) {
parallelForEach(symtab.ctx.objFileInstances, [&](ObjFile *file) {
MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
for (auto &sym : syms)
- if (Symbol *s = map.lookup(sym)) {
- Log(symtab.ctx) << "overriding " << sym->getName() << " by "
- << s->getName() << " (in " << file->getName() << ")";
+ if (Symbol *s = map.lookup(sym))
sym = s;
- }
});
}
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index cce0075b6cfb2..0a88807c00dd5 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -257,8 +257,6 @@ void SymbolTable::loadMinGWSymbols() {
}
for (auto sym : undefs) {
- Log(ctx) << "trying fixup " << sym->getName() << ": " << sym->kind() << ','
- << !!sym->isUsedInRegularObj;
auto *undef = dyn_cast<Undefined>(sym);
if (!undef)
continue;
@@ -461,13 +459,6 @@ void SymbolTable::resolveRemainingUndefines(std::vector<Undefined *> &aliases) {
for (auto &i : symMap) {
Symbol *sym = i.second;
-
- if (auto name = sym->getName(); !name.ends_with("__") &&
- !name.starts_with("__guard") &&
- !name.starts_with("__nm_"))
- Log(ctx) << "checking for " << name << ": " << sym->kind()
- << " used: " << (sym->isUsedInRegularObj != 0);
-
auto *undef = dyn_cast<Undefined>(sym);
if (!undef)
continue;
@@ -534,7 +525,6 @@ void SymbolTable::resolveRemainingUndefines(std::vector<Undefined *> &aliases) {
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
- Log(ctx) << "inserting " << name;
bool inserted = false;
Symbol *&sym = symMap[CachedHashStringRef(name)];
if (!sym) {
diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h
index 9e8cd4aa0cfdc..c86ded860876b 100644
--- a/lld/COFF/Symbols.h
+++ b/lld/COFF/Symbols.h
@@ -56,7 +56,7 @@ class Symbol {
DefinedAbsoluteKind,
DefinedSyntheticKind,
- UndefinedKind, // = 7
+ UndefinedKind,
LazyArchiveKind,
LazyObjectKind,
LazyDLLSymbolKind,
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 9664215f4bdc8..21ab9d17a26f9 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1299,7 +1299,6 @@ void Writer::createImportTables() {
<< file->symtab.printSymbol(impSym);
delayIdata.add(impSym);
} else {
- Log(ctx) << "populating import entry for " << impSym->getName();
idata.add(impSym);
}
}
diff --git a/lld/test/COFF/weak-wrap-import.test b/lld/test/COFF/weak-wrap-import.test
deleted file mode 100644
index a4c4d56fc7597..0000000000000
--- a/lld/test/COFF/weak-wrap-import.test
+++ /dev/null
@@ -1,360 +0,0 @@
-REQUIRES: x86, shell
-
-RUN: rm -f %t.dir/* && split-file %s %t.dir/ && cd %t.dir
-
-RUN: llc rtdll.ll -o rtdll.o --filetype=obj
-RUN: ld.lld -m i386pep -shared -o rtdll.dll rtdll.o --entry= --out-implib rtdll.dll.a --dynamicbase
-
-RUN: llvm-mc -filetype=obj -triple=x86_64-mingw crt0-x86_64-mingw.s -o crt0.o
-RUN: llvm-mc -filetype=obj -triple=x86_64-mingw dllcrt0-x86_64-mingw.s -o dllcrt0.o
-RUN: llc crt1.ll -o crt1.o --filetype=obj
-
-RUN: llc overrider.ll -o overrider.o --filetype=obj
-RUN: llvm-ar rc somelib.a overrider.o
-RUN: llvm-as overrider.ll -o overrider.bc
-
-RUN: llc somedll.ll -o somedll.o --filetype=obj
-RUN: ld.lld -m i386pep --dynamicbase --entry _start --wrap theweak \
-RUN: -shared -o somedll.dll somedll.o dllcrt0.o crt1.o rtdll.dll.a --out-implib somedll.dll.a
-
-RUN: env NAME=noref DEPS= sh run.sh CHECK
-RUN: env NAME=use DEPS= sh run.sh CHECK,CHECK-IMP
-RUN: env NAME=override-only DEPS=overrider.o sh run.sh CHECK,CHECK-IMP-LLD,CHECK-REL
-RUN: env NAME=override-use DEPS=overrider.o sh run.sh CHECK,CHECK-IMP,CHECK-REL
-RUN: env NAME=linklib-noref DEPS=somelib.a sh run.sh CHECK,CHECK-IMP-LLD,CHECK-REL
-RUN: env NAME=linklib-use DEPS=somelib.a sh run.sh CHECK,CHECK-IMP,CHECK-REL
-RUN: env NAME=linkdll-noref DEPS=somedll.dll.a sh run.sh CHECK,CHECK-IMP-LLD,SOMEDLL
-RUN: env NAME=linkdll-use DEPS=somedll.dll.a sh run.sh CHECK,CHECK-IMP,CHECK-REL-LLD,SOMEDLL,SOMEDLL-IMP-LLD
-
-#--- check-lld.txt
-CHECK: 0200[[#%x,ADDR:]] D ref_theweak
-CHECK: File
-SOMEDLL: Import {
-SOMEDLL-NEXT: Name: somedll.dll
-SOMEDLL-IMP: Symbol: theweak
-SOMEDLL-IMP-LLD: Symbol: theweak
-SOMEDLL: }
-CHECK: Import {
-CHECK-NEXT: Name: rtdll.dll
-CHECK-IMP: Symbol: __wrap_theweak
-CHECK-IMP-LLD: Symbol: __wrap_theweak
-CHECK: }
-CHECK: BaseReloc [
-CHECK-REL: Type: DIR64
-CHECK-REL-NEXT: Address: 0x[[#%X,ADDR]]
-CHECK-REL-LLD: Type: DIR64
-CHECK-REL-LLD-NEXT: Address: 0x[[#%X,ADDR]]
-CHECK: ]
-
-#--- check-bfd.txt
-CHECK: 0200[[#%x,ADDR:]] D ref_theweak
-CHECK: File
-CHECK: Import {
-CHECK-NEXT: Name: rtdll.dll
-CHECK-IMP: Symbol: __wrap_theweak
-CHECK-IMP-BFD: Symbol: __wrap_theweak
-CHECK: }
-SOMEDLL: Import {
-SOMEDLL-NEXT: Name: somedll.dll
-SOMEDLL-IMP: Symbol: theweak
-SOMEDLL-IMP-BFD: Symbol: theweak
-SOMEDLL: }
-CHECK: BaseReloc [
-CHECK-REL: Type: DIR64
-CHECK-REL-NEXT: Address: 0x[[#%X,ADDR]]
-CHECK-REL-BFD: Type: DIR64
-CHECK-REL-BFD-NEXT: Address: 0x[[#%X,ADDR]]
-CHECK: ]
-
-#--- run.sh
-set -ex
-RUNBIN=true
-LINKER=lld
-run() {
- if [ "$ASLR" = ON ]; then
- dynamicbase=--dynamicbase
- ASLR=.aslr
- else
- dynamicbase=
- ASLR=
- fi
- ld.$LINKER -m i386pep $dynamicbase --entry _start --subsystem console --wrap theweak --image-base 0x02000000 \
- -o $NAME$LTO$ASLR.exe crt0.o crt1.o $NAME.o $DEPS rtdll.dll.a
- llvm-nm $NAME$LTO$ASLR.exe > $NAME$LTO$ASLR.dump
- llvm-readobj --hex-dump=.data --coff-basereloc --coff-imports $NAME$LTO$ASLR.exe >> $NAME$LTO$ASLR.dump
- FileCheck --input-file=$NAME$LTO$ASLR.dump check-$LINKER.txt --allow-unused-prefixes --check-prefixes=$1 \
- --implicit-check-not=.dll --implicit-check-not="Symbol: {{[a-z_]*}}theweak" --implicit-check-not=DIR64
- [ -z "$RUNBIN" ] || ./$NAME$LTO$ASLR.exe
-}
-if ! uname -a | grep -E -iq 'cygwin|mingw|msys|wsl'; then
- RUNBIN=
-fi
-llc $NAME.ll -o $NAME.o --filetype=obj
-run "$@"
-[ -z "$RUNBIN" ] || ASLR=ON run "$@"
-if [ $LINKER = lld ]; then
- llvm-as $NAME.ll -o $NAME.bc
- LTO=.lto run "$@"
- [ -z "$RUNBIN" ] || LTO=.lto ASLR=ON run "$@"
-fi
-
-#--- noref.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
-declare dllimport i32 @is_overridden() nounwind
-define dso_local i32 @main() nounwind {
- %1 = call i32 @is_overridden()
- %3 = icmp ne i32 %1, u0x00
- %4 = zext i1 %3 to i32
- ; return success if not overridden
- ret i32 %4
-}
-
-#--- use.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
-declare i32 @theweak(i32) nounwind
-
-declare dllimport i32 @is_overridden() nounwind
-define dso_local i32 @main() nounwind {
- %1 = call i32 @is_overridden()
- %2 = call i32 @theweak(i32 %1)
- %3 = icmp ne i32 %2, u0x02
- %4 = zext i1 %3 to i32
- ; return success if not overridden and used fallback
- ret i32 %4
-}
-
-#--- overrider.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
-define dso_local i32 @theweak(i32 %i) nounwind {
- %1 = or i32 %i, u0x04
- ret i32 %1
-}
-define i32 @anchor(i32 %i) nounwind {
- ret i32 %i
-}
-
-#--- override-only.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
-declare i32 @theweak(i32) nounwind
-
-declare dllimport i32 @is_overridden() nounwind
-define dso_local i32 @main() nounwind {
- %1 = call i32 @is_overridden()
- %3 = icmp ne i32 %1, u0x01
- %4 = zext i1 %3 to i32
- ; return success if overridden
- ret i32 %4
-}
-
-#--- override-use.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
-declare i32 @theweak(i32) nounwind
-
-declare dllimport i32 @is_overridden() nounwind
-define dso_local i32 @main() nounwind {
- %1 = call i32 @is_overridden()
- %2 = call i32 @theweak(i32 %1)
- %3 = icmp ne i32 %2, u0x5
- %4 = zext i1 %3 to i32
- ; return success if overridden and used local obj
- ret i32 %4
-}
-
-#--- linklib-noref.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
-declare i32 @theweak(i32) nounwind
-declare i32 @anchor(i32) nounwind
-
-declare dllimport i32 @is_overridden() nounwind
-define dso_local i32 @main() nounwind {
- %1 = call i32 @is_overridden()
- %3 = icmp ne i32 %1, u0x01
- %4 = zext i1 %3 to i32
- %5 = call i32 @anchor(i32 %4)
- ; return success if overridden
- ret i32 %4
-}
-
-#--- linklib-use.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
-declare i32 @theweak(i32) nounwind
-declare i32 @anchor(i32) nounwind
-
-declare dllimport i32 @is_overridden() nounwind
-define dso_local i32 @main() nounwind {
- %1 = call i32 @is_overridden()
- %2 = call i32 @theweak(i32 %1)
- %3 = icmp ne i32 %2, u0x5
- %4 = zext i1 %3 to i32
- %5 = call i32 @anchor(i32 %4)
- ; return success if overridden and used local obj
- ret i32 %4
-}
-
-#--- linkdll-noref.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
-declare i32 @theweak(i32) nounwind
-declare i32 @anchor(i32) nounwind
-
-declare dllimport i32 @is_overridden() nounwind
-define dso_local i32 @main() nounwind {
- %1 = call i32 @is_overridden()
- %3 = icmp ne i32 %1, u0x01
- %4 = zext i1 %3 to i32
- %5 = call i32 @anchor(i32 %4)
- ; return success if overridden
- ret i32 %4
-}
-
-#--- linkdll-use.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
-declare i32 @theweak(i32) nounwind
-declare i32 @anchor(i32) nounwind
-
-declare dllimport i32 @is_overridden() nounwind
-define dso_local i32 @main() nounwind {
- %1 = call i32 @is_overridden()
- %2 = call i32 @theweak(i32 %1)
- %3 = icmp ne i32 %2, u0x9
- %4 = zext i1 %3 to i32
- %5 = call i32 @anchor(i32 %4)
- ; return success if overridden and used from dll
- ret i32 %4
-}
-
-#--- crt0-x86_64-mingw.s
- .text
- .globl _start
- .p2align 4
-_start:
- call premain
- sub $64, %rsp
- xor %r8, %r8
- movq %r8, 40(%rsp)
- lea 40(%rsp), %rdx
- mov %rdx, 48(%rsp)
- movq %r8, 56(%rsp)
- addq $8, %rdx
- mov $1, %ecx
- call main // ret = main(1, { "", nullptr });
- cmp $127, %eax
- mov $1, %edx
- cmovbe %eax, %edx // ret = (unsigned)ret >= 128 ? 1 : ret
- mov $-1, %rcx
- mov %rcx, %r10
- mov $0x2C, %eax
- syscall // ExitProcess(-1, ret)
- jmp .
-
- .section .data,"rw"
- .globl _dummy_data
-_dummy_data:
- .quad 0x1122334455667788
-
- .section .rdata,"r"
- .globl _dummy_rdata
-_dummy_rdata:
- .quad 0x1122334455667788
-
-#--- crt1.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
- at ref_theweak = dso_local global ptr @__real_theweak
-declare extern_weak i32 @__real_theweak(i32) nounwind
-
-declare dllimport void @do_override(ptr %fn) nounwind
-
-define dso_local void @premain() nounwind {
- %1 = load ptr, ptr @ref_theweak
- call void @do_override(ptr %1)
- ret void
-}
-
- at __RUNTIME_PSEUDO_RELOC_LIST__ = external dso_local constant ptr
- at __RUNTIME_PSEUDO_RELOC_LIST_END__ = external dso_local constant ptr
-
-define dso_local i32 @_pei386_runtime_relocator() {
- ret i32 trunc(i64 sub(i64 ptrtoint(ptr @__RUNTIME_PSEUDO_RELOC_LIST_END__ to i64),
- i64 ptrtoint(ptr @__RUNTIME_PSEUDO_RELOC_LIST__ to i64)) to i32)
-}
-
-#--- rtdll.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
- at fn_ptr = dso_local global ptr null
-define dllexport void @__main() nounwind {
- ret void
-}
-define dllexport void @do_override(ptr %fn) nounwind {
- %n = icmp eq ptr %fn, null
- br i1 %n, label %fin, label %do
-do:
- store ptr %fn, ptr @fn_ptr
- br label %fin
-fin:
- ret void
-}
-define dllexport i32 @is_overridden() nounwind {
- %fn = load ptr, ptr @fn_ptr
- %ne = icmp ne ptr %fn, null
- %r = zext i1 %ne to i32
- ret i32 %r
-}
-define dllexport i32 @__wrap_theweak(i32 %i) nounwind {
- %fn = load ptr, ptr @fn_ptr
- %n = icmp eq ptr %fn, null
- br i1 %n, label %eq, label %ne
-eq:
- %1 = tail call i32 @fallback(i32 %i)
- ret i32 %1
-ne:
- %2 = tail call i32 %fn(i32 %i)
- ret i32 %2
-}
-define dso_local i32 @fallback(i32 %i) nounwind {
- %1 = or i32 %i, u0x02
- ret i32 %1
-}
-
-#--- dllcrt0-x86_64-mingw.s
- .text
- .globl _start
- .p2align 4
-_start:
- call premain
- jmp dllmain
-
-#--- somedll.ll
-target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-windows-gnu"
-
-define dso_local void @dllmain() nounwind {
- ret void
-}
-define dllexport i32 @theweak(i32 %i) nounwind {
- %1 = or i32 %i, u0x08
- ret i32 %1
-}
-define dllexport i32 @anchor(i32 %i) nounwind {
- ret i32 %i
-}
>From ddbec97bd06c962eb66f8886228aa991d516f27f Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Fri, 5 Sep 2025 22:14:53 +0900
Subject: [PATCH 10/12] not to use ld.lld
---
lld/test/COFF/reloc-undefined-weak.s | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/lld/test/COFF/reloc-undefined-weak.s b/lld/test/COFF/reloc-undefined-weak.s
index 5f9baa7a3dfb0..dc0a230c37d4a 100644
--- a/lld/test/COFF/reloc-undefined-weak.s
+++ b/lld/test/COFF/reloc-undefined-weak.s
@@ -3,17 +3,17 @@
// Check that base-relocations for unresolved weak symbols will be omitted.
// RUN: rm -rf %t.dir && split-file %s %t.dir && cd %t.dir
-// RUN: llvm-mc -filetype=obj -triple=x86_64-mingw main.s -o main.o
-// RUN: llvm-mc -filetype=obj -triple=x86_64-mingw other.s -o other.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-mingw main.s -o main.obj
+// RUN: llvm-mc -filetype=obj -triple=x86_64-mingw other.s -o other.obj
-// RUN: ld.lld -m i386pep -dll -o other.dll other.o -entry= --export-all-symbols --out-implib other.dll.a
-// RUN: ld.lld -m i386pep -o main.exe main.o other.dll.a -e entry --wrap foo --verbose
+// RUN: lld-link -lldmingw -machine:x64 -dll -out:other.dll other.obj -noentry -export:foo -implib:other.lib
+// RUN: lld-link -lldmingw -machine:x64 -out:main.exe main.obj other.lib -entry:entry -wrap:foo -debug:symtab
// RUN: llvm-readobj --sections --symbols --coff-imports --coff-basereloc main.exe | FileCheck %s --implicit-check-not=other.dll
-// CHECK: Number: 4
+// CHECK: Number: 3
// CHECK-NEXT: Name: .data
// CHECK-NEXT: VirtualSize:
-// CHECK-NEXT: VirtualAddress: 0x[[#%x,SECTOP:0x4000]]
+// CHECK-NEXT: VirtualAddress: 0x[[#%x,SECTOP:0x3000]]
// CHECK: Name: ref_foo
// CHECK-NEXT: Value: [[#%d,SYMVAL:]]
// CHECK: BaseReloc [
>From 118d33098dd77b4eabfa00e8d7f66d9a8d55cf2a Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Fri, 5 Sep 2025 22:15:19 +0900
Subject: [PATCH 11/12] rewording
---
lld/test/COFF/wrap-dllimport.s | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/lld/test/COFF/wrap-dllimport.s b/lld/test/COFF/wrap-dllimport.s
index a1b4521fd75fa..a26e43b698960 100644
--- a/lld/test/COFF/wrap-dllimport.s
+++ b/lld/test/COFF/wrap-dllimport.s
@@ -1,7 +1,8 @@
// REQUIRES: x86
// Check that we can wrap a dllimported symbol, so that references to
-// __imp_<symbol> gets redirected to a symbol already exists or a defined local import instead
+// __imp_<symbol> gets redirected to a symbol that already exists or a defined
+// local import instead.
// RUN: split-file %s %t.dir
// RUN: llvm-mc -filetype=obj -triple=i686-win32-gnu %t.dir/main.s -o %t.main.obj
@@ -30,9 +31,9 @@
// which is the first 4 bytes of the .rdata section (above), which is a
// pointer that points at ___wrap_foo.
-// The second jmpl instruction in _entry points the null since the referenced symbol
-// `__imp____wrap_bar` is declared as a weak reference to prevent pull a reference
-// from an external DLL.
+// The second jmpl instruction in _entry points to null because the referenced
+// symbol `__imp____wrap_bar` is declared as a weak reference to prevent pull a
+// reference from an external DLL.
#--- main.s
.global _entry
>From 0f2c0e2c5fad4ebc9f113d68c3bfc525be92d0a6 Mon Sep 17 00:00:00 2001
From: kikairoya <kikairoya at gmail.com>
Date: Fri, 5 Sep 2025 22:13:01 +0900
Subject: [PATCH 12/12] drop "inherit weak"
---
lld/COFF/MinGW.cpp | 11 -----------
lld/test/COFF/wrap-inherit-weakness.ll | 16 ----------------
2 files changed, 27 deletions(-)
delete mode 100644 lld/test/COFF/wrap-inherit-weakness.ll
diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp
index 7c6f4281145ce..597c508115a34 100644
--- a/lld/COFF/MinGW.cpp
+++ b/lld/COFF/MinGW.cpp
@@ -233,17 +233,6 @@ void lld::coff::addWrappedSymbols(SymbolTable &symtab,
symtab.addUndefined(mangle("__wrap_" + name, symtab.machine));
v.push_back({sym, real, wrap});
- if (auto *usym = dyn_cast<Undefined>(sym)) {
- if (auto *ureal = dyn_cast<Undefined>(real);
- ureal && ureal->weakAlias && !usym->weakAlias) {
- usym->weakAlias = ureal->weakAlias;
- }
- if (auto *uwrap = dyn_cast<Undefined>(wrap);
- uwrap && usym->weakAlias && !uwrap->weakAlias) {
- uwrap->weakAlias = usym->weakAlias;
- }
- }
-
// These symbols may seem undefined initially, but don't bail out
// at symtab.reportUnresolvable() due to them, but let wrapSymbols
// below sort things out before checking finally with
diff --git a/lld/test/COFF/wrap-inherit-weakness.ll b/lld/test/COFF/wrap-inherit-weakness.ll
deleted file mode 100644
index e050e8fda37f2..0000000000000
--- a/lld/test/COFF/wrap-inherit-weakness.ll
+++ /dev/null
@@ -1,16 +0,0 @@
-; REQUIRES: x86
-
-; Check that 'weak' attribute will be inherited to the wrapped symbols.
-
-; RUN: llc %s -mtriple x86_64-mingw -o %t.o --filetype=obj
-; RUN: ld.lld -m i386pep -shared -o %t.dll %t.o --entry= --wrap fn
-
-declare extern_weak dso_local void @__real_fn() nounwind
-declare dso_local void @fn() nounwind
-declare dso_local void @__wrap_fn() nounwind
-
-define dllexport void @caller() nounwind {
- call void @__real_fn()
- call void @fn()
- ret void
-}
More information about the llvm-commits
mailing list