-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Never resolved function from blockaddress" linking xfs.ko #1215
Comments
This appears to fix all instances I found. I have no idea what is special about these two files, but I found this list experimentally. The other files in libxfs are not affected, but disabling LTO in only one of the two files is not sufficient. I also found this only happens with CONFIG_DYNAMIC_FTRACE. commit 18ed03a2163b8668553b9f63255a1697326b68ef
Author: Arnd Bergmann <arnd@arndb.de>
Date: Fri Dec 18 00:15:29 2020 +0100
xfs: work around clang lto issue
Something causes the link process to fail:
ld.lld: error: Never resolved function from blockaddress (Producer: 'LLVM11.0.1' Reader: 'LLVM 11.0.1')
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 04611a1068b4..df03efdb731e 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -12,6 +12,9 @@ obj-$(CONFIG_XFS_FS) += xfs.o
# this one should be compiled first, as the tracing macros can easily blow up
xfs-y += xfs_trace.o
+CFLAGS_REMOVE_libxfs/xfs_bmap.o += $(CC_FLAGS_LTO)
+CFLAGS_REMOVE_libxfs/xfs_inode_fork.o += $(CC_FLAGS_LTO)
+
# build the libxfs code first
xfs-y += $(addprefix libxfs/, \
xfs_ag.o \ |
The define internal fastcc void @trace_xfs_read_extent(...
...
29: ; preds = %20
%30 = inttoptr i64 %27 to %struct.tracepoint_func*
%31 = getelementptr inbounds %struct.tracepoint_func, %struct.tracepoint_func* %30, i64 0, i32 1
%32 = load i8*, i8** %31, align 8
%33 = call i32 @__traceiter_xfs_read_extent(i8* %32, %struct.xfs_inode* %0, %struct.xfs_iext_cursor* %1, i32 %2, i64 ptrtoint (i8* blockaddress(@xfs_iread_bmbt_block, %73) to i64)) #11
br label %34 Note |
This is one thing I've always disliked (or perhaps simply misunderstood) about LLVM's |
I wasn't able to reproduce with the following configs:
@arndb was this with thin LTO or full lto? Can you post the config if it's still reproducible? Non-reproducible with full LTO either, though I did get:
|
I can reproduce this with full LTO at least:
|
I was able to repro this just now building ARCH=i386 allmodconfig built with full LTO while testing this. I had to disable FTRACE, COMPILE_TEST, and GCOV.
|
I gave this a shot today, but wasn't able to repro with ToT LLVM (~clang-13) for aarch64+full LTO (or thin LTO) + XFS_FS. Strange. |
on i386, it's define internal fastcc void @trace_xfs_read_extent(
...
%call43 = call i32 @__SCT__tp_func_xfs_read_extent(i8* inreg %7, %struct.xfs_inode* inreg %ip, %struct.xfs_iext_cursor* inreg %cur, i32 %state, i32 ptrtoint (i8* blockaddress(@xfs_iformat_extents, %for.inc) to i32)) #8 (so it's a
I extended LLVM to scan the functions defined in the module when the "Never resolved function from blockaddress" error occurs, and I suspect there's a pass running during LTO which deletes what looks like dead functions without checking whether the function's address is taken via I think we can rerun the lld invocation with $ ld.lld -m elf_i386 -mllvm -import-instr-limit=5 -o fs/xfs/xfs.lto.o --whole-archive fs/xfs/xfs.o -mllvm -print-after-all 2> log.txt but grepping that for $ llvm-nm fs/xfs/xfs.o
...
libxfs/xfs_inode_fork.o:
...
-------- t xfs_iformat_extents Super weird that ld.lld -m elf_i386 -mllvm -import-instr-limit=5 -o fs/xfs/xfs.lto.o --whole-archive fs/xfs/xfs.o -mllvm -print-after-all 2>&1 |grep xfs_iext_state_to_fork
...
define internal %struct.xfs_ifork* @xfs_iext_state_to_fork(%struct.xfs_inode* inreg %0, i32 inreg %1) #0 align 64 {
...
define internal %struct.xfs_ifork* @xfs_iext_state_to_fork(%struct.xfs_inode* inreg %0, i32 inreg %1) #0 align 64 {
... and yet ld.lld -m elf_i386 -mllvm -import-instr-limit=5 -o fs/xfs/xfs.lto.o --whole-archive fs/xfs/xfs.o -mllvm -print-after-all 2>&1 |grep xfs_iformat_extents |
I'm reading through how LLVM performs LTO; I don't have the smoking gun yet, but it seems it does "summary-based DCE" where summary is referring to either |
also, it looks like this is possible related to diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 1d174909f9bd..198aee12cb3a 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -145,7 +145,7 @@ xfs_iformat_extents(
}
xfs_iext_insert(ip, &icur, &new, state);
- trace_xfs_read_extent(ip, &icur, state, _THIS_IP_);
+ /*trace_xfs_read_extent(ip, &icur, state, _THIS_IP_);*/
xfs_iext_next(ifp, &icur);
}
} builds. It looks like IPSCCP is sinking |
Hi, I'm trying to enable LTO for RISC-V, and can reproduce this issue. I used
or this:
Command used: |
amd64 in Linux 5.15.5 also produces this error by the script in #1516 |
I reduced down
It does not reproduce without |
I took a look at this bug for fun. Here's a hand-minimized repro: void f(long);
__attribute__((noinline)) static void fun(long x) {
f(x + 1);
}
void repro(void) {
fun(({
label:
(long)&&label;
}));
} $ clang -O2 -flto -c repro.c -o repro.i Relevant part of the LLVM IR, generated with: ...
define dso_local void @repro() #0 {
entry:
br label %label
label: ; preds = %entry
tail call fastcc void @fun()
ret void
}
define internal fastcc void @fun() unnamed_addr #1 {
entry:
tail call void @f(i64 add (i64 ptrtoint (i8* blockaddress(@repro, %label) to i64), i64 1)) #3
ret void
}
... We can see clang figured out that the first argument to Searching LLVM code for the source of the error message gives The code has some special handling of blockaddress IR constants, as a blockaddress that appears within a function F may reference a basic block from a different function G (as is the case in the IR for the bug repro). When materializing a function with a If After adding some debug prints, it appears that lld's use of BitcodeReader breaks this lazy blockaddress handling. In the repro case, the linker does materialize This causes the This looks like a fairly old bug in lld. Fixing it looks tricky - it seems that BitcodeReader requires that materialized Functions aren't modified while there are still functions that will be materialized later, and lld violates that assumption. Maintaining this invariant seems like it might conflict with the goal of lazy reading. Maybe one idea is to maintain some reverse dependency information in bitcode files. Then materializing a function F could trigger immediate materialization of all functions with a blockaddress pointing into F. |
It seems that there is progress on this issue from the LLVM side. Great to see! In the meantime for those experimenting with CLANG LTO kernels in dev/profiling environments, it's worth mentioning that disabling the XFS file system will allow you to build as normal as a temporary workaround, assuming you don't need XFS. I was able to build against 5.16.2 with 13.0.1-+rc1-1~exp4 and additional KFLAGS: Next when time permits I will be attempting to build with clang 14 followed by the ICX compiler, also LLVM based. This may help us track down these issues. |
This is fixed now in clang-15. I've requested a backport to clang-14.0.1 (we'll see if that request is accepted or not). I think we still might want to disable XFS for LTO (or rather disable LTO on XFS) at least for older llvm versions? Maybe @arndb 's patch with a version check added, once we know whether 14.0.1 will also get the fix? |
IRLinker builds a work list of functions to materialize, then moves them from a source module to a destination module one at a time. This is a problem for blockaddress Constants, since they need not refer to the function they are used in; IPSCCP is quite good at sinking these constants deep into other functions when passed as arguments. This would lead to curious errors during LTO: ld.lld: error: Never resolved function from blockaddress ... based on the ordering of function definitions in IR. The problem was that IRLinker would basically do: for function f in worklist: materialize f splice f from source module to destination module in one pass, with Functions being lazily added to the running worklist. This confuses BitcodeReader, which cannot disambiguate whether a blockaddress is referring to a function which has not yet been parsed ("materialized") or is simply empty because its body was spliced out. This causes BitcodeReader to insert Functions into its BasicBlockFwdRefs list incorrectly, as it will never re-materialize an already materialized (but spliced out) function. Because of the possibility that blockaddress Constants may appear in Functions other than the ones they reference, this patch adds a new bitcode function code FUNC_CODE_BLOCKADDR_USERS that is a simple list of Functions that contain BlockAddress Constants that refer back to this Function, rather then the Function they are scoped in. We then materialize those functions when materializing `f` from the example loop above. This might over-materialize Functions should the user of BitcodeReader ultimately decide not to link those Functions, but we can at least now we can avoid this ordering related issue with blockaddresses. Fixes: llvm#52787 Fixes: ClangBuiltLinux/linux#1215 Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D120781 (cherry picked from commit 23ec578)
I would rather see something along the lines of: diff --git a/arch/Kconfig b/arch/Kconfig
index 3e35c5523fe4..8d4a92b71516 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -690,6 +690,7 @@ config LTO_NONE
config LTO_CLANG_FULL
bool "Clang Full LTO (EXPERIMENTAL)"
depends on HAS_LTO_CLANG
+ depends on CLANG_VERSION >= 140001
depends on !COMPILE_TEST
select LTO_CLANG
help as it better addresses the issue. XFS was not the only driver to trigger this (#1516) so adding something there feels wrong. We can talk about that once the backport request is addressed. |
It sounds like the backport request was rejected. Do we want to try to add a denylist of configs plus a version check or just the version check to |
Let's update the CLANG_VERSION for full LTO, once clang-15 is generally available in distributions? |
Sure, although that will likely be quite a while, given that LLVM 15.0.0 has to first be released. We can consider doing it sooner if we receive new reports about this issue. |
IRLinker builds a work list of functions to materialize, then moves them from a source module to a destination module one at a time. This is a problem for blockaddress Constants, since they need not refer to the function they are used in; IPSCCP is quite good at sinking these constants deep into other functions when passed as arguments. This would lead to curious errors during LTO: ld.lld: error: Never resolved function from blockaddress ... based on the ordering of function definitions in IR. The problem was that IRLinker would basically do: for function f in worklist: materialize f splice f from source module to destination module in one pass, with Functions being lazily added to the running worklist. This confuses BitcodeReader, which cannot disambiguate whether a blockaddress is referring to a function which has not yet been parsed ("materialized") or is simply empty because its body was spliced out. This causes BitcodeReader to insert Functions into its BasicBlockFwdRefs list incorrectly, as it will never re-materialize an already materialized (but spliced out) function. Because of the possibility that blockaddress Constants may appear in Functions other than the ones they reference, this patch adds a new bitcode function code FUNC_CODE_BLOCKADDR_USERS that is a simple list of Functions that contain BlockAddress Constants that refer back to this Function, rather then the Function they are scoped in. We then materialize those functions when materializing `f` from the example loop above. This might over-materialize Functions should the user of BitcodeReader ultimately decide not to link those Functions, but we can at least now we can avoid this ordering related issue with blockaddresses. Fixes: llvm/llvm-project#52787 Fixes: ClangBuiltLinux/linux#1215 Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D120781
Building randconfig arm64 kernels occasionally results in this error with LTO:
$ ld.lld -EL -maarch64elf -mllvm -import-instr-limit=5 -r -o xfs.lto.o --whole-archive xfs.o
ld.lld: error: Never resolved function from blockaddress (Producer: 'LLVM11.0.1' Reader: 'LLVM 11.0.1')
It turns out that this only happens in configurations that include xfs, but it also does happen for xfs as a loadable module, which makes it much easier to reproduce.
The attached archive contains a copy of the object files that go into an affected xfs.ko kernel module, with a oneline script for reproducing the problem.
xfs-lld-never-resolved-function.tar.gz
https://lore.kernel.org/lkml/CAK8P3a1Xfpt7QLkvxjtXKcgzcWkS8g9bmxD687+rqjTafTzKrg@mail.gmail.com/
The text was updated successfully, but these errors were encountered: