泪流满面,WARNING: modpost: Found 1 section mismatch(es).

看来编译时出现警告要非常重视,一定要对警告的意义非常清楚,这极可能是出现BUG的原因。

昨天调了一整个晚上,各种离奇的出错~~

其实编译内核模块时,已经提示我警告了,但我一直没注意:

  Building modules, stage 2.
  MODPOST 1 modules
WARNING: modpost: Found 1 section mismatch(es).
To see full details build your kernel with:
'make CONFIG_DEBUG_SECTION_MISMATCH=y'
  CC      /home/zausiu/linux-3.0.66/mm/sksm/sksm.mod.o
  LD [M]  /home/zausiu/linux-3.0.66/mm/sksm/sksm.ko

警告告诉我使用 'make CONFIG_DEBUG_SECTION_MISMATCH=y'

我以为要编译整棵kenel sourcecode tree时打开DEBUG_SECTION_MISMATCH编译选项,在我的虚机里编译一次要几个小时啊,果断拒绝了。其实在内核代码树外单独编译内核模块时也只用DEBUG_SECTION_MISMATCH=y这个选项。

# make DEBUG_SECTION_MISMATCH=y

  Building modules, stage 2.
  MODPOST 1 modules
WARNING: /home/zausiu/linux-3.0.66/mm/sksm/sksm.o(.init.text+0x193): Section mismatch in reference from the function init_module() to the function .exit.text:sksm_slab_free()
The function __init init_module() references
a function __exit sksm_slab_free().
This is often seen when error handling in the init function
uses functionality in the exit path.
The fix is often to remove the __exit annotation of
sksm_slab_free() so it may be used outside an exit section.

至此,真相大白于天下~~ .init段的函数内调用了 .exist段的函数,把被调用函数去掉__exit指示即可!

//////////

至此,当出现离奇错误时。要高度重视编译时的警告,另外一个就是极有可能是因为竞争条件,还有个是栈溢出。

GCC内联汇编写的memcmp函数 for x86-64

今天写内核代码时要写一个比较两个页框(Page Frame)的函数,想到用内联汇编来写这个功能。下面是代码:

long cmp_x64(void *s1, void *s2, size_t n)
{
    size_t num = n / 8;
    register long res;

    __asm__ __volatile__
    (
     "testq %3,%3\n\t"               ; 测试num是不是0
     "repe  cmpsq\n\t"                ; 不停地比较直到cx寄存器为0或比较到差别
     "je        1f\n\t"              ; 两块内存相等,跳出,返回0.
     "sbbq      %0,%0\n\t"    ; sbb是x86的减法指令,会额外地减去CF(借位)的值,这样%0就会是0或者-1
     "orq       $1,%0\n"         ; 把立即数1或到%0上,这样%0就会是1或者-1.
     "1:"
         : "=&a"(res)          ;  传入变量res放入寄存器ax,且这个变量是输出值(=),不要与其它输入输出共用寄存器(&)
     : "0"(res), "S"(s1), "D"(s2), "c"(num)  ; 输入列表
     : "cc");           // clobber list 告诉gcc在这段内联汇编中哪些寄存器被显式/隐式修改.If our instruction can alter the condition code register, we have to add "cc" to the list of clobbered registers.

    return res;
}

Linux内核中的宏可变参数(GCC的宏可变参数)

Linux内核中的宏可变参数(GCC的宏可变参数)。
写内核模块的时候为了调试方便,经常需要wrap一下printk函数。下面的宏定义非常有实用价值。
注意两个井号~~
记到博客里~~

