Skip to content
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

lld discards sections that start with ".gnu.linkonce." preventing kernel modules from being loaded #329

Closed
nickdesaulniers opened this issue Jan 26, 2019 · 7 comments
Assignees
Labels
[BUG] llvm A bug that should be fixed in upstream LLVM [FIXED][LLVM] 8 This bug was fixed in LLVM 8.0 [TOOL] lld The issue is relevant to LLD linker

Comments

@nickdesaulniers
Copy link
Member

nickdesaulniers commented Jan 26, 2019

Filing a copy of this internal bug I stumbled upon yesterday at work, so that it's visible for others looking to use LLD:

Hmmm...looks like there's a problem loading kernel modules.

redacted:/data/local/tmp # insmod redacted.ko                                  
insmod: failed to load redacted.ko: Exec format error
1|redacted:/data/local/tmp # dmesg | tail -n 1                                           
[  265.108479] redacted: No module found in object

I'll probably need to dig into how the kernel load modules to see what's going wrong.

kernel/module.c:

             info->index.mod = find_sec(info, ".gnu.linkonce.this_module");          
             if (!info->index.mod) {                                                 
                     pr_warn("%s: No module found in object\n",                      
                             info->name ?: "(missing .modinfo name field)");

__this_module is a D (public data) symbol with bfd but U (undefined reference) with lld.
.gnu.linkonce.this_module is listed as a section with readelf with bfd, but is missing with lld.

readelf bfd:
    47: 0000000000000000   896 OBJECT  GLOBAL DEFAULT   21 __this_module
readelf lld:
    57: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  UND __this_module

Now to see if lld is accidentally or intentionally omitting this data/symbol/section, or if the linker script is malformed.

https://reviews.llvm.org/D28430 looks like it might be problematic. Looks like it purposely discards any section name that starts with ".gnu.linkonce.". Seems like that code is still in lld.

May I present, my most significant contribution to mankind to date:

diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 9a6c3487c173..c8f05f297d5b 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -735,7 +735,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
   // sections. Drop those sections to avoid duplicate symbol errors.
   // FIXME: This is glibc PR20543, we should remove this hack once that has been
   // fixed for a while.
-  if (Name.startswith(".gnu.linkonce."))
+  if (Name.startswith(".gnu.linkonce.t."))
     return &InputSection::Discarded;
 
   // If we are creating a new .build-id section, strip existing .build-id

https://sourceware.org/bugzilla/show_bug.cgi?id=20543

Will post patch to phabricator upstream Monday, assuming I can figure out arcanist+the new github monorepo (and remember my svn password, if those are still in use).

@nickdesaulniers nickdesaulniers added [BUG] llvm A bug that should be fixed in upstream LLVM [PATCH] Exists There is a patch that fixes this issue [TOOL] lld The issue is relevant to LLD linker labels Jan 26, 2019
@nickdesaulniers nickdesaulniers self-assigned this Jan 26, 2019
@nickdesaulniers
Copy link
Member Author

@nickdesaulniers nickdesaulniers added [PATCH] Submitted A patch has been submitted for review and removed [PATCH] Exists There is a patch that fixes this issue labels Jan 26, 2019
@nickdesaulniers
Copy link
Member Author

Fixed: https://reviews.llvm.org/rL352302

Need to request it gets cherry picked into the lld-8 release.

@nickdesaulniers nickdesaulniers added [PATCH] Accepted A submitted patch has been accepted upstream and removed [PATCH] Submitted A patch has been submitted for review labels Jan 27, 2019
@nickdesaulniers
Copy link
Member Author

nickdesaulniers commented Jan 27, 2019

https://llvm.org/pr40485

@nickdesaulniers nickdesaulniers added the [FIXED][LLVM] 9 This bug was fixed in LLVM 9.0 label Jan 27, 2019
dtzWill pushed a commit to llvm-mirror/lld that referenced this issue Jan 28, 2019
Redirecting to URL 'https://llvm.org/svn/llvm-project/lld/trunk':
------------------------------------------------------------------------
r352302 | nickdesaulniers | 2019-01-27 03:54:23 +0100 (Sun, 27 Jan 2019) | 33 lines

lld: elf: discard more specific .gnu.linkonce section

Summary:
lld discards .gnu.linonce.* sections work around a bug in glibc.
https://sourceware.org/bugzilla/show_bug.cgi?id=20543

Unfortunately, the Linux kernel uses a section named
.gnu.linkonce.this_module to store infomation about kernel modules. The
kernel reads data from this section when loading kernel modules, and
errors if it fails to find this section. The current behavior of lld
discards this section when kernel modules are linked, so kernel modules
linked with lld are unloadable by the linux kernel.

The Linux kernel should use a comdat section instead of .gnu.linkonce.
The minimum version of binutils supported by the kernel supports comdat
sections. The kernel is also not relying on the old linkonce behavior;
it seems to have chosen a name that contains a deprecated GNU feature.

Changing the section name now in the kernel would require all kernel
modules to be recompiled to make use of the new section name. Instead,
rather than discarding .gnu.linkonce.*, let's discard the more specific
section name to continue working around the glibc issue while supporting
linking Linux kernel modules.

Link: ClangBuiltLinux/linux#329

Reviewers: pcc, espindola

Reviewed By: pcc

Subscribers: nathanchance, emaste, arichardson, void, srhines

Differential Revision: https://reviews.llvm.org/D57294
------------------------------------------------------------------------


git-svn-id: https://llvm.org/svn/llvm-project/lld/branches/release_80@352355 91177308-0d34-0410-b5e6-96231b3b80d8
llvm-git-migration pushed a commit to llvm/llvm-project that referenced this issue Jan 28, 2019
Redirecting to URL 'https://llvm.org/svn/llvm-project/lld/trunk':
------------------------------------------------------------------------
r352302 | nickdesaulniers | 2019-01-27 03:54:23 +0100 (Sun, 27 Jan 2019) | 33 lines

lld: elf: discard more specific .gnu.linkonce section

Summary:
lld discards .gnu.linonce.* sections work around a bug in glibc.
https://sourceware.org/bugzilla/show_bug.cgi?id=20543

Unfortunately, the Linux kernel uses a section named
.gnu.linkonce.this_module to store infomation about kernel modules. The
kernel reads data from this section when loading kernel modules, and
errors if it fails to find this section. The current behavior of lld
discards this section when kernel modules are linked, so kernel modules
linked with lld are unloadable by the linux kernel.

The Linux kernel should use a comdat section instead of .gnu.linkonce.
The minimum version of binutils supported by the kernel supports comdat
sections. The kernel is also not relying on the old linkonce behavior;
it seems to have chosen a name that contains a deprecated GNU feature.

Changing the section name now in the kernel would require all kernel
modules to be recompiled to make use of the new section name. Instead,
rather than discarding .gnu.linkonce.*, let's discard the more specific
section name to continue working around the glibc issue while supporting
linking Linux kernel modules.

Link: ClangBuiltLinux/linux#329

Reviewers: pcc, espindola

Reviewed By: pcc

Subscribers: nathanchance, emaste, arichardson, void, srhines

Differential Revision: https://reviews.llvm.org/D57294
------------------------------------------------------------------------

llvm-svn: 352355
llvm-git-migration pushed a commit to llvm/llvm-project that referenced this issue Jan 28, 2019
Summary:
lld discards .gnu.linonce.* sections work around a bug in glibc.
https://sourceware.org/bugzilla/show_bug.cgi?id=20543

Unfortunately, the Linux kernel uses a section named
.gnu.linkonce.this_module to store infomation about kernel modules. The
kernel reads data from this section when loading kernel modules, and
errors if it fails to find this section. The current behavior of lld
discards this section when kernel modules are linked, so kernel modules
linked with lld are unloadable by the linux kernel.

The Linux kernel should use a comdat section instead of .gnu.linkonce.
The minimum version of binutils supported by the kernel supports comdat
sections. The kernel is also not relying on the old linkonce behavior;
it seems to have chosen a name that contains a deprecated GNU feature.

Changing the section name now in the kernel would require all kernel
modules to be recompiled to make use of the new section name. Instead,
rather than discarding .gnu.linkonce.*, let's discard the more specific
section name to continue working around the glibc issue while supporting
linking Linux kernel modules.

Link: ClangBuiltLinux/linux#329

Reviewers: pcc, espindola

Reviewed By: pcc

Subscribers: nathanchance, emaste, arichardson, void, srhines

Differential Revision: https://reviews.llvm.org/D57294

llvm-svn: 352302
@shenki
Copy link
Member

shenki commented Jan 29, 2019

The Linux kernel should use a comdat section instead of .gnu.linkonce.
The minimum version of binutils supported by the kernel supports comdat
sections. The kernel is also not relying on the old linkonce behavior;
it seems to have chosen a name that contains a deprecated GNU feature.

Have we brought this up with the kernel maintainers?

We can fix the module section name issue with something like this:

diff --git a/kernel/module.c b/kernel/module.c
index 2ad1b5239910..5cef8e0bbc75 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2978,7 +2978,7 @@ static int setup_load_info(struct load_info *info, int flags)
                return -ENOEXEC;
        }
 
