1. 程式人生 > >linux環境下編譯linux0.11核心

linux環境下編譯linux0.11核心

原部落格很老了,我並沒有編譯通過,網上大多編譯成功的是用gcc-4.3以下的版本,也有在gcc-4.6編譯成功的,折騰了幾天,這是我在網上找到的最新的資料了,

但是ubuntu源裡面最老的版本也是gcc4.7版本的,嘗試編譯低版本的gcc原始碼,但編譯不通過.

上面的連結是gcc4.6.1下編譯成功的.有興趣的可以研究一下,在更高gcc版本的編譯.

 最近在看《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

出錯原因: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 \

相關推薦

linux環境編譯linux0.11核心

原部落格很老了,我並沒有編譯通過,網上大多編譯成功的是用gcc-4.3以下的版本,也有在gcc-4.6編譯成功的,折騰了幾天,這是我在網上找到的最新的資料了, 但是ubuntu源裡面最老的版本也是gcc4.7版本的,嘗試編譯低版本的gcc原始碼,但編譯不通過. 上面的

Linux 環境編譯 0.11版本核心 kernel

原文地址:http://chfj007.blog.163.com/blog/static/173145044201132523034138/ 最近在看《linux核心0.11完全註釋》一書,由於書中涉及組合語言的地方眾多,本人在大學時組合語言學得一塌糊塗,所以實在看不下去了

ubutu14 編譯linux0.11核心

下載 linux-0.11-gdb-rh9-050619.tar.gz 程式碼,以它為藍本編譯。 1. boot/head.s:45: Error: unsupported instruction `mov' 原因: 這是因為本機系統為64位, 因此需要給所有Makefi

Linux環境編譯安裝Mysql

mysql上一篇文章介紹了手工編譯安裝Apache,這篇文章將繼續之前的文章,介紹如何編譯安裝Mysql。 - 二、 編譯安裝Mycql 1. 首先解壓mysql文件到/opt目錄。 tar zxvf /opt/lamp/mysql-5.5.24.tar.gz -C /opt/ 2.確認安裝 gcc 、

linux環境編譯運行OpenCV程序的兩種方法

https 鏈接庫 pen vco ons 程序 TP uil htm 一、命令行Command Line 1 g++ opencv_test.cpp -o opencv_test `pkg-config --cflags --libs opencv` 2 ./op

linux環境編譯C++ 程式

在linux環境下編譯C++ 程式 單個原始檔生成可執行程式 下面是一個儲存在檔案 helloworld.cpp 中一個簡單的 C++ 程式的程式碼: 單個原始檔生成可執行程式 /* helloworld.cpp */ #include <iostream> int main

linux環境編譯執行OpenCV程式的兩種方法

  原來以為在Ubuntu下安裝好了OpenCV之後,自己寫個簡單的程式應該很容易吧,但是呢,就是為了編譯一個簡單的顯示圖片的程式我都快被弄崩潰了。   在谷歌和上StackOverFlow檢視相關問題解答之後,我下面就介紹Command Line和CMake兩種方式。

linux環境編譯不成功

[[email protected] 01]$ javac -cp *.jar zxing_test/Test.java zxing_test/Test.java:12: package com.google.zxing.client.j2se does not

bochs編譯linux0.11 (轉)

/********************************************轉自:http://blog.csdn.net/s_ware/archive/2007/03/22/1537088.aspx*******************************

Linux 環境手工編譯安裝Apache

Apache手工編譯安裝Apache 實驗準備: 1.VMwore 12 環境下Red Hat 6.5版本虛擬機一臺 2.相關軟件包:apr、apr-util、httpd 備註:apache官網下載http://www.apache.org/ 將實驗所需的軟件包下載好,並解壓到指定文件夾 `` 一、Apach

Linux 環境 PHP 擴展的變異編譯與安裝

font spa mysql 所有 sqli 技術 php 操作 size (操作系統 Centos7, 已安裝 mysqli 為例) 1,進入到 PHP 解壓後的源碼包的的 ext 文件夾 2,查看是否存在 mysqli 擴展 => ls 3,這裏既是所有 PHP

Linux環境c程序的編譯和執行

環境變量 動態 main.c tor direct 環境 沒有 stdlib.h share 1 單個文件的編譯和執行創建main.c文件,內容如下: #include <stdio.h> #include <stdlib.h> int main

linux環境編譯apk

kali linux apktool apktool d -f xxx.apk -o xxx 反編譯後生成的檔案目錄 名稱 存放內容 assets (未被編譯)專案的assets資料夾

Linux環境c程式的編譯和執行

1 單個檔案的編譯和執行建立main.c檔案,內容如下: #include <stdio.h> #include <stdlib.h> int main(void){ printf("Hello world!\n"); return 0; };   編譯:

LINUX編譯c++11的程式碼

 C++11,(即ISO/IEC 14882:2011),是目前的C++程式語言的最新正式標準。它取代了第二版標準(第一版公開於1998年,第二版於2003年更新,分別通稱C++98以及C++03,兩者差異很小)。新的標準包含核心語言的新機能,而且擴充套件C++標準程式庫。C++11新標準

交叉編譯arm Linux環境的android-tools-adb

前言     專案使用Rockchip的3399挖掘機demo板,使用官方提供的Debian Linux SDK(官方github原始碼連結:https://github.com/rockchip-linux)進行開發定製。當前需要將Android上的除錯工具adb移

Linux環境如何編譯和執行c程式

1 單個檔案的編譯和執行 建立main.c檔案,內容如下:  編譯: 執行: 2 多個檔案的編譯和執行建立sum.c檔案,內容如下: 建立main.c檔案,內容如下:   編譯:    生成可執行檔案,檔名為main: 執行程式:

Linux環境如何編譯和執行c程序

文件的 ron 當前 cto directory 變量 沒有 執行文件 nbsp 1 單個文件的編譯和執行 創建main.c文件,內容如下: 編譯: 執行: 2 多個文件的編譯和執行創建sum.c文件,內容如下: 創建main.c文件,內容如下: 編譯:

語言程式的編譯、連結具體過程及Linux環境的具體例項

我們知道一個C語言程式從編寫完成到生成可執行檔案分為預處理、編譯、彙編、連結,最後再生成可執行檔案。 預處理階段 前處理器主要做四部分工作,分別是:標頭檔案展開、巨集替換、去註釋以及條件編譯。 (1)標頭檔案展開就是編譯器會根據字元#開頭的命令去讀取相應的系統檔案或者自定義檔案, 並把相應的

Linux環境使用VSCode編譯makefile檔案的注意事項

Linux環境下使用VSCode編譯makefile檔案的注意事項 首先安裝C/C++的兩個依賴   在debug,launch會自動的生成下方的launch.json     launch.json { // Use IntelliSense to l