当构建Linux内核时出现链接错误,我该如何修复?

4
我正在尝试在Ubuntu 16.04 LTS中编译4.4内核版本。我添加或修改了一些代码,将写入块的块号存储到自定义缓冲区的块I / O层中。
我修改了[linux-kernel-location]/block/blk-core.c(原始)的代码:
...
#include <custom/custom-buffer.h>
...
blk_qt_t submit_bio(int rw, struct bio *bio)
{
    ...
    if(rw & WRITE)
    {
        unsigned long cntUnit = bio->bi_bdev->bd_super->s_blocks / bdev_logical_block_size(bio->bi_bdev);
        unsigned long blk_no = bio->bi_iter.bi_sector / cntUnit;

        count_vm_events(PGPGOUT, count);

        custom_buf_write_blk_no(blk_no);
    }
    ...
}
...

[linux-kernel-location]/block/Makefile (原链接):

请确认以上内容是否正确,谢谢!
...
obj-y += custom/

[linux-kernel-location]/block/Kconfig (original):

...
source "block/custom/Kconfig"

我创建了目录[linux-kernel-location]/include/custom, [linux-kernel-location]/block/custom。接着,我创建了文件[linux-kernel-location]/include/custom/custom-buffer.h:

#ifndef _CUSTOM_BUFFER_H_
#define _CUSTOM_BUFFER_H_

extern int custom_buf_write_blk_no(unsigned long blk_no);

#endif

[linux-kernel-location]/block/custom/Makefile: (该文件路径)
obj-y += custom-buffer.o

[linux-kernel-location]/block/custom/Kconfig:

config CUSTOM_BUFFER
    tristate
    depends on BLOCK
    default y

[linux-kernel-location]/block/custom/custom-buffer.c(包括使用EXPORT_SYMBOL宏定义的custom_buf_write_blk_no(unsigned long blk_no))。

我在Linux内核位置的shell中输入了make命令,得到了以下结果:

