如何修复构建Linux内核时发生的链接错误?

时间:2017-10-14 21:47:57

标签: c linux linux-kernel linker-errors

我试图在Ubuntu 16.04 LTS中编译内核版本4.4。我添加或修改了一些代码,将块I / O层中写入块的块号存储到自定义缓冲区中。

我修改了代码[linux-kernel-location] /block/blk-core.c (original)

...
#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 (original)

...
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内核-位置] /块/自定义/生成文件:

obj-y += custom-buffer.o

[Linux内核-位置] /块/定制/的Kconfig:

config CUSTOM_BUFFER
    tristate
    depends on BLOCK
    default y

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

我在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信函错误。我正确地修复它以便编译好。

找到拼写错误太难了......

1 个答案:

答案 0 :(得分:1)

是的,很难找到拼写错误。但编译器试图向我们展示打字错误的位置。

我试图重现您的问题,以撰写可能有助于其他人访问此问题的答案。

首先,如果您在文件名中输入错误会发生什么?让我们说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。 来自documentation

  

最简单的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”将这些文件合并到一个内置的.o文件中。         build-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。那么为什么我们有未定义的参考?好吧,我们可以使用block/build-in.o

调查objdump -t block/built-in.o | grep custom中的符号
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