感谢这篇文章的作者:    http://www.cnblogs.com/strugglesometimes/p/4231359.html

编译是个很蛋疼的事情,本想把linux0.12在bochs上跑起来然后就可以各模块的学习,没想各种问题。

问题1:

1 gas -c -o boot/head.o boot/head.s
2 make: gas: Command not found

gas已过时,将所有Makfile里gas -> as

具体解决方法

1
msed gas as

msed 是个简单的shell 函数,具体定义见下面的传送门。

传送门:http://www.cnblogs.com/strugglesometimes/p/4231348.html

问题2:

 1 boot/head.s:43: Error: unsupported instruction `mov'
2 boot/head.s:47: Error: unsupported instruction `mov'
3 boot/head.s:59: Error: unsupported instruction `mov'
4 boot/head.s:61: Error: unsupported instruction `mov'
5 boot/head.s:136: Error: invalid instruction suffix for `push'
6 boot/head.s:137: Error: invalid instruction suffix for `push'
7 boot/head.s:138: Error: invalid instruction suffix for `push'
8 boot/head.s:139: Error: invalid instruction suffix for `push'
9 boot/head.s:140: Error: invalid instruction suffix for `push'
10 boot/head.s:151: Error: invalid instruction suffix for `push'
11 boot/head.s:152: Error: invalid instruction suffix for `push'
12 boot/head.s:153: Error: invalid instruction suffix for `push'
13 boot/head.s:154: Error: operand type mismatch for `push'
14 boot/head.s:155: Error: operand type mismatch for `push'
15 boot/head.s:161: Error: invalid instruction suffix for `push'
16 boot/head.s:163: Error: invalid instruction suffix for `pop'
17 boot/head.s:165: Error: operand type mismatch for `pop'
18 boot/head.s:166: Error: operand type mismatch for `pop'
19 boot/head.s:167: Error: invalid instruction suffix for `pop'
20 boot/head.s:168: Error: invalid instruction suffix for `pop'
21 boot/head.s:169: Error: invalid instruction suffix for `pop'
22 boot/head.s:214: Error: unsupported instruction `mov'
23 boot/head.s:215: Error: unsupported instruction `mov'
24 boot/head.s:217: Error: unsupported instruction `mov'

这是由于在64位机器上编译的原因,需要告诉编译器,我们要编译32位的code,在所有Makefile的AS后面添加 --32,CFLAGS中加-m32

具体解决方法

msed as$ as\ --32
msed -O -O\ -m32

问题3:

boot/head.s: Assembler messages:
boot/head.s:231: Error: alignment not a power of 2
make: *** [boot/head.o] Error

把align n -> align 2^n

具体解决方法

sed -i 's/align 2/align 4/g' boot/head.s
sed -i 's/align 3/align 8/g' boot/head.s

问题4:

gcc: error: unrecognized command line option ‘-fcombine-regs’
gcc: error: unrecognized command line option ‘-mstring-insns’

把这两个删掉即可,现在GCC已经不支持了

具体解决方法

msed -fcombine-regs \
msed -mstring-insns \

问题5:

额。。。。为了更快的找到Error的地方,我把所有的warning 都关掉了即在CFLAGS 中加-w

具体解决方法

msed -Wall -w

问题6:

In file included from init/main.c:8:0:
init/main.c:23:29: error: static declaration of ‘fork’ follows non-static declaration
static inline _syscall0(int,fork)
^
include/unistd.h:151:6: note: in definition of macro ‘_syscall0’
type name(void) \
^
init/main.c:24:29: error: static declaration of ‘pause’ follows non-static declaration
static inline _syscall0(int,pause)
^
include/unistd.h:151:6: note: in definition of macro ‘_syscall0’
type name(void) \
^
include/unistd.h:241:5: note: previous declaration of ‘pause’ was here
int pause(void);
^
init/main.c:26:29: error: static declaration of ‘sync’ follows non-static declaration
static inline _syscall0(int,sync)
^
include/unistd.h:151:6: note: in definition of macro ‘_syscall0’
type name(void) \
^
include/unistd.h:252:5: note: previous declaration of ‘sync’ was here
int sync(void);

