zoukankan      html  css  js  c++  java
  • Linux 环境下编译 0.11版本内核 kernel

    http://linux.chinaitlab.com/soft/878778_2.html


    最近在看《linux 0.11完全注释》一书,由于书中涉及汇编语言的地方众多,本人在大学时汇编语言学得一塌糊涂,所以实在看不下去了,头都大了只好匆匆看了个头尾(前面 几章和最后一章)。看来即使有《九阴真经》这样的武功秘籍,内功不够也是修炼不出来神马来的。于是索性下了个0.11版本的kernel下来尝试编译一 把。

     

    linux-0.11.tar.gz 下载地址:

     

    下面开始工作:

     

    1 tar xvfz linux-0.11.tar.gz

    2 cd linux-0.11

    3 make

    make: as86: Command not finded

     

    make: ***

     

    出错原因:as86 汇编器未安装

     

    解决办法:

     

    yum install dev86* (请务必保证网络畅通,如果使用Debian Linux系统命令改为 apt-get install dev86*

     

    下载dev86-0.16.3-8.i386.rpm安装 下载地址 http://www.oldlinux.org/Linux.old/study/tools/

     

    4 make

     

    gas -c -o boot/head.o boot/head.s

     

    make: gas: Command not finded

     

    make: *** [boot/head.o] Error 127

     

    出错原因:gas 汇编器未安装

     

    解决办法:

     

    yum install binutils* (请确保网络正常)

     

    下载binutils-2.20.tar.gz安装 下载地址http://ftp.gnu.org/gnu/binutils/

    tar xvfz binutils-2.20.tar.gz

    ./configure

    make

    make install

     

    确认 Gnu assembler 已经安装

    which as

    /usr/local/bin/as

     

    5 make

     

    gas -c -o boot/head.o boot/head.s

    make: gas: Command not found

    make: *** [boot/head.o] Error 127

     

    出错原因:gasgld 的名称已经过时,现在GNU assembler的名称是 as

     

    解决办法:

     

    修改主 Makefile 文件

     

    AS =gas 修改为 AS =as

    LD =gld 修改为 LD =ld

     

    6make

     

    as -c -o boot/head.o boot/head.s

    as: unrecognized option '-c'

    make: *** [boot/head.o] Error 1

     

    出错原因:as 语法和1991年的时候有了一些变化

     

    解决办法:

     

    修改 Makefile 文件

     

    $(AS) -c -o $*.o $< 修改为 $(AS) -o $*.o $<

     

    7make

     

    as -o boot/head.o boot/head.s

    boot/head.s: Assembler messages:

    boot/head.s:231: Error: alignment not a power of 2

    make: *** [boot/head.o] Error 1

     

    出错原因:.align 2 是汇编语言指示符,其含义是指存储边界对齐调整;

    “2”表示把随后的代码或数据的偏移位置调整到地址值最后2比特位为零的位置(2^2),即按4字节对齐内存地址。

    不过现在GNU as直接是写出对齐的值而非2的次方值了。

     

    .align 2 应该改为 .align 4

    .align 3 应该改为 .align 8

     

    解决办法:

     

    修改 boot/head.s 文件

     

    .align 2 应该改为 .align 4

    .align 3 应该改为 .align 8

     

    8make

     

    cc1: error: unrecognized command line option "-mstring-insns"

    cc1: error: unrecognized command line option "-fcombine-regs"

    make: *** [init/main.o] Error 1

     

    解决办法:

     

    修改 Makefile 文件

     

    -fcombine-regs -mstring-insns 删除或者注释掉

     

    9make

     

    In file include from init/main.c:9:

    include/unistd.h:207: warning: function return types not compatible due to 'volatile'

    include/unistd.h:208: warning: function return types not compatible due to 'volatile'

    init/main.c:24: error: static declaration of 'fork' follows non-static declaration

    init/main.c:26: error: static declaration of 'pause' follows non-static declaration

    include/unistd.h:224: note: previous declaration of 'pause' was here

    init/main.c:30: error: static declaration of 'sync' follows non-static declaration

    include/unistd.h:235: note: previous declaration of 'sync' was here

    init/main.c:108: warning: return type of 'main' is not 'int'

    make: *** [init/main.o] Error 1

     

    解决办法:

     

    修改 init/main.c 文件

     

    static inline _syscall0(int,fork) 修改为 inline _syscall0(int,fork)

    static inline _syscall0(int,pause) 修改为 inline _syscall0(int,pause)

    static inline _syscall1(int,setup,void *,BIOS) 修改为 inline _syscall1(int,setup,void *,BIOS)

    static inline _syscall0(int,sync) 修改为 inline _syscall0(int,sync)

     

    10make

     

    (cd kernel; make)

    make[1]: Entering directory '***/linux-0.11/kernel'

    gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs -finline-functions -mstring-insns -nostdinc -I../include

    -c -o sched.o sched.c

    cc1: error: unrecognized command line option "-mstring-insns"

    cc1: error: unrecognized command line option "-fcombine-regs"

    make[1]: *** [sched.o] Error 1

    make[1]: Leaving directiory '***/linux-0.11/kernel'

    make: *** [kernel/kernel.o] Error 2

     

    解决办法:

     

    修改 kernel目录下 Makefile 文件

     

    -fcombine-regs -mstring-insns 删除或者注释掉

     

    11make

     

    gas -c -o system_call.o system_call.s

    make[1]: gas: Command not found

    make[1]: *** [system_call.o] Error 127

    make[1]: Leaving directory '***/linux-0.11/kernel'

    make: *** [kernel/kernel.o] Error 2

     

    解决办法:

     

    修改 kernel目录下 Makefile 文件

     

    AS =gas 修改为 AS =as

    LD =gld 修改为 LD =ld

    $(AS) -c -o $*.o $< 修改为 $(AS) -o $*.o $<

     

    12make

     

    fork.c:In function 'copy_process':

    fork.c:121: warning: suggest parentheses around assignment used as truth value

    fork.c:In function 'copy_mem':

    fork.c:54: error: can't find a register in class 'DREG' while reloading 'asm'

    fork.c:55: error: can't find a register in class 'DREG' while reloading 'asm'

    fork.c:46: error: 'asm' operand has impossible constraints

    fork.c:47: error: 'asm' operand has impossible constraints

    fork.c:54: error: 'asm' operand has impossible constraints

    fork.c:55: error: 'asm' operand has impossible constraints

    make[1]: *** [fork.o] Error 1

    make[1]: Leaving directory '***/linux-0.11/kernel'

    make: *** [kernel/kernel.o] Error 2

     

    kernel/fork.c 54 行:

     

    可以看到这样的调用 set_base(p->ldt[1],new_code_base);

    include/linux/sched.h 188 —— 211 行:

     

    可以看到 set_base 的实现

     

    #define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )

     

    #define _set_base(addr,base)

    __asm__("movw %%dx,%0 "

    "rorl $16,%%edx "

    "movb %%dl,%1 "

    "movb %%dh,%2"

    ::"m" (*((addr)+2)),

    "m" (*((addr)+4)),

    "m" (*((addr)+7)),

    "d" (base)

    :"dx")

     

    为这里涉及到汇编的知识,哥卡在这里一直没解决并且郁闷了好久,最后只好看回《linux内核0.11完全注释》一书。赵炯博士在 http://www.oldlinux.org/Linux.old/kernel/0.1x/ 这里提供了修改 linux-0.11-060618-gcc4.tar.gz 好的 0.11版本的内核。

     

    于是这个时候比较工具 Beyond Compare 就派上用场了。

     

    #define _set_base(addr,base) 修改为 #define _set_base(addr,base)

    __asm__("movw %%dx,%0 " __asm__("push %%edx "

    "rorl $16,%%edx " "movw %%dx,%0 "

    "movb %%dl,%1 " "rorl $16,%%edx "

    "movb %%dh,%2" "movb %%dl,%1 "

    ::"m" (*((addr)+2)), "movb %%dh,%2 "

    "m" (*((addr)+4)), "pop %%edx"

    "m" (*((addr)+7)), ::"m" (*((addr)+2)),

    "d" (base) "m" (*((addr)+4)),

    :"dx") "m" (*((addr)+7)),

    "d" (base) )

     

    #define switch_to(n) {

    struct {long a,b;} __tmp;

    __asm__("cmpl %%ecx,_current "

    "je 1f "

    "movw %%dx,%1 "

    "xchgl %%ecx,_current "

    "ljmp %0 " ------------------------------这里修改为 "ljmp *%0 "

    "cmpl %%ecx,_last_task_used_math "

    "jne 1f "

    "clts "

    "1:"

    ::"m" (*&__tmp.a),"m" (*&__tmp.b),

    "d" (_TSS(n)),"c" ((long) task[n]));

    }

     

    #define _get_base(addr) ({ 修改为 static inline unsigned long _get_base(char * addr)

    unsigned long __base; {

    __asm__("movb %3,%%dh " unsigned long __base;

    movb %2,%%dl " __asm__("movb %3,%%dh "

    shll $16,%%edx " "movb %2,%%dl "

    movw %1,%%dx" "shll $16,%%edx "

    "=d" (__base) "movw %1,%%dx"

    "m" (*((addr)+2)), :"=&d" (__base)

    "m" (*((addr)+4)), :"m" (*((addr)+2)),

    "m" (*((addr)+7))); "m" (*((addr)+4)),

    __base;}) "m" (*((addr)+7)));

    return __base;

    }

     

    注意:

    由于GNU as汇编器不断进化的原因,需要将 *.s 文件中

    类似

    .globl _idt,_gdt,_pg_dir,_tmp_floppy_area

    修改为

    .globl idt,gdt,pg_dir,tmp_floppy_area

     

    不然虽然编译通过,但是连接的时候将出现类似这样的错误

    boot/head.o: In function 'setup_idt':

    (.text+0x87): undefined reference to '_idt'

    boot/head.o: In function 'idt_descr':

    (.text+0x54ac): undefined reference to '_idt'

    kernel/kernel.o: In function 'sched_init':

    (.text+0x37c): undefined reference to '_idt'

     

     

    GCC中基本的内联汇编:__asm____volatile__("InstructionList");

     

    __asm__(

    "movl $1,%eax "

    "xor %ebx,%ebx "

    "int $0x80"

    );

     

    带有C/C++表达式的内联汇编:

     

    __asm__ __volatile__("InstructionList"

    :Output

    :Input

    :Clobber/Modify);

     

    4个部分都不是必须的,任何一个部分都可以为空,其规则为:

     

    1、如果Clobber/Modify 为空,则其前面的冒号(:)必须省略。

     

    2、如果OutputInputClobber/Modify都为空,OutputInput之前的冒号(:)既可以省略,也可以不省略。

     

    3、如果InputClobber/Modify为空,但Output不为空,Input前的冒号(:)既可以省略,也可以不省略。

     

    4、如果后面的部分不为空,而前面的部分为空,则前面的冒号(:)都必须保留,否则无法说明不为空的部分究竟是第几部分。

     

     

     

    每一个InputOutput表达式都必须指定自己的操作约束Operation Constraint,这里将讨论在80386平台上所可能使用的操作约束。

     

    当前的输入或输出需要借助一个寄存器时,需要为其指定一个寄存器约束,可以直接指定一个寄存器的名字。

     

    常用的寄存器约束的缩写

    约束 意义

    r 表示使用一个通用寄存器,由 GCC %eax/%ax/%al,%ebx/%bx/%bl,%ecx/%cx/%cl,%edx/%dx/%dl中选取一个GCC认为合适的。

    g 表示使用任意一个寄存器,由GCC在所有的可以使用的寄存器中选取一个GCC认为合适的。

    q 表示使用一个通用寄存器,和约束r的意义相同。

    a 表示使用%eax/%ax/%al

    b 表示使用%ebx/%bx/%bl

    c 表示使用%ecx/%cx/%cl

    d 表示使用%edx/%dx/%dl

    D 表示使用%edi/%di

    S 表示使用%esi/%si

    f 表示使用浮点寄存器

    t 表示使用第一个浮点寄存器

    u 表示使用第二个浮点寄存器

     

    如果一个Input/Output 操作表达式的C/C++表达式表现为一个内存地址,不想借助于任何寄存器,则可以使用内存约束。比如:

    __asm__("lidt%0":"=m"(__idt_addr));

    __asm__("lidt%0"::"m"(__idt_addr));

     

     

     

    修饰符 输入/输出 意义

    = O 表示此Output操作表达式是Write-Only的。

    + O 表示此Output操作表达式是Read-Write的。

    & O 表示此Output操作表达式独占为其指定的寄存器。

    % I 表示此Input 操作表达式中的C/C++表达式可以和下一 个Input操作表达式中的C/C++表达式互换

     

    --------------------------------------------------------------------------------------------------------------------------------------------------------------

     

    13make

     

    In file included from stat.c:13:

    ../include/asm/segment.h: Assembler messages:

    ../include/asm/segment.h:27: Error: bad register name '%sil'

    make[1]: *** [stat.o] Error 1

    make[1]: Leaving directory '***/linux-0.11/fs'

    make: *** [fs/fs.o] Error 2

     

    出错原因:

     

    fs 目录下的 Makefile 中编译选项使用了 -O 优化选项导致寄存器错误

     

     

    解决方法:

     

    fs目录下的Makefile 文件中的

    CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer

    修改为

    CFLAGS =-Wall -fstrength-reduce -fomit-frame-pointer

     

    14make

     

    tools/build.c: In function 'main':

    tools/build.c:75: warning: implicit declaration of function 'MAJOR'

    tools/build.c:76: warning: implicit declaration of function 'MINOR'

    tmp/ccsMKTAS.o: In function 'main':

    build.c:(.text+0xe1): undefined reference to 'MAJOR'

    build.c:(.text+0xf7): undefined reference to 'MINOR'

    collect2: ld returned 1 exit status

     

    出错原因:'MAJOR' 'MINOR' 未定义

     

    解决办法:

     

    我们可以在 include/linux/fs.h 文件中找到

     

    #define MAJOR(a) (((unsigned)(a))>>8)

    #define MINOR(a) ((a)&0xff)

     

    而在 tools/build.c 中也有包含 #include

    那么再看第一层目录中的主 Makefile 文件

     

    tools/build: tools/build.c

    $(CC) $(CFLAGS)

    -o tools/build tools/build.c

     

    好象确实没有引用头文件

     

    简单的添加 -Iinclude

    重新编译后出现一堆报标准C库头文件的错误

     

    再添加 -nostdinc

    又报 stderr fprintf 之类的错误

     

    没折,只好将

    #define MAJOR(a) (((unsigned)(a))>>8)

    #define MINOR(a) ((a)&0xff)

    添加到 tools/build.c 文件中,然后删除 #include

     

    15make

     

    make[1]: Leaving directory '***/linux-0.11/lib'

    ld -s -x -M boot/head.o init/main.o

    kernel/kernel.o mm/mm.o fs/fs.o

    kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a

    kernel/math/math.a

    lib/lib.a

    -o tools/system > System.map

    ld: warning: cannot find entry symbol _start; defaulting to 08048a0

    gcc -Wall -O -fstrength-reduce -fomit-frame-pointer

    -o tools/build tools/build.c

    tools/build boot/bootsect boot/setup tools/system /dev/hd6 > Image

    /dev/hd6: No such file or directory

    Couldn't stat root device.

    make: *** [Image] Error 1

     

    解决办法:

     

    将第一层主 Makefile 文件中的

     

    tools/system: boot/head.o init/main.o

    $(ARCHIVES) $(DRIVERS) $(MATH) $(LIBS)

    $(LD) $(LDFLAGS) boot/head.o init/main.o

    $(ARCHIVES)

    $(DRIVERS)

    $(MATH)

    $(LIBS)

    -o tools/system > System.map

     

    修改为

     

    tools/system: boot/head.o init/main.o

    $(ARCHIVES) $(DRIVERS) $(MATH) $(LIBS)

    $(LD) $(LDFLAGS) boot/head.o init/main.o

    $(ARCHIVES)

    $(DRIVERS)

    $(MATH)

    $(LIBS)

    -o tools/system

    nm tools/system | grep -v '(compiled)|(.o$$)|( [aU] )|(..ng$$)|(LASH[RL]DI)'| sort > System.map

     

    nm命令将目标文件中的各种符号列出来。

     

     

    ROOT_DEV=/dev/hd6 修改为 ROOT_DEV=

     

    16make

     

    /DISCARD/

    *(.note.GNU-stack)

    *(.gnu_debuglink)

    *(.gnu.lto_*)

    OUTPUT(tools/system elf32-i386)

    nm tools/system | grep -v '(compiled)|(.o$$)|( [aU] )|(..ng$$)|(LASH[RL]DI)'| sort > System.map

    nm: tools/system: no symbols

    gcc -Wall -O -fstrength-reduce -fomit-frame-pointer

    -o tools/build tools/build.c

    tools/build boot/bootsect boot/setup tools/system > Image

    Root device is (3, 6)

    Boot sector 512 bytes.

    Setup is 312 bytes.

    Non-Gcc header of 'system'

    make: *** [Image] Error 1

     

    解决办法:

     

    将第一层主 Makefile 文件中的

     

    LDFLAGS =-s -x -M

    修改为

    LDFLAGS =-m elf_i386 -Ttext 0 -e startup_32

     

     

    Image: boot/bootsect boot/setup tools/system tools/build

    tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) > Image

    sync

    修改为

    Image: boot/bootsect boot/setup tools/system tools/build

    objcopy -O binary -R .note -R .comment tools/system tools/kernel

    tools/build boot/bootsect boot/setup tools/kernel $(ROOT_DEV) > Image

    rm tools/kernel -f

    sync

     

    objcopy命令能复制和转化目标文件

    objcopy -O binary -R .note -R .comment tools/system tools/kernel

    -O binary tools/system tools/kernel tools/system 生成二进制文件 tools/kernel

    -R .note -R .comment 删除 .note段 和 .comment

     

     

    tools/build.c 文件中的

    if (((long *) buf)[5] != 0)

    die("Non-GCC header of 'system'");

    这段代码注释掉

    //if (((long *) buf)[5] != 0)

    // die("Non-GCC header of 'system'");

     

    17make

     

    ld -m elf_i386 -Ttext 0 -e startup_32 boot/head.o init/main.o

    kernel/kernel.o mm/mm.o fs/fs.o

    kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a

    kernel/math/math.a

    lib/lib.a

    -o tools/system

    nm tools/system | grep -v '(compiled)|(.o$$)|( [aU] )|(..ng$$)|(LASH[RL]DI)'| sort > System.map

    gcc -Wall -O -fstrength-reduce -fomit-frame-pointer

    -o tools/build tools/build.c

    objcopy -O binary -R .note -R .comment tools/system tools/kernel

    tools/build boot/bootsect boot/setup tools/system > Image

    Root device is (3, 6)

    Boot sector 512 bytes.

    Setup is 312 bytes.

    System is 128323 bytes.

    rm tools/kernel -f

    sync

     

    终于编译 linux 内核 0.11 版本成功了!

     

     

     

    最 后也可以利用赵炯博士在http://www.oldlinux.org/Linux.old/kernel/0.1x/ 这里提供了修改 linux-0.11-060618-gcc4.tar.gz 好的 0.11版本的内核进行编译,只要修改以下 Makefile -mcpu=i386 -march=i386 还需要将 kernel/blk_drv/blk.h 文件第87行 将 #elif 修改为 #else 就可以编译通过了。

     

     

    总结:编译需要一个过程,学习也是同样需要一个过程。虽然可以利用赵博士修改好的 kernel-0.11 版快速的编译内核,但是那样就不会遇到太多有价值的编译问题,而解决这些问题就是一个学习过程,相信赵博士在编译0.11版本内核的时候也遇到了这些问 题。这样我想起了高中解数学难题的时候,高手解体时总是省略了一些因式分解的过程,而对于菜鸟来说这些省略的过程是非常重要的。

     

    /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}
    <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
    阅读(4419) | 评论(1) | 转发(4) |
    给主人留下些什么吧!~~
    34_avatar_small.jpg

    uubuge2014-02-27 23:15:28

    写得非常好,大多数我遇到的困难都让你写在里面了,楼主能否给我发一个你修改好的源码包,我到现在还没编译过去,quejing@163.com

    评论热议
  • 相关阅读:
    MySQL三种备份
    四层和七层负载均衡的区别
    触发器及触发器的作用
    sql 存储过程
    自动ftp 上传
    #题目:有10 台被监控主机、一台监控机,在监控机上编写脚本,一旦某台被监控机器/ 分区适用率大于80%, 就发邮件报警放到crontab 里面, 每10 分钟检查一次
    /proc/sys 子目录的作用
    Linking code for an enhanced application binary interface (ABI) with decode time instruction optimization
    facebook webdriver 学习
    WebDriverException: Message: A session is either terminated or not started
  • 原文地址:https://www.cnblogs.com/ztguang/p/12648136.html
Copyright © 2011-2022 走看看