#define seclvl_printk(verb, type, fmt, arg...)			\
	do {							\
		if (verbosity >= verb) {			\
			static unsigned long _prior;		\
			unsigned long _now = jiffies;		\
			if ((_now - _prior) > HZ) {		\
				printk(type "%s: %s: " fmt,	\
					MY_NAME, __FUNCTION__ ,	\
					## arg);		\
				_prior = _now;			\
			}					\
		}						\
	} while (0)

今天用Debian时总遇到locale的错误.

我的debian一般把LC_ALL设成en_US.UTF-8。这次dpkg-reconfigure locales时没有选美国英语,而是用了香港英语。于是就出错了。

解决方法的关键在于  /etc/environment 文件,  dpkg-reconfigure locales 命令用来配置local,以及locale命令列出当前期待的locale,还有 local-gen 命令可以生成local.

debian报得错误类似于:

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = "en_US:en",
    LC_ALL = (unset),
    LANG = "en_US"
    are supported and installed on your system.

////////////

另外今天还解决了编译内核后,用新内核启动时报错:

kernel panic – not syncing VFS: unable to mount root fs on unknown block (0, 0)

// 通常这是因为对应文件系统被编译成模块,那么就应该生成initrd加载对应的文件驱动模块。在debian下,用update-initramfs 命令生成对应的initrd. 如: update-initramfs -c -k 3.0.63

 

git的排错神器pickaxe和git blame

git log -Sstring 这里的-S选项被称作pickaxe,这是一个非常好的排错工具。

比如: git log -Sinclude –pretty=oneline –abbrev-commit init/version.c

会把减少了,或者增加了include的commit全部找出来。

要注意的是,如果有一个提交增加和减少include的次数一样,这个commit不会被列出来。

/////////////

另外一个排错工作是 git blame:

git blame可以用来帮助查找引入bug的commit。git blame告诉你谁,什么时候,是哪个commit更改了某个文件。

如: git blame -L 32, init/version.c

使用gdb和虚拟机调试内核

调试内核很麻烦,即使是有了虚拟机的帮助。在这里记下一些关键的东西,以备忘 。

#  编译内核后, 用新内核启动系统失败,报错 “unable to mount fs ….” 之类.

需要用 update-initramfs 生成initram。

# 对于grub2,我增加了一个自定义的grub开机启动项用来调试内核,如下:

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
echo "Add Debugging entry"
cat << EOF
menuentry "Debian debug 3.7.4"{
set root=(hd0,1)
linux /boot/vmlinuz-3.7.4 root=/dev/vda1 ro quiet kgdboc=ttyS0,115200 kgdbwait
initrd /boot/initrd.img-3.7.4
}
EOF

/////////

the above grub configuration file resides in /etc/grub.d/

# client在虚拟机里启动后在内核调试断点处停下。这时在host机用gdb调试.

# gdb vmlinux

set remotebaud 115200

target remote /dev/pts/0

此时gdb输入continue命令让客户机的系统继续运行。如果想断下正在运行的client内核,在client机中使用magic SysR:  echo "g" > /proc/sysrq-trigger

 

Okular是linux下最好用的pdf阅读工具

我记得对于大多数Gnome桌面环境,Evince是默认的pdf阅读软件。今天不知道怎么回事,发现evince没有了。当时我不记得evince这个名字了,就apt-cache search pdf 随便装上了xpdf-viewer。太他妈难用了啊~~就卸载了,然后google: The Best PDF Viewer on Linux。找到了Okular,也是免费软件,装上一用。不错哈哈哈.贴一张网络上的图片:

另外今天才知道, Adobe也有出linux下的pdf阅读软件。

显示Gnome3任务栏

Gnome3桌面较之Gnome2有了非常大的区别~

第一眼看上去有惊艳的感觉~多用了一点时间,发现没有任务栏真是相当的不方便啊。我觉得最方便的还是Win7的方式。

那怎么把Gnome3消失的任务栏找回来呢?通过安装一个安装包搞定。

我用的是Debian 6.06 Wheazy

zausiu@accolade:~$ cat /etc/debian_version
6.0.6

对于Debian家族的ubuntu应该也是适用的。

# apt-get install tint2

$ tint2 &

于是久违的gnome任务又回来了~

Gnome的任务栏又回来了
Gnome的任务栏又回来了

 

Let the Universal Access Preferences Taskbar Icon Disappear让统一访问首选项在任务栏上消失

我用的是Debian Wheezy Stable系统。今天不知道怎么搞得,把任务栏上面弄出个 配置Universal Access Preferences的图标。右链点击也没有让我选择退出的选项。

搜索了一下,知道用 gnome-keyboard-properties 把这个该死的图标去掉。

1. alt+F2  输入 gnome-keyboard-properties

2. 选中Accessibility ,取消 Accessibility features can be toggled with keyboard shortcuts.

这几天调linux内核源代码,好困难好困难。

Linux内核Makefiles教程(二)

接第一篇 

3.3.可加载模块目标 obj-m (Loadable module goals – obj-m)

obj-m指定将被构建为可加载内核模块的对象文件(object file)。

一个模块可以从一个源文件构建或者从多个源文件构建。如果模块仅仅从一个源文件构建,kbuild makefile仅仅把对象文件加到obj-m。如下:

       #drivers/isdn/i4l/Makefile

        obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

在这个例子中,$(CONFIG_ISDN_PPP_BSDCOMP)被求值为m.

If a kernel module is built from several source files, you specify that you want to build a module in the same way as above.

如果一个内核模块需要从多个源文件构建,你也是按照刚才提到的那一行指定。不过,除此之外,还要额外地指定,你的内核模块需要哪些对象文件。所以还需要设置<模块名>-objs变量。如下:

       #drivers/isdn/i4l/Makefile

        obj-$(CONFIG_ISDN) += isdn.o

        isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o

在这个例子中,模块名是 isdn 。Kbuild将编译isdn-objs列出的所有对象文件,然后运行$(LD) –r把这些对象文件链接成一个文件isdn.o。

Kbuild用-objs后缀或者-y后缀识别构成复合对象文件(composite objects)的对象文件。这样,Makefile就可以使用CONFIG_* 符号来确定一个对象文件是不是一个复合对象文件的一部分。如下:

       #fs/ext2/Makefile

        obj-$(CONFIG_EXT2_FS)        += ext2.o

        ext2-y                       := balloc.o bitmap.o

        ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o

在上例中,如果$(CONFIG_EXT2_FS_XATTR)求值为y,则xattr.o是复合对象文件ext2.o的组成部分。

当然,如果你要把对象文件编译进入内核映象文件。也可以应用上述语法。比如,如果CONFIG_EXT2_FS=y,kbuild就会构建一个ext2.o文件,如你所想,再把这个文件链接到build-in.o。

3.4. 导出符号的对象文件

并不需要在Makefile中为模块使用特殊的标记来导出符号。

3.5. 库文件目标(Library file goals – lib-y)

在obj-*中指定的对象文件列表或者被用来构建内核模块,或者被内建到内核映象文件之中。Makefile还能指定创建库文件的对象文件。所有在lib-y中指定的对象文件会被用来在对应文件夹下创建一个库文件。注意已经在obj-y中列出过的对象文件,如果再在lib-y中列出,则不会被用来创建库文件,因为这些对象文件将是全局可见的。为了一致性,lib-m中列出的对象文件会被包含到lib.a。

注意,同一个kbuild makefile会同时指定被内建到内核映象中的对象文件,也会指定用来创建库文件的对象文件。因此,在同一个文件夹下面有可能同时存在built-in.o和lib.a文件。

       #arch/i386/lib/Makefile

        lib-y    := checksum.o delay.o

上例中,会基于checksum.o和delay.o创建一个库文件lib.a。为了让kbuild意识到该目录下有lib.a库文件被创建,这个目录需要被列入到libs-y。本教程将在6.3节”列出需要遍历的路径”中详述。

lib-y的使用通常受限于 lib/ 和 arch/*/lib。

3.6. 深入遍历子目录夹

每个Makefile文件只负则在当前文件夹下面构建对象。在子目录下面的构建则由子目录下面的对象Makefile负责。不过你需要使用使用obj-y或者obj-m告诉kbuild系统将进入哪些子目录。比如话:当前目录是fs/,ext2/是当前目录下面的一个子目录,为了告诉kbuild进入ext2/目录,使用以下的语句:

        #fs/Makefile

        obj-$(CONFIG_EXT2_FS) += ext2/

如果CONFIG_EXT2_FS被求值为y(内建)或者m(模块),那么obj-*变量就会告诉kbuild需要进入ext2/子目录继续编译。

Kbuild仅仅使用这个信息来通知是否进入某个子目录,而进入后的子目录下面是用内建方式编译还是编译成模块则是由子目录下面的Makefile文件指定。最好像上例那个使用CONFIG_*变量。这样的好处是,如果CONFIG_*变量的求值既不是y也不是m,那么kbuild就完全可以忽略掉某子目录了。

3.7. 编译选项/标识

EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS

所有的EXTRA_VARIABLES仅仅作用于它们被赋值的kbuild makefile,应用于所有该makefile文件中执行的命令。

$(EXTRA_CFLAGS)指定了编译C文件的C编译器的编译选项。

Example:

        # drivers/sound/emu10k1/Makefile

        EXTRA_CFLAGS += -I$(obj)

        ifdef DEBUG

            EXTRA_CFLAGS += -DEMU10K1_DEBUG

        endif

变量$( EXTRA_CFLAGS)是必要的,因为最上级的Makefile定义的$(CFLAGS)作用于整个linux内核代码树。

而$(EXTRA_AFLAGS)的作用域则是每个文件夹下面单独的Makefile。

比如下面的例子编译汇编语言程序。

        #arch/x86_64/kernel/Makefile

        EXTRA_AFLAGS := -traditional

$(EXTRA_LDFLAGS) 用于当前Makefile文件中的$(LD)。

$(EXTRA_ARFLAGS) 则用于当前Makefile文件中的$(AR)。

Example:

        #arch/m68k/fpsp040/Makefile

        EXTRA_LDFLAGS := -x

未完待续

copyright ykyi.net