这里是由于include/unistd.h 中声明了一次pause() sync() fork(), 而在main.c 中通过宏又定义了这三个函数,但定义时多了static 限定,与声明不同,所以出错。所以直接把unistd.h中的声明去掉。

问题7:

init/main.c:179:12: error: static declaration of ‘printf’ follows non-static declaration
static int printf(const char *fmt, ...)

这个问题困扰了好久,网上的解决方案都是把static去掉,但是这样做,后面在链接的时候会出现另一个错误undefined reference to '_put'. 新的问题是由于GCC会对printf进行优化,把无参的printf优化成put,而linux0.12的libc中又没有实现put才会导致新的问题。那么现在回到这个问题上,猜测应该也是由于GCC本身对printf这个函数名有特别的关照所致,所以把printf稍微改下名,printf -> printw。发现果然就编译通过了。

具体解决方案:

sed -i 's/ printf/ printw/g' init/main.c

问题8:

init/main.c: In function ‘main’:
init/main.c:176:3: error: ‘asm’ operand has impossible constraints
__asm__("int $0x80"::"a" (__NR_pause):"ax");

类似的问题在后面编译中出现好多,C内嵌汇编的格式__asm__(汇编语句:输入寄存器:输出寄存器:可能被修改的寄存器),最新的GCC规定输入或输出寄存器不能出现在可能被修改的寄存器中,目前看到网上的方法是把所有类似问题的可能被修改的寄存器全部删掉。

具体解决方法

find -type f -exec sed -i 's/:\"\w\{2\}\"\(,\"\w\{2\}\"\)*)/:) /g' {} \;

问题9:

make[1]: gld: Command not found

同gas, 把gld -> ld

具体解决方法

msed gld ld

问题10:

ld -r -o kernel.o sched.o sys_call.o traps.o asm.o fork.o panic.o printk.o vsprintf.o sys.o exit.o signal.o mktime.o
ld: Relocatable linking with relocations from format elf32-i386 (sched.o) to format elf64-x86-64 (kernel.o) is not supported

同问题2,告诉ld以32位链接,在ld命令后面加 -m elf_i386

具体解决方法

msed ld$ ld\ -m\ elf_i386

问题11:

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

去segment.h 的第27行找,没找到sil相关的东西,根据网上的方法,把=r或r 改成=q或q,果然就好了,这里应该是编译器造成的,r表示任意寄存器,在编译的时候就用了sil这个寄存器,可为什么无效还会被用到呢。q表示使用eax,ebx,ecx,edx中任意一个。

具体解决方法

sed -i s'/r"/q"/g' include/asm/segment.h

问题12:

exec.c: In function ‘copy_strings’:
exec.c:162:44: error: lvalue required as left operand of assignment
!(pag = (char *) page[p/PAGE_SIZE] =
if (!(pag = (char *) page[p/PAGE_SIZE]) &&
!(pag = (char *) page[p/PAGE_SIZE] =
(unsigned long *) get_free_page()))
return 0;

以上是原始code,以下是OK的code

if ((!page[p/PAGE_SIZE]) &&
!(page[p/PAGE_SIZE] =
(unsigned long *) get_free_page()))
return 0;
else
pag = (char *) page[p/PAGE_SIZE];

问题13:

In file included from floppy.c:42:0:
blk.h:90:6: error: #elif with no expression
#elif

这里把第90行的#elif -> #else

问题14:

make[1]: gar: Command not found

老问题了,gar -> ar

msed gar ar

问题15:

malloc.c: In function ‘malloc’:
malloc.c:156:46: error: lvalue required as left operand of assignment
bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();

和问题12一样

bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();

上面是原始的,下面是OK的,把代码拆分下就好

cp = get_free_page();
bdesc->page = bdesc->freeptr = (void *) cp;

========================================================================================

 9、ld: warning: cannot find entry symbol _start; defaulting to 0000000008048098

ld -m elf_i386 -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 0000000008048098

这是因为ld在将所有目标文件链接起来时,不知道程序的入口点在哪里。由内核的启动过程知其从head.s中开始执行,因此给head.s的 .text 段添加一句 .globl startup_32,然后给 ./Makefile 中的ld加上选项 -e startup_32 以指定入口点。

另外注意,仅指定入口点的标号还不够,后续使用tools/build构建Image仍会出错,因为此时程序入口点的地址仍是0x8048098(见上方出错信息的最后一行),而在tools/build.c中处理system模块时,认定的合法入口点地址为0x0:

tools/build.c:
if ((id=open(argv[],O_RDONLY,))<)
die("Unable to open 'system'");
if (read(id,buf,GCC_HEADER) != GCC_HEADER)
die("Unable to read header of 'system'");
if (((long *) buf)[] != ) //判断入口点地址是否为0x0
die("Non-GCC header of 'system'");

因此还需添加 -Ttext 0 选项使startup_32标号对应的地址为0x0(更详细的说明见ld的手册,另有一个讨论见这里)。

还有一个问题是,上述代码中第161行上执行的检查是buf[]中第24-27的四个字节的内容,因为程序假设在这个位置上保存着ELF头中的程序入口地址,然而事实上对于本机的GCC编译出的目标文件,使用readelf命令查看其ELF头格式如下:

~/Src/LinuxKernel/0.11/linux-0.11-deb$ readelf -h tools/system
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          52 (bytes into file)
  ...

再结合od命令的结果:

~/Src/LinuxKernel/0.11/linux-0.11-deb$ od -w4 -N 80 -x tools/system
0000000 457f 464c
0000004 0101 0001
0000010 0000 0000
*
0000020 0002 0003
0000024 0001 0000
0000030 0000 0000
0000034 0034 0000
...

可以看出入口点地址事实上位于ELF头中第28-30字节的位置上,也就是((long*)buf)[6]处,所以应对tools/build.c作对应的修改。(关于ELF头的格式,更详细的讨论见这里)

10.

gcc  -m32 -Wall -O -fstrength-reduce -fomit-frame-pointer -mtune=i386       -o tools/build tools/build.c In file included from /usr/include/features.h:395:0,                  from /usr/include/stdio.h:27,                  from tools/build.c:23: /usr/include/gnu/stubs.h:7:27: fatal error: gnu/stubs-32.h: No such file or directory  # include <gnu/stubs-32.h>

很显然这又是一个因64位系统上缺少32位库导致的问题(更多细节见这里),从源里装个32位库即可:

sudo aptitude install libc6-dev-i386

11.

tools/build.c: In function ‘main’: tools/build.c:72:4: warning: implicit declaration of function ‘MAJOR’ [-Wimplicit-function-declaration]     major_root = MAJOR(sb.st_rdev); tools/build.c:73:4: warning: implicit declaration of function ‘MINOR’ [-Wimplicit-function-declaration]     minor_root = MINOR(sb.st_rdev); /tmp/cctAdnmd.o: In function `main': build.c:(.text+0xc7): undefined reference to `MAJOR' build.c:(.text+0xe1): undefined reference to `MINOR' collect2: error: ld returned 1 exit status

build.c中包含的是标准库的头文件 /usr/include/linux/fs.h ,但是这个头文件里并没有实现MAJOR和MINOR宏。解决方法很简单,从include/linux/fs.h中把这两个宏复制到build.c中即可:

#define MAJOR(a) (((unsigned)(a))>>8)
    #define MINOR(a) ((a)&0xff)

12.

tools/build boot/bootsect boot/setup tools/system /dev/hd6 > Image /dev/hd6: No such file or directory Couldn't stat root device.

这是因为在源代码顶层目录的Makefile中所指定的根设备为/dev/hd6(代表第二个硬盘的第一个分区), 而本机上并不存在这个设备所致。Linus当年之所以指定根设备为/dev/hd6, 是因为他把Linux 0.11安装在了机子的第二块硬盘上。我们这里打算通过在bochs中模拟软盘来启动编译好的系统,故在顶层目录Makefile中设定根设备为软盘:

ROOT_DEV=FLOPPY

tools/build.c使用Makefile中指定的ROOT_DEV对应的设备号覆盖Image文件中的第509、510字节(即地址508、509处),这两个字节所保存的根设备号将被bootsect.s使用。

tools/build.c  115    buf[508] = (char)minor_root 116    buf[509] = (char)major_root 117    i = write(1, buf, 512);    //注意标准输出已经被重定向至Image文件

3.总结

基本上编译中会遇到的问题就是这些,另推荐这篇博文, 主要介绍的是在32位Ubuntu 11系统下编译并调试运行linux 0.11的过程。编译成功源代码只是第一步,接下来通过调试源代码弄清内核的工作细节才是最艰苦的,不过那将是另一个故事了:-)