...
LD    init/built-in.o
block/built-in.o: In function `submit_bio':
[linux-kernel-location]/block/blk-core.c:2117: undefined reference to `custom_buf_write_blk_no'
block/built-in.o:(___ksymtab+custom_buf_write_blk_no+0x0): undefined reference to `custom_buf_write_blk_no'
Makefile:927: recipe for target 'vmlinux' failed
make: *** [vmlinux] Error 1

我的猜测是我需要修复Makefile,如何修复?
编辑:我也知道这是因为链接器在链接过程中找不到符号。但我不知道如何在Kbuild系统应用的Makefile中修复它。
自己解决:custom-buffer.c有一个错误的字母。我正确修复了它,所以编译成功了。
找错别字太难了...

@KenWhite 我也知道这是由于链接器找不到符号而导致的。但我不知道如何修复 Kbuild 系统中的 Makefile。 - monadef
顺便提一下,SystemTap 可以在不重新编译内核的情况下捕获块号。 - myaut
@myaut 这是为了理解在nilfs2中写入时的行为模式。我需要在写入过程中的目标块编号以及请求写入该块时的时间值。 - monadef
@JakubPiskorz 是的。在步骤 CC block/custom/custom-buffer.oLD block/custom/built-in.oLD block/built-in.o 中,没有发生任何事情。但是在下一步 LD init/built-in.o 中出现了一个错误。 - monadef
@monadef 在你的设置中一定有些不寻常的地方,我刚刚克隆了4.4内核源代码 git clone --depth 1 --single-branch --branch v4.4 git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git,添加了你描述的完全相同的文件。使用虚拟实现: int custom_buf_write_blk_no(unsigned long blk_no) { printk(KERN_INFO "WIP NUMBER %lu\n", blk_no); return 0; } EXPORT_SYMBOL(custom_buf_write_blk_no);。它可以编译。 - Jakub Piskorz
显示剩余3条评论
1个回答

4

是的,很难发现拼写错误。但是编译器会试图向我们展示出错的位置。

我尝试重现您的问题,以撰写一篇可以帮助其他访问此问题的人的答案。

首先,如果您在文件名中拼写有误会发生什么?比如说 custom/custom-buffe.c

内核构建系统会抱怨:

CHK     include/generated/compile.h
make[2]: *** No rule to make target 'block/custom/custom-buffer.o', needed by 'block/custom/built-in.o'.  Stop.
scripts/Makefile.build:403: recipe for target 'block/custom' failed
make[1]: *** [block/custom] Error 2
Makefile:943: recipe for target 'block' failed
make: *** [block] Error 2

因此,很明显,构建规则正在查找创建custom-buffer.o的文件,但是它丢失了。默认情况下,应该有custom-buffer.c。 来自文档

最简单的kbuild makefile只包含一行:

例如: obj-y += foo.o

这告诉kbuild在该目录中存在一个对象,名为foo.o。foo.o将从foo.c或foo.S构建。

这不是您的情况。所以,我在函数定义中犯了一个错(buff vs buf):
int custom_buff_write_blk_no(unsigned long blk_no) {
  printk(KERN_INFO "WIP NUMBER %lu\n", blk_no);
  return 0;
}
EXPORT_SYMBOL(custom_buff_write_blk_no);

现在,在构建后,我从编译器得到了信息:

LD      init/built-in.o
block/built-in.o: In function `submit_bio':
(.text+0x8bb0): undefined reference to `custom_buf_write_blk_no'
Makefile:929: recipe for target 'vmlinux' failed
make: *** [vmlinux] Error 1

我们可以通过执行make V=1命令来追踪LD步骤的具体操作:
+ ld -m elf_x86_64 --build-id -o .tmp_vmlinux1 -T ./arch/x86/kernel/vmlinux.lds arch/x86/kernel/head_64.o arch/x86/kernel/head64.o arch/x86/kernel/head.o init/built-in.o --start-gr
oup usr/built-in.o arch/x86/built-in.o kernel/built-in.o certs/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o lib/lib.
a arch/x86/lib/lib.a lib/built-in.o arch/x86/lib/built-in.o drivers/built-in.o sound/built-in.o firmware/built-in.o arch/x86/pci/built-in.o arch/x86/power/built-in.o arch/x86/video
/built-in.o arch/x86/ras/built-in.o net/built-in.o virt/built-in.o --end-group
block/built-in.o: In function `submit_bio':
(.text+0x8bb0): undefined reference to `custom_buf_write_blk_no'

首先,我们认为一切都是正确的,我们的custom_buf_write_blk_no符号应该在文件block/custom/build-in.o中。但是,在这里我们没有看到这个文件。但是,Kbuild系统会递归地将所有对象合并到一个build-in.o文件中:

Kbuild编译所有$(obj-y)文件。然后调用“$(LD) -r”将这些文件合并成一个内置的built-in.o文件。built-in.o稍后由父Makefile链接到vmlinux中。

所以它应该在block/build-in.o中。为了确保,我们可以通过调查make V=1输出来跟踪它:
...
ld -m elf_x86_64   -r -o block/custom/built-in.o block/custom/custom-buffer.o
...
ld -m elf_x86_64   -r -o block/built-in.o block/bio.o block/elevator.o block/blk-core.o block/blk-tag.o block/blk-sysfs.o block/blk-flush.o block/blk-settings.o block/blk-ioc.o 
block/blk-map.o block/blk-exec.o block/blk-merge.o block/blk-softirq.o block/blk-timeout.o block/blk-iopoll.o block/blk-lib.o block/blk-mq.o block/blk-mq-tag.o block/blk-mq-sysfs.o
block/blk-mq-cpu.o block/blk-mq-cpumap.o block/ioctl.o block/genhd.o block/scsi_ioctl.o block/partition-generic.o block/ioprio.o block/partitions/built-in.o block/bounce.o block/b
sg.o block/noop-iosched.o block/deadline-iosched.o block/cfq-iosched.o block/compat_ioctl.o block/custom/built-in.o 

确实,我们有自定义缓冲区custom-buffer.o。那么为什么会出现未定义的引用呢?好的,我们可以通过使用objdump -t block/built-in.o | grep custom来调查在block/build-in.o中的符号:

0000000000000000 l    d  ___ksymtab+custom_buff_write_blk_no    0000000000000000 ___ksymtab+custom_buff_write_blk_no
0000000000000000 l    df *ABS*  0000000000000000 custom-buffer.c
000000000000132e l     O __ksymtab_strings      0000000000000019 __kstrtab_custom_buff_write_blk_no
0000000000000000         *UND*  0000000000000000 custom_buf_write_blk_no
0000000000000000 g     O ___ksymtab+custom_buff_write_blk_no    0000000000000010 __ksymtab_custom_buff_write_blk_no
0000000000025ed0 g     F .text  0000000000000017 custom_buff_write_blk_no

现在我们看到符号custom_buff_write_blk_no,编译器抱怨他正在寻找custom_buf_write_blk_no

我必须这样做!我没想到我会使用 objdump……你已经完美地复制了它!你是第一个给我写出如此易懂答案的人! - monadef

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接