-       info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
+       info->index.mod = find_sec(info, ".data.this_module");
        if (!info->index.mod) {
                pr_warn("%s: No module found in object\n",
                        info->name ?: "(missing .modinfo name field)");
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 26bf886bd168..8964eb8e6d0a 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -2164,7 +2164,7 @@ static void add_header(struct buffer *b, struct module *mod)
        buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
        buf_printf(b, "\n");
        buf_printf(b, "__visible struct module __this_module\n");
-       buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
+       buf_printf(b, "__attribute__((section(\".data.this_module\"))) = {\n");
        buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
        if (mod->has_init)
                buf_printf(b, "\t.init = init_module,\n");

I happen to share an office with the author of the module loader and they said: this is the reason the module loader is in the kernel, so we can make arbitrary changes and not worry about an external tool depending on them. You're right that it was just an arbitrary string, however it does follow the semantics of linkonce (each module needs one of these descriptions, but only one of them).

I did some more digging and I wasn't sure where you read that the linkonce section was deprecated?

Secondly, a grep for .gnu.linkonce shows that most arches use this in their vdso linker scripts, so the vdso might have been broken with clang in addition to modules.

$ git grep -l gnu.linkonce
arch/arc/kernel/vmlinux.lds.S
arch/arm/vdso/vdso.lds.S
arch/arm64/kernel/vdso/vdso.lds.S
arch/c6x/kernel/vmlinux.lds.S
arch/ia64/hp/sim/boot/bootloader.lds
arch/ia64/kernel/gate.lds.S
arch/ia64/kernel/vmlinux.lds.S
arch/mips/vdso/vdso.lds.S
arch/nds32/kernel/vdso/vdso.lds.S
arch/powerpc/kernel/vdso32/vdso32.lds.S
arch/powerpc/kernel/vdso64/vdso64.lds.S
arch/riscv/kernel/vdso/vdso.lds.S
arch/s390/kernel/vdso32/vdso32.lds.S
arch/s390/kernel/vdso64/vdso64.lds.S
arch/sh/kernel/vsyscall/vsyscall.lds.S
arch/sparc/vdso/vdso-layout.lds.S
arch/um/kernel/dyn.lds.S
arch/um/kernel/uml.lds.S
arch/x86/entry/vdso/vdso-layout.lds.S
arch/x86/um/vdso/vdso-layout.lds.S
arch/xtensa/kernel/vmlinux.lds.S
include/asm-generic/vmlinux.lds.h
kernel/module.c
scripts/mod/modpost.c
tools/perf/util/probe-event.c

@nickdesaulniers
Copy link
Member Author

I did some more digging and I wasn't sure where you read that the linkonce section was deprecated?

Most of that wording is from pcc, who does a lot of work on LLD. I start an email thread with all of us.

@nickdesaulniers
Copy link
Member Author

Secondly, a grep for .gnu.linkonce shows that most arches use this in their vdso linker scripts, so the vdso might have been broken with clang in addition to modules.

Oh! Thank you for pointing this out. How can you check from userspace that this exists correctly? Doesn't it show up under /proc//maps IIRC?

@nickdesaulniers nickdesaulniers added [FIXED][LLVM] 8 This bug was fixed in LLVM 8.0 and removed [FIXED][LLVM] 9 This bug was fixed in LLVM 9.0 labels Jan 29, 2019
@nickdesaulniers
Copy link
Member Author

Fixed in lld-9, but the patch was cherry picked to the lld-8 release branch (so will be available in lld-8).

vutung2311 added a commit to vutung2311/starlte that referenced this issue Feb 12, 2019
@tpimh tpimh removed the [PATCH] Accepted A submitted patch has been accepted upstream label Feb 25, 2019
ajohnson-uoregon pushed a commit to ajohnson-uoregon/clang-rewrite-only that referenced this issue Jul 17, 2022
Redirecting to URL 'https://llvm.org/svn/llvm-project/lld/trunk':
------------------------------------------------------------------------
r352302 | nickdesaulniers | 2019-01-27 03:54:23 +0100 (Sun, 27 Jan 2019) | 33 lines

lld: elf: discard more specific .gnu.linkonce section

Summary:
lld discards .gnu.linonce.* sections work around a bug in glibc.
https://sourceware.org/bugzilla/show_bug.cgi?id=20543

Unfortunately, the Linux kernel uses a section named
.gnu.linkonce.this_module to store infomation about kernel modules. The
kernel reads data from this section when loading kernel modules, and
errors if it fails to find this section. The current behavior of lld
discards this section when kernel modules are linked, so kernel modules
linked with lld are unloadable by the linux kernel.

The Linux kernel should use a comdat section instead of .gnu.linkonce.
The minimum version of binutils supported by the kernel supports comdat
sections. The kernel is also not relying on the old linkonce behavior;
it seems to have chosen a name that contains a deprecated GNU feature.

Changing the section name now in the kernel would require all kernel
modules to be recompiled to make use of the new section name. Instead,
rather than discarding .gnu.linkonce.*, let's discard the more specific
section name to continue working around the glibc issue while supporting
linking Linux kernel modules.

Link: ClangBuiltLinux/linux#329

Reviewers: pcc, espindola

Reviewed By: pcc

Subscribers: nathanchance, emaste, arichardson, void, srhines

Differential Revision: https://reviews.llvm.org/D57294
------------------------------------------------------------------------

llvm-svn: 352355
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[BUG] llvm A bug that should be fixed in upstream LLVM [FIXED][LLVM] 8 This bug was fixed in LLVM 8.0 [TOOL] lld The issue is relevant to LLD linker
Projects
None yet
Development

No branches or pull requests

3 participants