============================================================================

http://chfj007.blog.163.com/blog/static/173145044201132523034138/

Linux 环境下编译 0.11版本内核 kernel

系统环境:Fedora 13 + gcc-4.4.5

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

linux-0.11.tar.gz 下载地址:ftp://ftp.kernel.org/pub/linux/kernel/Historic/old-versions/

下面开始工作:

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

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

解决办法:

修改主 Makefile 文件

将 AS =gas 修改为 AS =as
   将 LD =gld 修改为 LD =ld

6、make

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 $<

7、make

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

8、make

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 删除或者注释掉

9、make

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)

10、make

(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 删除或者注释掉

11、make

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 $<

12、make

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\n\t" \
 "rorl $16,%%edx\n\t" \
 "movb %%dl,%1\n\t" \
 "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\n\t" \                 __asm__("push %%edx\n\t" \   
       "rorl $16,%%edx\n\t" \                                                "movw %%dx,%0\n\t" \       
       "movb %%dl,%1\n\t" \                                                 "rorl $16,%%edx\n\t" \      
       "movb %%dh,%2" \                                                     "movb %%dl,%1\n\t" \        
       ::"m" (*((addr)+2)), \                                                    "movb %%dh,%2\n\t" \            
         "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\n\t" \
                       "je 1f\n\t" \
                       "movw %%dx,%1\n\t" \
                       "xchgl %%ecx,_current\n\t" \
                       "ljmp %0\n\t" \ ------------------------------这里修改为 "ljmp *%0\n\t" \
                       "cmpl %%ecx,_last_task_used_math\n\t" \
                       "jne 1f\n\t" \
                       "clts\n" \
                        "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\n\t" \                       unsigned long __base;                                               
   movb %2,%%dl\n\t" \                                              __asm__("movb %3,%%dh\n\t" \
   shll $16,%%edx\n\t" \                                                              "movb %2,%%dl\n\t" \
   movw %1,%%dx" \                                                                  "shll $16,%%edx\n\t" \
   "=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\r\t"
"xor %ebx,%ebx\r\t"
"int $0x80"
);

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

__asm__ __volatile__("InstructionList"
                                    :Output
                                    :Input
                                    :Clobber/Modify);

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

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

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

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

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

每一个Input和Output表达式都必须指定自己的操作约束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++表达式互换

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

13、make

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 \

14、make

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 <linux/fs.h>
    那么再看第一层目录中的主 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 <linux/fs.h>

15、make

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=

16、make

/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'");

17、make

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版本内核的时候也遇到了这些问题。这样我想起了高中解数学难题的时候,高手解体时总是省略了一些因式分解的过程,而对于菜鸟来说这些省略的过程是非常重要的。

===================================================================================================

bochs下安装linux-0.11

首先非常感谢赵炯老师给我们提供了丰富的资源,包括他写的《Linux内核完全注释》和他维护的网站www.oldlinux.org

一、准备工作
软件:bochs-20060202.tar.gz
软盘映像:http://www.oldlinux.org/Linux.old/images/bootimage-0.11-20040305
          http://www.oldlinux.org/Linux.old/images/rootimage-0.11-20040305

二、.bochsrc文件(注释已删掉)
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
ata0-master: type=disk, path=minix203.img, cylinders=940, heads=6, spt=17, translation=none
boot: a
floppy_bootsig_check: disabled=0
log: bochsout.txt
panic: action=ask
error: action=report
info: action=report
debug: action=ignore
debugger_log: -
parport1: enabled=1, file="parport.out"
vga_update_interval: 300000
keyboard_serial_delay: 250
keyboard_paste_delay: 100000
mouse: enabled=1
private_colormap: enabled=0
ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
keyboard_mapping: enabled=0, map=

三、制作软盘映像
mshost:/usr/local/bochs # ./bximage
========================================================================
                                bximage
                  Disk Image Creation Tool for Bochs
        $Id: bximage.c,v 1.31 2005/11/20 20:26:35 vruppert Exp $
========================================================================

Do you want to create a floppy disk image or a hard disk image?
Please type hd or fd. [hd]

What kind of image should I create?
Please type flat, sparse or growing. [flat]

Enter the hard disk size in megabytes, between 1 and 129023
[10]
mshost:/usr/local/bochs # ./bximage
========================================================================
                                bximage
                  Disk Image Creation Tool for Bochs
        $Id: bximage.c,v 1.31 2005/11/20 20:26:35 vruppert Exp $
========================================================================

Do you want to create a floppy disk image or a hard disk image?
Please type hd or fd. [hd] fd

Choose the size of floppy disk image to create, in megabytes.
Please type 0.16, 0.18, 0.32, 0.36, 0.72, 1.2, 1.44, 1.68, 1.72, or 2.88.
[1.44]
I will create a floppy image with
  cyl=80
  heads=2
  sectors per track=18
  total sectors=2880
  total bytes=1474560

What should I name the image?
[a.img] a.img

Writing: [] Done.

I wrote 1474560 bytes to a.img.

The following line should appear in your bochsrc:
  floppya: image="a.img", status=inserted

四、制作启动盘和根文件系统盘
首先按照步骤三再作一张b.img,然后运行下列命令:
dd if=bootimage-0.11-20040305 of=a.img
dd if=rootimage-0.11-20040305 of=b.img

五、启动
mshost:/usr/local/bochs # ./bochs
启动后会出现
Insert root floppy and press ENTER
之后cp b.img a.img(注意备份a.img),最后回车,linux-0.11就启动起来了!

========================================================

questions:

1、用bochs调试遇到"Unable to mount root"

把启动盘的Image文件(bootimage)的第509,510字节修改成0x1d, 0x02。这两个字节是根文件系统所在设备号。0x021d表示第2个软盘(b:)设备。

2、为什么在转到B盘后一直显示的是Reset-floppy called

请使用Bochs 2.1.1版本再试试。

linux0.12 编译过程的更多相关文章

  1. linux0.12 链接过程

    终于编译OK了..可链接就是一大堆错误 问题1: boot/head.o: In function `startup_32': (.text+0x10): undefined reference to ...

  2. Hadoop源码编译过程

    一.           为什么要编译Hadoop源码 Hadoop是使用Java语言开发的,但是有一些需求和操作并不适合使用java,所以就引入了本地库(Native Libraries)的概念,通 ...

  3. android 编译过程

    引用:http://www.cnblogs.com/devinzhang/archive/2011/12/20/2294686.html http://blog.sina.com.cn/s/blog_ ...

  4. C语言编译过程详解

    前言 C语言程序从源代码到二进制行程序都经历了那些过程?本文以Linux下C语言的编译过程为例,讲解C语言程序的编译过程. 编写hello world C程序: // hello.c #include ...

  5. 编译过程中,termcap.h 文件找不到路径 licli.a终于生成

    编译过程中,termcap.h      文件找不到路径   查看是linux  源码下找不到termcap.h文件   安装了所有关于*cap*的源码包也不起作用     今天终于解决了这个问题,搜 ...

  6. Spark源码的编译过程详细解读(各版本)

    说在前面的话   重新试多几次.编译过程中会出现下载某个包的时间太久,这是由于连接网站的过程中会出现假死,按ctrl+c,重新运行编译命令. 如果出现缺少了某个文件的情况,则要先清理maven(使用命 ...

  7. linux0.12 学习总序(不断更新状态中)

    最近有空闲时间,想静下心来学点东西.一直对kernel有兴趣,又苦于无从下手,就拿linux0.12练手.尝试了解并熟悉kernel各模块工作原理. 接下来的博客主要用来记录自己所遇到的问题和解决的方 ...

  8. c++应用程序文件的编译过程

    这里讲下C++文件的编译过程及其中模板的编译过程: 一:一般的C++应用程序的编译过程.     一般说来,C++应用程序的编译过程分为三个阶段.模板也是一样的. 在cpp文件中展开include文件 ...

  9. Qt打开外部程序和文件夹需要注意的细节(Qt调用VC写的动态库,VC需要用C的方式输出函数,否则MinGW32编译过程会报错)

    下午写程序中遇到几个小细节,需要在这里记录一下. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 QProcess *process = new QProcess(this ...

随机推荐

  1. Linux同步时间命令ntpdate

    转自:http://orgcent.com/linux-ntpdate/ 由于要同步Linux服务器的时间,为了保证时间的高度准确性,放弃date命令而转向ntpdate(同步时间命令). 方案如下: ...

  2. WinpCap 使用线程发数,明明发了,返回值0是OK的啊,怎么抓包看不到,难道不支持多线程。。。

    if (!m_adapterHandle){    return false;}int rst = pcap_sendpacket((pcap_t*)m_adapterHandle,data ,dat ...

  3. php中如何实现网上商城用户历史浏览记录的代码

    /如是COOKIE 里面不为空,则往里面增加一个商品ID if (!empty($_COOKIE['SHOP']['history'])){ //取得COOKIE里面的值,并用逗号把它切割成一个数组 ...

  4. android入门到熟练(一)

    1.andro系统架构:Linux内核层(提供驱动),系统运行库层和android运行时库(提供C/C++库的主要特性,如SQLite,OpenGL,Webkit等和Dalvik虚拟机),应用框架层, ...

  5. 创建对象的两种方法: new 和 面向对象(对象字面量)及对象属性访问方法

    创建对象的两种方法: new 和 面向对象(对象字面量)用 new 时:var o = new Object();o.name = "lin3615";alert(o.name); ...

  6. freeswitch 拨号时添加自定义变量

    Using Channel Variables in Dialplan Condition Statements Channel variables can be used in conditions ...

  7. CoreProfiler/NanoProfiler

    使用CoreProfiler/NanoProfiler实现跨平台&应用的整合性能调试 摘要 NanoProfiler是一个开源.NET性能调试类库,CoreProfiler是其.NET Cor ...

  8. scrollView and tableView

    As we all know, tableView is the subclass of scrollView,  tableView has every properties that scroll ...

  9. 手写js面向对象选项卡插件

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  10. python 运行 hadoop 2.0 mapreduce 程序

    要点:#!/usr/bin/python 因为要发送到各个节点,所以py文件必须是可执行的. 1) 统计(所有日志)独立ip数目,即不同ip的总数 ####################本地测试## ...